react-native-insider 8.1.0 → 9.0.0-nh

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 (48) hide show
  1. package/README.md +89 -660
  2. package/RNInsider.podspec +33 -12
  3. package/android/build.gradle +16 -7
  4. package/android/src/main/java/com/useinsider/react/RNInsiderAppFrameViewManager.java +253 -0
  5. package/android/src/main/java/com/useinsider/react/RNInsiderModule.java +238 -178
  6. package/android/src/main/java/com/useinsider/react/RNInsiderPackage.java +5 -1
  7. package/android/src/main/java/com/useinsider/react/RNUtils.java +111 -0
  8. package/babel.config.js +4 -1
  9. package/index.d.ts +196 -161
  10. package/index.js +60 -11
  11. package/ios/RNInsider/RNInsider.m +245 -341
  12. package/ios/RNInsider/RNInsiderAppFrameView.h +33 -0
  13. package/ios/RNInsider/RNInsiderAppFrameView.mm +315 -0
  14. package/ios/RNInsider/RNNotificationHandler.h +4 -1
  15. package/ios/RNInsider/RNNotificationHandler.m +16 -18
  16. package/ios/RNInsider/RNUtils.h +2 -0
  17. package/ios/RNInsider/RNUtils.m +79 -0
  18. package/package.json +43 -12
  19. package/src/EventHandler.js +17 -0
  20. package/src/InsiderAppFrame.d.ts +45 -0
  21. package/src/InsiderAppFrame.js +265 -0
  22. package/src/InsiderAppFrameLogic.d.ts +35 -0
  23. package/src/InsiderAppFrameLogic.js +192 -0
  24. package/src/InsiderAppFrameStatus.d.ts +22 -0
  25. package/src/InsiderAppFrameStatus.js +35 -0
  26. package/src/InsiderAppFramesError.d.ts +25 -0
  27. package/src/InsiderAppFramesError.js +77 -0
  28. package/src/InsiderEvent.js +1 -0
  29. package/src/InsiderEvents.d.ts +93 -0
  30. package/src/InsiderEvents.js +124 -0
  31. package/src/InsiderIdentifier.js +1 -1
  32. package/src/InsiderUser.d.ts +3 -2
  33. package/src/InsiderUser.js +27 -0
  34. package/src/Util.js +2 -1
  35. package/src/specs/InsiderAppFrameNativeComponent.ts +54 -0
  36. package/.orbit-output/config/MASTER.md +0 -129
  37. package/.orbit-output/config/architecture/API_DOCS.md +0 -342
  38. package/.orbit-output/config/architecture/ARCHITECTURE.md +0 -209
  39. package/.orbit-output/config/architecture/CODE-CATALOG.md +0 -172
  40. package/.orbit-output/config/architecture/project.yaml +0 -138
  41. package/.orbit-output/config/automation/AUTOMATION-SETUP.md +0 -50
  42. package/.orbit-output/config/enforcement/ENFORCEMENT-RULES.md +0 -41
  43. package/.orbit-output/config/enforcement/validate.sh +0 -49
  44. package/.orbit-output/skills/custom/academy-doc-generator.md +0 -598
  45. package/android/.settings/org.eclipse.buildship.core.prefs +0 -13
  46. package/android/src/test/java/com/useinsider/react/RNInsiderModuleTest.java +0 -169
  47. package/docs/app-cards/app-cards_new.md +0 -569
  48. package/ios/RNInsiderTests/RNInsiderTriggerPushProcessTests.m +0 -91
package/RNInsider.podspec CHANGED
@@ -1,6 +1,25 @@
1
1
  require 'json'
2
+ require 'shellwords'
2
3
  package_json = JSON.parse(File.read('package.json'))
3
4
 
5
+ react_native_search_root = defined?(Pod::Config) ? Pod::Config.instance.installation_root.to_s : __dir__
6
+
7
+ # A standard React Native Podfile has already required react_native_pods by the time this runs,
8
+ # so a failure here is only fatal when nothing else defined install_modules_dependencies.
9
+ react_native_pods_load_error = nil
10
+ begin
11
+ require File.join(File.dirname(`node --print "require.resolve('react-native/package.json', {paths: [process.argv[1]]})" #{Shellwords.escape(react_native_search_root)}`), "scripts/react_native_pods")
12
+ rescue LoadError, Errno::ENOENT => e
13
+ react_native_pods_load_error = e
14
+ end
15
+
16
+ unless defined?(install_modules_dependencies)
17
+ raise Pod::Informative, "[RNInsider] Could not load react-native/scripts/react_native_pods.rb " \
18
+ "resolving react-native from #{react_native_search_root}: " \
19
+ "#{react_native_pods_load_error&.message || 'install_modules_dependencies is undefined'}. " \
20
+ "Make sure node is on PATH and react-native is installed for this app"
21
+ end
22
+
4
23
  Pod::Spec.new do |s|
5
24
  s.name = 'RNInsider'
6
25
  s.version = package_json['version']
@@ -9,19 +28,21 @@ Pod::Spec.new do |s|
9
28
  s.authors = package_json['author']
10
29
  s.license = 'MIT'
11
30
  s.platform = :ios, '12.0'
12
- s.source = {:http => 'https://mobilesdk.useinsider.com/iOS/15.1.2/InsiderMobileIOSFramework.zip'}
13
- s.source_files = 'ios/RNInsider/*.{h,m}'
31
+ s.source = {:http => 'https://mobilesdk.useinsider.com/iOS/16.2.1/InsiderMobileIOSFramework.zip'}
32
+ s.source_files = 'ios/RNInsider/*.{h,m,mm}'
14
33
  s.requires_arc = true
34
+ s.compiler_flags = '-fobjc-arc-exceptions'
15
35
  s.static_framework = true
16
- s.dependency 'React'
17
- s.dependency 'InsiderMobile', '15.1.2'
18
- s.dependency 'InsiderGeofence', '1.2.4'
19
- s.dependency 'InsiderHybrid', '1.7.6'
20
-
21
- s.test_spec 'Tests' do |test_spec|
22
- test_spec.source_files = 'ios/RNInsiderTests/**/*.{h,m}'
23
- test_spec.frameworks = 'XCTest'
24
- test_spec.requires_app_host = false
25
- test_spec.dependency 'OCMock', '~> 3.9'
36
+ install_modules_dependencies(s)
37
+ s.dependency 'InsiderMobile', '16.2.1'
38
+ s.dependency 'InsiderGeofence', '1.3.0'
39
+ s.dependency 'InsiderHybrid', '1.8.0'
40
+ if Dir.exist?(File.join(__dir__, 'ios', 'RNInsiderTests'))
41
+ s.test_spec 'Tests' do |test_spec|
42
+ test_spec.source_files = 'ios/RNInsiderTests/**/*.{h,m,mm}'
43
+ test_spec.frameworks = 'XCTest'
44
+ test_spec.requires_app_host = false
45
+ test_spec.dependency 'OCMock', '~> 3.9'
46
+ end
26
47
  end
27
48
  end
@@ -2,15 +2,24 @@ buildscript {
2
2
  repositories {
3
3
  google()
4
4
  mavenCentral()
5
- maven { url "https://developer.huawei.com/repo/"}
6
5
  }
7
6
 
8
7
  dependencies {
9
8
  classpath 'com.android.tools.build:gradle:8.4.2'
9
+ classpath 'com.facebook.react:react-native-gradle-plugin'
10
10
  }
11
11
  }
12
12
 
13
13
  apply plugin: 'com.android.library'
14
+ apply plugin: 'com.facebook.react'
15
+
16
+ // Codegen runs on this package's own specs: RNInsiderAppFrameViewManager implements the generated
17
+ // interface, so it must exist when the library compiles. libraryName must match codegenConfig.name.
18
+ react {
19
+ jsRootDir = file("../src/specs")
20
+ libraryName = "RNInsiderSpec"
21
+ codegenJavaPackageName = "com.useinsider.react"
22
+ }
14
23
 
15
24
  def getVersionFromPartner(config, fallback) {
16
25
  rootProject.ext.has(config) ? rootProject.ext.get(config) : fallback
@@ -40,28 +49,28 @@ android {
40
49
  repositories {
41
50
  google()
42
51
  mavenCentral()
43
- maven { url "https://developer.huawei.com/repo/"}
44
52
  maven { url "https://mobilesdk.useinsider.com/android" }
45
53
  }
46
54
 
47
55
 
48
56
  dependencies {
49
57
  implementation "com.facebook.react:react-native:${getVersionFromPartner('reactNativeVersion', '+')}"
50
- implementation 'com.useinsider:insider:16.0.9'
51
- implementation 'com.useinsider:insiderhybrid:1.3.4'
58
+ implementation 'com.useinsider:insider:17.3.1-nh'
59
+ implementation 'com.useinsider:insiderhybrid:1.4.0'
52
60
 
53
61
  implementation 'androidx.security:security-crypto:1.1.0-alpha06'
54
62
  implementation 'androidx.legacy:legacy-support-v4:1.0.0'
55
63
  implementation 'androidx.lifecycle:lifecycle-process:2.8.3'
56
64
  implementation "androidx.work:work-runtime:2.9.1"
57
65
 
66
+ // App Frames needs webkit at runtime (compileOnly in the native SDK); without it template actions
67
+ // never arrive. Held below 1.16.0, whose kotlin-stdlib 2.1 breaks older-Kotlin hosts (RN 0.76).
68
+ implementation 'androidx.webkit:webkit:1.15.0'
69
+
58
70
  implementation 'com.google.firebase:firebase-messaging:24.0.0'
59
71
  implementation 'com.google.android.gms:play-services-location:21.3.0'
60
72
  implementation 'com.google.android.play:review:2.0.1'
61
73
 
62
- implementation 'com.huawei.hms:push:6.13.0.300'
63
- implementation 'com.huawei.hms:ads-identifier:3.4.62.300'
64
- implementation 'com.huawei.hms:location:6.16.0.302'
65
74
 
66
75
  testImplementation 'junit:junit:4.13.2'
67
76
  testImplementation 'org.mockito:mockito-core:5.12.0'
@@ -0,0 +1,253 @@
1
+ package com.useinsider.react;
2
+
3
+ import androidx.annotation.NonNull;
4
+ import androidx.annotation.Nullable;
5
+
6
+ import com.facebook.react.bridge.ReactContext;
7
+ import com.facebook.react.bridge.WritableMap;
8
+ import com.facebook.react.bridge.Arguments;
9
+ import com.facebook.react.module.annotations.ReactModule;
10
+ import com.facebook.react.uimanager.SimpleViewManager;
11
+ import com.facebook.react.uimanager.ThemedReactContext;
12
+ import com.facebook.react.uimanager.UIManagerHelper;
13
+ import com.facebook.react.uimanager.ViewManagerDelegate;
14
+ import com.facebook.react.uimanager.annotations.ReactProp;
15
+ import com.facebook.react.uimanager.events.Event;
16
+ import com.facebook.react.uimanager.events.EventDispatcher;
17
+ import com.facebook.react.viewmanagers.InsiderAppFrameViewManagerDelegate;
18
+ import com.facebook.react.viewmanagers.InsiderAppFrameViewManagerInterface;
19
+
20
+ import com.useinsider.insider.Insider;
21
+ import com.useinsider.insider.InsiderAppFramesError;
22
+ import com.useinsider.insider.InsiderAppFramesView;
23
+ import com.useinsider.insider.InsiderAppFramesViewListener;
24
+ import com.useinsider.insider.InsiderAppFramesViewStatus;
25
+
26
+ import org.json.JSONObject;
27
+
28
+ import java.util.HashMap;
29
+ import java.util.Map;
30
+
31
+ /**
32
+ * Fabric ViewManager for the {@code InsiderAppFrameView} component, backed by the native
33
+ * {@link InsiderAppFramesView}.
34
+ *
35
+ * <p>Status and error codes are forwarded as enum {@code name()}s, which must match the values in
36
+ * {@code src/InsiderAppFrameStatus.js} and {@code src/InsiderAppFramesError.js}. There is no
37
+ * compile-time link: a rename on one side shows up only as an unrecognized value at runtime.</p>
38
+ */
39
+ @ReactModule(name = RNInsiderAppFrameViewManager.NAME)
40
+ public class RNInsiderAppFrameViewManager
41
+ extends SimpleViewManager<InsiderAppFramesView>
42
+ implements InsiderAppFrameViewManagerInterface<InsiderAppFramesView> {
43
+
44
+ public static final String NAME = "InsiderAppFrameView";
45
+
46
+ private final ViewManagerDelegate<InsiderAppFramesView> delegate =
47
+ new InsiderAppFrameViewManagerDelegate<>(this);
48
+
49
+ // Event names and payload keys must match src/specs/InsiderAppFrameNativeComponent.ts;
50
+ // a mismatch fails silently at runtime.
51
+ private static final String EVENT_ON_STATUS_CHANGE = "onStatusChange";
52
+ private static final String EVENT_ON_LOAD_ERROR = "onLoadError";
53
+ private static final String EVENT_ON_HEIGHT_CHANGE = "onHeightChange";
54
+ private static final String EVENT_ON_DISMISS_REQUEST = "onDismissRequest";
55
+ private static final String EVENT_ON_ACTION = "onAction";
56
+
57
+ private static final String KEY_PLACEMENT_ID = "placementId";
58
+ private static final String KEY_STATUS = "status";
59
+ private static final String KEY_PREVIOUS_STATUS = "previousStatus";
60
+ private static final String KEY_CODE = "code";
61
+ private static final String KEY_MESSAGE = "message";
62
+ private static final String KEY_CAUSE = "cause";
63
+ private static final String KEY_DISMISS_CODE = "dismissCode";
64
+ private static final String KEY_HEIGHT = "height";
65
+ private static final String KEY_DATA = "data";
66
+
67
+ private static final String ERROR_CODE_UNKNOWN = "UNKNOWN";
68
+ private static final String EMPTY_ACTION_DATA = "{}";
69
+
70
+ @NonNull
71
+ @Override
72
+ public String getName() {
73
+ return NAME;
74
+ }
75
+
76
+ @Nullable
77
+ @Override
78
+ protected ViewManagerDelegate<InsiderAppFramesView> getDelegate() {
79
+ return delegate;
80
+ }
81
+
82
+ @NonNull
83
+ @Override
84
+ protected InsiderAppFramesView createViewInstance(@NonNull ThemedReactContext context) {
85
+ InsiderAppFramesView view = new InsiderAppFramesView(context);
86
+ view.setAppFramesListener(new FrameListener());
87
+ return view;
88
+ }
89
+
90
+ @Override
91
+ public void onDropViewInstance(@NonNull InsiderAppFramesView view) {
92
+ view.setAppFramesListener(null);
93
+ super.onDropViewInstance(view);
94
+ }
95
+
96
+ @Override
97
+ @ReactProp(name = "placementId")
98
+ public void setPlacementId(InsiderAppFramesView view, @Nullable String placementId) {
99
+ view.setPlacementId(placementId);
100
+ }
101
+
102
+ @Override
103
+ public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
104
+ // Extend super's map: it registers onAccessibilityAction, which NativeProps inherits
105
+ // from ViewProps. ViewManager's base implementation returns null.
106
+ Map<String, Object> events = super.getExportedCustomDirectEventTypeConstants();
107
+ if (events == null) {
108
+ events = new HashMap<>();
109
+ }
110
+ for (String name : new String[]{
111
+ EVENT_ON_STATUS_CHANGE, EVENT_ON_LOAD_ERROR,
112
+ EVENT_ON_HEIGHT_CHANGE, EVENT_ON_DISMISS_REQUEST, EVENT_ON_ACTION}) {
113
+ events.put(name, mapBuilderOf("registrationName", name));
114
+ }
115
+ return events;
116
+ }
117
+
118
+ private static Map<String, String> mapBuilderOf(String key, String value) {
119
+ Map<String, String> map = new HashMap<>();
120
+ map.put(key, value);
121
+ return map;
122
+ }
123
+
124
+ private void emit(InsiderAppFramesView view, String eventName, WritableMap payload) {
125
+ ReactContext reactContext = UIManagerHelper.getReactContext(view);
126
+ EventDispatcher dispatcher =
127
+ UIManagerHelper.getEventDispatcherForReactTag(reactContext, view.getId());
128
+ if (dispatcher == null) {
129
+ // Not expected: Fabric records the event emitter before creating the view. Reported
130
+ // because JS mirrors status and error from these events, so a drop would desync it.
131
+ reportDroppedEvent(eventName, view.getId());
132
+ return;
133
+ }
134
+ dispatcher.dispatchEvent(new FrameEvent(
135
+ UIManagerHelper.getSurfaceId(view), view.getId(), eventName, payload));
136
+ }
137
+
138
+ /**
139
+ * Reports through the SDK's error channel, like the rest of this bridge, rather than logcat.
140
+ * Package-private as a test seam: {@code Insider.Instance} cannot be stubbed.
141
+ */
142
+ void reportDroppedEvent(String eventName, int viewId) {
143
+ Insider.Instance.putException(new IllegalStateException(
144
+ "Dropped " + eventName + ": no EventDispatcher for view " + viewId + " yet."));
145
+ }
146
+
147
+ /**
148
+ * Reports an action payload that could not be serialized and reaches JS as {@code {}}.
149
+ * Package-private as a test seam, like {@link #reportDroppedEvent}.
150
+ */
151
+ void reportUnserializableAction(int viewId) {
152
+ Insider.Instance.putException(new IllegalStateException(
153
+ "Action data for view " + viewId + " could not be serialized; forwarding {}."));
154
+ }
155
+
156
+ private static WritableMap basePayload(InsiderAppFramesView view) {
157
+ WritableMap payload = Arguments.createMap();
158
+ String placementId = view.getPlacementId();
159
+ payload.putString(KEY_PLACEMENT_ID, placementId == null ? "" : placementId);
160
+ return payload;
161
+ }
162
+
163
+ private static class FrameEvent extends Event<FrameEvent> {
164
+ private final String eventName;
165
+ private final WritableMap payload;
166
+
167
+ FrameEvent(int surfaceId, int viewTag, String eventName, WritableMap payload) {
168
+ super(surfaceId, viewTag);
169
+ this.eventName = eventName;
170
+ this.payload = payload;
171
+ }
172
+
173
+ @Override
174
+ public String getEventName() {
175
+ return eventName;
176
+ }
177
+
178
+ @Override
179
+ protected WritableMap getEventData() {
180
+ return payload;
181
+ }
182
+
183
+ @Override
184
+ public boolean canCoalesce() {
185
+ // Event coalesces same-name events by default, which would drop status transitions
186
+ // and heights; both native SDKs deliver every event, so none of the five coalesce.
187
+ return false;
188
+ }
189
+ }
190
+
191
+ private class FrameListener implements InsiderAppFramesViewListener {
192
+ @Override
193
+ public void onStatusChanged(@NonNull InsiderAppFramesView view,
194
+ @NonNull InsiderAppFramesViewStatus status,
195
+ @NonNull InsiderAppFramesViewStatus previousStatus) {
196
+ WritableMap payload = basePayload(view);
197
+ payload.putString(KEY_STATUS, status.name());
198
+ payload.putString(KEY_PREVIOUS_STATUS, previousStatus.name());
199
+ emit(view, EVENT_ON_STATUS_CHANGE, payload);
200
+ }
201
+
202
+ @Override
203
+ public void onLoadFailed(@NonNull InsiderAppFramesView view,
204
+ @NonNull InsiderAppFramesError error) {
205
+ WritableMap payload = basePayload(view);
206
+ payload.putString(KEY_CODE, error.getCode() == null
207
+ ? ERROR_CODE_UNKNOWN : error.getCode().name());
208
+ // The canonical per-code text, the same text iOS sends as localizedDescription.
209
+ payload.putString(KEY_MESSAGE, error.getMessage() == null ? "" : error.getMessage());
210
+ // Only the message crosses the bridge; empty rather than null because the codegen
211
+ // payload is non-nullable.
212
+ Throwable cause = error.getCause();
213
+ payload.putString(KEY_CAUSE,
214
+ cause == null || cause.getMessage() == null ? "" : cause.getMessage());
215
+ // NO_DISMISS_CODE (-1) unless a template reported a dismissal.
216
+ payload.putInt(KEY_DISMISS_CODE, error.getDismissCode());
217
+ emit(view, EVENT_ON_LOAD_ERROR, payload);
218
+ }
219
+
220
+ @Override
221
+ public void onHeightChangeRequested(@NonNull InsiderAppFramesView view, int optimalHeight) {
222
+ // The SDK reports px; React Native layout uses dp, as iOS already reports.
223
+ double heightDp = optimalHeight / view.getResources().getDisplayMetrics().density;
224
+
225
+ WritableMap payload = basePayload(view);
226
+ payload.putDouble(KEY_HEIGHT, heightDp);
227
+ // JS applies the height: Fabric always passes an EXACTLY measure spec, so the native
228
+ // view cannot size itself.
229
+ emit(view, EVENT_ON_HEIGHT_CHANGE, payload);
230
+ }
231
+
232
+ @Override
233
+ public void onDismissRequested(@NonNull InsiderAppFramesView view) {
234
+ // Event only: collapsing the slot is the host app's decision, as on native.
235
+ emit(view, EVENT_ON_DISMISS_REQUEST, basePayload(view));
236
+ }
237
+
238
+ @Override
239
+ public void onActionTriggered(@NonNull InsiderAppFramesView view,
240
+ @NonNull JSONObject actionData) {
241
+ WritableMap payload = basePayload(view);
242
+ // toString() returns null when serialization fails (e.g. NaN), but the codegen
243
+ // payload is non-nullable.
244
+ String json = actionData.toString();
245
+ if (json == null) {
246
+ reportUnserializableAction(view.getId());
247
+ json = EMPTY_ACTION_DATA;
248
+ }
249
+ payload.putString(KEY_DATA, json);
250
+ emit(view, EVENT_ON_ACTION, payload);
251
+ }
252
+ }
253
+ }