craft-native 0.0.244 → 0.0.246
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.
- package/dist/android/src/index.d.ts +20 -0
- package/dist/android/src/index.js +5 -0
- package/dist/android/templates/CraftNativeBackground.kt.template +36 -2
- package/dist/android/templates/CraftNativeHaptics.kt.template +124 -0
- package/dist/android/templates/CraftNativeShell.kt.template +282 -72
- package/dist/android/templates/MainActivityNative.kt.template +8 -7
- package/dist/api/mobile.d.ts +71 -3
- package/dist/browser/storage.d.ts +11 -0
- package/dist/browser.d.ts +9 -0
- package/dist/browser.js +66 -13
- package/dist/cli.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/ios/src/index.d.ts +32 -1
- package/dist/ios/src/index.js +6 -0
- package/dist/ios/templates/CraftApp.swift +8 -0
- package/dist/ios/templates/CraftHybrid.swift +192 -16
- package/dist/ios/templates/CraftNativeActions.swift +63 -5
- package/dist/ios/templates/CraftNativeFlatList.swift +13 -6
- package/dist/ios/templates/CraftNativeScreen.swift +396 -66
- package/dist/ios/templates/CraftWebAudio.swift +21 -13
- package/dist/mobile-testing.js +9 -3
- package/dist/mobile.js +33 -3
- package/package.json +1 -1
|
@@ -205,11 +205,21 @@ enum CraftNativeActions {
|
|
|
205
205
|
complete(requestToken, failure("CAPABILITY_DISABLED", "Secure storage is disabled"), completion)
|
|
206
206
|
return
|
|
207
207
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
208
|
+
let write = { () -> Result<Any, CraftNativeActionError> in
|
|
209
|
+
let result = secureStorage(method: method, args: args)
|
|
210
|
+
// A key the web page shares (`shareStorage`): the page gets it too,
|
|
211
|
+
// so a sign-in on a native screen signs the page in.
|
|
212
|
+
if case .success = result, ["set", "remove", "delete"].contains(method), let key = args.first as? String {
|
|
213
|
+
CraftHybrid.shared.nativeWroteShared(nativeKey: key, value: method == "set" ? args.count > 1 ? args[1] as? String : nil : nil)
|
|
214
|
+
}
|
|
215
|
+
return result
|
|
216
|
+
}
|
|
217
|
+
// A write that moves the sign-in token is the account's change:
|
|
218
|
+
// every screen hears it (CraftSession). Reads skip the check.
|
|
219
|
+
if ["set", "remove", "delete", "clear"].contains(method) {
|
|
220
|
+
sync = CraftSession.observe(key: method == "clear" ? nil : args.first as? String, config: config, write)
|
|
221
|
+
} else {
|
|
222
|
+
sync = write()
|
|
213
223
|
}
|
|
214
224
|
case ("Biometrics", "isAvailable"):
|
|
215
225
|
sync = config.enableBiometric ? .success(biometricContext().canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil)) : failure("CAPABILITY_DISABLED", "Biometric authentication is disabled")
|
|
@@ -1423,6 +1433,54 @@ extension CraftNativeActions {
|
|
|
1423
1433
|
}
|
|
1424
1434
|
}
|
|
1425
1435
|
|
|
1436
|
+
/// The signed-in account: the token kept in secure storage under
|
|
1437
|
+
/// `sessionTokenKey` (default `auth.token`). Whoever moves it, a native
|
|
1438
|
+
/// screen's `craft.secureStorage`, the page's own sign-in through a
|
|
1439
|
+
/// `shareStorage` key, or a sign-out's clear, posts `changed` once with
|
|
1440
|
+
/// `key`, `token` and `previous` (NSNull when signed out), after the Keychain
|
|
1441
|
+
/// holds the new value. Each native screen hands it to its script as
|
|
1442
|
+
/// `SESSION_CHANGED` and to `craft.session.onChange` (CraftNativeScreen).
|
|
1443
|
+
enum CraftSession {
|
|
1444
|
+
static let changed = Notification.Name("craftSessionChanged")
|
|
1445
|
+
static let defaultKey = "auth.token"
|
|
1446
|
+
/// One write and its before and after at a time, so two quick writes
|
|
1447
|
+
/// from different queues are two changes, never one reported twice.
|
|
1448
|
+
private static let lock = NSLock()
|
|
1449
|
+
|
|
1450
|
+
static func tokenKey(_ config: CraftConfig) -> String {
|
|
1451
|
+
guard let key = config.sessionTokenKey, !key.isEmpty else { return defaultKey }
|
|
1452
|
+
return key
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
/// The token now, as `craft.secureStorage.getSync` reads it; nil when
|
|
1456
|
+
/// signed out (an empty token is no account either).
|
|
1457
|
+
static func token(_ config: CraftConfig) -> String? {
|
|
1458
|
+
guard config.enableSecureStorage,
|
|
1459
|
+
let value = CraftNativeActions.webSecureValue(forKey: tokenKey(config)), !value.isEmpty else { return nil }
|
|
1460
|
+
return value
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
/// Run `write`, and post `changed` when it moved the token. `key` is the
|
|
1464
|
+
/// key written; nil for a clear, which can remove every key.
|
|
1465
|
+
static func observe<T>(key: String?, config: CraftConfig, _ write: () -> T) -> T {
|
|
1466
|
+
let name = tokenKey(config)
|
|
1467
|
+
guard key == nil || key == name else { return write() }
|
|
1468
|
+
lock.lock()
|
|
1469
|
+
let before = token(config)
|
|
1470
|
+
let result = write()
|
|
1471
|
+
let after = token(config)
|
|
1472
|
+
lock.unlock()
|
|
1473
|
+
if before != after { post(key: name, token: after, previous: before) }
|
|
1474
|
+
return result
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
static func post(key: String, token: String?, previous: String?) {
|
|
1478
|
+
let info: [String: Any] = ["key": key, "token": token ?? NSNull(), "previous": previous ?? NSNull()]
|
|
1479
|
+
let send = { NotificationCenter.default.post(name: changed, object: nil, userInfo: info) }
|
|
1480
|
+
if Thread.isMainThread { send() } else { DispatchQueue.main.async(execute: send) }
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1426
1484
|
/// Last-known data for a screen's first frame: one JSON file per name in
|
|
1427
1485
|
/// `Application Support/craft-snapshots/<name>.json`. A web page writes them
|
|
1428
1486
|
/// (`snapshots.set` in the mobile API) and a native screen reads them
|
|
@@ -52,11 +52,19 @@ final class CraftNativeFlatList: UICollectionView, UICollectionViewDelegateFlowL
|
|
|
52
52
|
var onRecycle: ((String) -> Void)?
|
|
53
53
|
override func prepareForReuse() {
|
|
54
54
|
super.prepareForReuse()
|
|
55
|
-
|
|
55
|
+
recycle()
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/// The row this cell showed is gone; its views stay in the cell, and
|
|
59
|
+
/// the next row it shows reuses them when it has the same shape.
|
|
60
|
+
func recycle() {
|
|
61
|
+
if let identity = representedIdentity { onRecycle?(identity) }
|
|
62
|
+
representedIdentity = nil
|
|
63
|
+
onRecycle = nil
|
|
56
64
|
}
|
|
57
65
|
|
|
58
66
|
func host(_ view: UIView, identity: String) {
|
|
59
|
-
if representedIdentity != identity {
|
|
67
|
+
if let shown = representedIdentity, shown != identity { recycle() }
|
|
60
68
|
representedIdentity = identity
|
|
61
69
|
guard hostedView !== view else { return }
|
|
62
70
|
hostedView?.removeFromSuperview()
|
|
@@ -72,11 +80,9 @@ final class CraftNativeFlatList: UICollectionView, UICollectionViewDelegateFlowL
|
|
|
72
80
|
}
|
|
73
81
|
|
|
74
82
|
func releaseHostedView() {
|
|
75
|
-
|
|
83
|
+
recycle()
|
|
76
84
|
hostedView?.removeFromSuperview()
|
|
77
85
|
hostedView = nil
|
|
78
|
-
representedIdentity = nil
|
|
79
|
-
onRecycle = nil
|
|
80
86
|
}
|
|
81
87
|
|
|
82
88
|
override func preferredLayoutAttributesFitting(
|
|
@@ -354,7 +360,8 @@ final class CraftNativeFlatList: UICollectionView, UICollectionViewDelegateFlowL
|
|
|
354
360
|
|
|
355
361
|
@objc private func refreshTriggered() {
|
|
356
362
|
refreshHandler?()
|
|
357
|
-
|
|
363
|
+
// Once the script has answered the pull, on its own thread or not.
|
|
364
|
+
CraftNativeScriptThread.afterScript { [weak self] in
|
|
358
365
|
guard let self, !self.refreshingProp, self.nativeRefreshControl.isRefreshing else { return }
|
|
359
366
|
self.nativeRefreshControl.endRefreshing()
|
|
360
367
|
}
|