Browse Source

ios: SDK v2 pass one

- cleanup
- API simplification (single loadURL method)
- JitsiMeet singleton for linking helpers and globals
- Linking moved to app
efficient_tiling
Saúl Ibarra Corretgé 6 years ago
parent
commit
dbc88b972e

+ 13
- 14
ios/app/src/AppDelegate.m View File

@@ -19,11 +19,10 @@
19 19
 #import "FIRUtilities.h"
20 20
 #import "Types.h"
21 21
 
22
-#import <JitsiMeet/JitsiMeet.h>
23
-
24 22
 @import Crashlytics;
25 23
 @import Fabric;
26 24
 @import Firebase;
25
+@import JitsiMeet;
27 26
 
28 27
 
29 28
 @implementation AppDelegate
@@ -40,10 +39,10 @@
40 39
 
41 40
     // Set the conference activity type defined in this application.
42 41
     // This cannot be defined by the SDK.
43
-    JitsiMeetView.conferenceActivityType = JitsiMeetConferenceActivityType;
42
+    [JitsiMeet sharedInstance].conferenceActivityType = JitsiMeetConferenceActivityType;
43
+    [[JitsiMeet sharedInstance] application:application didFinishLaunchingWithOptions:launchOptions];
44 44
 
45
-    return [JitsiMeetView application:application
46
-        didFinishLaunchingWithOptions:launchOptions];
45
+    return YES;
47 46
 }
48 47
 
49 48
 #pragma mark Linking delegate methods
@@ -63,9 +62,9 @@
63 62
            NSURL *dynamicLinkURL = dynamicLink.url;
64 63
            if (dynamicLinkURL) {
65 64
              userActivity.webpageURL = dynamicLinkURL;
66
-             [JitsiMeetView application:application
67
-                   continueUserActivity:userActivity
68
-                     restorationHandler:restorationHandler];
65
+             [[JitsiMeet sharedInstance] application:application
66
+                                continueUserActivity:userActivity
67
+                                  restorationHandler:restorationHandler];
69 68
            }
70 69
         }];
71 70
 
@@ -75,9 +74,9 @@
75 74
     }
76 75
 
77 76
     // 2. Default to plain old, non-Firebase-assisted Universal Links.
78
-    return [JitsiMeetView application:application
79
-                 continueUserActivity:userActivity
80
-                   restorationHandler:restorationHandler];
77
+    return [[JitsiMeet sharedInstance] application:application
78
+                              continueUserActivity:userActivity
79
+                                restorationHandler:restorationHandler];
81 80
 }
82 81
 
83 82
 - (BOOL)application:(UIApplication *)app
@@ -100,9 +99,9 @@
100 99
         }
101 100
     }
102 101
 
103
-    return [JitsiMeetView application:app
104
-                              openURL:openUrl
105
-                              options:options];
102
+    return [[JitsiMeet sharedInstance] application:app
103
+                                           openURL:openUrl
104
+                                           options:options];
106 105
 }
107 106
 
108 107
 @end

+ 7
- 12
ios/app/src/ViewController.m View File

@@ -1,5 +1,6 @@
1 1
 /*
2
- * Copyright @ 2017-present Atlassian Pty Ltd
2
+ * Copyright @ 2018-present 8x8, Inc.
3
+ * Copyright @ 2017-2018 Atlassian Pty Ltd
3 4
  *
4 5
  * Licensed under the Apache License, Version 2.0 (the "License");
5 6
  * you may not use this file except in compliance with the License.
@@ -15,18 +16,14 @@
15 16
  */
16 17
 
17 18
 #import <Availability.h>
18
-#import <CoreSpotlight/CoreSpotlight.h>
19
-#import <MobileCoreServices/MobileCoreServices.h>
19
+
20
+@import CoreSpotlight;
21
+@import MobileCoreServices;
22
+@import Intents;  // Needed for NSUserActivity suggestedInvocationPhrase
20 23
 
21 24
 #import "Types.h"
22 25
 #import "ViewController.h"
23 26
 
24
-// Needed for NSUserActivity suggestedInvocationPhrase
25
-@import Intents;
26
-
27
-
28
-@interface ViewController ()
29
-@end
30 27
 
31 28
 @implementation ViewController
32 29
 
@@ -42,11 +39,9 @@
42 39
     // anyway.
43 40
     view.welcomePageEnabled = YES;
44 41
 
45
-    [view loadURL:nil];
42
+    [view loadURL:[[JitsiMeet sharedInstance] getInitialURL]];
46 43
 }
47 44
 
48
-
49
-
50 45
 // JitsiMeetViewDelegate
51 46
 
52 47
 - (void)_onJitsiMeetViewDelegateEvent:(NSString *)name

+ 12
- 4
ios/sdk/sdk.xcodeproj/project.pbxproj View File

@@ -13,7 +13,6 @@
13 13
 		0B44A0191F902126009D1D64 /* MPVolumeViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B44A0181F902126009D1D64 /* MPVolumeViewManager.m */; };
14 14
 		0B49424520AD8DBD00BD2DE0 /* outgoingStart.wav in Resources */ = {isa = PBXBuildFile; fileRef = 0B49424320AD8DBD00BD2DE0 /* outgoingStart.wav */; };
15 15
 		0B49424620AD8DBD00BD2DE0 /* outgoingRinging.wav in Resources */ = {isa = PBXBuildFile; fileRef = 0B49424420AD8DBD00BD2DE0 /* outgoingRinging.wav */; };
16
-		0B7C2CFD200F51D60060D076 /* LaunchOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B7C2CFC200F51D60060D076 /* LaunchOptions.m */; };
17 16
 		0B93EF7E1EC9DDCD0030D24D /* RCTBridgeWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B93EF7C1EC9DDCD0030D24D /* RCTBridgeWrapper.h */; };
18 17
 		0B93EF7F1EC9DDCD0030D24D /* RCTBridgeWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B93EF7D1EC9DDCD0030D24D /* RCTBridgeWrapper.m */; };
19 18
 		0BA13D311EE83FF8007BEF7F /* ExternalAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = 0BA13D301EE83FF8007BEF7F /* ExternalAPI.m */; };
@@ -45,6 +44,8 @@
45 44
 		C6CC49AF207412CF000DFA42 /* PiPViewCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6CC49AE207412CF000DFA42 /* PiPViewCoordinator.swift */; };
46 45
 		C6F99C15204DB63E0001F710 /* JitsiMeetView+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = C6F99C13204DB63D0001F710 /* JitsiMeetView+Private.h */; };
47 46
 		DEFC743F21B178FA00E4DD96 /* LocaleDetector.m in Sources */ = {isa = PBXBuildFile; fileRef = DEFC743D21B178FA00E4DD96 /* LocaleDetector.m */; };
47
+		DEFE535421FB1BF800011A3A /* JitsiMeet.m in Sources */ = {isa = PBXBuildFile; fileRef = DEFE535321FB1BF800011A3A /* JitsiMeet.m */; };
48
+		DEFE535621FB2E8300011A3A /* ReactUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = DEFE535521FB2E8300011A3A /* ReactUtils.m */; };
48 49
 /* End PBXBuildFile section */
49 50
 
50 51
 /* Begin PBXFileReference section */
@@ -55,7 +56,6 @@
55 56
 		0B44A0181F902126009D1D64 /* MPVolumeViewManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPVolumeViewManager.m; sourceTree = "<group>"; };
56 57
 		0B49424320AD8DBD00BD2DE0 /* outgoingStart.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; name = outgoingStart.wav; path = ../../sounds/outgoingStart.wav; sourceTree = "<group>"; };
57 58
 		0B49424420AD8DBD00BD2DE0 /* outgoingRinging.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; name = outgoingRinging.wav; path = ../../sounds/outgoingRinging.wav; sourceTree = "<group>"; };
58
-		0B7C2CFC200F51D60060D076 /* LaunchOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LaunchOptions.m; sourceTree = "<group>"; };
59 59
 		0B93EF7A1EC608550030D24D /* CoreText.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = System/Library/Frameworks/CoreText.framework; sourceTree = SDKROOT; };
60 60
 		0B93EF7C1EC9DDCD0030D24D /* RCTBridgeWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBridgeWrapper.h; sourceTree = "<group>"; };
61 61
 		0B93EF7D1EC9DDCD0030D24D /* RCTBridgeWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBridgeWrapper.m; sourceTree = "<group>"; };
@@ -93,6 +93,10 @@
93 93
 		C6CC49AE207412CF000DFA42 /* PiPViewCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PiPViewCoordinator.swift; sourceTree = "<group>"; };
94 94
 		C6F99C13204DB63D0001F710 /* JitsiMeetView+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "JitsiMeetView+Private.h"; sourceTree = "<group>"; };
95 95
 		DEFC743D21B178FA00E4DD96 /* LocaleDetector.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LocaleDetector.m; sourceTree = "<group>"; };
96
+		DEFE535321FB1BF800011A3A /* JitsiMeet.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JitsiMeet.m; sourceTree = "<group>"; };
97
+		DEFE535521FB2E8300011A3A /* ReactUtils.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ReactUtils.m; sourceTree = "<group>"; };
98
+		DEFE535721FB2E9E00011A3A /* ReactUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ReactUtils.h; sourceTree = "<group>"; };
99
+		DEFE535821FB311F00011A3A /* JitsiMeet+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "JitsiMeet+Private.h"; sourceTree = "<group>"; };
96 100
 /* End PBXFileReference section */
97 101
 
98 102
 /* Begin PBXFrameworksBuildPhase section */
@@ -158,16 +162,19 @@
158 162
 				0BA13D301EE83FF8007BEF7F /* ExternalAPI.m */,
159 163
 				0BD906E91EC0C00300C8C18E /* Info.plist */,
160 164
 				0BD906E81EC0C00300C8C18E /* JitsiMeet.h */,
165
+				DEFE535821FB311F00011A3A /* JitsiMeet+Private.h */,
166
+				DEFE535321FB1BF800011A3A /* JitsiMeet.m */,
161 167
 				0B412F161EDEC65D00B1A0A6 /* JitsiMeetView.h */,
162 168
 				0B412F171EDEC65D00B1A0A6 /* JitsiMeetView.m */,
163 169
 				C6F99C13204DB63D0001F710 /* JitsiMeetView+Private.h */,
164 170
 				0B412F1B1EDEC80100B1A0A6 /* JitsiMeetViewDelegate.h */,
165
-				0B7C2CFC200F51D60060D076 /* LaunchOptions.m */,
166 171
 				DEFC743D21B178FA00E4DD96 /* LocaleDetector.m */,
167 172
 				0B44A0181F902126009D1D64 /* MPVolumeViewManager.m */,
168 173
 				C6A3426B204F127900E062DD /* picture-in-picture */,
169 174
 				0BCA495D1EC4B6C600B793EE /* POSIX.m */,
170 175
 				0BCA495E1EC4B6C600B793EE /* Proximity.m */,
176
+				DEFE535721FB2E9E00011A3A /* ReactUtils.h */,
177
+				DEFE535521FB2E8300011A3A /* ReactUtils.m */,
171 178
 				0B93EF7C1EC9DDCD0030D24D /* RCTBridgeWrapper.h */,
172 179
 				0B93EF7D1EC9DDCD0030D24D /* RCTBridgeWrapper.m */,
173 180
 			);
@@ -447,7 +454,6 @@
447 454
 				0B93EF7F1EC9DDCD0030D24D /* RCTBridgeWrapper.m in Sources */,
448 455
 				0BA13D311EE83FF8007BEF7F /* ExternalAPI.m in Sources */,
449 456
 				0BCA49601EC4B6C600B793EE /* POSIX.m in Sources */,
450
-				0B7C2CFD200F51D60060D076 /* LaunchOptions.m in Sources */,
451 457
 				C6CC49AF207412CF000DFA42 /* PiPViewCoordinator.swift in Sources */,
452 458
 				DEFC743F21B178FA00E4DD96 /* LocaleDetector.m in Sources */,
453 459
 				0BCA495F1EC4B6C600B793EE /* AudioMode.m in Sources */,
@@ -455,11 +461,13 @@
455 461
 				0BCA49611EC4B6C600B793EE /* Proximity.m in Sources */,
456 462
 				A480429C21EE335600289B73 /* AmplitudeModule.m in Sources */,
457 463
 				C69EFA0C209A0F660027712B /* JMCallKitEmitter.swift in Sources */,
464
+				DEFE535621FB2E8300011A3A /* ReactUtils.m in Sources */,
458 465
 				C6A34261204EF76800E062DD /* DragGestureController.swift in Sources */,
459 466
 				A4A934E9212F3ADB001E9388 /* Dropbox.m in Sources */,
460 467
 				C69EFA0D209A0F660027712B /* JMCallKitProxy.swift in Sources */,
461 468
 				C69EFA0E209A0F660027712B /* JMCallKitListener.swift in Sources */,
462 469
 				0B412F191EDEC65D00B1A0A6 /* JitsiMeetView.m in Sources */,
470
+				DEFE535421FB1BF800011A3A /* JitsiMeet.m in Sources */,
463 471
 			);
464 472
 			runOnlyForDeploymentPostprocessing = 0;
465 473
 		};

+ 23
- 0
ios/sdk/src/JitsiMeet+Private.h View File

@@ -0,0 +1,23 @@
1
+/*
2
+ * Copyright @ 2019-present 8x8, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+#import "JitsiMeet.h"
18
+
19
+@interface JitsiMeet ()
20
+
21
+- (RCTBridge *)getReactBridge;
22
+
23
+@end

+ 29
- 2
ios/sdk/src/JitsiMeet.h View File

@@ -1,5 +1,6 @@
1 1
 /*
2
- * Copyright @ 2017-present Atlassian Pty Ltd
2
+ * Copyright @ 2018-present 8x8, Inc.
3
+ * Copyright @ 2017-2018 Atlassian Pty Ltd
3 4
  *
4 5
  * Licensed under the Apache License, Version 2.0 (the "License");
5 6
  * you may not use this file except in compliance with the License.
@@ -14,6 +15,32 @@
14 15
  * limitations under the License.
15 16
  */
16 17
 
17
-// JitsiMeetView
18 18
 #import <JitsiMeet/JitsiMeetView.h>
19 19
 #import <JitsiMeet/JitsiMeetViewDelegate.h>
20
+
21
+@interface JitsiMeet : NSObject
22
+
23
+@property (copy, nonatomic, nullable) NSString *conferenceActivityType;
24
+
25
+#pragma mak - This class is a singleton
26
+
27
++ (instancetype)sharedInstance;
28
+
29
+#pragma mark - Methods that the App delegate must call
30
+
31
+-             (BOOL)application:(UIApplication *_Nonnull)application
32
+  didFinishLaunchingWithOptions:(NSDictionary *_Nonnull)launchOptions;
33
+
34
+-    (BOOL)application:(UIApplication * _Nonnull)application
35
+  continueUserActivity:(NSUserActivity * _Nonnull)userActivity
36
+    restorationHandler:(void (^ _Nullable)(NSArray * _Nullable))restorationHandler;
37
+
38
+- (BOOL)application:(UIApplication *)app
39
+            openURL:(NSURL *)url
40
+            options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options;
41
+
42
+#pragma mark - Utility methods
43
+
44
+- (NSDictionary *)getInitialURL;
45
+
46
+@end

+ 161
- 0
ios/sdk/src/JitsiMeet.m View File

@@ -0,0 +1,161 @@
1
+/*
2
+ * Copyright @ 2019-present 8x8, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+#import <Intents/Intents.h>
18
+
19
+#import "Dropbox.h"
20
+#import "JitsiMeet+Private.h"
21
+#import "JitsiMeetView+Private.h"
22
+#import "RCTBridgeWrapper.h"
23
+#import "ReactUtils.h"
24
+
25
+#import <RNGoogleSignin/RNGoogleSignin.h>
26
+
27
+
28
+@implementation JitsiMeet {
29
+    RCTBridgeWrapper *_bridgeWrapper;
30
+    NSDictionary *_launchOptions;
31
+}
32
+
33
+#pragma mak - This class is a singleton
34
+
35
++ (instancetype)sharedInstance {
36
+    static JitsiMeet *sharedInstance = nil;
37
+    static dispatch_once_t onceToken;
38
+
39
+    dispatch_once(&onceToken, ^{
40
+        sharedInstance = [[self alloc] init];
41
+    });
42
+
43
+    return sharedInstance;
44
+}
45
+
46
+- (instancetype)init {
47
+    if (self = [super init]) {
48
+        // Initialize the on and only bridge for interfacing with React Native.
49
+        _bridgeWrapper = [[RCTBridgeWrapper alloc] init];
50
+
51
+        // Register a fatal error handler for React.
52
+        registerReactFatalErrorHandler();
53
+    }
54
+
55
+    return self;
56
+}
57
+
58
+#pragma mark - Methods that the App delegate must call
59
+
60
+-             (BOOL)application:(UIApplication *)application
61
+  didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
62
+
63
+    _launchOptions = [launchOptions copy];
64
+
65
+    [Dropbox setAppKey];
66
+
67
+    return YES;
68
+}
69
+
70
+-    (BOOL)application:(UIApplication *)application
71
+  continueUserActivity:(NSUserActivity *)userActivity
72
+    restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler {
73
+
74
+    id url = [self urlFromUserActivity:userActivity];
75
+
76
+    return url && [JitsiMeetView loadURLInViews:url];
77
+}
78
+
79
+- (BOOL)application:(UIApplication *)app
80
+            openURL:(NSURL *)url
81
+            options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
82
+
83
+    if ([Dropbox application:app openURL:url options:options]) {
84
+        return YES;
85
+    }
86
+
87
+    if ([RNGoogleSignin application:app
88
+                            openURL:url
89
+                  sourceApplication:options[UIApplicationOpenURLOptionsSourceApplicationKey]
90
+                         annotation:options[UIApplicationOpenURLOptionsAnnotationKey]]) {
91
+        return YES;
92
+    }
93
+
94
+    return [JitsiMeetView loadURLInViews:@{ @"url" : url.absoluteString }];
95
+}
96
+
97
+#pragma mark - Utility methods
98
+
99
+- (NSDictionary *)getInitialURL {
100
+    if (_launchOptions[UIApplicationLaunchOptionsURLKey]) {
101
+        NSURL *url = _launchOptions[UIApplicationLaunchOptionsURLKey];
102
+        return @{ @"url" : url.absoluteString };
103
+    } else {
104
+        NSDictionary *userActivityDictionary
105
+            = _launchOptions[UIApplicationLaunchOptionsUserActivityDictionaryKey];
106
+        NSUserActivity *userActivity
107
+            = [userActivityDictionary objectForKey:@"UIApplicationLaunchOptionsUserActivityKey"];
108
+        if (userActivity != nil) {
109
+            return [self urlFromUserActivity:userActivity];
110
+        }
111
+    }
112
+
113
+    return nil;
114
+}
115
+
116
+- (NSDictionary *)urlFromUserActivity:(NSUserActivity *)userActivity {
117
+    NSString *activityType = userActivity.activityType;
118
+
119
+    if ([activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) {
120
+        // App was started by opening a URL in the browser
121
+        return @{ @"url" : userActivity.webpageURL.absoluteString };
122
+    } else if ([activityType isEqualToString:@"INStartAudioCallIntent"]
123
+               || [activityType isEqualToString:@"INStartVideoCallIntent"]) {
124
+        // App was started by a CallKit Intent
125
+        INIntent *intent = userActivity.interaction.intent;
126
+        NSArray<INPerson *> *contacts;
127
+        NSString *url;
128
+        BOOL startAudioOnly = NO;
129
+
130
+        if ([intent isKindOfClass:[INStartAudioCallIntent class]]) {
131
+            contacts = ((INStartAudioCallIntent *) intent).contacts;
132
+            startAudioOnly = YES;
133
+        } else if ([intent isKindOfClass:[INStartVideoCallIntent class]]) {
134
+            contacts = ((INStartVideoCallIntent *) intent).contacts;
135
+        }
136
+
137
+        if (contacts && (url = contacts.firstObject.personHandle.value)) {
138
+            return @{
139
+                     @"config": @{@"startAudioOnly":@(startAudioOnly)},
140
+                     @"url": url
141
+                     };
142
+        }
143
+    } else if (self.conferenceActivityType && [activityType isEqualToString:self.conferenceActivityType]) {
144
+        // App was started by continuing a registered NSUserActivity (SiriKit, Handoff, ...)
145
+        NSString *url;
146
+
147
+        if ((url = userActivity.userInfo[@"url"])) {
148
+            return @{ @"url" : url };
149
+        }
150
+    }
151
+
152
+    return nil;
153
+}
154
+
155
+#pragma mark - Private API methods
156
+
157
+- (RCTBridge *)getReactBridge {
158
+    return _bridgeWrapper.bridge;
159
+}
160
+
161
+@end

+ 3
- 2
ios/sdk/src/JitsiMeetView+Private.h View File

@@ -1,5 +1,6 @@
1 1
 /*
2
- * Copyright @ 2017-present Atlassian Pty Ltd
2
+ * Copyright @ 2018-present 8x8, Inc.
3
+ * Copyright @ 2017-2018 Atlassian Pty Ltd
3 4
  *
4 5
  * Licensed under the Apache License, Version 2.0 (the "License");
5 6
  * you may not use this file except in compliance with the License.
@@ -18,7 +19,7 @@
18 19
 
19 20
 @interface JitsiMeetView ()
20 21
 
21
-+ (NSDictionary *)conferenceURLFromUserActivity:(NSUserActivity *)userActivity;
22 22
 + (instancetype)viewForExternalAPIScope:(NSString *)externalAPIScope;
23
++ (BOOL)loadURLInViews:(NSDictionary *)urlObject;
23 24
 
24 25
 @end

+ 3
- 22
ios/sdk/src/JitsiMeetView.h View File

@@ -1,5 +1,6 @@
1 1
 /*
2
- * Copyright @ 2017-present Atlassian Pty Ltd
2
+ * Copyright @ 2018-present 8x8, Inc.
3
+ * Copyright @ 2017-2018 Atlassian Pty Ltd
3 4
  *
4 5
  * Licensed under the Apache License, Version 2.0 (the "License");
5 6
  * you may not use this file except in compliance with the License.
@@ -33,26 +34,6 @@
33 34
 
34 35
 @property (nonatomic) BOOL welcomePageEnabled;
35 36
 
36
-+             (BOOL)application:(UIApplication *_Nonnull)application
37
-  didFinishLaunchingWithOptions:(NSDictionary *_Nonnull)launchOptions;
38
-
39
-+    (BOOL)application:(UIApplication * _Nonnull)application
40
-  continueUserActivity:(NSUserActivity * _Nonnull)userActivity
41
-    restorationHandler:(void (^ _Nullable)(NSArray * _Nullable))restorationHandler;
42
-
43
-+ (BOOL)application:(UIApplication *)app
44
-            openURL:(NSURL *)url
45
-            options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options;
46
-
47
-+ (BOOL)application:(UIApplication * _Nonnull)application
48
-            openURL:(NSURL * _Nonnull)URL
49
-  sourceApplication:(NSString * _Nullable)sourceApplication
50
-         annotation:(id _Nullable)annotation __deprecated;
51
-
52
-- (void)loadURL:(NSURL * _Nullable)url;
53
-
54
-- (void)loadURLObject:(NSDictionary * _Nullable)urlObject;
55
-
56
-- (void)loadURLString:(NSString * _Nullable)urlString;
37
+- (void)loadURL:(NSDictionary * _Nullable)urlObject;
57 38
 
58 39
 @end

+ 32
- 249
ios/sdk/src/JitsiMeetView.m View File

@@ -1,5 +1,6 @@
1 1
 /*
2
- * Copyright @ 2017-present Atlassian Pty Ltd
2
+ * Copyright @ 2018-present 8x8, Inc.
3
+ * Copyright @ 2017-2018 Atlassian Pty Ltd
3 4
  *
4 5
  * Licensed under the Apache License, Version 2.0 (the "License");
5 6
  * you may not use this file except in compliance with the License.
@@ -14,62 +15,15 @@
14 15
  * limitations under the License.
15 16
  */
16 17
 
17
-#import <Intents/Intents.h>
18
-
19 18
 #include <mach/mach_time.h>
20 19
 
21
-#import <React/RCTAssert.h>
22
-#import <React/RCTLinkingManager.h>
23 20
 #import <React/RCTRootView.h>
24 21
 
25
-#import <RNGoogleSignin/RNGoogleSignin.h>
26
-
27
-#import "Dropbox.h"
22
+#import "JitsiMeet+Private.h"
28 23
 #import "JitsiMeetView+Private.h"
29
-#import "RCTBridgeWrapper.h"
30 24
 
31
-/**
32
- * A `RCTFatalHandler` implementation which swallows JavaScript errors. In the
33
- * Release configuration, React Native will (intentionally) raise an unhandled
34
- * `NSException` for an unhandled JavaScript error. This will effectively kill
35
- * the application. `_RCTFatal` is suitable to be in accord with the Web i.e.
36
- * not kill the application.
37
- */
38
-RCTFatalHandler _RCTFatal = ^(NSError *error) {
39
-    id jsStackTrace = error.userInfo[RCTJSStackTraceKey];
40
-    @try {
41
-        NSString *name
42
-            = [NSString stringWithFormat:@"%@: %@",
43
-                        RCTFatalExceptionName,
44
-                        error.localizedDescription];
45
-        NSString *message
46
-            = RCTFormatError(error.localizedDescription, jsStackTrace, 75);
47
-        [NSException raise:name format:@"%@", message];
48
-    } @catch (NSException *e) {
49
-        if (!jsStackTrace) {
50
-            @throw;
51
-        }
52
-    }
53
-};
54 25
 
55
-/**
56
- * Helper function to register a fatal error handler for React. Our handler
57
- * won't kill the process, it will swallow JS errors and print stack traces
58
- * instead.
59
- */
60
-void registerFatalErrorHandler() {
61
-#if !DEBUG
62
-    // In the Release configuration, React Native will (intentionally) raise an
63
-    // unhandled `NSException` for an unhandled JavaScript error. This will
64
-    // effectively kill the application. In accord with the Web, do not kill the
65
-    // application.
66
-    if (!RCTGetFatalHandler()) {
67
-        RCTSetFatalHandler(_RCTFatal);
68
-    }
69
-#endif
70
-}
71
-
72
-@interface JitsiMeetView() {
26
+@implementation JitsiMeetView {
73 27
     /**
74 28
      * The unique identifier of this `JitsiMeetView` within the process for the
75 29
      * purposes of `ExternalAPI`. The name scope was inspired by postis which we
@@ -78,98 +32,24 @@ void registerFatalErrorHandler() {
78 32
     NSString *externalAPIScope;
79 33
 
80 34
     RCTRootView *rootView;
81
-}
82 35
 
83
-@end
84
-
85
-@implementation JitsiMeetView {
86 36
     NSNumber *_pictureInPictureEnabled;
87 37
 }
88 38
 
89 39
 @dynamic pictureInPictureEnabled;
90 40
 
91
-static NSString *_conferenceActivityType;
92
-
93
-static RCTBridgeWrapper *bridgeWrapper;
94
-
95
-/**
96
- * Copy of the `launchOptions` dictionary that the application was started with.
97
- * It is required for the initial URL to be used if a (Universal) link was used
98
- * to launch a new instance of the application.
99
- */
100
-static NSDictionary *_launchOptions;
101
-
102 41
 /**
103 42
  * The `JitsiMeetView`s associated with their `ExternalAPI` scopes (i.e. unique
104 43
  * identifiers within the process).
105 44
  */
106 45
 static NSMapTable<NSString *, JitsiMeetView *> *views;
107 46
 
108
-+             (BOOL)application:(UIApplication *)application
109
-  didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
110
-    // Store launch options, will be used when we create the bridge.
111
-    _launchOptions = [launchOptions copy];
112
-
113
-    [Dropbox setAppKey];
114
-
115
-    return YES;
116
-}
117
-
118
-#pragma mark Linking delegate helpers
119
-// https://facebook.github.io/react-native/docs/linking.html
120
-
121
-+    (BOOL)application:(UIApplication *)application
122
-  continueUserActivity:(NSUserActivity *)userActivity
123
-    restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler
124
-{
125
-    // XXX At least twice we received bug reports about malfunctioning loadURL
126
-    // in the Jitsi Meet SDK while the Jitsi Meet app seemed to functioning as
127
-    // expected in our testing. But that was to be expected because the app does
128
-    // not exercise loadURL. In order to increase the test coverage of loadURL,
129
-    // channel Universal linking through loadURL.
130
-
131
-    id url = [self conferenceURLFromUserActivity:userActivity];
132
-
133
-    if (url && [self loadURLObjectInViews:url]) {
134
-        return YES;
135
-    }
136
-
137
-    return [RCTLinkingManager application:application
138
-                     continueUserActivity:userActivity
139
-                       restorationHandler:restorationHandler];
140
-}
141
-
142
-+ (BOOL)application:(UIApplication *)app
143
-            openURL:(NSURL *)url
144
-            options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
145
-    if ([Dropbox application:app openURL:url options:options]) {
146
-        return YES;
147
-    }
148
-
149
-    if ([RNGoogleSignin application:app
150
-                            openURL:url
151
-                  sourceApplication:options[UIApplicationOpenURLOptionsSourceApplicationKey]
152
-                         annotation:options[UIApplicationOpenURLOptionsAnnotationKey]]) {
153
-        return YES;
154
-    }
155
-
156
-    // XXX At least twice we received bug reports about malfunctioning loadURL
157
-    // in the Jitsi Meet SDK while the Jitsi Meet app seemed to functioning as
158
-    // expected in our testing. But that was to be expected because the app does
159
-    // not exercise loadURL. In order to increase the test coverage of loadURL,
160
-    // channel Universal linking through loadURL.
161
-    if ([self loadURLInViews:url]) {
162
-        return YES;
163
-    }
164
-
165
-    return [RCTLinkingManager application:app openURL:url options:options];
166
-}
167
-
168
-+ (BOOL)application:(UIApplication *)application
169
-            openURL:(NSURL *)url
170
-  sourceApplication:(NSString *)sourceApplication
171
-         annotation:(id)annotation {
172
-    return [self application:application openURL:url options:@{}];
47
+/**
48
+ * This gets called automagically when the program starts.
49
+ */
50
+__attribute__((constructor))
51
+static void initializeViewsMap() {
52
+    views = [NSMapTable strongToWeakObjectsMapTable];
173 53
 }
174 54
 
175 55
 #pragma mark Initializers
@@ -201,19 +81,26 @@ static NSMapTable<NSString *, JitsiMeetView *> *views;
201 81
     return self;
202 82
 }
203 83
 
204
-#pragma mark API
205
-
206 84
 /**
207
- * Loads a specific `NSURL` which may identify a conference to join. If the
208
- * specified `NSURL` is `nil` and the Welcome page is enabled, the Welcome page
209
- * is displayed instead.
85
+ * Internal initialization:
210 86
  *
211
- * @param url The `NSURL` to load which may identify a conference to join.
87
+ * - sets the background color
88
+ * - initializes the external API scope
212 89
  */
213
-- (void)loadURL:(NSURL *)url {
214
-    [self loadURLString:url ? url.absoluteString : nil];
90
+- (void)initWithXXX {
91
+    // Hook this JitsiMeetView into ExternalAPI.
92
+    externalAPIScope = [NSUUID UUID].UUIDString;
93
+    [views setObject:self forKey:externalAPIScope];
94
+
95
+    // Set a background color which is in accord with the JavaScript and Android
96
+    // parts of the application and causes less perceived visual flicker than
97
+    // the default background color.
98
+    self.backgroundColor
99
+    = [UIColor colorWithRed:.07f green:.07f blue:.07f alpha:1];
215 100
 }
216 101
 
102
+#pragma mark API
103
+
217 104
 /**
218 105
  * Loads a specific URL which may identify a conference to join. The URL is
219 106
  * specified in the form of an `NSDictionary` of properties which (1)
@@ -224,7 +111,7 @@ static NSMapTable<NSString *, JitsiMeetView *> *views;
224 111
  *
225 112
  * @param urlObject The URL to load which may identify a conference to join.
226 113
  */
227
-- (void)loadURLObject:(NSDictionary *)urlObject {
114
+- (void)loadURL:(NSDictionary *_Nullable)urlObject {
228 115
     NSMutableDictionary *props = [[NSMutableDictionary alloc] init];
229 116
 
230 117
     if (self.defaultURL) {
@@ -242,14 +129,14 @@ static NSMapTable<NSString *, JitsiMeetView *> *views;
242 129
         props[@"url"] = urlObject;
243 130
     }
244 131
 
245
-    // XXX The method loadURLObject: is supposed to be imperative i.e. a second
132
+    // XXX The method loadURL: is supposed to be imperative i.e. a second
246 133
     // invocation with one and the same URL is expected to join the respective
247 134
     // conference again if the first invocation was followed by leaving the
248 135
     // conference. However, React and, respectively,
249 136
     // appProperties/initialProperties are declarative expressions i.e. one and
250 137
     // the same URL will not trigger an automatic re-render in the JavaScript
251 138
     // source code. The workaround implemented bellow introduces imperativeness
252
-    // in React Component props by defining a unique value per loadURLObject:
139
+    // in React Component props by defining a unique value per loadURL:
253 140
     // invocation.
254 141
     props[@"timestamp"] = @(mach_absolute_time());
255 142
 
@@ -257,8 +144,9 @@ static NSMapTable<NSString *, JitsiMeetView *> *views;
257 144
         // Update props with the new URL.
258 145
         rootView.appProperties = props;
259 146
     } else {
147
+        RCTBridge *bridge = [[JitsiMeet sharedInstance] getReactBridge];
260 148
         rootView
261
-            = [[RCTRootView alloc] initWithBridge:bridgeWrapper.bridge
149
+            = [[RCTRootView alloc] initWithBridge:bridge
262 150
                                        moduleName:@"App"
263 151
                                 initialProperties:props];
264 152
         rootView.backgroundColor = self.backgroundColor;
@@ -272,28 +160,6 @@ static NSMapTable<NSString *, JitsiMeetView *> *views;
272 160
     }
273 161
 }
274 162
 
275
-/**
276
- * Loads a specific URL `NSString` which may identify a conference to
277
- * join. If the specified URL `NSString` is `nil` and the Welcome page is
278
- * enabled, the Welcome page is displayed instead.
279
- *
280
- * @param urlString The URL `NSString` to load which may identify a conference
281
- * to join.
282
- */
283
-- (void)loadURLString:(NSString *)urlString {
284
-    [self loadURLObject:urlString ? @{ @"url": urlString } : nil];
285
-}
286
-
287
-#pragma conferenceActivityType getter / setter
288
-
289
-+ (NSString *)conferenceActivityType {
290
-    return _conferenceActivityType;
291
-}
292
-
293
-+ (void) setConferenceActivityType:(NSString *)conferenceActivityType {
294
-    _conferenceActivityType = conferenceActivityType;
295
-}
296
-
297 163
 #pragma pictureInPictureEnabled getter / setter
298 164
 
299 165
 - (void) setPictureInPictureEnabled:(BOOL)pictureInPictureEnabled {
@@ -318,19 +184,7 @@ static NSMapTable<NSString *, JitsiMeetView *> *views;
318 184
 
319 185
 #pragma mark Private methods
320 186
 
321
-/**
322
- * Loads a specific `NSURL` in all existing `JitsiMeetView`s.
323
- *
324
- * @param url The `NSURL` to load in all existing `JitsiMeetView`s.
325
- * @return `YES` if the specified `url` was submitted for loading in at least
326
- * one `JitsiMeetView`; otherwise, `NO`.
327
- */
328
-+ (BOOL)loadURLInViews:(NSURL *)url {
329
-    return
330
-        [self loadURLObjectInViews:url ? @{ @"url": url.absoluteString } : nil];
331
-}
332
-
333
-+ (BOOL)loadURLObjectInViews:(NSDictionary *)urlObject {
187
++ (BOOL)loadURLInViews:(NSDictionary *)urlObject {
334 188
     BOOL handled = NO;
335 189
 
336 190
     if (views) {
@@ -339,7 +193,7 @@ static NSMapTable<NSString *, JitsiMeetView *> *views;
339 193
                 = [self viewForExternalAPIScope:externalAPIScope];
340 194
 
341 195
             if (view) {
342
-                [view loadURLObject:urlObject];
196
+                [view loadURL:urlObject];
343 197
                 handled = YES;
344 198
             }
345 199
         }
@@ -348,79 +202,8 @@ static NSMapTable<NSString *, JitsiMeetView *> *views;
348 202
     return handled;
349 203
 }
350 204
 
351
-+ (NSDictionary *)conferenceURLFromUserActivity:(NSUserActivity *)userActivity {
352
-    NSString *activityType = userActivity.activityType;
353
-
354
-    if ([activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) {
355
-        // App was started by opening a URL in the browser
356
-        return @{ @"url" : userActivity.webpageURL.absoluteString };
357
-    } else if ([activityType isEqualToString:@"INStartAudioCallIntent"]
358
-               || [activityType isEqualToString:@"INStartVideoCallIntent"]) {
359
-        // App was started by a CallKit Intent
360
-        INIntent *intent = userActivity.interaction.intent;
361
-        NSArray<INPerson *> *contacts;
362
-        NSString *url;
363
-        BOOL startAudioOnly = NO;
364
-
365
-        if ([intent isKindOfClass:[INStartAudioCallIntent class]]) {
366
-            contacts = ((INStartAudioCallIntent *) intent).contacts;
367
-            startAudioOnly = YES;
368
-        } else if ([intent isKindOfClass:[INStartVideoCallIntent class]]) {
369
-            contacts = ((INStartVideoCallIntent *) intent).contacts;
370
-        }
371
-
372
-        if (contacts && (url = contacts.firstObject.personHandle.value)) {
373
-            return @{
374
-                @"config": @{@"startAudioOnly":@(startAudioOnly)},
375
-                @"url": url
376
-                };
377
-        }
378
-    } else if (_conferenceActivityType && [activityType isEqualToString:_conferenceActivityType]) {
379
-        // App was started by continuing a registered NSUserActivity (SiriKit, Handoff, ...)
380
-        NSString *url;
381
-
382
-        if ((url = userActivity.userInfo[@"url"])) {
383
-            return @{ @"url" : url };
384
-        }
385
-    }
386
-
387
-    return nil;
388
-}
389
-
390 205
 + (instancetype)viewForExternalAPIScope:(NSString *)externalAPIScope {
391 206
     return [views objectForKey:externalAPIScope];
392 207
 }
393 208
 
394
-/**
395
- * Internal initialization:
396
- *
397
- * - sets the background color
398
- * - creates the React bridge
399
- * - loads the necessary custom fonts
400
- * - registers a custom fatal error error handler for React
401
- */
402
-- (void)initWithXXX {
403
-    static dispatch_once_t dispatchOncePredicate;
404
-
405
-    dispatch_once(&dispatchOncePredicate, ^{
406
-        // Initialize the static state of JitsiMeetView.
407
-        bridgeWrapper
408
-            = [[RCTBridgeWrapper alloc] initWithLaunchOptions:_launchOptions];
409
-        views = [NSMapTable strongToWeakObjectsMapTable];
410
-
411
-        // Register a fatal error handler for React.
412
-        registerFatalErrorHandler();
413
-    });
414
-
415
-    // Hook this JitsiMeetView into ExternalAPI.
416
-    externalAPIScope = [NSUUID UUID].UUIDString;
417
-    [views setObject:self forKey:externalAPIScope];
418
-
419
-    // Set a background color which is in accord with the JavaScript and Android
420
-    // parts of the application and causes less perceived visual flicker than
421
-    // the default background color.
422
-    self.backgroundColor
423
-        = [UIColor colorWithRed:.07f green:.07f blue:.07f alpha:1];
424
-}
425
-
426 209
 @end

+ 0
- 56
ios/sdk/src/LaunchOptions.m View File

@@ -1,56 +0,0 @@
1
-/*
2
- * Copyright @ 2018-present Atlassian Pty Ltd
3
- *
4
- * Licensed under the Apache License, Version 2.0 (the "License");
5
- * you may not use this file except in compliance with the License.
6
- * You may obtain a copy of the License at
7
- *
8
- *     http://www.apache.org/licenses/LICENSE-2.0
9
- *
10
- * Unless required by applicable law or agreed to in writing, software
11
- * distributed under the License is distributed on an "AS IS" BASIS,
12
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- * See the License for the specific language governing permissions and
14
- * limitations under the License.
15
- */
16
-
17
-#import "JitsiMeetView+Private.h"
18
-
19
-#import <React/RCTBridge.h>
20
-#import <React/RCTBridgeModule.h>
21
-
22
-@interface LaunchOptions : NSObject<RCTBridgeModule>
23
-
24
-@property (nonatomic, weak) RCTBridge *bridge;
25
-
26
-@end
27
-
28
-@implementation LaunchOptions
29
-
30
-RCT_EXPORT_MODULE();
31
-
32
-- (dispatch_queue_t)methodQueue {
33
-    return dispatch_get_main_queue();
34
-}
35
-
36
-RCT_EXPORT_METHOD(getInitialURL:(RCTPromiseResolveBlock)resolve
37
-                  reject:(__unused RCTPromiseRejectBlock)reject) {
38
-    id initialURL = nil;
39
-
40
-    if (self.bridge.launchOptions[UIApplicationLaunchOptionsURLKey]) {
41
-        NSURL *url = self.bridge.launchOptions[UIApplicationLaunchOptionsURLKey];
42
-        initialURL = url.absoluteString;
43
-    } else {
44
-        NSDictionary *userActivityDictionary
45
-            = self.bridge.launchOptions[UIApplicationLaunchOptionsUserActivityDictionaryKey];
46
-        NSUserActivity *userActivity
47
-            = [userActivityDictionary objectForKey:@"UIApplicationLaunchOptionsUserActivityKey"];
48
-        if (userActivity != nil) {
49
-            initialURL = [JitsiMeetView conferenceURLFromUserActivity:userActivity];
50
-        }
51
-    }
52
-
53
-    resolve(initialURL != nil ? initialURL : (id)kCFNull);
54
-}
55
-
56
-@end

+ 0
- 2
ios/sdk/src/RCTBridgeWrapper.h View File

@@ -34,6 +34,4 @@
34 34
 
35 35
 @property (nonatomic, readonly, strong)  RCTBridge *bridge;
36 36
 
37
-- (instancetype)initWithLaunchOptions:(NSDictionary *)launchOptions;
38
-
39 37
 @end

+ 2
- 2
ios/sdk/src/RCTBridgeWrapper.m View File

@@ -22,12 +22,12 @@
22 22
  */
23 23
 @implementation RCTBridgeWrapper
24 24
 
25
-- (instancetype)initWithLaunchOptions:(NSDictionary *)launchOptions {
25
+- (instancetype)init {
26 26
     self = [super init];
27 27
     if (self) {
28 28
         _bridge
29 29
             = [[RCTBridge alloc] initWithDelegate:self
30
-                                    launchOptions:launchOptions];
30
+                                    launchOptions:nil];
31 31
     }
32 32
 
33 33
     return self;

+ 22
- 0
ios/sdk/src/ReactUtils.h View File

@@ -0,0 +1,22 @@
1
+/*
2
+ * Copyright @ 2019-present 8x8, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+#ifndef ReactUtils_h
18
+#define ReactUtils_h
19
+
20
+void registerReactFatalErrorHandler(void);
21
+
22
+#endif /* ReactUtils_h */

+ 60
- 0
ios/sdk/src/ReactUtils.m View File

@@ -0,0 +1,60 @@
1
+/*
2
+ * Copyright @ 2019-present 8x8, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+#import <React/RCTAssert.h>
18
+
19
+#import "ReactUtils.h"
20
+
21
+/**
22
+ * A `RCTFatalHandler` implementation which swallows JavaScript errors. In the
23
+ * Release configuration, React Native will (intentionally) raise an unhandled
24
+ * `NSException` for an unhandled JavaScript error. This will effectively kill
25
+ * the application. `_RCTFatal` is suitable to be in accord with the Web i.e.
26
+ * not kill the application.
27
+ */
28
+RCTFatalHandler _RCTFatal = ^(NSError *error) {
29
+    id jsStackTrace = error.userInfo[RCTJSStackTraceKey];
30
+    @try {
31
+        NSString *name
32
+        = [NSString stringWithFormat:@"%@: %@",
33
+           RCTFatalExceptionName,
34
+           error.localizedDescription];
35
+        NSString *message
36
+        = RCTFormatError(error.localizedDescription, jsStackTrace, 75);
37
+        [NSException raise:name format:@"%@", message];
38
+    } @catch (NSException *e) {
39
+        if (!jsStackTrace) {
40
+            @throw;
41
+        }
42
+    }
43
+};
44
+
45
+/**
46
+ * Helper function to register a fatal error handler for React. Our handler
47
+ * won't kill the process, it will swallow JS errors and print stack traces
48
+ * instead.
49
+ */
50
+void registerReactFatalErrorHandler() {
51
+#if !DEBUG
52
+    // In the Release configuration, React Native will (intentionally) raise an
53
+    // unhandled `NSException` for an unhandled JavaScript error. This will
54
+    // effectively kill the application. In accord with the Web, do not kill the
55
+    // application.
56
+    if (!RCTGetFatalHandler()) {
57
+        RCTSetFatalHandler(_RCTFatal);
58
+    }
59
+#endif
60
+}

Loading…
Cancel
Save