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
@@ -1,10 +1,10 @@
1
1
  """Encrypted key/value storage for secrets (tokens, credentials).
2
2
 
3
3
  [`SecureStore`][pythonnative.SecureStore] persists small string values
4
- in the iOS Keychain and Android ``EncryptedSharedPreferences``, the
5
- right place for auth tokens and other secrets that
6
- [`AsyncStorage`][pythonnative.AsyncStorage] (plain, unencrypted) should
7
- never hold.
4
+ in the iOS Keychain and Android ``EncryptedSharedPreferences`` (the
5
+ native ``SecureStore`` module), the right place for auth tokens and
6
+ other secrets that [`AsyncStorage`][pythonnative.AsyncStorage] (plain,
7
+ unencrypted) should never hold.
8
8
 
9
9
  All methods are synchronous and return a ``bool`` (writes/deletes) or
10
10
  ``Optional[str]`` (reads). On desktop the module falls back to an
@@ -22,12 +22,9 @@ Example:
22
22
 
23
23
  from __future__ import annotations
24
24
 
25
- from typing import Dict, Optional
25
+ from typing import Optional
26
26
 
27
- from ..utils import IS_ANDROID, IS_IOS
28
-
29
- _SERVICE = "com.pythonnative.securestore"
30
- _desktop_store: Dict[str, str] = {}
27
+ from .registry import native_module
31
28
 
32
29
 
33
30
  class SecureStore:
@@ -36,158 +33,24 @@ class SecureStore:
36
33
  @staticmethod
37
34
  def set_item(key: str, value: str) -> bool:
38
35
  """Store ``value`` under ``key``. Returns ``True`` on success."""
39
- if IS_IOS:
40
- return _ios_set(key, value)
41
- if IS_ANDROID:
42
- return _android_set(key, value)
43
- _desktop_store[key] = value
44
- return True
36
+ try:
37
+ return bool(native_module("SecureStore").call("set_item", key=key, value=value))
38
+ except Exception:
39
+ return False
45
40
 
46
41
  @staticmethod
47
42
  def get_item(key: str) -> Optional[str]:
48
43
  """Return the value for ``key``, or ``None`` if absent."""
49
- if IS_IOS:
50
- return _ios_get(key)
51
- if IS_ANDROID:
52
- return _android_get(key)
53
- return _desktop_store.get(key)
44
+ try:
45
+ value = native_module("SecureStore").call("get_item", key=key)
46
+ except Exception:
47
+ return None
48
+ return None if value is None else str(value)
54
49
 
55
50
  @staticmethod
56
51
  def delete_item(key: str) -> bool:
57
52
  """Delete ``key``. Returns ``True`` if it existed and was removed."""
58
- if IS_IOS:
59
- return _ios_delete(key)
60
- if IS_ANDROID:
61
- return _android_delete(key)
62
- return _desktop_store.pop(key, None) is not None
63
-
64
-
65
- # ======================================================================
66
- # iOS: Security framework (Keychain)
67
- # ======================================================================
68
-
69
-
70
- def _ios_query(key: str) -> Dict[str, object]:
71
- from rubicon.objc import ObjCClass
72
-
73
- NSDictionary = ObjCClass("NSMutableDictionary")
74
- query = NSDictionary.alloc().init()
75
- query.setObject_forKey_("genp", "class") # kSecClassGenericPassword shorthand
76
- query.setObject_forKey_(_SERVICE, "svce")
77
- query.setObject_forKey_(key, "acct")
78
- return query
79
-
80
-
81
- def _ios_set(key: str, value: str) -> bool:
82
- try:
83
- from ctypes import CDLL, util
84
-
85
- from rubicon.objc import ObjCClass
86
-
87
- sec = CDLL(util.find_library("Security"))
88
- query = _ios_query(key)
89
- sec.SecItemDelete(query.ptr)
90
- data = ObjCClass("NSString").stringWithString_(value).dataUsingEncoding_(4) # UTF-8
91
- query.setObject_forKey_(data, "v_Data")
92
- status = sec.SecItemAdd(query.ptr, None)
93
- return status == 0
94
- except Exception:
95
- return False
96
-
97
-
98
- def _ios_get(key: str) -> Optional[str]:
99
- try:
100
- from ctypes import CDLL, byref, c_void_p, util
101
-
102
- from rubicon.objc import ObjCClass
103
-
104
- sec = CDLL(util.find_library("Security"))
105
- query = _ios_query(key)
106
- query.setObject_forKey_(True, "r_Data")
107
- query.setObject_forKey_("m_Limit_One", "m_Limit")
108
- result = c_void_p(0)
109
- status = sec.SecItemCopyMatching(query.ptr, byref(result))
110
- if status != 0 or not result.value:
111
- return None
112
- data = ObjCClass("NSData").alloc() # placeholder to keep import used
113
- del data
114
- ns = ObjCClass("NSString").alloc().initWithData_encoding_(result, 4)
115
- return str(ns) if ns is not None else None
116
- except Exception:
117
- return None
118
-
119
-
120
- def _ios_delete(key: str) -> bool:
121
- try:
122
- from ctypes import CDLL, util
123
-
124
- sec = CDLL(util.find_library("Security"))
125
- return sec.SecItemDelete(_ios_query(key).ptr) == 0
126
- except Exception:
127
- return False
128
-
129
-
130
- # ======================================================================
131
- # Android: EncryptedSharedPreferences
132
- # ======================================================================
133
-
134
-
135
- def _android_prefs() -> Optional[object]:
136
- try:
137
- from java import jclass
138
-
139
- from ..utils import get_android_context
140
-
141
- ctx = get_android_context()
142
- MasterKey = jclass("androidx.security.crypto.MasterKey")
143
- Builder = jclass("androidx.security.crypto.MasterKey$Builder")
144
- EncryptedSharedPreferences = jclass("androidx.security.crypto.EncryptedSharedPreferences")
145
- KeyScheme = jclass("androidx.security.crypto.EncryptedSharedPreferences$PrefKeyEncryptionScheme")
146
- ValueScheme = jclass("androidx.security.crypto.EncryptedSharedPreferences$PrefValueEncryptionScheme")
147
- master = Builder(ctx).setKeyScheme(MasterKey.KeyScheme.AES256_GCM).build()
148
- return EncryptedSharedPreferences.create(
149
- ctx,
150
- _SERVICE,
151
- master,
152
- KeyScheme.AES256_SIV,
153
- ValueScheme.AES256_GCM,
154
- )
155
- except Exception:
156
- return None
157
-
158
-
159
- def _android_set(key: str, value: str) -> bool:
160
- prefs = _android_prefs()
161
- if prefs is None:
162
- return False
163
- try:
164
- editor = prefs.edit()
165
- editor.putString(key, value)
166
- return bool(editor.commit())
167
- except Exception:
168
- return False
169
-
170
-
171
- def _android_get(key: str) -> Optional[str]:
172
- prefs = _android_prefs()
173
- if prefs is None:
174
- return None
175
- try:
176
- value = prefs.getString(key, None)
177
- return str(value) if value is not None else None
178
- except Exception:
179
- return None
180
-
181
-
182
- def _android_delete(key: str) -> bool:
183
- prefs = _android_prefs()
184
- if prefs is None:
185
- return False
186
- try:
187
- if not prefs.contains(key):
53
+ try:
54
+ return bool(native_module("SecureStore").call("delete_item", key=key))
55
+ except Exception:
188
56
  return False
189
- editor = prefs.edit()
190
- editor.remove(key)
191
- return bool(editor.commit())
192
- except Exception:
193
- return False
@@ -2,8 +2,8 @@
2
2
 
3
3
  [`Share.share`][pythonnative.Share] is a coroutine that opens
4
4
  ``UIActivityViewController`` (iOS) or an ``ACTION_SEND`` chooser
5
- (Android) and resolves to ``True`` once the user completes a share or
6
- ``False`` if they dismiss it.
5
+ (Android) through the native ``Share`` module and resolves to ``True``
6
+ once the user completes a share or ``False`` if they dismiss it.
7
7
 
8
8
  Example:
9
9
  ```python
@@ -19,15 +19,9 @@ Example:
19
19
 
20
20
  from __future__ import annotations
21
21
 
22
- import asyncio
23
- from typing import Any, Callable, Dict, Optional
22
+ from typing import Optional
24
23
 
25
- from .. import diagnostics
26
- from ..runtime import resolve_future
27
- from ..utils import IS_ANDROID, IS_IOS
28
-
29
- # Retain pool so iOS completion handlers aren't collected early.
30
- _pending: Dict[int, Any] = {}
24
+ from .registry import native_module
31
25
 
32
26
 
33
27
  class Share:
@@ -51,106 +45,7 @@ class Share:
51
45
  ``True`` if the user completed a share, ``False`` if they
52
46
  cancelled or no share UI is available.
53
47
  """
54
- loop = asyncio.get_running_loop()
55
- future: asyncio.Future[bool] = loop.create_future()
56
-
57
- def _done(ok: bool) -> None:
58
- resolve_future(future, ok)
59
-
60
- if IS_IOS:
61
- _ios_share(_done, message=message, url=url, title=title)
62
- elif IS_ANDROID:
63
- _android_share(_done, message=message, url=url, title=title)
64
- else:
65
- _done(False)
66
-
67
- return await future
68
-
69
-
70
- # ======================================================================
71
- # iOS: UIActivityViewController
72
- # ======================================================================
73
-
74
-
75
- def _ios_share(
76
- on_done: Callable[[bool], None],
77
- message: Optional[str],
78
- url: Optional[str],
79
- title: Optional[str],
80
- ) -> None:
81
- del title
82
- try:
83
- from rubicon.objc import Block, ObjCClass
84
-
85
- items = ObjCClass("NSMutableArray").alloc().init()
86
- if message:
87
- items.addObject_(message)
88
- if url:
89
- nsurl = ObjCClass("NSURL").URLWithString_(url)
90
- if nsurl is not None:
91
- items.addObject_(nsurl)
92
-
93
- controller = (
94
- ObjCClass("UIActivityViewController").alloc().initWithActivityItems_applicationActivities_(items, None)
95
- )
96
-
97
- token = id(controller)
98
- _pending[token] = controller
99
-
100
- def _completion(activity: Any, completed: bool, items_: Any, error: Any) -> None:
101
- del activity, items_, error
102
- _pending.pop(token, None)
103
- try:
104
- on_done(bool(completed))
105
- except Exception:
106
- diagnostics.swallowed("share._ios_share._completion")
107
-
108
- controller.setCompletionWithItemsHandler_(
109
- Block(_completion, None, ObjCClass("NSString"), Block, ObjCClass("NSArray"), ObjCClass("NSError"))
110
- )
111
-
112
- app = ObjCClass("UIApplication").sharedApplication
113
- top = app.keyWindow.rootViewController
114
- while top is not None and top.presentedViewController is not None:
115
- top = top.presentedViewController
116
- if top is not None:
117
- top.presentViewController_animated_completion_(controller, True, None)
118
- else:
119
- _pending.pop(token, None)
120
- on_done(False)
121
- except Exception:
122
- on_done(False)
123
-
124
-
125
- # ======================================================================
126
- # Android: ACTION_SEND chooser
127
- # ======================================================================
128
-
129
-
130
- def _android_share(
131
- on_done: Callable[[bool], None],
132
- message: Optional[str],
133
- url: Optional[str],
134
- title: Optional[str],
135
- ) -> None:
136
- try:
137
- from java import jclass
138
-
139
- from ..utils import get_android_context
140
-
141
- Intent = jclass("android.content.Intent")
142
- intent = Intent(Intent.ACTION_SEND)
143
- intent.setType("text/plain")
144
- body = "\n".join(part for part in (message, url) if part)
145
- intent.putExtra(Intent.EXTRA_TEXT, body)
146
- if title:
147
- intent.putExtra(Intent.EXTRA_SUBJECT, title)
148
-
149
- chooser = Intent.createChooser(intent, title or "Share")
150
- chooser.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
151
- get_android_context().startActivity(chooser)
152
- # ACTION_SEND chooser gives no completion callback; report
153
- # success once the chooser has been launched.
154
- on_done(True)
155
- except Exception:
156
- on_done(False)
48
+ try:
49
+ return bool(await native_module("Share").call_async("share", message=message, url=url, title=title))
50
+ except Exception:
51
+ return False
@@ -1,34 +1,25 @@
1
- """Platform-specific native-view creation and update logic.
2
-
3
- This package provides the
4
- [`NativeViewRegistry`][pythonnative.native_views.NativeViewRegistry]
5
- that maps element type names (e.g., `"Text"`, `"Button"`) to
6
- platform-specific
7
- [`ViewHandler`][pythonnative.native_views.base.ViewHandler]
8
- implementations, and owns the **tag table** mapping each
9
- reconciler-assigned integer tag to its live native view.
10
-
11
- The reconciler communicates exclusively through
12
- [`apply_mutations`][pythonnative.native_views.NativeViewRegistry.apply_mutations]:
13
- one ordered batch of create/update/insert/remove/destroy/frame ops per
14
- commit (see `pythonnative.mutations`). Imperative escape hatches
15
- (commands, animation control, intrinsic measurement) resolve views
16
- through the same tag table.
17
-
18
- Platform handlers live in dedicated submodules:
19
-
20
- - `pythonnative.native_views.base`: shared `ViewHandler` protocol and
21
- utilities.
22
- - `pythonnative.native_views.android`: Android handlers
23
- (Chaquopy / Java bridge).
24
- - `pythonnative.native_views.ios`: iOS handlers (rubicon-objc).
25
- - `pythonnative.native_views.desktop`: Tkinter preview handlers.
26
-
27
- All platform-branching is handled at registration time via lazy
28
- imports, so this package can be imported on any platform for testing.
29
- A mock registry can be installed via
30
- [`set_registry`][pythonnative.native_views.set_registry] to drive the
31
- reconciler with no real native views.
1
+ """The view backend the reconciler commits to.
2
+
3
+ The reconciler talks to exactly one object, obtained from
4
+ [`get_registry`][pythonnative.native_views.get_registry], through a
5
+ small protocol: ``apply_mutations`` (one ordered batch of
6
+ create/update/insert/destroy/frame ops per commit, see
7
+ `pythonnative.mutations`), ``resolve_view``, ``measure_intrinsic``,
8
+ ``command``, and the animation hooks. Two implementations exist:
9
+
10
+ - [`BridgeBackend`][pythonnative.native_views.bridge_backend.BridgeBackend]
11
+ (iOS and Android): serializes each commit and hands it to the native
12
+ runtime through the bridge; Swift and Kotlin component managers own
13
+ every platform view. Python holds no native objects.
14
+ - [`NativeViewRegistry`][pythonnative.native_views.NativeViewRegistry]
15
+ (desktop preview and tests): maps element type names to Python
16
+ [`ViewHandler`][pythonnative.native_views.base.ViewHandler]
17
+ implementations (`pythonnative.native_views.desktop` renders with
18
+ Tkinter) and owns the tag table itself.
19
+
20
+ Platform selection happens lazily on first use, so this package
21
+ imports on any platform. Tests install a mock with
22
+ [`set_registry`][pythonnative.native_views.set_registry].
32
23
  """
33
24
 
34
25
  import math
@@ -292,98 +283,88 @@ class NativeViewRegistry:
292
283
  # Singleton registry
293
284
  # ======================================================================
294
285
 
295
- _registry: Optional[NativeViewRegistry] = None
286
+ _registry: Any = None
296
287
 
297
288
 
298
- def _active_platform_name() -> str:
299
- """Return ``"android"``, ``"desktop"``, or ``"ios"`` for the active runtime."""
300
- from ..utils import IS_ANDROID, IS_DESKTOP
301
-
302
- if IS_ANDROID:
303
- return "android"
304
- if IS_DESKTOP:
305
- return "desktop"
306
- return "ios"
307
-
308
-
309
- def _register_builtin_handlers(registry: NativeViewRegistry) -> None:
310
- """Register every built-in handler for the active platform.
311
-
312
- The desktop (Tkinter) backend is selected when ``pn preview`` sets
313
- ``PN_PLATFORM=desktop``; otherwise this picks Android (on device) or
314
- iOS (the default off-device path, exercised by the iOS templates and
315
- by tests that install the ``[ios]`` extra). Off-device unit tests
316
- typically inject a mock registry via ``set_registry`` instead.
317
- """
318
- from ..utils import IS_ANDROID, IS_DESKTOP
319
-
320
- if IS_ANDROID:
321
- from .android import register_handlers
322
- elif IS_DESKTOP:
323
- from .desktop import register_handlers
324
- else:
325
- from .ios import register_handlers
326
- register_handlers(registry)
327
-
328
-
329
- def _install_sdk_handlers(registry: NativeViewRegistry) -> None:
289
+ def _install_sdk_handlers(registry: Any) -> None:
330
290
  """Copy decorator-registered SDK handlers + entry-point plugins.
331
291
 
332
292
  Imported lazily so unit tests that never touch the SDK don't pay the
333
- entry-point discovery cost.
293
+ entry-point discovery cost. Only meaningful for the Python-handler
294
+ registry (desktop / tests); on device the native runtime owns
295
+ component managers and Python handlers are recorded but never run.
334
296
  """
335
297
  try:
336
298
  from ..sdk._components import install_into_registry as _sdk_install
337
299
  except Exception:
338
300
  return
339
301
  try:
340
- _sdk_install(registry, _active_platform_name())
302
+ _sdk_install(registry)
341
303
  except Exception:
342
304
  # A misbehaving plugin must not break PythonNative's startup.
343
305
  pass
344
306
 
345
307
 
346
- def get_registry() -> NativeViewRegistry:
347
- """Return the process-wide registry, lazily registering handlers.
308
+ def _create_backend() -> Any:
309
+ """Build the backend for the active platform.
310
+
311
+ iOS and Android get the bridge backend. ``pn preview``
312
+ (``PN_PLATFORM=desktop``) gets the Tkinter handler registry.
313
+ Anywhere else (plain unit tests) there is no renderer at all, so
314
+ the registry is empty: tests inject a
315
+ ``pythonnative.testing.FakeBackend`` with ``set_registry`` and a
316
+ stray commit raises a clear "unknown element type" rather than
317
+ silently importing a platform module.
318
+ """
319
+ from ..utils import IS_ANDROID, IS_DESKTOP, IS_IOS
320
+
321
+ if IS_IOS or IS_ANDROID:
322
+ from .bridge_backend import BridgeBackend
348
323
 
349
- The first call instantiates the registry, registers either the
350
- Android or iOS handlers based on `IS_ANDROID`, then layers on every
351
- decorator-registered SDK handler (and any handlers exposed by
352
- third-party packages via the
353
- [`pythonnative.handlers`][pythonnative.sdk.ENTRY_POINT_GROUP] entry
354
- point group). Subsequent calls return the same instance.
324
+ return BridgeBackend()
325
+ registry = NativeViewRegistry()
326
+ if IS_DESKTOP:
327
+ from .desktop import register_handlers
328
+
329
+ register_handlers(registry)
330
+ _install_sdk_handlers(registry)
331
+ return registry
332
+
333
+
334
+ def get_registry() -> Any:
335
+ """Return the process-wide view backend, creating it on first use.
355
336
 
356
337
  Returns:
357
- The active `NativeViewRegistry`.
338
+ A [`BridgeBackend`][pythonnative.native_views.bridge_backend.BridgeBackend]
339
+ on device, otherwise a `NativeViewRegistry` (Tkinter handlers
340
+ under ``pn preview``, plus every decorator-registered SDK
341
+ handler and any handlers exposed by third-party packages via
342
+ the [`pythonnative.handlers`][pythonnative.sdk.ENTRY_POINT_GROUP]
343
+ entry point group).
358
344
  """
359
345
  global _registry
360
346
  if _registry is not None:
361
347
  return _registry
362
- _registry = NativeViewRegistry()
363
- _register_builtin_handlers(_registry)
364
- _install_sdk_handlers(_registry)
348
+ _registry = _create_backend()
365
349
  return _registry
366
350
 
367
351
 
368
- def refresh_registry() -> NativeViewRegistry:
369
- """Re-run SDK handler installation against the existing registry.
352
+ def refresh_registry() -> Any:
353
+ """Re-run SDK handler installation against the existing backend.
370
354
 
371
355
  Call this after registering a new component at runtime if the
372
356
  registry has already been instantiated. This is mostly useful in
373
357
  REPL sessions and tests; the normal flow is "register, then call
374
358
  [`get_registry`][pythonnative.native_views.get_registry]" and the
375
359
  handlers come along automatically.
376
-
377
- Returns:
378
- The active `NativeViewRegistry`.
379
360
  """
380
361
  registry = get_registry()
381
362
  _install_sdk_handlers(registry)
382
363
  return registry
383
364
 
384
365
 
385
- def set_registry(registry: Optional[NativeViewRegistry]) -> None:
386
- """Install a custom registry (primarily for testing).
366
+ def set_registry(registry: Any) -> None:
367
+ """Install a custom backend (primarily for testing).
387
368
 
388
369
  Replaces the lazy singleton so subsequent
389
370
  [`get_registry`][pythonnative.native_views.get_registry] calls
@@ -393,7 +374,7 @@ def set_registry(registry: Optional[NativeViewRegistry]) -> None:
393
374
  rebuild it from scratch.
394
375
 
395
376
  Args:
396
- registry: The replacement registry, or ``None`` to clear.
377
+ registry: The replacement backend, or ``None`` to clear.
397
378
  """
398
379
  global _registry
399
380
  _registry = registry