diff --git a/CHANGELOG.md b/CHANGELOG.md index 95fd5e15..f79251ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.2.3 + +* Android fixes to make it work on some devices when installed via Play Store. + ## 0.2.2 * Exclude `x86` from supported ABIs. diff --git a/android/build.gradle b/android/build.gradle index b314283a..65688149 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,5 +1,5 @@ group 'com.flet.serious_python' -version '0.2.2' +version '0.2.3' buildscript { repositories { diff --git a/example/flask_example/README.md b/example/flask_example/README.md index e141cb30..96ad665c 100644 --- a/example/flask_example/README.md +++ b/example/flask_example/README.md @@ -1,16 +1,14 @@ # flask_example -A new Flutter project. +Important: to make `serious_python` work in your own Android app: -## Getting Started +If you build an App Bundle Edit `android/gradle.properties` and add the flag: -This project is a starting point for a Flutter application. +``` +android.bundle.enableUncompressedNativeLibs=false +``` -A few resources to get you started if this is your first Flutter project: -- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) +If you build an APK Make sure `android/app/src/AndroidManifest.xml` has `android:extractNativeLibs="true"` in the `` tag. -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference. +For more information, see the [public issue](https://issuetracker.google.com/issues/147096055). \ No newline at end of file diff --git a/example/flask_example/android/app/src/main/AndroidManifest.xml b/example/flask_example/android/app/src/main/AndroidManifest.xml index 0a7f2d7e..ea56d134 100644 --- a/example/flask_example/android/app/src/main/AndroidManifest.xml +++ b/example/flask_example/android/app/src/main/AndroidManifest.xml @@ -2,7 +2,8 @@ + android:icon="@mipmap/ic_launcher" + android:extractNativeLibs="true"> ` tag. -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference. +For more information, see the [public issue](https://issuetracker.google.com/issues/147096055). \ No newline at end of file diff --git a/example/flet_example/android/app/src/main/AndroidManifest.xml b/example/flet_example/android/app/src/main/AndroidManifest.xml index 85a078a0..50dfe3ab 100644 --- a/example/flet_example/android/app/src/main/AndroidManifest.xml +++ b/example/flet_example/android/app/src/main/AndroidManifest.xml @@ -2,7 +2,8 @@ + android:icon="@mipmap/ic_launcher" + android:extractNativeLibs="true"> ('getNativeLibraryDir'); debugPrint("getNativeLibraryDir: $nativeLibraryDir"); - var pythonLibPath = await extractFileZip( - "$nativeLibraryDir/libpythonbundle.so", - targetPath: "python_bundle"); + var bundlePath = "$nativeLibraryDir/libpythonbundle.so"; + + if (!await File(bundlePath).exists()) { + throw Exception("Python bundle not found: $bundlePath"); + } + + var pythonLibPath = + await extractFileZip(bundlePath, targetPath: "python_bundle"); debugPrint("pythonLibPath: $pythonLibPath"); @@ -60,8 +65,11 @@ class SeriousPythonAndroid extends SeriousPythonPlatform { receivePort.close(); isolate.kill(); - var r2 = File("$pythonLibPath/out.txt").readAsStringSync(); - debugPrint("Result out.txt: $r2"); + var out = File("out.txt"); + if (out.existsSync()) { + var r = out.readAsStringSync(); + debugPrint("Result from out.txt: $r"); + } }); } else { // sync run @@ -121,7 +129,16 @@ void runPythonProgram(List arguments) async { var programDirPath = p.dirname(pythonProgramPath); var programModuleName = p.basenameWithoutExtension(pythonProgramPath); - var loadLynamicLibraries = [ + var programDirPathFiles = await getDirFiles(programDirPath); + var pythonLibPathFiles = await getDirFiles(pythonLibPath); + + debugPrint("programDirPath: $programDirPath"); + debugPrint("programModuleName: $programModuleName"); + debugPrint("pythonLibPath: $pythonLibPath"); + debugPrint("programDirPathFiles: $programDirPathFiles"); + debugPrint("pythonLibPathFiles: $pythonLibPathFiles"); + + var loadDynamicLibraries = [ "libffi.so", "libcrypto1.1.so", "libsqlite3.so", @@ -138,13 +155,8 @@ void runPythonProgram(List arguments) async { "$pythonLibPath/stdlib.zip" ]; - var currentDir = pythonLibPath; - - // set current dir - Directory.current = currentDir; - // load dynamic libraries - for (var loadDynamicLibrary in loadLynamicLibraries) { + for (var loadDynamicLibrary in loadDynamicLibraries) { DynamicLibrary.open(loadDynamicLibrary); } @@ -208,7 +220,18 @@ void runPythonProgram(List arguments) async { // run user program final moduleNamePtr = programModuleName.toNativeUtf8(); - cpython.PyImport_ImportModule(moduleNamePtr.cast()); + var modulePtr = cpython.PyImport_ImportModule(moduleNamePtr.cast()); + if (modulePtr == nullptr) { + final pType = + calloc.allocate>(sizeOf>()); + final pValue = + calloc.allocate>(sizeOf>()); + final pTrace = + calloc.allocate>(sizeOf>()); + cpython.PyErr_Fetch(pType, pValue, pTrace); + cpython.PyErr_NormalizeException(pType, pValue, pTrace); + cpython.PyErr_Display(pType.value, pValue.value, pTrace.value); + } // final pythonCodePtr = pythonCode.toNativeUtf8(); // int r = dartpyc.PyRun_SimpleString(pythonCodePtr.cast()); // debugPrint("PyRun_SimpleString result: $r"); @@ -218,3 +241,13 @@ void runPythonProgram(List arguments) async { debugPrint("after Py_Finalize"); sendPort.send("Python program exited"); } + +Future getDirFiles(String path, {bool recursive = false}) async { + final dir = Directory(path); + if (!await dir.exists()) { + return ""; + } + return (await dir.list(recursive: recursive).toList()) + .map((file) => file.path) + .join('\n'); +} diff --git a/lib/src/utils.dart b/lib/src/utils.dart index 1d43d9f4..a1185bd4 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -30,11 +30,17 @@ Future extractAssetOrFile(String path, // unpack from asset or file debugPrint("Start unpacking app archive"); List data; - if (isAsset) { - final bytes = await rootBundle.load(path); - data = bytes.buffer.asUint8List(); - } else { - data = await File(path).readAsBytes(); + + try { + if (isAsset) { + final bytes = await rootBundle.load(path); + data = bytes.buffer.asUint8List(); + } else { + data = await File(path).readAsBytes(); + } + } catch (_) { + await destDir.delete(recursive: true); + rethrow; } Archive archive = ZipDecoder().decodeBytes(data); diff --git a/pubspec.yaml b/pubspec.yaml index ce0e513c..b8e2467d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: serious_python description: A cross-platform plugin for adding embedded Python runtime to your Flutter apps. homepage: https://flet.dev repository: https://github.com/flet-dev/serious-python -version: 0.2.2 +version: 0.2.3 platforms: ios: