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.
Files changed (174) hide show
  1. pythonnative/__init__.py +6 -4
  2. pythonnative/_ios_log.py +1 -1
  3. pythonnative/alerts.py +34 -88
  4. pythonnative/bootstrap.py +90 -0
  5. pythonnative/bridge/__init__.py +306 -0
  6. pythonnative/bridge/android.py +78 -0
  7. pythonnative/bridge/codec.py +164 -0
  8. pythonnative/bridge/fake.py +236 -0
  9. pythonnative/bridge/ios.py +138 -0
  10. pythonnative/components/layout.py +65 -3
  11. pythonnative/gestures.py +13 -10
  12. pythonnative/hooks.py +41 -26
  13. pythonnative/hosts/__init__.py +13 -36
  14. pythonnative/hosts/native.py +348 -0
  15. pythonnative/images.py +6 -5
  16. pythonnative/native_modules/__init__.py +30 -29
  17. pythonnative/native_modules/app_state.py +10 -6
  18. pythonnative/native_modules/battery.py +20 -84
  19. pythonnative/native_modules/biometrics.py +11 -124
  20. pythonnative/native_modules/camera.py +15 -291
  21. pythonnative/native_modules/clipboard.py +14 -109
  22. pythonnative/native_modules/desktop.py +322 -0
  23. pythonnative/native_modules/file_system.py +15 -21
  24. pythonnative/native_modules/haptics.py +19 -129
  25. pythonnative/native_modules/linking.py +24 -137
  26. pythonnative/native_modules/location.py +28 -180
  27. pythonnative/native_modules/net_info.py +25 -135
  28. pythonnative/native_modules/notifications.py +36 -257
  29. pythonnative/native_modules/permissions.py +20 -184
  30. pythonnative/native_modules/registry.py +513 -0
  31. pythonnative/native_modules/secure_store.py +18 -155
  32. pythonnative/native_modules/share.py +8 -113
  33. pythonnative/native_views/__init__.py +67 -86
  34. pythonnative/native_views/bridge_backend.py +264 -0
  35. pythonnative/platform.py +19 -15
  36. pythonnative/platform_metrics.py +3 -3
  37. pythonnative/project/android.py +0 -3
  38. pythonnative/project/builder.py +38 -16
  39. pythonnative/project/config.py +12 -2
  40. pythonnative/project/plugins.py +366 -0
  41. pythonnative/py.typed +0 -0
  42. pythonnative/runtime.py +35 -203
  43. pythonnative/sdk/__init__.py +48 -33
  44. pythonnative/sdk/_components.py +57 -76
  45. pythonnative/storage.py +18 -243
  46. pythonnative/templates/android_template/app/build.gradle +6 -9
  47. pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/MainActivity.kt +34 -166
  48. pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/ScreenFragment.kt +13 -151
  49. pythonnative/templates/android_template/pythonnative/build.gradle +48 -0
  50. pythonnative/templates/android_template/pythonnative/src/main/AndroidManifest.xml +11 -0
  51. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/PNBridge.kt +214 -0
  52. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/PythonHost.kt +20 -0
  53. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/animation/AnimationSpecs.kt +141 -0
  54. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/animation/PNAnimator.kt +249 -0
  55. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/bridge/JsonUtil.kt +175 -0
  56. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/bridge/MainThread.kt +32 -0
  57. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/bridge/PNLog.kt +33 -0
  58. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/bridge/PNRegistry.kt +82 -0
  59. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/bridge/PNTransaction.kt +80 -0
  60. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/bridge/TransactionApplier.kt +115 -0
  61. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/bridge/ViewRegistry.kt +74 -0
  62. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/BuiltinComponents.kt +35 -0
  63. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ButtonManager.kt +33 -0
  64. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ComponentManager.kt +213 -0
  65. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ContainerManagers.kt +69 -0
  66. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ControlManagers.kt +186 -0
  67. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/DatePickerManager.kt +123 -0
  68. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ImageLoader.kt +141 -0
  69. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ImageManager.kt +156 -0
  70. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ModalManager.kt +134 -0
  71. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/PNColor.kt +201 -0
  72. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/PickerManager.kt +87 -0
  73. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/PortalManager.kt +55 -0
  74. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/PressableManager.kt +122 -0
  75. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ScrollViewManager.kt +214 -0
  76. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/SegmentedControlManager.kt +113 -0
  77. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/StatusBarManager.kt +52 -0
  78. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/TabBarManager.kt +131 -0
  79. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/TextInputManager.kt +245 -0
  80. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/TextManager.kt +233 -0
  81. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ViewStyler.kt +355 -0
  82. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/VirtualListManager.kt +179 -0
  83. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/WebViewManager.kt +149 -0
  84. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/gestures/GestureArbiter.kt +233 -0
  85. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/gestures/GestureCoordinator.kt +127 -0
  86. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/gestures/GestureRecognizers.kt +527 -0
  87. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/BuiltinModules.kt +73 -0
  88. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/DeviceModules.kt +316 -0
  89. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/HostModule.kt +97 -0
  90. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/MediaModules.kt +200 -0
  91. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/NativeModule.kt +135 -0
  92. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/NotificationsModule.kt +100 -0
  93. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/PermissionsModule.kt +88 -0
  94. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/StorageModules.kt +89 -0
  95. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/SystemModules.kt +178 -0
  96. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/plugins/GeneratedPlugins.kt +16 -0
  97. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/screens/Navigator.kt +116 -0
  98. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/screens/PNScreenFragment.kt +223 -0
  99. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/screens/ScreenRegistry.kt +80 -0
  100. pythonnative/templates/android_template/{app/src/main/java/com/pythonnative/android_template → pythonnative/src/main/java/com/pythonnative/runtime/views}/PNAccessibilityDelegate.kt +5 -4
  101. pythonnative/templates/android_template/{app/src/main/java/com/pythonnative/android_template → pythonnative/src/main/java/com/pythonnative/runtime/views}/PNBorderDrawable.kt +12 -3
  102. pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/views/PNEditText.kt +18 -0
  103. pythonnative/templates/android_template/{app/src/main/java/com/pythonnative/android_template → pythonnative/src/main/java/com/pythonnative/runtime/views}/PNFrameLayout.kt +9 -10
  104. pythonnative/templates/android_template/{app/src/main/java/com/pythonnative/android_template → pythonnative/src/main/java/com/pythonnative/runtime/views}/PNVirtualListView.java +9 -12
  105. pythonnative/templates/android_template/pythonnative/src/test/java/com/pythonnative/runtime/AnimationSpecsTest.kt +75 -0
  106. pythonnative/templates/android_template/pythonnative/src/test/java/com/pythonnative/runtime/GestureArbiterTest.kt +197 -0
  107. pythonnative/templates/android_template/pythonnative/src/test/java/com/pythonnative/runtime/PNColorTest.kt +47 -0
  108. pythonnative/templates/android_template/pythonnative/src/test/java/com/pythonnative/runtime/PNTransactionTest.kt +78 -0
  109. pythonnative/templates/android_template/pythonnative/src/test/java/com/pythonnative/runtime/PromiseTest.kt +75 -0
  110. pythonnative/templates/android_template/settings.gradle +1 -0
  111. pythonnative/templates/ios_template/PythonNativeKit/Package.swift +21 -0
  112. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Animation/PNAnimator.swift +301 -0
  113. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Bridge/PNBridge.swift +191 -0
  114. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Bridge/PNRegistry.swift +140 -0
  115. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Bridge/PNTransaction.swift +165 -0
  116. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Bridge/PNViewRegistry.swift +53 -0
  117. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNButtonManagers.swift +206 -0
  118. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNColor.swift +173 -0
  119. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNComponentManager.swift +183 -0
  120. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNContainerView.swift +56 -0
  121. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNControlManagers.swift +281 -0
  122. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNImageManager.swift +221 -0
  123. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNOverlayManagers.swift +243 -0
  124. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNPressableManager.swift +114 -0
  125. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNScrollViewManager.swift +197 -0
  126. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNTabBarManager.swift +106 -0
  127. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNTextInputManager.swift +289 -0
  128. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNTextManager.swift +230 -0
  129. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNTransform.swift +82 -0
  130. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNViewManager.swift +86 -0
  131. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNViewState.swift +87 -0
  132. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNViewStyler.swift +340 -0
  133. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNVirtualListManager.swift +257 -0
  134. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNWebViewManager.swift +124 -0
  135. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Gestures/PNGestureCoordinator.swift +260 -0
  136. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Modules/AlertModule.swift +92 -0
  137. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Modules/HostModule.swift +158 -0
  138. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Modules/LifecycleModules.swift +174 -0
  139. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Modules/MediaModules.swift +177 -0
  140. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Modules/PNNativeModule.swift +125 -0
  141. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Modules/PermissionModules.swift +251 -0
  142. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Modules/SystemModules.swift +251 -0
  143. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Plugins/PNPluginRegistration.swift +8 -0
  144. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Screens/PNScreenRegistry.swift +46 -0
  145. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Screens/PNViewController.swift +251 -0
  146. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Support/PNCompat.swift +46 -0
  147. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Support/PNJSON.swift +173 -0
  148. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Support/PNLog.swift +47 -0
  149. pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Support/PNWindow.swift +51 -0
  150. pythonnative/templates/ios_template/PythonNativeKit/Tests/PythonNativeKitTests/PNColorTests.swift +50 -0
  151. pythonnative/templates/ios_template/PythonNativeKit/Tests/PythonNativeKitTests/PNGestureTests.swift +101 -0
  152. pythonnative/templates/ios_template/PythonNativeKit/Tests/PythonNativeKitTests/PNManagerTests.swift +124 -0
  153. pythonnative/templates/ios_template/PythonNativeKit/Tests/PythonNativeKitTests/PNModuleTests.swift +98 -0
  154. pythonnative/templates/ios_template/PythonNativeKit/Tests/PythonNativeKitTests/PNTransactionTests.swift +91 -0
  155. pythonnative/templates/ios_template/ios_template/AppDelegate.swift +8 -50
  156. pythonnative/templates/ios_template/ios_template/Info.plist +4 -4
  157. pythonnative/templates/ios_template/ios_template/PythonRuntime.swift +38 -46
  158. pythonnative/templates/ios_template/ios_template/SceneDelegate.swift +11 -16
  159. pythonnative/templates/ios_template/ios_template/ViewController.swift +12 -142
  160. pythonnative/templates/ios_template/ios_template.xcodeproj/project.pbxproj +47 -1
  161. pythonnative/utils.py +4 -82
  162. pythonnative/virtual_rows.py +3 -3
  163. {pythonnative-0.36.0.dist-info → pythonnative-0.37.0.dist-info}/METADATA +3 -5
  164. pythonnative-0.37.0.dist-info/RECORD +263 -0
  165. pythonnative/hosts/android.py +0 -269
  166. pythonnative/hosts/ios.py +0 -404
  167. pythonnative/native_views/android.py +0 -3702
  168. pythonnative/native_views/ios.py +0 -5253
  169. pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/Navigator.kt +0 -43
  170. pythonnative-0.36.0.dist-info/RECORD +0 -155
  171. {pythonnative-0.36.0.dist-info → pythonnative-0.37.0.dist-info}/WHEEL +0 -0
  172. {pythonnative-0.36.0.dist-info → pythonnative-0.37.0.dist-info}/entry_points.txt +0 -0
  173. {pythonnative-0.36.0.dist-info → pythonnative-0.37.0.dist-info}/licenses/LICENSE +0 -0
  174. {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
- implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
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
- // Set content view to the NavHost layout; the initial screen
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
- batteryReceiver?.let {
67
- try {
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
- if (!pythonReady) return
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
- if (!pythonReady) return
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
- intent.dataString?.let { dispatchUrl(it) }
95
+ BuiltinModules.onNewIntent(intent)
118
96
  }
119
97
 
120
- // MARK: - AppState forwarding
121
-
122
98
  override fun onResume() {
123
99
  super.onResume()
124
- dispatchAppState("active")
100
+ if (pythonReady) BuiltinModules.onActivityResumed()
125
101
  }
126
102
 
127
103
  override fun onPause() {
128
104
  super.onPause()
129
- dispatchAppState("inactive")
105
+ if (pythonReady) BuiltinModules.onActivityPaused()
130
106
  }
131
107
 
132
108
  override fun onStop() {
133
109
  super.onStop()
134
- dispatchAppState("background")
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 android.os.Bundle
4
- import android.os.Handler
5
- import android.os.Looper
6
- import android.util.Log
7
- import android.view.LayoutInflater
8
- import android.view.View
9
- import android.view.ViewGroup
10
- import android.widget.FrameLayout
11
- import androidx.activity.OnBackPressedCallback
12
- import androidx.core.os.bundleOf
13
- import androidx.fragment.app.Fragment
14
- import com.chaquo.python.PyObject
15
- import com.chaquo.python.Python
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>