Skip to content

Bootstrap backend for Android Library project #1963

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions pythonforandroid/bootstraps/common/build/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ def compile_dir(dfn, optimize_python=True):
def make_package(args):
# If no launcher is specified, require a main.py/main.pyo:
if (get_bootstrap_name() != "sdl" or args.launcher is None) and \
get_bootstrap_name() != "webview":
get_bootstrap_name() not in ["webview", "library"]:
# (webview doesn't need an entrypoint, apparently)
if args.private is None or (
not exists(join(realpath(args.private), 'main.py')) and
Expand Down Expand Up @@ -509,8 +509,9 @@ def make_package(args):
aars=aars,
jars=jars,
android_api=android_api,
build_tools_version=build_tools_version
)
build_tools_version=build_tools_version,
is_library=get_bootstrap_name() == 'library',
)

# ant build templates
render(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ allprojects {
}
}

{% if is_library %}
apply plugin: 'com.android.library'
{% else %}
apply plugin: 'com.android.application'
{% endif %}

android {
compileSdkVersion {{ android_api }}
Expand Down
9 changes: 9 additions & 0 deletions pythonforandroid/bootstraps/library/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from pythonforandroid.bootstraps.service_only import ServiceOnlyBootstrap


class LibraryBootstrap(ServiceOnlyBootstrap):

name = 'library'


bootstrap = LibraryBootstrap()
89 changes: 89 additions & 0 deletions pythonforandroid/bootstraps/library/build/blacklist.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# prevent user to include invalid extensions
*.apk
*.pxd

# eggs
*.egg-info

# unit test
unittest/*

# python config
config/makesetup

# unused kivy files (platform specific)
kivy/input/providers/wm_*
kivy/input/providers/mactouch*
kivy/input/providers/probesysfs*
kivy/input/providers/mtdev*
kivy/input/providers/hidinput*
kivy/core/camera/camera_videocapture*
kivy/core/spelling/*osx*
kivy/core/video/video_pyglet*
kivy/tools
kivy/tests/*
kivy/*/*.h
kivy/*/*.pxi

# unused encodings
lib-dynload/*codec*
encodings/cp*.pyo
encodings/tis*
encodings/shift*
encodings/bz2*
encodings/iso*
encodings/undefined*
encodings/johab*
encodings/p*
encodings/m*
encodings/euc*
encodings/k*
encodings/unicode_internal*
encodings/quo*
encodings/gb*
encodings/big5*
encodings/hp*
encodings/hz*

# unused python modules
bsddb/*
wsgiref/*
hotshot/*
pydoc_data/*
tty.pyo
anydbm.pyo
nturl2path.pyo
LICENCE.txt
macurl2path.pyo
dummy_threading.pyo
audiodev.pyo
antigravity.pyo
dumbdbm.pyo
sndhdr.pyo
__phello__.foo.pyo
sunaudio.pyo
os2emxpath.pyo
multiprocessing/dummy*

# unused binaries python modules
lib-dynload/termios.so
lib-dynload/_lsprof.so
lib-dynload/*audioop.so
lib-dynload/_hotshot.so
lib-dynload/_heapq.so
lib-dynload/_json.so
lib-dynload/grp.so
lib-dynload/resource.so
lib-dynload/pyexpat.so
lib-dynload/_ctypes_test.so
lib-dynload/_testcapi.so

# odd files
plat-linux3/regen

#>sqlite3
# conditionnal include depending if some recipes are included or not.
sqlite3/*
lib-dynload/_sqlite3.so
#<sqlite3

1 change: 1 addition & 0 deletions pythonforandroid/bootstraps/library/build/jni/Android.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include $(call all-subdir-makefiles)
7 changes: 7 additions & 0 deletions pythonforandroid/bootstraps/library/build/jni/Application.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

# Uncomment this if you're using STL in your project
# See CPLUSPLUS-SUPPORT.html in the NDK documentation for more information
# APP_STL := stlport_static

# APP_ABI := armeabi armeabi-v7a x86
APP_ABI := $(ARCH)
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := main

# Add your application source files here...
LOCAL_SRC_FILES := start.c pyjniusjni.c

LOCAL_CFLAGS += -I$(PYTHON_INCLUDE_ROOT) $(EXTRA_CFLAGS)

LOCAL_SHARED_LIBRARIES := python_shared

LOCAL_LDLIBS := -llog $(EXTRA_LDLIBS)

LOCAL_LDFLAGS += -L$(PYTHON_LINK_ROOT) $(APPLICATION_ADDITIONAL_LDFLAGS)

include $(BUILD_SHARED_LIBRARY)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := main

LOCAL_SRC_FILES := YourSourceHere.c

include $(BUILD_SHARED_LIBRARY)
$(call import-module,SDL)LOCAL_PATH := $(call my-dir)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

#define BOOTSTRAP_NAME_LIBRARY
#define BOOTSTRAP_USES_NO_SDL_HEADERS

const char bootstrap_name[] = "library";

Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@

#include <pthread.h>
#include <jni.h>

#define LOGI(...) do {} while (0)
#define LOGE(...) do {} while (0)

#include "android/log.h"

/* These JNI management functions are taken from SDL2, but modified to refer to pyjnius */

/* #define LOG(n, x) __android_log_write(ANDROID_LOG_INFO, (n), (x)) */
/* #define LOGP(x) LOG("python", (x)) */
#define LOG_TAG "Python_android"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)


/* Function headers */
JNIEnv* Android_JNI_GetEnv(void);
static void Android_JNI_ThreadDestroyed(void*);

static pthread_key_t mThreadKey;
static JavaVM* mJavaVM;

int Android_JNI_SetupThread(void)
{
Android_JNI_GetEnv();
return 1;
}

/* Library init */
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
{
JNIEnv *env;
mJavaVM = vm;
LOGI("JNI_OnLoad called");
if ((*mJavaVM)->GetEnv(mJavaVM, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
LOGE("Failed to get the environment using GetEnv()");
return -1;
}
/*
* Create mThreadKey so we can keep track of the JNIEnv assigned to each thread
* Refer to http://developer.android.com/guide/practices/design/jni.html for the rationale behind this
*/
if (pthread_key_create(&mThreadKey, Android_JNI_ThreadDestroyed) != 0) {

__android_log_print(ANDROID_LOG_ERROR, "pyjniusjni", "Error initializing pthread key");
}
Android_JNI_SetupThread();

return JNI_VERSION_1_4;
}

JNIEnv* Android_JNI_GetEnv(void)
{
/* From http://developer.android.com/guide/practices/jni.html
* All threads are Linux threads, scheduled by the kernel.
* They're usually started from managed code (using Thread.start), but they can also be created elsewhere and then
* attached to the JavaVM. For example, a thread started with pthread_create can be attached with the
* JNI AttachCurrentThread or AttachCurrentThreadAsDaemon functions. Until a thread is attached, it has no JNIEnv,
* and cannot make JNI calls.
* Attaching a natively-created thread causes a java.lang.Thread object to be constructed and added to the "main"
* ThreadGroup, making it visible to the debugger. Calling AttachCurrentThread on an already-attached thread
* is a no-op.
* Note: You can call this function any number of times for the same thread, there's no harm in it
*/

JNIEnv *env;
int status = (*mJavaVM)->AttachCurrentThread(mJavaVM, &env, NULL);
if(status < 0) {
LOGE("failed to attach current thread");
return 0;
}

/* From http://developer.android.com/guide/practices/jni.html
* Threads attached through JNI must call DetachCurrentThread before they exit. If coding this directly is awkward,
* in Android 2.0 (Eclair) and higher you can use pthread_key_create to define a destructor function that will be
* called before the thread exits, and call DetachCurrentThread from there. (Use that key with pthread_setspecific
* to store the JNIEnv in thread-local-storage; that way it'll be passed into your destructor as the argument.)
* Note: The destructor is not called unless the stored value is != NULL
* Note: You can call this function any number of times for the same thread, there's no harm in it
* (except for some lost CPU cycles)
*/
pthread_setspecific(mThreadKey, (void*) env);

return env;
}

static void Android_JNI_ThreadDestroyed(void* value)
{
/* The thread is being destroyed, detach it from the Java VM and set the mThreadKey value to NULL as required */
JNIEnv *env = (JNIEnv*) value;
if (env != NULL) {
(*mJavaVM)->DetachCurrentThread(mJavaVM);
pthread_setspecific(mThreadKey, NULL);
}
}

void *WebView_AndroidGetJNIEnv()
{
return Android_JNI_GetEnv();
}
Empty file.
Loading