pythonnative 0.36.0__py3-none-any.whl → 0.37.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pythonnative/__init__.py +6 -4
- pythonnative/_ios_log.py +1 -1
- pythonnative/alerts.py +34 -88
- pythonnative/bootstrap.py +90 -0
- pythonnative/bridge/__init__.py +306 -0
- pythonnative/bridge/android.py +78 -0
- pythonnative/bridge/codec.py +164 -0
- pythonnative/bridge/fake.py +236 -0
- pythonnative/bridge/ios.py +138 -0
- pythonnative/components/layout.py +65 -3
- pythonnative/gestures.py +13 -10
- pythonnative/hooks.py +41 -26
- pythonnative/hosts/__init__.py +13 -36
- pythonnative/hosts/native.py +348 -0
- pythonnative/images.py +6 -5
- pythonnative/native_modules/__init__.py +30 -29
- pythonnative/native_modules/app_state.py +10 -6
- pythonnative/native_modules/battery.py +20 -84
- pythonnative/native_modules/biometrics.py +11 -124
- pythonnative/native_modules/camera.py +15 -291
- pythonnative/native_modules/clipboard.py +14 -109
- pythonnative/native_modules/desktop.py +322 -0
- pythonnative/native_modules/file_system.py +15 -21
- pythonnative/native_modules/haptics.py +19 -129
- pythonnative/native_modules/linking.py +24 -137
- pythonnative/native_modules/location.py +28 -180
- pythonnative/native_modules/net_info.py +25 -135
- pythonnative/native_modules/notifications.py +36 -257
- pythonnative/native_modules/permissions.py +20 -184
- pythonnative/native_modules/registry.py +513 -0
- pythonnative/native_modules/secure_store.py +18 -155
- pythonnative/native_modules/share.py +8 -113
- pythonnative/native_views/__init__.py +67 -86
- pythonnative/native_views/bridge_backend.py +264 -0
- pythonnative/platform.py +19 -15
- pythonnative/platform_metrics.py +3 -3
- pythonnative/project/android.py +0 -3
- pythonnative/project/builder.py +38 -16
- pythonnative/project/config.py +12 -2
- pythonnative/project/plugins.py +366 -0
- pythonnative/py.typed +0 -0
- pythonnative/runtime.py +35 -203
- pythonnative/sdk/__init__.py +48 -33
- pythonnative/sdk/_components.py +57 -76
- pythonnative/storage.py +18 -243
- pythonnative/templates/android_template/app/build.gradle +6 -9
- pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/MainActivity.kt +34 -166
- pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/ScreenFragment.kt +13 -151
- pythonnative/templates/android_template/pythonnative/build.gradle +48 -0
- pythonnative/templates/android_template/pythonnative/src/main/AndroidManifest.xml +11 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/PNBridge.kt +214 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/PythonHost.kt +20 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/animation/AnimationSpecs.kt +141 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/animation/PNAnimator.kt +249 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/bridge/JsonUtil.kt +175 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/bridge/MainThread.kt +32 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/bridge/PNLog.kt +33 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/bridge/PNRegistry.kt +82 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/bridge/PNTransaction.kt +80 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/bridge/TransactionApplier.kt +115 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/bridge/ViewRegistry.kt +74 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/BuiltinComponents.kt +35 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ButtonManager.kt +33 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ComponentManager.kt +213 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ContainerManagers.kt +69 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ControlManagers.kt +186 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/DatePickerManager.kt +123 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ImageLoader.kt +141 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ImageManager.kt +156 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ModalManager.kt +134 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/PNColor.kt +201 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/PickerManager.kt +87 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/PortalManager.kt +55 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/PressableManager.kt +122 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ScrollViewManager.kt +214 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/SegmentedControlManager.kt +113 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/StatusBarManager.kt +52 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/TabBarManager.kt +131 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/TextInputManager.kt +245 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/TextManager.kt +233 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ViewStyler.kt +355 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/VirtualListManager.kt +179 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/WebViewManager.kt +149 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/gestures/GestureArbiter.kt +233 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/gestures/GestureCoordinator.kt +127 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/gestures/GestureRecognizers.kt +527 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/BuiltinModules.kt +73 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/DeviceModules.kt +316 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/HostModule.kt +97 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/MediaModules.kt +200 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/NativeModule.kt +135 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/NotificationsModule.kt +100 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/PermissionsModule.kt +88 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/StorageModules.kt +89 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/SystemModules.kt +178 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/plugins/GeneratedPlugins.kt +16 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/screens/Navigator.kt +116 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/screens/PNScreenFragment.kt +223 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/screens/ScreenRegistry.kt +80 -0
- pythonnative/templates/android_template/{app/src/main/java/com/pythonnative/android_template → pythonnative/src/main/java/com/pythonnative/runtime/views}/PNAccessibilityDelegate.kt +5 -4
- pythonnative/templates/android_template/{app/src/main/java/com/pythonnative/android_template → pythonnative/src/main/java/com/pythonnative/runtime/views}/PNBorderDrawable.kt +12 -3
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/views/PNEditText.kt +18 -0
- pythonnative/templates/android_template/{app/src/main/java/com/pythonnative/android_template → pythonnative/src/main/java/com/pythonnative/runtime/views}/PNFrameLayout.kt +9 -10
- pythonnative/templates/android_template/{app/src/main/java/com/pythonnative/android_template → pythonnative/src/main/java/com/pythonnative/runtime/views}/PNVirtualListView.java +9 -12
- pythonnative/templates/android_template/pythonnative/src/test/java/com/pythonnative/runtime/AnimationSpecsTest.kt +75 -0
- pythonnative/templates/android_template/pythonnative/src/test/java/com/pythonnative/runtime/GestureArbiterTest.kt +197 -0
- pythonnative/templates/android_template/pythonnative/src/test/java/com/pythonnative/runtime/PNColorTest.kt +47 -0
- pythonnative/templates/android_template/pythonnative/src/test/java/com/pythonnative/runtime/PNTransactionTest.kt +78 -0
- pythonnative/templates/android_template/pythonnative/src/test/java/com/pythonnative/runtime/PromiseTest.kt +75 -0
- pythonnative/templates/android_template/settings.gradle +1 -0
- pythonnative/templates/ios_template/PythonNativeKit/Package.swift +21 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Animation/PNAnimator.swift +301 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Bridge/PNBridge.swift +191 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Bridge/PNRegistry.swift +140 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Bridge/PNTransaction.swift +165 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Bridge/PNViewRegistry.swift +53 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNButtonManagers.swift +206 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNColor.swift +173 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNComponentManager.swift +183 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNContainerView.swift +56 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNControlManagers.swift +281 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNImageManager.swift +221 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNOverlayManagers.swift +243 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNPressableManager.swift +114 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNScrollViewManager.swift +197 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNTabBarManager.swift +106 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNTextInputManager.swift +289 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNTextManager.swift +230 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNTransform.swift +82 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNViewManager.swift +86 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNViewState.swift +87 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNViewStyler.swift +340 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNVirtualListManager.swift +257 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNWebViewManager.swift +124 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Gestures/PNGestureCoordinator.swift +260 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Modules/AlertModule.swift +92 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Modules/HostModule.swift +158 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Modules/LifecycleModules.swift +174 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Modules/MediaModules.swift +177 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Modules/PNNativeModule.swift +125 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Modules/PermissionModules.swift +251 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Modules/SystemModules.swift +251 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Plugins/PNPluginRegistration.swift +8 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Screens/PNScreenRegistry.swift +46 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Screens/PNViewController.swift +251 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Support/PNCompat.swift +46 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Support/PNJSON.swift +173 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Support/PNLog.swift +47 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Support/PNWindow.swift +51 -0
- pythonnative/templates/ios_template/PythonNativeKit/Tests/PythonNativeKitTests/PNColorTests.swift +50 -0
- pythonnative/templates/ios_template/PythonNativeKit/Tests/PythonNativeKitTests/PNGestureTests.swift +101 -0
- pythonnative/templates/ios_template/PythonNativeKit/Tests/PythonNativeKitTests/PNManagerTests.swift +124 -0
- pythonnative/templates/ios_template/PythonNativeKit/Tests/PythonNativeKitTests/PNModuleTests.swift +98 -0
- pythonnative/templates/ios_template/PythonNativeKit/Tests/PythonNativeKitTests/PNTransactionTests.swift +91 -0
- pythonnative/templates/ios_template/ios_template/AppDelegate.swift +8 -50
- pythonnative/templates/ios_template/ios_template/Info.plist +4 -4
- pythonnative/templates/ios_template/ios_template/PythonRuntime.swift +38 -46
- pythonnative/templates/ios_template/ios_template/SceneDelegate.swift +11 -16
- pythonnative/templates/ios_template/ios_template/ViewController.swift +12 -142
- pythonnative/templates/ios_template/ios_template.xcodeproj/project.pbxproj +47 -1
- pythonnative/utils.py +4 -82
- pythonnative/virtual_rows.py +3 -3
- {pythonnative-0.36.0.dist-info → pythonnative-0.37.0.dist-info}/METADATA +3 -5
- pythonnative-0.37.0.dist-info/RECORD +263 -0
- pythonnative/hosts/android.py +0 -269
- pythonnative/hosts/ios.py +0 -404
- pythonnative/native_views/android.py +0 -3702
- pythonnative/native_views/ios.py +0 -5253
- pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/Navigator.kt +0 -43
- pythonnative-0.36.0.dist-info/RECORD +0 -155
- {pythonnative-0.36.0.dist-info → pythonnative-0.37.0.dist-info}/WHEEL +0 -0
- {pythonnative-0.36.0.dist-info → pythonnative-0.37.0.dist-info}/entry_points.txt +0 -0
- {pythonnative-0.36.0.dist-info → pythonnative-0.37.0.dist-info}/licenses/LICENSE +0 -0
- {pythonnative-0.36.0.dist-info → pythonnative-0.37.0.dist-info}/top_level.txt +0 -0
|
@@ -49,18 +49,15 @@ android {
|
|
|
49
49
|
|
|
50
50
|
dependencies {
|
|
51
51
|
|
|
52
|
+
// The PythonNative runtime: component managers, native modules,
|
|
53
|
+
// gestures, animations, and the screen fragment. Its AndroidX and
|
|
54
|
+
// Material dependencies are exposed transitively.
|
|
55
|
+
implementation project(':pythonnative')
|
|
56
|
+
|
|
52
57
|
implementation 'androidx.core:core-ktx:1.8.0'
|
|
53
58
|
implementation 'androidx.appcompat:appcompat:1.4.1'
|
|
54
59
|
implementation 'com.google.android.material:material:1.5.0'
|
|
55
|
-
|
|
56
|
-
implementation 'androidx.recyclerview:recyclerview:1.3.2'
|
|
57
|
-
// Pull-to-refresh (ScrollView's refresh_control prop)
|
|
58
|
-
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
|
|
59
|
-
// SecureStore (EncryptedSharedPreferences)
|
|
60
|
-
implementation 'androidx.security:security-crypto:1.1.0'
|
|
61
|
-
// Biometrics (BiometricPrompt)
|
|
62
|
-
implementation 'androidx.biometric:biometric:1.1.0'
|
|
63
|
-
// AndroidX Navigation for Fragment-based navigation
|
|
60
|
+
// AndroidX Navigation for Fragment-based navigation (activity_main.xml)
|
|
64
61
|
implementation 'androidx.navigation:navigation-fragment-ktx:2.7.7'
|
|
65
62
|
implementation 'androidx.navigation:navigation-ui-ktx:2.7.7'
|
|
66
63
|
testImplementation 'junit:junit:4.13.2'
|
|
@@ -1,15 +1,8 @@
|
|
|
1
1
|
package com.pythonnative.android_template
|
|
2
2
|
|
|
3
|
-
import android.content.BroadcastReceiver
|
|
4
|
-
import android.content.Context
|
|
5
3
|
import android.content.Intent
|
|
6
|
-
import android.content.IntentFilter
|
|
7
|
-
import android.os.BatteryManager
|
|
8
4
|
import android.graphics.Color
|
|
9
5
|
import android.graphics.Typeface
|
|
10
|
-
import android.net.ConnectivityManager
|
|
11
|
-
import android.net.Network
|
|
12
|
-
import android.net.NetworkCapabilities
|
|
13
6
|
import android.os.Bundle
|
|
14
7
|
import android.util.Log
|
|
15
8
|
import android.util.TypedValue
|
|
@@ -18,12 +11,20 @@ import android.widget.TextView
|
|
|
18
11
|
import androidx.appcompat.app.AppCompatActivity
|
|
19
12
|
import com.chaquo.python.Python
|
|
20
13
|
import com.chaquo.python.android.AndroidPlatform
|
|
21
|
-
|
|
14
|
+
import com.pythonnative.runtime.PNBridge
|
|
15
|
+
import com.pythonnative.runtime.PythonHost
|
|
16
|
+
import com.pythonnative.runtime.modules.BuiltinModules
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The single activity. It starts Python, wires the `PNBridge` host
|
|
20
|
+
* callback into `pythonnative.bridge.native_callback`, runs the
|
|
21
|
+
* protocol handshake, and forwards activity callbacks to the Kotlin
|
|
22
|
+
* native modules. Screens live in `ScreenFragment`s inside the
|
|
23
|
+
* `NavHostFragment` from `activity_main.xml`.
|
|
24
|
+
*/
|
|
22
25
|
class MainActivity : AppCompatActivity() {
|
|
23
26
|
private val TAG = javaClass.simpleName
|
|
24
27
|
private var pythonReady = false
|
|
25
|
-
private var networkCallback: ConnectivityManager.NetworkCallback? = null
|
|
26
|
-
private var batteryReceiver: BroadcastReceiver? = null
|
|
27
28
|
|
|
28
29
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
29
30
|
super.onCreate(savedInstanceState)
|
|
@@ -33,10 +34,14 @@ class MainActivity : AppCompatActivity() {
|
|
|
33
34
|
Python.start(AndroidPlatform(this))
|
|
34
35
|
}
|
|
35
36
|
try {
|
|
36
|
-
|
|
37
|
-
// loads via nav_graph startDestination.
|
|
38
|
-
setContentView(R.layout.activity_main)
|
|
37
|
+
PNBridge.setContext(this)
|
|
39
38
|
val py = Python.getInstance()
|
|
39
|
+
PNBridge.setHost(object : PythonHost {
|
|
40
|
+
override fun callback(kind: String, tag: Long, name: String, payloadJson: String): String? =
|
|
41
|
+
py.getModule("pythonnative.bridge")
|
|
42
|
+
.callAttr("native_callback", kind, tag, name, payloadJson)
|
|
43
|
+
?.toString()
|
|
44
|
+
})
|
|
40
45
|
if (BuildConfig.DEBUG) {
|
|
41
46
|
// Dev-only writable source overlay for hot reload.
|
|
42
47
|
py.getModule("pythonnative.hot_reload").callAttr(
|
|
@@ -44,55 +49,35 @@ class MainActivity : AppCompatActivity() {
|
|
|
44
49
|
filesDir.absolutePath
|
|
45
50
|
)
|
|
46
51
|
}
|
|
52
|
+
// Handshake with the runtime library (raises on a protocol
|
|
53
|
+
// mismatch, before any screen is created), enable dev mode in
|
|
54
|
+
// debug builds, and warm the asyncio runtime.
|
|
55
|
+
py.getModule("pythonnative.bootstrap").callAttr("start", BuildConfig.DEBUG, true)
|
|
47
56
|
// Import the entry module now so a broken app fails here,
|
|
48
57
|
// with a full traceback, instead of inside the first fragment.
|
|
49
58
|
py.getModule(getString(R.string.pn_entry_module))
|
|
50
59
|
pythonReady = true
|
|
60
|
+
// Set content view to the NavHost layout; the initial screen
|
|
61
|
+
// loads via nav_graph startDestination.
|
|
62
|
+
setContentView(R.layout.activity_main)
|
|
51
63
|
} catch (e: Exception) {
|
|
52
64
|
Log.e("PythonNative", "Bootstrap failed", e)
|
|
53
65
|
showBootstrapError(e)
|
|
54
66
|
return
|
|
55
67
|
}
|
|
56
|
-
|
|
57
|
-
// A cold start from a deep link carries the URL on the launch intent.
|
|
58
|
-
intent?.dataString?.let { dispatchUrl(it) }
|
|
59
|
-
|
|
60
|
-
registerNetworkCallback()
|
|
61
|
-
registerBatteryReceiver()
|
|
62
68
|
}
|
|
63
69
|
|
|
64
70
|
override fun onDestroy() {
|
|
65
71
|
super.onDestroy()
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
unregisterReceiver(it)
|
|
69
|
-
} catch (e: Exception) {
|
|
70
|
-
Log.e("PythonNative", "unregisterReceiver(battery) failed", e)
|
|
71
|
-
}
|
|
72
|
-
batteryReceiver = null
|
|
73
|
-
}
|
|
74
|
-
networkCallback?.let {
|
|
75
|
-
try {
|
|
76
|
-
(getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager)
|
|
77
|
-
.unregisterNetworkCallback(it)
|
|
78
|
-
} catch (e: Exception) {
|
|
79
|
-
Log.e("PythonNative", "unregisterNetworkCallback failed", e)
|
|
80
|
-
}
|
|
81
|
-
networkCallback = null
|
|
82
|
-
}
|
|
72
|
+
BuiltinModules.onActivityDestroyed(this)
|
|
73
|
+
PNBridge.clearContext(this)
|
|
83
74
|
}
|
|
84
75
|
|
|
85
76
|
@Deprecated("Deprecated in Java")
|
|
86
77
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
|
78
|
+
@Suppress("DEPRECATION")
|
|
87
79
|
super.onActivityResult(requestCode, resultCode, data)
|
|
88
|
-
|
|
89
|
-
try {
|
|
90
|
-
Python.getInstance()
|
|
91
|
-
.getModule("pythonnative.native_modules")
|
|
92
|
-
.callAttr("dispatch_activity_result", requestCode, resultCode, data)
|
|
93
|
-
} catch (e: Exception) {
|
|
94
|
-
Log.e("PythonNative", "dispatch_activity_result failed", e)
|
|
95
|
-
}
|
|
80
|
+
BuiltinModules.onActivityResult(requestCode, resultCode, data)
|
|
96
81
|
}
|
|
97
82
|
|
|
98
83
|
override fun onRequestPermissionsResult(
|
|
@@ -101,147 +86,30 @@ class MainActivity : AppCompatActivity() {
|
|
|
101
86
|
grantResults: IntArray
|
|
102
87
|
) {
|
|
103
88
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
|
104
|
-
|
|
105
|
-
try {
|
|
106
|
-
Python.getInstance()
|
|
107
|
-
.getModule("pythonnative.native_modules")
|
|
108
|
-
.callAttr("dispatch_permissions_result", requestCode, permissions.toList(), grantResults.toList())
|
|
109
|
-
} catch (e: Exception) {
|
|
110
|
-
Log.e("PythonNative", "dispatch_permissions_result failed", e)
|
|
111
|
-
}
|
|
89
|
+
BuiltinModules.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
|
112
90
|
}
|
|
113
91
|
|
|
114
92
|
override fun onNewIntent(intent: Intent) {
|
|
115
93
|
super.onNewIntent(intent)
|
|
116
94
|
setIntent(intent)
|
|
117
|
-
|
|
95
|
+
BuiltinModules.onNewIntent(intent)
|
|
118
96
|
}
|
|
119
97
|
|
|
120
|
-
// MARK: - AppState forwarding
|
|
121
|
-
|
|
122
98
|
override fun onResume() {
|
|
123
99
|
super.onResume()
|
|
124
|
-
|
|
100
|
+
if (pythonReady) BuiltinModules.onActivityResumed()
|
|
125
101
|
}
|
|
126
102
|
|
|
127
103
|
override fun onPause() {
|
|
128
104
|
super.onPause()
|
|
129
|
-
|
|
105
|
+
if (pythonReady) BuiltinModules.onActivityPaused()
|
|
130
106
|
}
|
|
131
107
|
|
|
132
108
|
override fun onStop() {
|
|
133
109
|
super.onStop()
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
private fun dispatchAppState(state: String) {
|
|
138
|
-
if (!pythonReady) return
|
|
139
|
-
try {
|
|
140
|
-
Python.getInstance()
|
|
141
|
-
.getModule("pythonnative.native_modules.app_state")
|
|
142
|
-
.callAttr("dispatch_app_state", state)
|
|
143
|
-
} catch (e: Exception) {
|
|
144
|
-
Log.e("PythonNative", "dispatch_app_state($state) failed", e)
|
|
145
|
-
}
|
|
110
|
+
if (pythonReady) BuiltinModules.onActivityStopped()
|
|
146
111
|
}
|
|
147
112
|
|
|
148
|
-
// MARK: - NetInfo forwarding
|
|
149
|
-
|
|
150
|
-
// Live connectivity updates. The callback must be a NetworkCallback
|
|
151
|
-
// subclass, which Chaquopy's dynamic_proxy can't create from Python
|
|
152
|
-
// (interfaces only), so the registration lives here and forwards
|
|
153
|
-
// into the pythonnative net_info module.
|
|
154
|
-
private fun registerNetworkCallback() {
|
|
155
|
-
if (!pythonReady || networkCallback != null) return
|
|
156
|
-
try {
|
|
157
|
-
val manager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
|
158
|
-
val callback = object : ConnectivityManager.NetworkCallback() {
|
|
159
|
-
override fun onAvailable(network: Network) = dispatchNetInfo()
|
|
160
|
-
override fun onLost(network: Network) = dispatchNetInfo()
|
|
161
|
-
override fun onCapabilitiesChanged(
|
|
162
|
-
network: Network,
|
|
163
|
-
capabilities: NetworkCapabilities
|
|
164
|
-
) = dispatchNetInfo()
|
|
165
|
-
}
|
|
166
|
-
manager.registerDefaultNetworkCallback(callback)
|
|
167
|
-
networkCallback = callback
|
|
168
|
-
} catch (e: Exception) {
|
|
169
|
-
Log.e("PythonNative", "registerDefaultNetworkCallback failed", e)
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
private fun dispatchNetInfo() {
|
|
174
|
-
// NetworkCallback fires on a ConnectivityManager binder thread;
|
|
175
|
-
// hop to the main thread before crossing into Python.
|
|
176
|
-
runOnUiThread {
|
|
177
|
-
if (!pythonReady) return@runOnUiThread
|
|
178
|
-
try {
|
|
179
|
-
Python.getInstance()
|
|
180
|
-
.getModule("pythonnative.native_modules.net_info")
|
|
181
|
-
.callAttr("dispatch_android_change")
|
|
182
|
-
} catch (e: Exception) {
|
|
183
|
-
Log.e("PythonNative", "dispatch_android_change failed", e)
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// MARK: - Battery forwarding
|
|
189
|
-
|
|
190
|
-
// ACTION_BATTERY_CHANGED is a sticky broadcast, so registering also
|
|
191
|
-
// delivers the current level immediately.
|
|
192
|
-
private fun registerBatteryReceiver() {
|
|
193
|
-
if (!pythonReady || batteryReceiver != null) return
|
|
194
|
-
try {
|
|
195
|
-
val receiver = object : BroadcastReceiver() {
|
|
196
|
-
override fun onReceive(context: Context?, intent: Intent?) {
|
|
197
|
-
if (intent == null) return
|
|
198
|
-
val level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
|
|
199
|
-
val scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
|
|
200
|
-
val status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1)
|
|
201
|
-
val fraction = if (level >= 0 && scale > 0) level.toDouble() / scale.toDouble() else -1.0
|
|
202
|
-
val state = when (status) {
|
|
203
|
-
BatteryManager.BATTERY_STATUS_CHARGING -> "charging"
|
|
204
|
-
BatteryManager.BATTERY_STATUS_FULL -> "full"
|
|
205
|
-
BatteryManager.BATTERY_STATUS_DISCHARGING,
|
|
206
|
-
BatteryManager.BATTERY_STATUS_NOT_CHARGING -> "unplugged"
|
|
207
|
-
else -> "unknown"
|
|
208
|
-
}
|
|
209
|
-
dispatchBattery(fraction, state)
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
registerReceiver(receiver, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
|
|
213
|
-
batteryReceiver = receiver
|
|
214
|
-
} catch (e: Exception) {
|
|
215
|
-
Log.e("PythonNative", "registerReceiver(battery) failed", e)
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
private fun dispatchBattery(level: Double, state: String) {
|
|
220
|
-
if (!pythonReady) return
|
|
221
|
-
try {
|
|
222
|
-
Python.getInstance()
|
|
223
|
-
.getModule("pythonnative.native_modules.battery")
|
|
224
|
-
.callAttr("dispatch_battery", level, state)
|
|
225
|
-
} catch (e: Exception) {
|
|
226
|
-
Log.e("PythonNative", "dispatch_battery failed", e)
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// MARK: - Deep links
|
|
231
|
-
|
|
232
|
-
private fun dispatchUrl(url: String) {
|
|
233
|
-
if (!pythonReady) return
|
|
234
|
-
try {
|
|
235
|
-
Python.getInstance()
|
|
236
|
-
.getModule("pythonnative.native_modules.linking")
|
|
237
|
-
.callAttr("dispatch_url", url)
|
|
238
|
-
} catch (e: Exception) {
|
|
239
|
-
Log.e("PythonNative", "dispatch_url failed", e)
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
// MARK: - Bootstrap error UI
|
|
244
|
-
|
|
245
113
|
private fun showBootstrapError(error: Exception) {
|
|
246
114
|
val text = TextView(this)
|
|
247
115
|
text.text = "PythonNative could not start\n\n" + Log.getStackTraceString(error)
|
|
@@ -1,154 +1,16 @@
|
|
|
1
1
|
package com.pythonnative.android_template
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
import com.chaquo.python.android.AndroidPlatform
|
|
17
|
-
|
|
18
|
-
class ScreenFragment : Fragment() {
|
|
19
|
-
private val TAG = javaClass.simpleName
|
|
20
|
-
private var screen: PyObject? = null
|
|
21
|
-
private val hotReloadHandler = Handler(Looper.getMainLooper())
|
|
22
|
-
private val hotReloadRunnable = object : Runnable {
|
|
23
|
-
override fun run() {
|
|
24
|
-
try {
|
|
25
|
-
screen?.callAttr("hot_reload_tick")
|
|
26
|
-
} catch (e: Exception) {
|
|
27
|
-
Log.w(TAG, "hot_reload_tick failed", e)
|
|
28
|
-
} finally {
|
|
29
|
-
hotReloadHandler.postDelayed(this, 500)
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
override fun onCreate(savedInstanceState: Bundle?) {
|
|
35
|
-
super.onCreate(savedInstanceState)
|
|
36
|
-
if (!Python.isStarted()) {
|
|
37
|
-
context?.let { Python.start(AndroidPlatform(it)) }
|
|
38
|
-
}
|
|
39
|
-
try {
|
|
40
|
-
val py = Python.getInstance()
|
|
41
|
-
// PythonNative imports the entry module (app.entry_point in
|
|
42
|
-
// pythonnative.toml, staged into R.string.pn_entry_module)
|
|
43
|
-
// and looks up its top-level `App` attribute. Pushed screens
|
|
44
|
-
// pass an explicit path in the fragment arguments.
|
|
45
|
-
val screenPath = arguments?.getString("screen_path") ?: getString(R.string.pn_entry_module)
|
|
46
|
-
val argsJson = arguments?.getString("args_json")
|
|
47
|
-
val filesRoot = requireContext().filesDir.absolutePath
|
|
48
|
-
val devRoot = "$filesRoot/pythonnative_dev"
|
|
49
|
-
val hotReload = py.getModule("pythonnative.hot_reload")
|
|
50
|
-
hotReload.callAttr("configure_dev_environment", filesRoot)
|
|
51
|
-
val pnScreen = py.getModule("pythonnative.hosts")
|
|
52
|
-
screen = pnScreen.callAttr("create_screen", screenPath, requireActivity(), argsJson)
|
|
53
|
-
screen?.callAttr("enable_hot_reload", "$devRoot/reload.json", devRoot)
|
|
54
|
-
} catch (e: Exception) {
|
|
55
|
-
Log.e(TAG, "Failed to instantiate screen", e)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Offer the system back action to Python (`use_back_handler`)
|
|
59
|
-
// before running the default pop/finish behavior.
|
|
60
|
-
requireActivity().onBackPressedDispatcher.addCallback(
|
|
61
|
-
this,
|
|
62
|
-
object : OnBackPressedCallback(true) {
|
|
63
|
-
override fun handleOnBackPressed() {
|
|
64
|
-
val consumed = try {
|
|
65
|
-
screen?.callAttr("on_back_pressed")?.toBoolean() ?: false
|
|
66
|
-
} catch (e: Exception) {
|
|
67
|
-
Log.w(TAG, "on_back_pressed failed", e)
|
|
68
|
-
false
|
|
69
|
-
}
|
|
70
|
-
if (!consumed) {
|
|
71
|
-
isEnabled = false
|
|
72
|
-
requireActivity().onBackPressedDispatcher.onBackPressed()
|
|
73
|
-
isEnabled = true
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
override fun onCreateView(
|
|
81
|
-
inflater: LayoutInflater,
|
|
82
|
-
container: ViewGroup?,
|
|
83
|
-
savedInstanceState: Bundle?
|
|
84
|
-
): View? {
|
|
85
|
-
// Create a simple container which Python-native views can be attached to.
|
|
86
|
-
val frame = FrameLayout(requireContext())
|
|
87
|
-
frame.layoutParams = ViewGroup.LayoutParams(
|
|
88
|
-
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
89
|
-
ViewGroup.LayoutParams.MATCH_PARENT
|
|
90
|
-
)
|
|
91
|
-
return frame
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
95
|
-
super.onViewCreated(view, savedInstanceState)
|
|
96
|
-
// Python side will call set_root_view to attach a native view to Activity.
|
|
97
|
-
// In fragment-based architecture, the Activity will set contentView once,
|
|
98
|
-
// so we ensure the fragment's container is available for Python to target.
|
|
99
|
-
// Expose the fragment container to Python so the screen host can attach into it.
|
|
100
|
-
try {
|
|
101
|
-
val py = Python.getInstance()
|
|
102
|
-
val utils = py.getModule("pythonnative.utils")
|
|
103
|
-
utils.callAttr("set_android_fragment_container", view)
|
|
104
|
-
// Now that container exists, invoke on_create so Python can attach its root view
|
|
105
|
-
screen?.callAttr("on_create")
|
|
106
|
-
hotReloadHandler.removeCallbacks(hotReloadRunnable)
|
|
107
|
-
hotReloadHandler.postDelayed(hotReloadRunnable, 500)
|
|
108
|
-
} catch (e: Exception) {
|
|
109
|
-
Log.e(TAG, "on_create failed", e)
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
override fun onStart() {
|
|
114
|
-
super.onStart()
|
|
115
|
-
try { screen?.callAttr("on_start") } catch (e: Exception) { Log.w(TAG, "on_start failed", e) }
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
override fun onResume() {
|
|
119
|
-
super.onResume()
|
|
120
|
-
try { screen?.callAttr("on_resume") } catch (e: Exception) { Log.w(TAG, "on_resume failed", e) }
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
override fun onPause() {
|
|
124
|
-
super.onPause()
|
|
125
|
-
try { screen?.callAttr("on_pause") } catch (e: Exception) { Log.w(TAG, "on_pause failed", e) }
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
override fun onStop() {
|
|
129
|
-
super.onStop()
|
|
130
|
-
try { screen?.callAttr("on_stop") } catch (e: Exception) { Log.w(TAG, "on_stop failed", e) }
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
override fun onDestroyView() {
|
|
134
|
-
super.onDestroyView()
|
|
135
|
-
hotReloadHandler.removeCallbacks(hotReloadRunnable)
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
override fun onDestroy() {
|
|
139
|
-
super.onDestroy()
|
|
140
|
-
hotReloadHandler.removeCallbacks(hotReloadRunnable)
|
|
141
|
-
try { screen?.callAttr("on_destroy") } catch (e: Exception) { Log.w(TAG, "on_destroy failed", e) }
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
companion object {
|
|
145
|
-
fun newInstance(screenPath: String, argsJson: String?): ScreenFragment {
|
|
146
|
-
val f = ScreenFragment()
|
|
147
|
-
f.arguments = bundleOf(
|
|
148
|
-
"screen_path" to screenPath,
|
|
149
|
-
"args_json" to argsJson
|
|
150
|
-
)
|
|
151
|
-
return f
|
|
152
|
-
}
|
|
153
|
-
}
|
|
3
|
+
import com.pythonnative.runtime.screens.PNScreenFragment
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The app's screen fragment (named by `nav_graph.xml`). The start
|
|
7
|
+
* destination has no `screen_path` argument, so it shows the entry
|
|
8
|
+
* module from `pythonnative.toml` (staged into `R.string.pn_entry_module`);
|
|
9
|
+
* pushed screens carry an explicit path.
|
|
10
|
+
*/
|
|
11
|
+
class ScreenFragment : PNScreenFragment() {
|
|
12
|
+
override fun defaultPath(): String = getString(R.string.pn_entry_module)
|
|
13
|
+
|
|
14
|
+
override fun defaultDevRoot(): String? =
|
|
15
|
+
if (BuildConfig.DEBUG) "${requireContext().filesDir.absolutePath}/pythonnative_dev" else null
|
|
154
16
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
plugins {
|
|
2
|
+
id 'com.android.library'
|
|
3
|
+
id 'org.jetbrains.kotlin.android'
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
android {
|
|
7
|
+
namespace 'com.pythonnative.runtime'
|
|
8
|
+
compileSdk 34
|
|
9
|
+
|
|
10
|
+
defaultConfig {
|
|
11
|
+
minSdk 24
|
|
12
|
+
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
buildFeatures {
|
|
16
|
+
buildConfig false
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
compileOptions {
|
|
20
|
+
sourceCompatibility JavaVersion.VERSION_1_8
|
|
21
|
+
targetCompatibility JavaVersion.VERSION_1_8
|
|
22
|
+
}
|
|
23
|
+
kotlinOptions {
|
|
24
|
+
jvmTarget = '1.8'
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
testOptions {
|
|
28
|
+
unitTests.returnDefaultValues = true
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
dependencies {
|
|
33
|
+
api 'androidx.core:core-ktx:1.8.0'
|
|
34
|
+
api 'androidx.appcompat:appcompat:1.4.1'
|
|
35
|
+
api 'com.google.android.material:material:1.5.0'
|
|
36
|
+
api 'androidx.recyclerview:recyclerview:1.3.2'
|
|
37
|
+
api 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
|
|
38
|
+
api 'androidx.security:security-crypto:1.1.0'
|
|
39
|
+
api 'androidx.biometric:biometric:1.1.0'
|
|
40
|
+
api 'androidx.dynamicanimation:dynamicanimation:1.0.0'
|
|
41
|
+
// Screen navigation (PNScreenFragment inside the app's NavHostFragment).
|
|
42
|
+
api 'androidx.navigation:navigation-fragment-ktx:2.7.7'
|
|
43
|
+
api 'androidx.navigation:navigation-ui-ktx:2.7.7'
|
|
44
|
+
|
|
45
|
+
testImplementation 'junit:junit:4.13.2'
|
|
46
|
+
// Real org.json for host-side unit tests (the android.jar stubs are empty).
|
|
47
|
+
testImplementation 'org.json:json:20231013'
|
|
48
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
3
|
+
|
|
4
|
+
<!-- Runtime-gated on Android 13+ (API 33); requested by the
|
|
5
|
+
Notifications module before posting. -->
|
|
6
|
+
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
|
7
|
+
<uses-permission android:name="android.permission.VIBRATE" />
|
|
8
|
+
<uses-permission android:name="android.permission.INTERNET" />
|
|
9
|
+
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
|
10
|
+
|
|
11
|
+
</manifest>
|