pushwoosh-react-native-plugin 7.0.0 → 7.0.1
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Pod::Spec.new do |s|
|
|
2
2
|
s.name = "pushwoosh-react-native-plugin"
|
|
3
|
-
s.version = "7.0.
|
|
3
|
+
s.version = "7.0.1"
|
|
4
4
|
s.summary = "React Native Pushwoosh Push Notifications module"
|
|
5
5
|
s.requires_arc = true
|
|
6
6
|
s.author = 'Pushwoosh'
|
|
@@ -20,5 +20,5 @@ Pod::Spec.new do |s|
|
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
s.dependency 'PushwooshXCFramework', '7.2.6'
|
|
23
|
-
s.dependency 'PushwooshInboxUIXCFramework'
|
|
23
|
+
s.dependency 'PushwooshInboxUIXCFramework', '7.0.42'
|
|
24
24
|
end
|
|
@@ -9,6 +9,7 @@ import com.facebook.react.bridge.Callback;
|
|
|
9
9
|
import com.facebook.react.bridge.ReactContext;
|
|
10
10
|
import com.facebook.react.bridge.WritableMap;
|
|
11
11
|
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
|
12
|
+
import com.pushwoosh.internal.utils.PWLog;
|
|
12
13
|
|
|
13
14
|
public class EventDispatcher {
|
|
14
15
|
|
|
@@ -37,7 +38,15 @@ public class EventDispatcher {
|
|
|
37
38
|
|
|
38
39
|
List<Callback> list = subscribers.get(event);
|
|
39
40
|
for (Callback subscriber : list) {
|
|
40
|
-
|
|
41
|
+
try {
|
|
42
|
+
subscriber.invoke(objects);
|
|
43
|
+
} catch (Exception e) {
|
|
44
|
+
// A callback bound to a runtime that is already gone throws, and React Native
|
|
45
|
+
// throws on a second invocation of a callback as well. The subscribers behind
|
|
46
|
+
// it, and the clear() below, have to happen anyway - otherwise the bad callback
|
|
47
|
+
// stays in the list and takes down every dispatch that follows.
|
|
48
|
+
PWLog.exception(e);
|
|
49
|
+
}
|
|
41
50
|
}
|
|
42
51
|
|
|
43
52
|
// A native module is supposed to invoke its callback only once!
|
|
@@ -61,17 +61,39 @@ public class PushwooshPlugin extends PushwooshPluginSpec implements LifecycleEve
|
|
|
61
61
|
private static final String PUSH_RECEIVED_EVENT = Pushwoosh.PUSH_RECEIVE_EVENT;
|
|
62
62
|
private static final String PUSH_RECEIVED_JS_EVENT = "pushReceived";
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
private
|
|
68
|
-
|
|
69
|
-
private
|
|
70
|
-
private
|
|
71
|
-
|
|
72
|
-
|
|
64
|
+
// Per bundle. The callbacks belong to the JS runtime that subscribed them and "JS has called
|
|
65
|
+
// init()" is true of that runtime alone, so this state goes away with the module React Native
|
|
66
|
+
// tears down - a late teardown has nothing left to reach into the next module with.
|
|
67
|
+
private final EventDispatcher mEventDispatcher = new EventDispatcher();
|
|
68
|
+
private boolean mInitialized = false;
|
|
69
|
+
private boolean mPushCallbackRegistered = false;
|
|
70
|
+
private boolean mReceivedPushCallbackRegistered = false;
|
|
71
|
+
|
|
72
|
+
// Per process. A push handed over before JS could take it outlives the React instance it
|
|
73
|
+
// arrived at: the next init() replays it.
|
|
74
|
+
private static PendingPush sReceivedPush;
|
|
75
|
+
private static PendingPush sStartPush;
|
|
73
76
|
private static final Object sStartPushLock = new Object();
|
|
74
77
|
|
|
78
|
+
// A push and what has already been done with it. Both paths to JS are replayed to a bundle
|
|
79
|
+
// that comes later - the device event by init(), the deprecated callback by onPushOpen() /
|
|
80
|
+
// onPushReceived() - and each of them only until the push has gone that way once. Without
|
|
81
|
+
// that, every new React instance was handed the last push of the process again: a pushOpened
|
|
82
|
+
// re-routing a deep link the app had already handled, and a launch push taking the place of
|
|
83
|
+
// the one-shot callback registration the new bundle was making.
|
|
84
|
+
private static final class PendingPush {
|
|
85
|
+
final String data;
|
|
86
|
+
boolean sentAsEvent;
|
|
87
|
+
boolean sentToCallback;
|
|
88
|
+
|
|
89
|
+
PendingPush(String data) {
|
|
90
|
+
this.data = data;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// The module JS is talking to, published on the first call from JS rather than in the
|
|
95
|
+
// constructor: TurboModuleManager.invalidate() constructs the module JS never required, and
|
|
96
|
+
// such a stillborn one must not take the live module's place.
|
|
75
97
|
private static PushwooshPlugin INSTANCE = null;
|
|
76
98
|
|
|
77
99
|
private InboxUiStyleManager inboxUiInboxUiStyleManager;
|
|
@@ -79,8 +101,6 @@ public class PushwooshPlugin extends PushwooshPluginSpec implements LifecycleEve
|
|
|
79
101
|
public PushwooshPlugin(ReactApplicationContext reactContext) {
|
|
80
102
|
super(reactContext);
|
|
81
103
|
|
|
82
|
-
INSTANCE = this;
|
|
83
|
-
|
|
84
104
|
reactContext.addLifecycleEventListener(this);
|
|
85
105
|
|
|
86
106
|
Context applicationContext = AndroidPlatformModule.getApplicationContext();
|
|
@@ -122,18 +142,21 @@ public class PushwooshPlugin extends PushwooshPluginSpec implements LifecycleEve
|
|
|
122
142
|
Pushwoosh.getInstance().setAppId(appId);
|
|
123
143
|
|
|
124
144
|
synchronized (sStartPushLock) {
|
|
125
|
-
if (
|
|
126
|
-
sendEvent(PUSH_RECEIVED_JS_EVENT, ConversionUtil.stringToJSONObject(
|
|
145
|
+
if (sReceivedPush != null && !sReceivedPush.sentAsEvent) {
|
|
146
|
+
sendEvent(PUSH_RECEIVED_JS_EVENT, ConversionUtil.stringToJSONObject(sReceivedPush.data));
|
|
147
|
+
sReceivedPush.sentAsEvent = true;
|
|
127
148
|
}
|
|
128
149
|
|
|
129
|
-
if (
|
|
130
|
-
sendEvent(PUSH_OPEN_JS_EVENT, ConversionUtil.stringToJSONObject(
|
|
150
|
+
if (sStartPush != null && !sStartPush.sentAsEvent) {
|
|
151
|
+
sendEvent(PUSH_OPEN_JS_EVENT, ConversionUtil.stringToJSONObject(sStartPush.data));
|
|
152
|
+
sStartPush.sentAsEvent = true;
|
|
131
153
|
}
|
|
132
154
|
|
|
133
155
|
// Under the same lock as the replay above: a push taking the lock between the replay
|
|
134
|
-
// and this flag would find
|
|
135
|
-
//
|
|
136
|
-
|
|
156
|
+
// and this flag would find the gate closed, skip its own send, and never be replayed
|
|
157
|
+
// either.
|
|
158
|
+
mInitialized = true;
|
|
159
|
+
INSTANCE = this;
|
|
137
160
|
}
|
|
138
161
|
|
|
139
162
|
if (success != null) {
|
|
@@ -167,13 +190,16 @@ public class PushwooshPlugin extends PushwooshPluginSpec implements LifecycleEve
|
|
|
167
190
|
@ReactMethod
|
|
168
191
|
public void onPushOpen(Callback callback) {
|
|
169
192
|
synchronized (sStartPushLock) {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
193
|
+
INSTANCE = this;
|
|
194
|
+
|
|
195
|
+
if (!mPushCallbackRegistered && sStartPush != null && !sStartPush.sentToCallback) {
|
|
196
|
+
callback.invoke(ConversionUtil.toWritableMap(ConversionUtil.stringToJSONObject(sStartPush.data)));
|
|
197
|
+
sStartPush.sentToCallback = true;
|
|
198
|
+
mPushCallbackRegistered = true;
|
|
173
199
|
return;
|
|
174
200
|
}
|
|
175
201
|
|
|
176
|
-
|
|
202
|
+
mPushCallbackRegistered = true;
|
|
177
203
|
mEventDispatcher.subscribe(PUSH_OPEN_EVENT, callback);
|
|
178
204
|
}
|
|
179
205
|
}
|
|
@@ -181,13 +207,16 @@ public class PushwooshPlugin extends PushwooshPluginSpec implements LifecycleEve
|
|
|
181
207
|
@ReactMethod
|
|
182
208
|
public void onPushReceived(Callback callback) {
|
|
183
209
|
synchronized (sStartPushLock) {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
210
|
+
INSTANCE = this;
|
|
211
|
+
|
|
212
|
+
if (!mReceivedPushCallbackRegistered && sReceivedPush != null && !sReceivedPush.sentToCallback) {
|
|
213
|
+
callback.invoke(ConversionUtil.toWritableMap(ConversionUtil.stringToJSONObject(sReceivedPush.data)));
|
|
214
|
+
sReceivedPush.sentToCallback = true;
|
|
215
|
+
mReceivedPushCallbackRegistered = true;
|
|
187
216
|
return;
|
|
188
217
|
}
|
|
189
218
|
|
|
190
|
-
|
|
219
|
+
mReceivedPushCallbackRegistered = true;
|
|
191
220
|
mEventDispatcher.subscribe(PUSH_RECEIVED_EVENT, callback);
|
|
192
221
|
}
|
|
193
222
|
}
|
|
@@ -600,29 +629,32 @@ public class PushwooshPlugin extends PushwooshPluginSpec implements LifecycleEve
|
|
|
600
629
|
public void onHostDestroy() {
|
|
601
630
|
PWLog.noise(TAG, "Host destroyed");
|
|
602
631
|
|
|
603
|
-
//
|
|
604
|
-
//
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
// teardown must not reset what the new module has already set up.
|
|
609
|
-
if (INSTANCE != this) {
|
|
610
|
-
return;
|
|
611
|
-
}
|
|
632
|
+
// Nothing is reset here: the host going down is the activity, not the JS runtime. React
|
|
633
|
+
// Native keeps the context and the JS bundle across activities, JS does not call init() or
|
|
634
|
+
// onPushOpen() a second time, and a push opened after the user left by Back has to reach
|
|
635
|
+
// that bundle. Everything JS set up is reset in invalidate(), where the runtime ends.
|
|
636
|
+
}
|
|
612
637
|
|
|
613
|
-
|
|
614
|
-
|
|
638
|
+
// React Native tears the module down with its React instance (legacy ModuleHolder.destroy(),
|
|
639
|
+
// TurboModuleManager.invalidate()). Everything JS set up lives on this module and goes with it;
|
|
640
|
+
// only the module's place as the live one has to be given up here. The cached push stays - the
|
|
641
|
+
// next init() replays it.
|
|
642
|
+
@Override
|
|
643
|
+
public void invalidate() {
|
|
644
|
+
super.invalidate();
|
|
645
|
+
PWLog.noise(TAG, "Module invalidated");
|
|
615
646
|
|
|
616
|
-
|
|
617
|
-
sReceivedPushData = null;
|
|
647
|
+
getReactApplicationContext().removeLifecycleEventListener(this);
|
|
618
648
|
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
//
|
|
623
|
-
//
|
|
624
|
-
|
|
625
|
-
INSTANCE
|
|
649
|
+
// A push can be delivered on the FCM thread while the runtime is going down, and every
|
|
650
|
+
// other accessor of the field holds the lock.
|
|
651
|
+
synchronized (sStartPushLock) {
|
|
652
|
+
// Only if this module is still the live one. The next module publishes itself on the
|
|
653
|
+
// first call from JS and the order of the two events is not guaranteed, so a late
|
|
654
|
+
// teardown must not unseat a module that has already taken over.
|
|
655
|
+
if (INSTANCE == this) {
|
|
656
|
+
INSTANCE = null;
|
|
657
|
+
}
|
|
626
658
|
}
|
|
627
659
|
}
|
|
628
660
|
|
|
@@ -635,12 +667,21 @@ public class PushwooshPlugin extends PushwooshPluginSpec implements LifecycleEve
|
|
|
635
667
|
|
|
636
668
|
try {
|
|
637
669
|
synchronized (sStartPushLock) {
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
670
|
+
PendingPush push = new PendingPush(pushData);
|
|
671
|
+
sStartPush = push;
|
|
672
|
+
|
|
673
|
+
PushwooshPlugin plugin = INSTANCE;
|
|
674
|
+
if (plugin == null || !plugin.hasLiveRuntime()) {
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
if (plugin.mPushCallbackRegistered) {
|
|
679
|
+
plugin.mEventDispatcher.dispatchEvent(PUSH_OPEN_EVENT, ConversionUtil.toWritableMap(ConversionUtil.stringToJSONObject(pushData)));
|
|
680
|
+
push.sentToCallback = true;
|
|
641
681
|
}
|
|
642
|
-
if (
|
|
643
|
-
|
|
682
|
+
if (plugin.mInitialized) {
|
|
683
|
+
plugin.sendEvent(PUSH_OPEN_JS_EVENT, ConversionUtil.stringToJSONObject(pushData));
|
|
684
|
+
push.sentAsEvent = true;
|
|
644
685
|
}
|
|
645
686
|
}
|
|
646
687
|
} catch (Exception e) {
|
|
@@ -653,17 +694,33 @@ public class PushwooshPlugin extends PushwooshPluginSpec implements LifecycleEve
|
|
|
653
694
|
mEventDispatcher.sendJSEvent(getReactApplicationContext(), event, ConversionUtil.toWritableMap(params));
|
|
654
695
|
}
|
|
655
696
|
|
|
697
|
+
// The React instance behind the module is still running. One on its way down is not: emitting
|
|
698
|
+
// into it throws, the catch around the callers swallows the failure, and the push is gone.
|
|
699
|
+
// Held back, it stays cached for the next init(). Callers hold sStartPushLock.
|
|
700
|
+
private boolean hasLiveRuntime() {
|
|
701
|
+
return getReactApplicationContext().hasActiveReactInstance();
|
|
702
|
+
}
|
|
703
|
+
|
|
656
704
|
static void messageReceived(String pushData) {
|
|
657
705
|
PWLog.info(TAG, "Push received: " + pushData);
|
|
658
706
|
|
|
659
707
|
try {
|
|
660
708
|
synchronized (sStartPushLock) {
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
709
|
+
PendingPush push = new PendingPush(pushData);
|
|
710
|
+
sReceivedPush = push;
|
|
711
|
+
|
|
712
|
+
PushwooshPlugin plugin = INSTANCE;
|
|
713
|
+
if (plugin == null || !plugin.hasLiveRuntime()) {
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
if (plugin.mReceivedPushCallbackRegistered) {
|
|
718
|
+
plugin.mEventDispatcher.dispatchEvent(PUSH_RECEIVED_EVENT, ConversionUtil.toWritableMap(ConversionUtil.stringToJSONObject(pushData)));
|
|
719
|
+
push.sentToCallback = true;
|
|
664
720
|
}
|
|
665
|
-
if (
|
|
666
|
-
|
|
721
|
+
if (plugin.mInitialized) {
|
|
722
|
+
plugin.sendEvent(PUSH_RECEIVED_JS_EVENT, ConversionUtil.stringToJSONObject(pushData));
|
|
723
|
+
push.sentAsEvent = true;
|
|
667
724
|
}
|
|
668
725
|
}
|
|
669
726
|
} catch (Exception e) {
|