zixflow-reactnative 1.1.2 → 1.1.4
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/README.md +2224 -322
- package/android/build.gradle +18 -1
- package/android/consumer-rules.pro +3 -2
- package/android/gradle.properties +1 -1
- package/android/src/main/java/com/zixflow/reactnative/sdk/NativeZixflowModule.kt +69 -24
- package/android/src/main/java/com/zixflow/reactnative/sdk/ZixflowReactNativePackage.kt +25 -1
- package/android/src/main/java/com/zixflow/reactnative/sdk/constant/Keys.kt +19 -3
- package/android/src/main/java/com/zixflow/reactnative/sdk/geofence/NativeGeofenceModule.kt +65 -0
- package/android/src/main/java/com/zixflow/reactnative/sdk/liveactivities/NativeLiveActivitiesModule.kt +310 -0
- package/android/src/main/java/com/zixflow/reactnative/sdk/logging/NativeZixflowLoggingModule.kt +2 -2
- package/android/src/main/java/com/zixflow/reactnative/sdk/messaginginapp/NativeMessagingInAppModule.kt +149 -10
- package/android/src/main/java/com/zixflow/reactnative/sdk/messaginginapp/ReactInboxEventListener.kt +99 -0
- package/android/src/main/java/com/zixflow/reactnative/sdk/messaginginbox/NotificationInboxBellViewManager.kt +38 -0
- package/android/src/main/java/com/zixflow/reactnative/sdk/messaginginbox/NotificationInboxViewManager.kt +30 -0
- package/android/src/main/java/com/zixflow/reactnative/sdk/messaginginbox/ReactComposeHostView.kt +96 -0
- package/android/src/main/java/com/zixflow/reactnative/sdk/messaginginbox/ReactNotificationInboxBellView.kt +48 -0
- package/android/src/main/java/com/zixflow/reactnative/sdk/messaginginbox/ReactNotificationInboxView.kt +17 -0
- package/android/src/main/java/com/zixflow/reactnative/sdk/messagingpush/NativeMessagingPushModule.kt +11 -1
- package/android/src/main/res/values/zixflow_config.xml +1 -1
- package/android/zixflow-core.gradle +17 -7
- package/docs/cocoapods-deployment-target-normalization.md +139 -0
- package/ios/cocoapods_deployment_target.rb +432 -0
- package/ios/wrappers/NativeZixflow.mm +37 -0
- package/ios/wrappers/NativeZixflow.swift +135 -1
- package/ios/wrappers/ZixflowReactNativeDeepLinkRequestStore.swift +123 -0
- package/ios/wrappers/ZixflowReactNativeDeepLinkRouter.swift +312 -0
- package/ios/wrappers/geofence/NativeGeofence.mm +46 -0
- package/ios/wrappers/geofence/NativeGeofence.swift +27 -0
- package/ios/wrappers/inapp/NativeMessagingInApp.mm +22 -0
- package/ios/wrappers/inapp/NativeMessagingInApp.swift +90 -0
- package/ios/wrappers/inbox/InboxHostContainment.swift +40 -0
- package/ios/wrappers/inbox/RCTNotificationInboxBellNative.h +12 -0
- package/ios/wrappers/inbox/RCTNotificationInboxBellNative.mm +98 -0
- package/ios/wrappers/inbox/RCTNotificationInboxViewNative.h +12 -0
- package/ios/wrappers/inbox/RCTNotificationInboxViewNative.mm +78 -0
- package/ios/wrappers/inbox/ReactInboxEventListener.swift +76 -0
- package/ios/wrappers/inbox/ReactNotificationInboxBellView.h +22 -0
- package/ios/wrappers/inbox/ReactNotificationInboxBellView.swift +109 -0
- package/ios/wrappers/inbox/ReactNotificationInboxView.h +22 -0
- package/ios/wrappers/inbox/ReactNotificationInboxView.swift +69 -0
- package/ios/wrappers/liveactivities/NativeLiveActivities.mm +83 -0
- package/ios/wrappers/liveactivities/NativeLiveActivities.swift +390 -0
- package/ios/wrappers/location/NativeLocation.swift +7 -5
- package/ios/wrappers/utils/ZixflowConfigUtils.swift +5 -9
- package/ios/wrappers/utils/ZixflowConstants.swift +4 -0
- package/ios/wrappers/zixflow_reactnative.h +6 -0
- package/lib/commonjs/components/NotificationInboxBellView.js +49 -0
- package/lib/commonjs/components/NotificationInboxBellView.js.map +1 -0
- package/lib/commonjs/components/NotificationInboxView.js +36 -0
- package/lib/commonjs/components/NotificationInboxView.js.map +1 -0
- package/lib/commonjs/components/index.js +14 -0
- package/lib/commonjs/components/index.js.map +1 -1
- package/lib/commonjs/index.js +81 -4
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/notification-inbox.js +1 -0
- package/lib/commonjs/notification-inbox.js.map +1 -1
- package/lib/commonjs/specs/components/NotificationInboxBellNativeComponent.ts +24 -0
- package/lib/commonjs/specs/components/NotificationInboxViewNativeComponent.ts +22 -0
- package/lib/commonjs/specs/modules/NativeZixflow.js.map +1 -1
- package/lib/commonjs/specs/modules/NativeZixflowGeofence.js +15 -0
- package/lib/commonjs/specs/modules/NativeZixflowGeofence.js.map +1 -0
- package/lib/commonjs/specs/modules/NativeZixflowLiveActivities.js +23 -0
- package/lib/commonjs/specs/modules/NativeZixflowLiveActivities.js.map +1 -0
- package/lib/commonjs/specs/modules/NativeZixflowMessagingInApp.js +3 -1
- package/lib/commonjs/specs/modules/NativeZixflowMessagingInApp.js.map +1 -1
- package/lib/commonjs/specs/modules/NativeZixflowMessagingPush.js +3 -1
- package/lib/commonjs/specs/modules/NativeZixflowMessagingPush.js.map +1 -1
- package/lib/commonjs/types/data-pipelines.js +15 -15
- package/lib/commonjs/types/data-pipelines.js.map +1 -1
- package/lib/commonjs/types/in-app.js +24 -1
- package/lib/commonjs/types/in-app.js.map +1 -1
- package/lib/commonjs/types/inbox.js +79 -0
- package/lib/commonjs/types/inbox.js.map +1 -0
- package/lib/commonjs/types/index.js +22 -0
- package/lib/commonjs/types/index.js.map +1 -1
- package/lib/commonjs/types/live-activities.js +85 -0
- package/lib/commonjs/types/live-activities.js.map +1 -0
- package/lib/commonjs/utils/param-validation.js +77 -2
- package/lib/commonjs/utils/param-validation.js.map +1 -1
- package/lib/commonjs/zixflow-cdp.js +101 -11
- package/lib/commonjs/zixflow-cdp.js.map +1 -1
- package/lib/commonjs/zixflow-geofence.js +55 -0
- package/lib/commonjs/zixflow-geofence.js.map +1 -0
- package/lib/commonjs/zixflow-inapp.js +120 -0
- package/lib/commonjs/zixflow-inapp.js.map +1 -1
- package/lib/commonjs/zixflow-liveactivities.js +85 -0
- package/lib/commonjs/zixflow-liveactivities.js.map +1 -0
- package/lib/commonjs/zixflow.js.map +1 -1
- package/lib/module/components/NotificationInboxBellView.js +44 -0
- package/lib/module/components/NotificationInboxBellView.js.map +1 -0
- package/lib/module/components/NotificationInboxView.js +31 -0
- package/lib/module/components/NotificationInboxView.js.map +1 -0
- package/lib/module/components/index.js +5 -0
- package/lib/module/components/index.js.map +1 -1
- package/lib/module/index.js +8 -3
- package/lib/module/index.js.map +1 -1
- package/lib/module/notification-inbox.js +1 -1
- package/lib/module/notification-inbox.js.map +1 -1
- package/lib/module/specs/components/NotificationInboxBellNativeComponent.ts +24 -0
- package/lib/module/specs/components/NotificationInboxViewNativeComponent.ts +22 -0
- package/lib/module/specs/modules/NativeZixflow.js.map +1 -1
- package/lib/module/specs/modules/NativeZixflowGeofence.js +13 -0
- package/lib/module/specs/modules/NativeZixflowGeofence.js.map +1 -0
- package/lib/module/specs/modules/NativeZixflowLiveActivities.js +21 -0
- package/lib/module/specs/modules/NativeZixflowLiveActivities.js.map +1 -0
- package/lib/module/specs/modules/NativeZixflowMessagingInApp.js +3 -1
- package/lib/module/specs/modules/NativeZixflowMessagingInApp.js.map +1 -1
- package/lib/module/specs/modules/NativeZixflowMessagingPush.js +3 -1
- package/lib/module/specs/modules/NativeZixflowMessagingPush.js.map +1 -1
- package/lib/module/types/data-pipelines.js +15 -15
- package/lib/module/types/data-pipelines.js.map +1 -1
- package/lib/module/types/in-app.js +24 -0
- package/lib/module/types/in-app.js.map +1 -1
- package/lib/module/types/inbox.js +75 -0
- package/lib/module/types/inbox.js.map +1 -0
- package/lib/module/types/index.js +2 -0
- package/lib/module/types/index.js.map +1 -1
- package/lib/module/types/live-activities.js +88 -0
- package/lib/module/types/live-activities.js.map +1 -0
- package/lib/module/utils/param-validation.js +77 -2
- package/lib/module/utils/param-validation.js.map +1 -1
- package/lib/module/zixflow-cdp.js +101 -11
- package/lib/module/zixflow-cdp.js.map +1 -1
- package/lib/module/zixflow-geofence.js +50 -0
- package/lib/module/zixflow-geofence.js.map +1 -0
- package/lib/module/zixflow-inapp.js +99 -1
- package/lib/module/zixflow-inapp.js.map +1 -1
- package/lib/module/zixflow-liveactivities.js +80 -0
- package/lib/module/zixflow-liveactivities.js.map +1 -0
- package/lib/module/zixflow.js +0 -6
- package/lib/module/zixflow.js.map +1 -1
- package/lib/typescript/commonjs/components/NotificationInboxBellView.d.ts +39 -0
- package/lib/typescript/commonjs/components/NotificationInboxBellView.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/NotificationInboxView.d.ts +25 -0
- package/lib/typescript/commonjs/components/NotificationInboxView.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/index.d.ts +4 -0
- package/lib/typescript/commonjs/components/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +8 -1
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/notification-inbox.d.ts +5 -0
- package/lib/typescript/commonjs/notification-inbox.d.ts.map +1 -1
- package/lib/typescript/commonjs/specs/components/NotificationInboxBellNativeComponent.d.ts +13 -0
- package/lib/typescript/commonjs/specs/components/NotificationInboxBellNativeComponent.d.ts.map +1 -0
- package/lib/typescript/commonjs/specs/components/NotificationInboxViewNativeComponent.d.ts +12 -0
- package/lib/typescript/commonjs/specs/components/NotificationInboxViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/commonjs/specs/modules/NativeZixflow.d.ts +6 -1
- package/lib/typescript/commonjs/specs/modules/NativeZixflow.d.ts.map +1 -1
- package/lib/typescript/commonjs/specs/modules/NativeZixflowGeofence.d.ts +13 -0
- package/lib/typescript/commonjs/specs/modules/NativeZixflowGeofence.d.ts.map +1 -0
- package/lib/typescript/commonjs/specs/modules/NativeZixflowLiveActivities.d.ts +31 -0
- package/lib/typescript/commonjs/specs/modules/NativeZixflowLiveActivities.d.ts.map +1 -0
- package/lib/typescript/commonjs/specs/modules/NativeZixflowMessagingInApp.d.ts +5 -1
- package/lib/typescript/commonjs/specs/modules/NativeZixflowMessagingInApp.d.ts.map +1 -1
- package/lib/typescript/commonjs/specs/modules/NativeZixflowMessagingPush.d.ts +1 -1
- package/lib/typescript/commonjs/specs/modules/NativeZixflowMessagingPush.d.ts.map +1 -1
- package/lib/typescript/commonjs/types/data-pipelines.d.ts +54 -18
- package/lib/typescript/commonjs/types/data-pipelines.d.ts.map +1 -1
- package/lib/typescript/commonjs/types/in-app.d.ts +22 -0
- package/lib/typescript/commonjs/types/in-app.d.ts.map +1 -1
- package/lib/typescript/commonjs/types/inbox.d.ts +97 -0
- package/lib/typescript/commonjs/types/inbox.d.ts.map +1 -0
- package/lib/typescript/commonjs/types/index.d.ts +2 -0
- package/lib/typescript/commonjs/types/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/types/live-activities.d.ts +161 -0
- package/lib/typescript/commonjs/types/live-activities.d.ts.map +1 -0
- package/lib/typescript/commonjs/utils/param-validation.d.ts +7 -0
- package/lib/typescript/commonjs/utils/param-validation.d.ts.map +1 -1
- package/lib/typescript/commonjs/zixflow-cdp.d.ts +38 -0
- package/lib/typescript/commonjs/zixflow-cdp.d.ts.map +1 -1
- package/lib/typescript/commonjs/zixflow-geofence.d.ts +36 -0
- package/lib/typescript/commonjs/zixflow-geofence.d.ts.map +1 -0
- package/lib/typescript/commonjs/zixflow-inapp.d.ts +36 -2
- package/lib/typescript/commonjs/zixflow-inapp.d.ts.map +1 -1
- package/lib/typescript/commonjs/zixflow-liveactivities.d.ts +66 -0
- package/lib/typescript/commonjs/zixflow-liveactivities.d.ts.map +1 -0
- package/lib/typescript/commonjs/zixflow.d.ts +0 -5
- package/lib/typescript/commonjs/zixflow.d.ts.map +1 -1
- package/lib/typescript/module/components/NotificationInboxBellView.d.ts +39 -0
- package/lib/typescript/module/components/NotificationInboxBellView.d.ts.map +1 -0
- package/lib/typescript/module/components/NotificationInboxView.d.ts +25 -0
- package/lib/typescript/module/components/NotificationInboxView.d.ts.map +1 -0
- package/lib/typescript/module/components/index.d.ts +4 -0
- package/lib/typescript/module/components/index.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +8 -1
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/notification-inbox.d.ts +5 -0
- package/lib/typescript/module/notification-inbox.d.ts.map +1 -1
- package/lib/typescript/module/specs/components/NotificationInboxBellNativeComponent.d.ts +13 -0
- package/lib/typescript/module/specs/components/NotificationInboxBellNativeComponent.d.ts.map +1 -0
- package/lib/typescript/module/specs/components/NotificationInboxViewNativeComponent.d.ts +12 -0
- package/lib/typescript/module/specs/components/NotificationInboxViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/module/specs/modules/NativeZixflow.d.ts +6 -1
- package/lib/typescript/module/specs/modules/NativeZixflow.d.ts.map +1 -1
- package/lib/typescript/module/specs/modules/NativeZixflowGeofence.d.ts +13 -0
- package/lib/typescript/module/specs/modules/NativeZixflowGeofence.d.ts.map +1 -0
- package/lib/typescript/module/specs/modules/NativeZixflowLiveActivities.d.ts +31 -0
- package/lib/typescript/module/specs/modules/NativeZixflowLiveActivities.d.ts.map +1 -0
- package/lib/typescript/module/specs/modules/NativeZixflowMessagingInApp.d.ts +5 -1
- package/lib/typescript/module/specs/modules/NativeZixflowMessagingInApp.d.ts.map +1 -1
- package/lib/typescript/module/specs/modules/NativeZixflowMessagingPush.d.ts +1 -1
- package/lib/typescript/module/specs/modules/NativeZixflowMessagingPush.d.ts.map +1 -1
- package/lib/typescript/module/types/data-pipelines.d.ts +54 -18
- package/lib/typescript/module/types/data-pipelines.d.ts.map +1 -1
- package/lib/typescript/module/types/in-app.d.ts +22 -0
- package/lib/typescript/module/types/in-app.d.ts.map +1 -1
- package/lib/typescript/module/types/inbox.d.ts +97 -0
- package/lib/typescript/module/types/inbox.d.ts.map +1 -0
- package/lib/typescript/module/types/index.d.ts +2 -0
- package/lib/typescript/module/types/index.d.ts.map +1 -1
- package/lib/typescript/module/types/live-activities.d.ts +161 -0
- package/lib/typescript/module/types/live-activities.d.ts.map +1 -0
- package/lib/typescript/module/utils/param-validation.d.ts +7 -0
- package/lib/typescript/module/utils/param-validation.d.ts.map +1 -1
- package/lib/typescript/module/zixflow-cdp.d.ts +38 -0
- package/lib/typescript/module/zixflow-cdp.d.ts.map +1 -1
- package/lib/typescript/module/zixflow-geofence.d.ts +36 -0
- package/lib/typescript/module/zixflow-geofence.d.ts.map +1 -0
- package/lib/typescript/module/zixflow-inapp.d.ts +36 -2
- package/lib/typescript/module/zixflow-inapp.d.ts.map +1 -1
- package/lib/typescript/module/zixflow-liveactivities.d.ts +66 -0
- package/lib/typescript/module/zixflow-liveactivities.d.ts.map +1 -0
- package/lib/typescript/module/zixflow.d.ts +0 -5
- package/lib/typescript/module/zixflow.d.ts.map +1 -1
- package/package.json +14 -5
- package/src/components/NotificationInboxBellView.tsx +55 -0
- package/src/components/NotificationInboxView.tsx +30 -0
- package/src/components/index.ts +6 -0
- package/src/index.ts +8 -3
- package/src/notification-inbox.ts +1 -1
- package/src/specs/components/NotificationInboxBellNativeComponent.ts +24 -0
- package/src/specs/components/NotificationInboxViewNativeComponent.ts +22 -0
- package/src/specs/modules/NativeZixflow.ts +9 -1
- package/src/specs/modules/NativeZixflowGeofence.ts +14 -0
- package/src/specs/modules/NativeZixflowLiveActivities.ts +39 -0
- package/src/specs/modules/NativeZixflowMessagingInApp.ts +12 -1
- package/src/specs/modules/NativeZixflowMessagingPush.ts +3 -1
- package/src/types/data-pipelines.ts +55 -19
- package/src/types/in-app.ts +23 -0
- package/src/types/inbox.ts +110 -0
- package/src/types/index.ts +2 -0
- package/src/types/live-activities.ts +170 -0
- package/src/utils/param-validation.ts +104 -1
- package/src/zixflow-cdp.ts +119 -13
- package/src/zixflow-geofence.ts +56 -0
- package/src/zixflow-inapp.ts +125 -2
- package/src/zixflow-liveactivities.ts +86 -0
- package/src/zixflow.ts +0 -6
- package/zixflow-reactnative-richpush.podspec +6 -3
- package/zixflow-reactnative.podspec +28 -2
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This packaged copy is owned by zixflow-reactnative and covered by its local test suite.
|
|
4
|
+
|
|
5
|
+
require "rubygems/version"
|
|
6
|
+
|
|
7
|
+
module Zixflow
|
|
8
|
+
# Normalizes every CocoaPods-generated target and every integrated application or extension
|
|
9
|
+
# target to a numeric iOS deployment target that the selected Xcode toolchain supports.
|
|
10
|
+
module CocoaPodsDeploymentTarget
|
|
11
|
+
BUILD_SETTING = "IPHONEOS_DEPLOYMENT_TARGET"
|
|
12
|
+
VERSION_PATTERN = /\A\d+(?:\.\d+){0,2}\z/.freeze
|
|
13
|
+
|
|
14
|
+
Record = Struct.new(
|
|
15
|
+
:project,
|
|
16
|
+
:target,
|
|
17
|
+
:configuration,
|
|
18
|
+
:original_effective,
|
|
19
|
+
:target_configuration_value,
|
|
20
|
+
:project_value,
|
|
21
|
+
:current,
|
|
22
|
+
:changed,
|
|
23
|
+
:configuration_object,
|
|
24
|
+
keyword_init: true
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
class AuditError < StandardError; end
|
|
28
|
+
|
|
29
|
+
module_function
|
|
30
|
+
|
|
31
|
+
# Raises low effective deployment settings to +minimum_ios_version+. A missing target setting
|
|
32
|
+
# resolves through its xcconfig and then the same-named project configuration. Numeric effective
|
|
33
|
+
# settings above the minimum are preserved. A selected non-numeric effective setting fails
|
|
34
|
+
# closed because its resolved value cannot be audited deterministically from the project.
|
|
35
|
+
def normalize!(installer, minimum_ios_version:, io: $stdout)
|
|
36
|
+
minimum = parse_version!(minimum_ios_version, context: "minimum iOS version")
|
|
37
|
+
targets = installer_targets(installer)
|
|
38
|
+
records = records_for(targets)
|
|
39
|
+
ensure_records!(records)
|
|
40
|
+
validate_numeric_settings!(records)
|
|
41
|
+
|
|
42
|
+
records = records.map do |record|
|
|
43
|
+
normalize_record!(record, minimum)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
audit_records!(records, minimum)
|
|
47
|
+
save_integrated_user_projects!(installer, records)
|
|
48
|
+
write_changes(io, records)
|
|
49
|
+
write_summary(io, records, minimum)
|
|
50
|
+
records
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Audits an installer without modifying it. This is useful from a second post-install check.
|
|
54
|
+
def audit!(installer, minimum_ios_version:, io: $stdout)
|
|
55
|
+
minimum = parse_version!(minimum_ios_version, context: "minimum iOS version")
|
|
56
|
+
records = records_for(installer_targets(installer))
|
|
57
|
+
ensure_records!(records)
|
|
58
|
+
|
|
59
|
+
audit_records!(records, minimum)
|
|
60
|
+
write_summary(io, records, minimum)
|
|
61
|
+
records
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Audits projects loaded by Xcodeproj. The caller owns loading the projects so this helper does
|
|
65
|
+
# not add a runtime dependency on Xcodeproj to the normal Podfile integration path.
|
|
66
|
+
def audit_projects!(projects, minimum_ios_version:, io: $stdout)
|
|
67
|
+
minimum = parse_version!(minimum_ios_version, context: "minimum iOS version")
|
|
68
|
+
targets = projects.flat_map { |project| project.targets }
|
|
69
|
+
records = records_for(targets)
|
|
70
|
+
ensure_records!(records)
|
|
71
|
+
|
|
72
|
+
audit_records!(records, minimum)
|
|
73
|
+
write_records(io, records, minimum)
|
|
74
|
+
records
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Returns the greater of two numeric iOS deployment targets. React Native integrations use
|
|
78
|
+
# this to preserve React Native's own floor when it is higher than Zixflow's floor.
|
|
79
|
+
def maximum(first, second)
|
|
80
|
+
first_version = parse_version!(first, context: "iOS version")
|
|
81
|
+
second_version = parse_version!(second, context: "iOS version")
|
|
82
|
+
[first_version, second_version].max.to_s
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def installer_targets(installer)
|
|
86
|
+
generated_projects = if installer.respond_to?(:generated_projects)
|
|
87
|
+
Array(installer.generated_projects).compact
|
|
88
|
+
else
|
|
89
|
+
[]
|
|
90
|
+
end
|
|
91
|
+
if generated_projects.empty? && installer.respond_to?(:pods_project)
|
|
92
|
+
generated_projects = [installer.pods_project].compact
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
pod_targets = generated_projects.flat_map { |project| project.targets }
|
|
96
|
+
user_targets = if installer.respond_to?(:aggregate_targets)
|
|
97
|
+
Array(installer.aggregate_targets).flat_map do |aggregate_target|
|
|
98
|
+
aggregate_target.respond_to?(:user_targets) ? Array(aggregate_target.user_targets) : []
|
|
99
|
+
end
|
|
100
|
+
else
|
|
101
|
+
[]
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
deduplicate_targets(pod_targets + user_targets)
|
|
105
|
+
end
|
|
106
|
+
private_class_method :installer_targets
|
|
107
|
+
|
|
108
|
+
def save_integrated_user_projects!(installer, records)
|
|
109
|
+
return unless installer.respond_to?(:aggregate_targets)
|
|
110
|
+
|
|
111
|
+
changed_project_paths = records.select(&:changed).map(&:project).uniq
|
|
112
|
+
return if changed_project_paths.empty?
|
|
113
|
+
|
|
114
|
+
projects = Array(installer.aggregate_targets).each_with_object([]) do |aggregate_target, result|
|
|
115
|
+
if aggregate_target.respond_to?(:user_project)
|
|
116
|
+
user_project = aggregate_target.user_project
|
|
117
|
+
result << user_project unless user_project.nil?
|
|
118
|
+
end
|
|
119
|
+
next unless aggregate_target.respond_to?(:user_targets)
|
|
120
|
+
|
|
121
|
+
Array(aggregate_target.user_targets).each do |target|
|
|
122
|
+
result << target.project if target.respond_to?(:project) && !target.project.nil?
|
|
123
|
+
end
|
|
124
|
+
end.compact
|
|
125
|
+
|
|
126
|
+
projects.select { |project| changed_project_paths.include?(project_path(project)) }
|
|
127
|
+
.uniq { |project| project_path(project) }
|
|
128
|
+
.each do |project|
|
|
129
|
+
unless project.respond_to?(:save)
|
|
130
|
+
raise AuditError, "Cannot save integrated user project #{project_path(project)}"
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
project.save
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
private_class_method :save_integrated_user_projects!
|
|
137
|
+
|
|
138
|
+
def deduplicate_targets(targets)
|
|
139
|
+
targets.each_with_object({}) do |target, unique|
|
|
140
|
+
project = target.respond_to?(:project) ? target.project : nil
|
|
141
|
+
project_key = project_path(project)
|
|
142
|
+
target_key = target.respond_to?(:uuid) ? target.uuid : target.object_id
|
|
143
|
+
unique[[project_key, target_key]] ||= target
|
|
144
|
+
end.values
|
|
145
|
+
end
|
|
146
|
+
private_class_method :deduplicate_targets
|
|
147
|
+
|
|
148
|
+
def normalize_record!(record, minimum)
|
|
149
|
+
current = record.current
|
|
150
|
+
current_version = current.nil? ? nil : parse_version!(current, context: record_context(record))
|
|
151
|
+
return record if current_version && current_version >= minimum
|
|
152
|
+
|
|
153
|
+
record.configuration_object.build_settings[BUILD_SETTING] = minimum.to_s
|
|
154
|
+
record.current = minimum.to_s
|
|
155
|
+
record.changed = true
|
|
156
|
+
record
|
|
157
|
+
end
|
|
158
|
+
private_class_method :normalize_record!
|
|
159
|
+
|
|
160
|
+
def records_for(targets)
|
|
161
|
+
targets.flat_map do |target|
|
|
162
|
+
project = target.respond_to?(:project) ? target.project : nil
|
|
163
|
+
target.build_configurations.map do |configuration|
|
|
164
|
+
context = configuration_context(project, target, configuration)
|
|
165
|
+
validate_no_conditional_settings!(configuration.build_settings, context: context)
|
|
166
|
+
target_setting_present = configuration.build_settings.key?(BUILD_SETTING)
|
|
167
|
+
target_value = normalized_setting(configuration.build_settings[BUILD_SETTING])
|
|
168
|
+
if target_setting_present
|
|
169
|
+
target_configuration_value = nil
|
|
170
|
+
project_value = nil
|
|
171
|
+
effective_value = target_value
|
|
172
|
+
else
|
|
173
|
+
target_configuration_present, target_configuration_value = configuration_file_setting(
|
|
174
|
+
configuration,
|
|
175
|
+
context: context
|
|
176
|
+
)
|
|
177
|
+
if target_configuration_present
|
|
178
|
+
project_value = nil
|
|
179
|
+
effective_value = target_configuration_value
|
|
180
|
+
else
|
|
181
|
+
project_configuration = matching_project_configuration(project, configuration.name)
|
|
182
|
+
project_value = effective_configuration_value(
|
|
183
|
+
project_configuration,
|
|
184
|
+
context: context
|
|
185
|
+
)
|
|
186
|
+
effective_value = project_value
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
Record.new(
|
|
190
|
+
project: project_path(project),
|
|
191
|
+
target: target.name.to_s,
|
|
192
|
+
configuration: configuration.name.to_s,
|
|
193
|
+
original_effective: effective_value,
|
|
194
|
+
target_configuration_value: target_configuration_value,
|
|
195
|
+
project_value: project_value,
|
|
196
|
+
current: effective_value,
|
|
197
|
+
changed: false,
|
|
198
|
+
configuration_object: configuration
|
|
199
|
+
)
|
|
200
|
+
end
|
|
201
|
+
end.sort_by { |record| [record.project, record.target, record.configuration] }
|
|
202
|
+
end
|
|
203
|
+
private_class_method :records_for
|
|
204
|
+
|
|
205
|
+
def effective_configuration_value(configuration, context:)
|
|
206
|
+
return nil if configuration.nil?
|
|
207
|
+
|
|
208
|
+
validate_no_conditional_settings!(configuration.build_settings, context: context)
|
|
209
|
+
|
|
210
|
+
if configuration.build_settings.key?(BUILD_SETTING)
|
|
211
|
+
return normalized_setting(configuration.build_settings[BUILD_SETTING])
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
_present, value = configuration_file_setting(configuration, context: context)
|
|
215
|
+
value
|
|
216
|
+
end
|
|
217
|
+
private_class_method :effective_configuration_value
|
|
218
|
+
|
|
219
|
+
def configuration_file_setting(configuration, context:)
|
|
220
|
+
synchronized_anchor = if configuration.respond_to?(:base_configuration_reference_anchor)
|
|
221
|
+
configuration.base_configuration_reference_anchor
|
|
222
|
+
end
|
|
223
|
+
synchronized_relative_path = if configuration.respond_to?(:base_configuration_reference_relative_path)
|
|
224
|
+
configuration.base_configuration_reference_relative_path
|
|
225
|
+
end
|
|
226
|
+
if synchronized_anchor || synchronized_relative_path
|
|
227
|
+
raise AuditError,
|
|
228
|
+
"#{context}: Cannot inspect synchronized-group xcconfig " \
|
|
229
|
+
"#{rendered_synchronized_path(synchronized_anchor, synchronized_relative_path)}. " \
|
|
230
|
+
"Use a standard xcconfig file reference before rerunning CocoaPods."
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
base_configuration_reference = if configuration.respond_to?(:base_configuration_reference)
|
|
234
|
+
configuration.base_configuration_reference
|
|
235
|
+
end
|
|
236
|
+
if base_configuration_reference
|
|
237
|
+
xcconfig_path = if base_configuration_reference.respond_to?(:real_path)
|
|
238
|
+
base_configuration_reference.real_path
|
|
239
|
+
end
|
|
240
|
+
unless xcconfig_path.respond_to?(:exist?) && xcconfig_path.exist? &&
|
|
241
|
+
xcconfig_path.respond_to?(:readable?) && xcconfig_path.readable?
|
|
242
|
+
rendered_path = xcconfig_path.nil? ? "(unresolved path)" : xcconfig_path.to_s
|
|
243
|
+
raise AuditError, "#{context}: Cannot read xcconfig #{rendered_path}"
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
unless defined?(::Xcodeproj::Config)
|
|
247
|
+
raise AuditError,
|
|
248
|
+
"#{context}: Cannot parse xcconfig #{xcconfig_path}; Xcodeproj::Config is unavailable"
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
begin
|
|
252
|
+
settings = ::Xcodeproj::Config.new(xcconfig_path).to_hash
|
|
253
|
+
rescue StandardError => error
|
|
254
|
+
raise AuditError,
|
|
255
|
+
"#{context}: Cannot parse xcconfig #{xcconfig_path}: " \
|
|
256
|
+
"#{error.class}: #{error.message}"
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
unless settings.respond_to?(:key?)
|
|
260
|
+
raise AuditError, "#{context}: Cannot inspect xcconfig #{xcconfig_path}"
|
|
261
|
+
end
|
|
262
|
+
validate_no_conditional_settings!(
|
|
263
|
+
settings,
|
|
264
|
+
context: "#{context}, xcconfig #{xcconfig_path}"
|
|
265
|
+
)
|
|
266
|
+
return [false, nil] unless settings.key?(BUILD_SETTING)
|
|
267
|
+
|
|
268
|
+
return [true, normalized_setting(settings[BUILD_SETTING])]
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
[false, nil]
|
|
272
|
+
end
|
|
273
|
+
private_class_method :configuration_file_setting
|
|
274
|
+
|
|
275
|
+
def validate_no_conditional_settings!(settings, context:)
|
|
276
|
+
conditional_setting_pattern = /\A#{Regexp.escape(BUILD_SETTING)}[[:space:]]*\[/
|
|
277
|
+
conditional_keys = settings.keys.map(&:to_s).select do |key|
|
|
278
|
+
key.match?(conditional_setting_pattern)
|
|
279
|
+
end.sort
|
|
280
|
+
return if conditional_keys.empty?
|
|
281
|
+
|
|
282
|
+
raise AuditError,
|
|
283
|
+
"#{context} has conditional #{BUILD_SETTING} settings that cannot be audited deterministically: " \
|
|
284
|
+
"#{conditional_keys.join(', ')}. Replace them with one numeric, unconditional #{BUILD_SETTING} " \
|
|
285
|
+
"before running this helper."
|
|
286
|
+
end
|
|
287
|
+
private_class_method :validate_no_conditional_settings!
|
|
288
|
+
|
|
289
|
+
def rendered_synchronized_path(anchor, relative_path)
|
|
290
|
+
anchor_path = if anchor.respond_to?(:path)
|
|
291
|
+
anchor.path
|
|
292
|
+
elsif anchor.respond_to?(:display_name)
|
|
293
|
+
anchor.display_name
|
|
294
|
+
else
|
|
295
|
+
"(unknown anchor)"
|
|
296
|
+
end
|
|
297
|
+
[anchor_path, relative_path].compact.map(&:to_s).reject(&:empty?).join("/")
|
|
298
|
+
end
|
|
299
|
+
private_class_method :rendered_synchronized_path
|
|
300
|
+
|
|
301
|
+
def matching_project_configuration(project, configuration_name)
|
|
302
|
+
return nil if project.nil? || !project.respond_to?(:build_configurations)
|
|
303
|
+
|
|
304
|
+
Array(project.build_configurations).find do |configuration|
|
|
305
|
+
configuration.name.to_s == configuration_name.to_s
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
private_class_method :matching_project_configuration
|
|
309
|
+
|
|
310
|
+
def ensure_records!(records)
|
|
311
|
+
return unless records.empty?
|
|
312
|
+
|
|
313
|
+
raise AuditError, "CocoaPods iOS deployment-target audit found no target configurations"
|
|
314
|
+
end
|
|
315
|
+
private_class_method :ensure_records!
|
|
316
|
+
|
|
317
|
+
def validate_numeric_settings!(records)
|
|
318
|
+
records.each do |record|
|
|
319
|
+
parse_version!(record.current, context: record_context(record)) unless record.current.nil?
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
private_class_method :validate_numeric_settings!
|
|
323
|
+
|
|
324
|
+
def audit_records!(records, minimum)
|
|
325
|
+
violations = records.each_with_object([]) do |record, result|
|
|
326
|
+
current = record.current
|
|
327
|
+
if current.nil?
|
|
328
|
+
result << "#{record_context(record)} is missing #{BUILD_SETTING}"
|
|
329
|
+
else
|
|
330
|
+
begin
|
|
331
|
+
version = parse_version!(current, context: record_context(record))
|
|
332
|
+
if version < minimum
|
|
333
|
+
result << "#{record_context(record)} is #{current}, below #{minimum}"
|
|
334
|
+
end
|
|
335
|
+
rescue AuditError => error
|
|
336
|
+
result << error.message
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
return if violations.empty?
|
|
342
|
+
|
|
343
|
+
raise AuditError, "CocoaPods iOS deployment-target audit failed:\n- #{violations.join("\n- ")}"
|
|
344
|
+
end
|
|
345
|
+
private_class_method :audit_records!
|
|
346
|
+
|
|
347
|
+
def write_summary(io, records, minimum)
|
|
348
|
+
return if io.nil?
|
|
349
|
+
|
|
350
|
+
changed = records.count(&:changed)
|
|
351
|
+
io.puts(
|
|
352
|
+
"Zixflow CocoaPods deployment-target audit passed: " \
|
|
353
|
+
"#{records.length} target configurations at iOS #{minimum} or newer (#{changed} normalized)."
|
|
354
|
+
)
|
|
355
|
+
end
|
|
356
|
+
private_class_method :write_summary
|
|
357
|
+
|
|
358
|
+
def write_changes(io, records)
|
|
359
|
+
return if io.nil?
|
|
360
|
+
|
|
361
|
+
records.select(&:changed).each do |record|
|
|
362
|
+
original = record.original_effective.nil? ? "missing" : record.original_effective
|
|
363
|
+
io.puts(
|
|
364
|
+
"Zixflow CocoaPods deployment target normalized: " \
|
|
365
|
+
"#{record_context(record)}: #{original} -> #{record.current}"
|
|
366
|
+
)
|
|
367
|
+
end
|
|
368
|
+
end
|
|
369
|
+
private_class_method :write_changes
|
|
370
|
+
|
|
371
|
+
def write_records(io, records, minimum)
|
|
372
|
+
return if io.nil?
|
|
373
|
+
|
|
374
|
+
io.puts(
|
|
375
|
+
"project\ttarget\tconfiguration\ttarget_#{BUILD_SETTING}\t" \
|
|
376
|
+
"target_xcconfig_#{BUILD_SETTING}\t" \
|
|
377
|
+
"project_#{BUILD_SETTING}\teffective_#{BUILD_SETTING}"
|
|
378
|
+
)
|
|
379
|
+
records.each do |record|
|
|
380
|
+
target_value = normalized_setting(record.configuration_object.build_settings[BUILD_SETTING])
|
|
381
|
+
io.puts(
|
|
382
|
+
[
|
|
383
|
+
record.project,
|
|
384
|
+
record.target,
|
|
385
|
+
record.configuration,
|
|
386
|
+
target_value,
|
|
387
|
+
record.target_configuration_value,
|
|
388
|
+
record.project_value,
|
|
389
|
+
record.current
|
|
390
|
+
].join("\t")
|
|
391
|
+
)
|
|
392
|
+
end
|
|
393
|
+
write_summary(io, records, minimum)
|
|
394
|
+
end
|
|
395
|
+
private_class_method :write_records
|
|
396
|
+
|
|
397
|
+
def parse_version!(value, context:)
|
|
398
|
+
normalized = normalized_setting(value)
|
|
399
|
+
unless normalized&.match?(VERSION_PATTERN)
|
|
400
|
+
rendered = normalized.nil? ? "missing" : normalized.inspect
|
|
401
|
+
raise AuditError, "#{context} has non-numeric #{BUILD_SETTING}: #{rendered}"
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
Gem::Version.new(normalized)
|
|
405
|
+
end
|
|
406
|
+
private_class_method :parse_version!
|
|
407
|
+
|
|
408
|
+
def normalized_setting(value)
|
|
409
|
+
normalized = value.nil? ? nil : value.to_s.strip
|
|
410
|
+
normalized.nil? || normalized.empty? ? nil : normalized
|
|
411
|
+
end
|
|
412
|
+
private_class_method :normalized_setting
|
|
413
|
+
|
|
414
|
+
def record_context(record)
|
|
415
|
+
"#{record.project}: target #{record.target}, configuration #{record.configuration}"
|
|
416
|
+
end
|
|
417
|
+
private_class_method :record_context
|
|
418
|
+
|
|
419
|
+
def configuration_context(project, target, configuration)
|
|
420
|
+
"#{project_path(project)}: target #{target.name}, configuration #{configuration.name}"
|
|
421
|
+
end
|
|
422
|
+
private_class_method :configuration_context
|
|
423
|
+
|
|
424
|
+
def project_path(project)
|
|
425
|
+
return "unknown-project" if project.nil?
|
|
426
|
+
return project.path.to_s if project.respond_to?(:path) && project.path
|
|
427
|
+
|
|
428
|
+
project.to_s
|
|
429
|
+
end
|
|
430
|
+
private_class_method :project_path
|
|
431
|
+
end
|
|
432
|
+
end
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
#import "utils/RCTZixflowUtils.h"
|
|
2
2
|
#import <React/RCTBridgeModule.h>
|
|
3
|
+
#import <React/RCTInvalidating.h>
|
|
3
4
|
#import <RNZixflowSpec/RNZixflowSpec.h>
|
|
4
5
|
|
|
6
|
+
@protocol NativeZixflowBridge <NativeZixflowSpec, RCTInvalidating>
|
|
7
|
+
- (void)setEventEmitter:(id)emitter;
|
|
8
|
+
@end
|
|
9
|
+
|
|
5
10
|
// Objective-C wrapper for new architecture TurboModule implementation
|
|
6
11
|
@interface RCTNativeZixflow : NSObject <NativeZixflowSpec>
|
|
7
12
|
// Bridge to Swift implementation for cross-language compatibility
|
|
@@ -30,6 +35,7 @@ RCT_EXPORT_MODULE()
|
|
|
30
35
|
RCT_ASSERT_NOT_NIL(swiftClass, @"NativeZixflow Swift class", @"during runtime lookup");
|
|
31
36
|
_swiftBridge = [[swiftClass alloc] init];
|
|
32
37
|
[self assertBridgeAvailable:@"creating NativeZixflow Swift instance"];
|
|
38
|
+
[_swiftBridge setEventEmitter:self];
|
|
33
39
|
}
|
|
34
40
|
return self;
|
|
35
41
|
}
|
|
@@ -47,6 +53,37 @@ RCT_EXPORT_MODULE()
|
|
|
47
53
|
[_swiftBridge initialize:config args:args resolve:resolve reject:reject];
|
|
48
54
|
}
|
|
49
55
|
|
|
56
|
+
- (void)setDeepLinkRoutingReady {
|
|
57
|
+
[self assertBridgeAvailable:@"during setDeepLinkRoutingReady"];
|
|
58
|
+
[_swiftBridge setDeepLinkRoutingReady];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
- (void)registerDeepLinkHandler {
|
|
62
|
+
[self assertBridgeAvailable:@"during registerDeepLinkHandler"];
|
|
63
|
+
[_swiftBridge registerDeepLinkHandler];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
- (void)unregisterDeepLinkHandler {
|
|
67
|
+
[self assertBridgeAvailable:@"during unregisterDeepLinkHandler"];
|
|
68
|
+
[_swiftBridge unregisterDeepLinkHandler];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
- (void)acknowledgeDeepLink:(NSString *)id handled:(BOOL)handled {
|
|
72
|
+
[self assertBridgeAvailable:@"during acknowledgeDeepLink"];
|
|
73
|
+
[_swiftBridge acknowledgeDeepLink:id handled:handled];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
- (void)invalidate {
|
|
77
|
+
[self assertBridgeAvailable:@"during invalidate"];
|
|
78
|
+
[_swiftBridge invalidate];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Pins the Codegen event name at compile time. Keep this in sync with the TypeScript spec and the
|
|
82
|
+
// runtime selector in NativeZixflow.swift.
|
|
83
|
+
- (void)emitOnDeepLinkReceived:(NSDictionary *)value {
|
|
84
|
+
[super emitOnDeepLinkReceived:value];
|
|
85
|
+
}
|
|
86
|
+
|
|
50
87
|
- (void)identify:(NSDictionary *)params {
|
|
51
88
|
[self assertBridgeAvailable:@"during identify"];
|
|
52
89
|
[_swiftBridge identify:params];
|
|
@@ -2,14 +2,102 @@ import ZixflowAnalytics
|
|
|
2
2
|
import ZixflowDataPipelines
|
|
3
3
|
import ZixflowInternalCommon
|
|
4
4
|
import ZixflowMessagingInApp
|
|
5
|
+
import Foundation
|
|
5
6
|
|
|
6
7
|
@objc(NativeZixflow)
|
|
7
8
|
public class NativeZixflow: NSObject {
|
|
8
9
|
private let logger: ZixflowInternalCommon.Logger = DIGraphShared.shared.logger
|
|
10
|
+
private weak var objcEventEmitter: AnyObject?
|
|
11
|
+
private var deepLinkHandlerToken: UUID?
|
|
9
12
|
/// Checks whether the Zixflow SDK has been initialized.
|
|
10
13
|
/// Returns `true` if the SDK has been successfully initialized, `false` otherwise.
|
|
11
14
|
private var isInitialized: Bool { Zixflow.shared.implementation != nil }
|
|
12
15
|
|
|
16
|
+
/// Installs React Native scene deep-link routing before the JavaScript bridge starts.
|
|
17
|
+
/// Call this at the start of `scene(_:willConnectTo:options:)` in a UIScene host.
|
|
18
|
+
@objc
|
|
19
|
+
public static func configureSceneDeepLinkRouting() {
|
|
20
|
+
// A natively initialized host owns its callback. Scene connection happens after
|
|
21
|
+
// application launch, so never replace a callback that native initialization installed.
|
|
22
|
+
guard Zixflow.shared.implementation == nil else { return }
|
|
23
|
+
ZixflowReactNativeDeepLinkRouter.install()
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/// Installs scene deep-link routing for the acknowledged JavaScript handler before the React
|
|
27
|
+
/// Native bridge starts. Call this at the start of `scene(_:willConnectTo:options:)` when the
|
|
28
|
+
/// host uses `Zixflow.setDeepLinkHandler`.
|
|
29
|
+
@objc
|
|
30
|
+
public static func configureAcknowledgedSceneDeepLinkRouting() {
|
|
31
|
+
// The cold scene connection happens before JavaScript can register its handler. Record the
|
|
32
|
+
// host's ownership choice now so initialization cannot drain a buffered URL into Linking.
|
|
33
|
+
guard Zixflow.shared.implementation == nil else { return }
|
|
34
|
+
ZixflowReactNativeDeepLinkRouter.installAcknowledgedHandler()
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/// Installs deep-link routing for an Expo-owned scene lifecycle.
|
|
38
|
+
///
|
|
39
|
+
/// Expo forwards scene URLs into React Native Linking itself, including on React Native
|
|
40
|
+
/// versions that do not expose the scene Linking selector used by the generic integration.
|
|
41
|
+
@objc
|
|
42
|
+
public static func configureExpoSceneDeepLinkRouting() {
|
|
43
|
+
guard Zixflow.shared.implementation == nil else { return }
|
|
44
|
+
// Native initialization preserves an existing callback when its config does not provide one.
|
|
45
|
+
ZixflowReactNativeDeepLinkRouter.installForExpoSceneLifecycle()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/// Marks the React Native Linking listener as ready for buffered scene URLs.
|
|
49
|
+
@objc
|
|
50
|
+
func setDeepLinkRoutingReady() {
|
|
51
|
+
ZixflowReactNativeDeepLinkRouter.markReactNativeReady()
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@objc
|
|
55
|
+
public func setEventEmitter(_ emitter: AnyObject) {
|
|
56
|
+
objcEventEmitter = emitter
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@objc
|
|
60
|
+
func registerDeepLinkHandler() {
|
|
61
|
+
guard objcEventEmitter != nil else {
|
|
62
|
+
logger.error("Zixflow could not register the React Native deep-link handler")
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
deepLinkHandlerToken = ZixflowReactNativeDeepLinkRouter.registerHandler { [weak self] id, url in
|
|
67
|
+
self?.sendDeepLink(id: id, url: url)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@objc
|
|
72
|
+
func unregisterDeepLinkHandler() {
|
|
73
|
+
guard let token = deepLinkHandlerToken else { return }
|
|
74
|
+
ZixflowReactNativeDeepLinkRouter.unregisterHandler(token)
|
|
75
|
+
deepLinkHandlerToken = nil
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@objc
|
|
79
|
+
func acknowledgeDeepLink(_ id: String, handled: Bool) {
|
|
80
|
+
ZixflowReactNativeDeepLinkRouter.acknowledge(id, handled: handled)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@objc
|
|
84
|
+
func invalidate() {
|
|
85
|
+
unregisterDeepLinkHandler()
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
private func sendDeepLink(id: String, url: String) {
|
|
89
|
+
guard let emitter = objcEventEmitter else { return }
|
|
90
|
+
|
|
91
|
+
// Codegen derives this selector from `onDeepLinkReceived` in NativeZixflow.ts. Keep it
|
|
92
|
+
// in sync with that spec property and the forwarding override in NativeZixflow.mm.
|
|
93
|
+
let selector = Selector(("emitOnDeepLinkReceived:"))
|
|
94
|
+
guard emitter.responds(to: selector) else {
|
|
95
|
+
logger.error("Zixflow could not emit a React Native deep-link event")
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
_ = emitter.perform(selector, with: ["id": id, "url": url] as NSDictionary)
|
|
99
|
+
}
|
|
100
|
+
|
|
13
101
|
/// Ensures that the Zixflow SDK is initialized before performing operations.
|
|
14
102
|
/// Logs an error and returns false if the SDK is not initialized.
|
|
15
103
|
private func ensureInitialized() -> Bool {
|
|
@@ -30,6 +118,7 @@ public class NativeZixflow: NSObject {
|
|
|
30
118
|
// Skip initialization if already initialized
|
|
31
119
|
if isInitialized {
|
|
32
120
|
logger.info("Zixflow SDK is already initialized. Skipping initialization.")
|
|
121
|
+
ZixflowReactNativeDeepLinkRouter.markReactNativeReady()
|
|
33
122
|
resolve(true)
|
|
34
123
|
return
|
|
35
124
|
}
|
|
@@ -48,12 +137,56 @@ public class NativeZixflow: NSObject {
|
|
|
48
137
|
|
|
49
138
|
let sdkConfigBuilder = try SDKConfigBuilder.create(from: config)
|
|
50
139
|
|
|
140
|
+
let shouldInstallSceneRouter =
|
|
141
|
+
ZixflowReactNativeDeepLinkRouter.isSceneLifecycleEnabled ||
|
|
142
|
+
(packageSource == "Expo" && ZixflowReactNativeDeepLinkRouter.isExpoSceneLifecycleEnabled)
|
|
143
|
+
if shouldInstallSceneRouter {
|
|
144
|
+
_ = sdkConfigBuilder.deepLinkCallback { url in
|
|
145
|
+
ZixflowReactNativeDeepLinkRouter.accept(url)
|
|
146
|
+
return true // React Native Linking cannot report handling; JavaScript owns fallback.
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
51
150
|
#if ZIXFLOW_LOCATION_ENABLED
|
|
52
|
-
|
|
151
|
+
// Geofence implies location: register the location module whenever location
|
|
152
|
+
// config is provided or geofence is enabled, since geofence relies on the
|
|
153
|
+
// location module's fixes.
|
|
154
|
+
#if ZIXFLOW_GEOFENCE_ENABLED
|
|
155
|
+
// Match NativeGeofence.module(from:): only a dictionary counts as configured,
|
|
156
|
+
// so a non-map value (e.g. null bridged from JS) doesn't imply location.
|
|
157
|
+
let geofenceConfigured = config["geofence"] as? [String: Any] != nil
|
|
158
|
+
#else
|
|
159
|
+
let geofenceConfigured = false
|
|
160
|
+
#endif
|
|
161
|
+
if let locationModule = NativeLocation.module(from: config, geofenceEnabled: geofenceConfigured) {
|
|
53
162
|
_ = sdkConfigBuilder.addModule(locationModule)
|
|
54
163
|
}
|
|
55
164
|
#endif
|
|
56
165
|
|
|
166
|
+
#if ZIXFLOW_GEOFENCE_ENABLED
|
|
167
|
+
// Geofence runs automatically once registered; relies on the location module above.
|
|
168
|
+
if let geofenceModule = NativeGeofence.module(from: config) {
|
|
169
|
+
_ = sdkConfigBuilder.addModule(geofenceModule)
|
|
170
|
+
}
|
|
171
|
+
#endif
|
|
172
|
+
|
|
173
|
+
#if ZIXFLOW_LIVEACTIVITIES_ENABLED
|
|
174
|
+
if let liveActivitiesModule = NativeLiveActivities.module(from: config) {
|
|
175
|
+
_ = sdkConfigBuilder.addModule(liveActivitiesModule)
|
|
176
|
+
}
|
|
177
|
+
#endif
|
|
178
|
+
|
|
179
|
+
// Customer value wins; default on when the geofence module is added, off otherwise.
|
|
180
|
+
#if ZIXFLOW_GEOFENCE_ENABLED
|
|
181
|
+
// Match NativeGeofence.module(from:): only a dictionary adds the module, so
|
|
182
|
+
// background delivery shouldn't default on for a non-map geofence value.
|
|
183
|
+
let geofenceAdded = config["geofence"] as? [String: Any] != nil
|
|
184
|
+
#else
|
|
185
|
+
let geofenceAdded = false
|
|
186
|
+
#endif
|
|
187
|
+
let allowBackgroundDelivery = (config["ios"] as? [String: Any])?["allowBackgroundDelivery"] as? Bool
|
|
188
|
+
_ = sdkConfigBuilder.allowBackgroundDelivery(allowBackgroundDelivery ?? geofenceAdded)
|
|
189
|
+
|
|
57
190
|
let builtConfig = sdkConfigBuilder.build()
|
|
58
191
|
|
|
59
192
|
// Only Zixflow.initialize must run on the main thread (e.g. for Location module).
|
|
@@ -77,6 +210,7 @@ public class NativeZixflow: NSObject {
|
|
|
77
210
|
self.logger.debug(
|
|
78
211
|
"Zixflow SDK (\(packageSource ?? "") \(packageVersion ?? "")) initialized with config: \(config)"
|
|
79
212
|
)
|
|
213
|
+
ZixflowReactNativeDeepLinkRouter.markReactNativeReady()
|
|
80
214
|
resolve(true)
|
|
81
215
|
}
|
|
82
216
|
} catch {
|