android: Complete support for android:extractNativeLibs=false
This is the non-legacy way to ship native libraries nowadays, leaving them in the .apk so that there doesn't need to be an extraction step and the app takes up less space.
This commit is contained in:
parent
598106c6dd
commit
e809c9eb92
|
|
@ -114,7 +114,7 @@ ignoreImports = {
|
|||
'toml.encoder': ['numpy'],
|
||||
'py._builtin': ['__builtin__'],
|
||||
|
||||
'site': ['android_log'],
|
||||
'site': ['android_support'],
|
||||
}
|
||||
|
||||
if sys.version_info >= (3, 8):
|
||||
|
|
|
|||
|
|
@ -192,14 +192,14 @@ SITE_PY_ANDROID = """
|
|||
# module.
|
||||
import sys, os
|
||||
from importlib import _bootstrap, _bootstrap_external
|
||||
from android_support import log_write as android_log_write
|
||||
from android_support import find_library
|
||||
|
||||
class AndroidExtensionFinder:
|
||||
@classmethod
|
||||
def find_spec(cls, fullname, path=None, target=None):
|
||||
soname = 'libpy.' + fullname + '.so'
|
||||
path = os.path.join(sys.platlibdir, soname)
|
||||
|
||||
if os.path.exists(path):
|
||||
path = find_library('py.' + fullname)
|
||||
if path:
|
||||
loader = _bootstrap_external.ExtensionFileLoader(fullname, path)
|
||||
return _bootstrap.ModuleSpec(fullname, loader, origin=path)
|
||||
|
||||
|
|
@ -210,8 +210,6 @@ sys.meta_path.append(AndroidExtensionFinder)
|
|||
from _frozen_importlib import _imp, FrozenImporter
|
||||
from io import RawIOBase, TextIOWrapper
|
||||
|
||||
from android_log import write as android_log_write
|
||||
|
||||
|
||||
sys.frozen = True
|
||||
|
||||
|
|
@ -869,7 +867,7 @@ class build_apps(setuptools.Command):
|
|||
if category:
|
||||
application.set('android:appCategory', category)
|
||||
application.set('android:debuggable', ('false', 'true')[self.android_debuggable])
|
||||
application.set('android:extractNativeLibs', 'true')
|
||||
application.set('android:extractNativeLibs', 'false')
|
||||
application.set('android:hardwareAccelerated', 'true')
|
||||
|
||||
app_icon = self.icon_objects.get('*', self.icon_objects.get(self.macos_main_app))
|
||||
|
|
|
|||
|
|
@ -232,10 +232,10 @@ def create_aab(command, basename, build_dir):
|
|||
config.optimizations.splits_config.Clear()
|
||||
if axml.extract_native_libs:
|
||||
config.optimizations.uncompress_native_libraries.enabled = False
|
||||
config.optimizations.uncompress_native_libraries.alignment = \
|
||||
UncompressNativeLibraries.PageAlignment.PAGE_ALIGNMENT_16K
|
||||
else:
|
||||
config.optimizations.uncompress_native_libraries.enabled = True
|
||||
config.optimizations.uncompress_native_libraries.alignment = \
|
||||
UncompressNativeLibraries.PageAlignment.PAGE_ALIGNMENT_16K
|
||||
config.compression.uncompressed_glob.append('res/raw/**')
|
||||
bundle.add_subfile('BundleConfig.pb', p3d.StringStream(config.SerializeToString()), 9)
|
||||
|
||||
|
|
|
|||
|
|
@ -19,11 +19,15 @@ using std::string;
|
|||
static Filename resolve_dso(const DSearchPath &path, const Filename &filename) {
|
||||
if (filename.is_local()) {
|
||||
if ((path.get_num_directories()==1)&&(path.get_directory(0)=="<auto>")) {
|
||||
#ifdef ANDROID
|
||||
return filename;
|
||||
#else
|
||||
// This is a special case, meaning to search in the same directory in
|
||||
// which libp3dtool.dll, or the exe, was started from.
|
||||
Filename dtoolpath = ExecutionEnvironment::get_dtool_name();
|
||||
DSearchPath spath(dtoolpath.get_dirname());
|
||||
return spath.find_file(filename);
|
||||
#endif
|
||||
} else {
|
||||
return path.find_file(filename);
|
||||
}
|
||||
|
|
@ -119,7 +123,13 @@ get_dso_symbol(void *handle, const string &name) {
|
|||
void *
|
||||
load_dso(const DSearchPath &path, const Filename &filename) {
|
||||
Filename abspath = resolve_dso(path, filename);
|
||||
#ifdef ANDROID
|
||||
// We just try to load it on Android, because we can't verify right now
|
||||
// whether it might just be an unextracted library.
|
||||
if (abspath.empty()) {
|
||||
#else
|
||||
if (!abspath.is_regular_file()) {
|
||||
#endif
|
||||
// Make sure the error flag is cleared, to prevent a subsequent call to
|
||||
// load_dso_error() from returning a previously stored error.
|
||||
dlerror();
|
||||
|
|
|
|||
|
|
@ -5967,10 +5967,10 @@ if PkgSkip("PYTHON") == 0:
|
|||
TargetAdd('classes.dex', input='org/jnius/NativeInvocationHandler.class')
|
||||
|
||||
PyTargetAdd('deploy-stubw_android_main.obj', opts=OPTS, input='android_main.cxx')
|
||||
PyTargetAdd('deploy-stubw_android_log.obj', opts=OPTS, input='android_log.c')
|
||||
PyTargetAdd('deploy-stubw_android_support.obj', opts=OPTS, input='android_support.cxx')
|
||||
PyTargetAdd('libdeploy-stubw.dll', input='android_native_app_glue.obj')
|
||||
PyTargetAdd('libdeploy-stubw.dll', input='deploy-stubw_android_main.obj')
|
||||
PyTargetAdd('libdeploy-stubw.dll', input='deploy-stubw_android_log.obj')
|
||||
PyTargetAdd('libdeploy-stubw.dll', input='deploy-stubw_android_support.obj')
|
||||
PyTargetAdd('libdeploy-stubw.dll', input=COMMON_PANDA_LIBS)
|
||||
PyTargetAdd('libdeploy-stubw.dll', input='libp3android.dll')
|
||||
PyTargetAdd('libdeploy-stubw.dll', opts=['DEPLOYSTUB', 'ANDROID'])
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ public class PandaActivity extends NativeActivity {
|
|||
/**
|
||||
* Returns the path to some other native library.
|
||||
*/
|
||||
public String findLibraryPath(String libname) {
|
||||
public String findLibrary(String libname) {
|
||||
BaseDexClassLoader classLoader = (BaseDexClassLoader)getClassLoader();
|
||||
return classLoader.findLibrary(libname);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ jmethodID jni_PandaActivity_readBitmap;
|
|||
jmethodID jni_PandaActivity_createBitmap;
|
||||
jmethodID jni_PandaActivity_compressBitmap;
|
||||
jmethodID jni_PandaActivity_showToast;
|
||||
jmethodID jni_PandaActivity_findLibrary;
|
||||
|
||||
jclass jni_Activity;
|
||||
jmethodID jni_Activity_setTitle;
|
||||
|
|
@ -83,6 +84,9 @@ jint JNI_OnLoad(JavaVM *jvm, void *reserved) {
|
|||
jni_PandaActivity_showToast = env->GetMethodID(jni_PandaActivity,
|
||||
"showToast", "(Ljava/lang/String;I)V");
|
||||
|
||||
jni_PandaActivity_findLibrary = env->GetMethodID(jni_PandaActivity,
|
||||
"findLibrary", "(Ljava/lang/String;)Ljava/lang/String;");
|
||||
|
||||
jni_Activity = env->FindClass("android/app/Activity");
|
||||
jni_Activity = (jclass) env->NewGlobalRef(jni_Activity);
|
||||
jni_Activity_setTitle = env->GetMethodID(jni_Activity,
|
||||
|
|
@ -144,6 +148,28 @@ void JNI_OnUnload(JavaVM *jvm, void *reserved) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
Filename android_find_library(ANativeActivity *activity, const std::string &lib) {
|
||||
Thread *thread = Thread::get_current_thread();
|
||||
JNIEnv *env = thread->get_jni_env();
|
||||
nassertr(env != nullptr, Filename());
|
||||
|
||||
jstring jlib = env->NewStringUTF(lib.c_str());
|
||||
jstring jresult = (jstring)env->CallObjectMethod(activity->clazz, jni_PandaActivity_findLibrary, jlib);
|
||||
env->DeleteLocalRef(jlib);
|
||||
|
||||
Filename result;
|
||||
if (jresult != nullptr) {
|
||||
const char *c_str = env->GetStringUTFChars(jresult, nullptr);
|
||||
result = c_str;
|
||||
env->ReleaseStringUTFChars(jresult, c_str);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the window title of the activity.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ extern jclass jni_BitmapFactory_Options;
|
|||
extern jfieldID jni_BitmapFactory_Options_outWidth;
|
||||
extern jfieldID jni_BitmapFactory_Options_outHeight;
|
||||
|
||||
EXPORT_CLASS Filename android_find_library(ANativeActivity *activity, const std::string &lib);
|
||||
EXPORT_CLASS void android_set_title(ANativeActivity *activity, const std::string &title);
|
||||
EXPORT_CLASS void android_show_toast(ANativeActivity *activity, const std::string &message, int duration);
|
||||
|
||||
|
|
|
|||
|
|
@ -50,8 +50,8 @@ extern "C" {
|
|||
} blobinfo = {(uint64_t)-1};
|
||||
}
|
||||
|
||||
// Defined in android_log.c
|
||||
extern "C" PyObject *PyInit_android_log();
|
||||
// Defined in android_support.cxx
|
||||
extern "C" PyObject *PyInit_android_support();
|
||||
|
||||
/**
|
||||
* Maps the binary blob at the given memory address to memory, and returns the
|
||||
|
|
@ -250,7 +250,7 @@ void android_main(struct android_app *app) {
|
|||
if (dst_moddef->code != nullptr) {
|
||||
dst_moddef->code = (unsigned char *)((uintptr_t)dst_moddef->code + (uintptr_t)blob);
|
||||
}
|
||||
__android_log_print(ANDROID_LOG_DEBUG, "Panda3D", "MOD: %s %p %d\n", dst_moddef->name, (void*)dst_moddef->code, dst_moddef->size);
|
||||
//__android_log_print(ANDROID_LOG_DEBUG, "Panda3D", "MOD: %s %p %d\n", dst_moddef->name, (void*)dst_moddef->code, dst_moddef->size);
|
||||
dst_moddef++;
|
||||
}
|
||||
PyImport_FrozenModules = new_modules;
|
||||
|
|
@ -265,10 +265,10 @@ void android_main(struct android_app *app) {
|
|||
return;
|
||||
}
|
||||
|
||||
// Register the android_log module.
|
||||
if (PyImport_AppendInittab("android_log", &PyInit_android_log) < 0) {
|
||||
// Register the android_support module.
|
||||
if (PyImport_AppendInittab("android_support", &PyInit_android_support) < 0) {
|
||||
android_cat.error()
|
||||
<< "Failed to register android_log module.\n";
|
||||
<< "Failed to register android_support module.\n";
|
||||
env->ReleaseStringUTFChars(libdir_jstr, libdir);
|
||||
return;
|
||||
}
|
||||
|
|
@ -279,6 +279,7 @@ void android_main(struct android_app *app) {
|
|||
config.buffered_stdio = 0;
|
||||
config.configure_c_stdio = 0;
|
||||
config.write_bytecode = 0;
|
||||
config.module_search_paths_set = 1; // Leave sys.path empty
|
||||
PyConfig_SetBytesString(&config, &config.platlibdir, libdir);
|
||||
env->ReleaseStringUTFChars(libdir_jstr, libdir);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
* license. You should have received a copy of this license along
|
||||
* with this source code in a file named "LICENSE."
|
||||
*
|
||||
* @file android_log.c
|
||||
* @file android_support.c
|
||||
* @author rdb
|
||||
* @date 2021-12-10
|
||||
*/
|
||||
|
|
@ -17,12 +17,14 @@
|
|||
|
||||
#include "Python.h"
|
||||
#include <android/log.h>
|
||||
#include "android_native_app_glue.h"
|
||||
#include "config_android.h"
|
||||
|
||||
/**
|
||||
* Writes a message to the Android log.
|
||||
*/
|
||||
static PyObject *
|
||||
_py_write(PyObject *self, PyObject *args) {
|
||||
_py_log_write(PyObject *self, PyObject *args) {
|
||||
int prio;
|
||||
char *tag;
|
||||
char *text;
|
||||
|
|
@ -33,14 +35,32 @@ _py_write(PyObject *self, PyObject *args) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path to a library, if it can be found.
|
||||
*/
|
||||
static PyObject *
|
||||
_py_find_library(PyObject *self, PyObject *args) {
|
||||
char *lib;
|
||||
if (PyArg_ParseTuple(args, "s", &lib)) {
|
||||
Filename result = android_find_library(panda_android_app->activity, lib);
|
||||
if (!result.empty()) {
|
||||
return PyUnicode_FromStringAndSize(result.c_str(), (Py_ssize_t)result.length());
|
||||
} else {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyMethodDef python_simple_funcs[] = {
|
||||
{ "write", &_py_write, METH_VARARGS },
|
||||
{ "log_write", &_py_log_write, METH_VARARGS },
|
||||
{ "find_library", &_py_find_library, METH_VARARGS },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static struct PyModuleDef android_log_module = {
|
||||
static struct PyModuleDef android_support_module = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"android_log",
|
||||
"android_support",
|
||||
NULL,
|
||||
-1,
|
||||
python_simple_funcs,
|
||||
|
|
@ -48,6 +68,6 @@ static struct PyModuleDef android_log_module = {
|
|||
};
|
||||
|
||||
__attribute__((visibility("default")))
|
||||
PyObject *PyInit_android_log() {
|
||||
return PyModule_Create(&android_log_module);
|
||||
extern "C" PyObject *PyInit_android_support() {
|
||||
return PyModule_Create(&android_support_module);
|
||||
}
|
||||
Loading…
Reference in New Issue