From 205dc5f0c33e19cd078dd2e92676cabbe7e3ec30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Tue, 8 Aug 2017 13:47:20 -0500 Subject: [PATCH] [RN] Simplify handling of universal / deeps links Handle them directly on the application and call view.loadURL instead of having a static method which needs to figure out what view to load the URL on. On iOS, update the deep link method delegate since we don't support iOS 8. In addition, remove linking handling from the JS side, so now changing props of the root component is The One And Only Way to change the URL at runtime. --- android/README.md | 8 --- .../org/jitsi/meet/sdk/JitsiMeetActivity.java | 7 +- .../org/jitsi/meet/sdk/JitsiMeetView.java | 30 -------- ios/README.md | 28 -------- ios/app/src/AppDelegate.m | 31 +++++---- ios/sdk/src/JitsiMeetView.h | 9 --- ios/sdk/src/JitsiMeetView.m | 69 ------------------- react/features/app/components/App.native.js | 46 ------------- 8 files changed, 25 insertions(+), 203 deletions(-) diff --git a/android/README.md b/android/README.md index 7c3130fb0..a43182767 100644 --- a/android/README.md +++ b/android/README.md @@ -208,14 +208,6 @@ Helper method which should be called from the activity's `onResume` method. This is a static method. -#### onNewIntent(intent) - -Helper method for integrating the *deep linking* functionality. If your app's -activity is launched in "singleTask" mode this method should be called from the -activity's `onNewIntent` method. - -This is a static method. - #### JitsiMeetViewListener `JitsiMeetViewListener` provides an interface apps can implement to listen to diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetActivity.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetActivity.java index 453557e7a..e1de4db7f 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetActivity.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetActivity.java @@ -200,7 +200,12 @@ public class JitsiMeetActivity */ @Override public void onNewIntent(Intent intent) { - JitsiMeetView.onNewIntent(intent); + Uri uri; + + if (Intent.ACTION_VIEW.equals(intent.getAction()) + && (uri = intent.getData()) != null) { + view.loadURLString(uri.toString()); + } } /** diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetView.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetView.java index 5a80f9900..7169fecf4 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetView.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetView.java @@ -19,8 +19,6 @@ package org.jitsi.meet.sdk; import android.app.Activity; import android.app.Application; import android.content.Context; -import android.content.Intent; -import android.net.Uri; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -207,34 +205,6 @@ public class JitsiMeetView extends FrameLayout { } } - /** - * Activity lifecycle method which should be called from - * Activity.onNewIntent so we can do the required internal - * processing. Note that this is only needed if the activity's "launchMode" - * was set to "singleTask". This is required for deep linking to work once - * the application is already running. - * - * @param intent - Intent instance which was received. - */ - public static void onNewIntent(Intent intent) { - // XXX At least twice we received bug reports about malfunctioning - // loadURL in the Jitsi Meet SDK while the Jitsi Meet app seemed to - // functioning as expected in our testing. But that was to be expected - // because the app does not exercise loadURL. In order to increase the - // test coverage of loadURL, channel deep linking through loadURL. - Uri uri; - - if (Intent.ACTION_VIEW.equals(intent.getAction()) - && (uri = intent.getData()) != null - && loadURLStringInViews(uri.toString())) { - return; - } - - if (reactInstanceManager != null) { - reactInstanceManager.onNewIntent(intent); - } - } - /** * The unique identifier of this {@code JitsiMeetView} within the process * for the purposes of {@link ExternalAPI}. The name scope was inspired by diff --git a/ios/README.md b/ios/README.md index 8922d03ab..7073c5b40 100644 --- a/ios/README.md +++ b/ios/README.md @@ -91,34 +91,6 @@ Loads a specific URL which may identify a conference to join. If the specified URL is `nil` and the Welcome page is enabled, the Welcome page is displayed instead. -#### Universal / deep linking - -In order to support Universal / deep linking, `JitsiMeetView` offers 2 class -methods that you app's delegate should call in order for the app to follow those -links. - -```objc -- (BOOL)application:(UIApplication *)application -continueUserActivity:(NSUserActivity *)userActivity - restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler -{ - return [JitsiMeetView application:application - continueUserActivity:userActivity - restorationHandler:restorationHandler]; -} - -- (BOOL)application:(UIApplication *)application - openURL:(NSURL *)url - sourceApplication:(NSString *)sourceApplication - annotation:(id)annotation -{ - return [JitsiMeetView application:application - openURL:url - sourceApplication:sourceApplication - annotation:annotation]; -} -``` - ### JitsiMeetViewDelegate This delegate is optional, and can be set on the `JitsiMeetView` instance using diff --git a/ios/app/src/AppDelegate.m b/ios/app/src/AppDelegate.m index 3073dc84a..7bb6af8fe 100644 --- a/ios/app/src/AppDelegate.m +++ b/ios/app/src/AppDelegate.m @@ -28,22 +28,29 @@ #pragma mark Linking delegate methods -- (BOOL)application:(UIApplication *)application - continueUserActivity:(NSUserActivity *)userActivity - restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler { - return [JitsiMeetView application:application - continueUserActivity:userActivity - restorationHandler:restorationHandler]; +- (BOOL)application:(UIApplication *)application + continueUserActivity:(NSUserActivity *)userActivity + restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler { + + if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) { + JitsiMeetView *view + = (JitsiMeetView *) self.window.rootViewController.view; + [view loadURL:userActivity.webpageURL]; + + return YES; + } + + return NO; } - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url - sourceApplication:(NSString *)sourceApplication - annotation:(id)annotation { - return [JitsiMeetView application:application - openURL:url - sourceApplication:sourceApplication - annotation:annotation]; + options:(NSDictionary *)options { + + JitsiMeetView *view = (JitsiMeetView *) self.window.rootViewController.view; + [view loadURL:url]; + + return YES; } @end diff --git a/ios/sdk/src/JitsiMeetView.h b/ios/sdk/src/JitsiMeetView.h index f328d8f44..885dcca08 100644 --- a/ios/sdk/src/JitsiMeetView.h +++ b/ios/sdk/src/JitsiMeetView.h @@ -28,15 +28,6 @@ + (BOOL)application:(UIApplication *_Nonnull)application didFinishLaunchingWithOptions:(NSDictionary *_Nonnull)launchOptions; -+ (BOOL)application:(UIApplication * _Nonnull)application - continueUserActivity:(NSUserActivity * _Nonnull)userActivity - restorationHandler:(void (^ _Nullable)(NSArray * _Nullable))restorationHandler; - -+ (BOOL)application:(UIApplication * _Nonnull)application - openURL:(NSURL * _Nonnull)URL - sourceApplication:(NSString * _Nullable)sourceApplication - annotation:(id _Nullable)annotation; - - (void)loadURL:(NSURL * _Nullable)url; - (void)loadURLObject:(NSDictionary * _Nullable)urlObject; diff --git a/ios/sdk/src/JitsiMeetView.m b/ios/sdk/src/JitsiMeetView.m index 0e0985da8..eaed6c373 100644 --- a/ios/sdk/src/JitsiMeetView.m +++ b/ios/sdk/src/JitsiMeetView.m @@ -18,7 +18,6 @@ #include #import -#import #import #import "JitsiMeetView+Private.h" @@ -133,48 +132,6 @@ static NSMapTable *views; return YES; } -#pragma mark Linking delegate helpers -// https://facebook.github.io/react-native/docs/linking.html - -+ (BOOL)application:(UIApplication *)application - continueUserActivity:(NSUserActivity *)userActivity - restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler -{ - // XXX At least twice we received bug reports about malfunctioning loadURL - // in the Jitsi Meet SDK while the Jitsi Meet app seemed to functioning as - // expected in our testing. But that was to be expected because the app does - // not exercise loadURL. In order to increase the test coverage of loadURL, - // channel Universal linking through loadURL. - if ([userActivity.activityType - isEqualToString:NSUserActivityTypeBrowsingWeb] - && [JitsiMeetView loadURLInViews:userActivity.webpageURL]) { - return YES; - } - - return [RCTLinkingManager application:application - continueUserActivity:userActivity - restorationHandler:restorationHandler]; -} - -+ (BOOL)application:(UIApplication *)application - openURL:(NSURL *)url - sourceApplication:(NSString *)sourceApplication - annotation:(id)annotation { - // XXX At least twice we received bug reports about malfunctioning loadURL - // in the Jitsi Meet SDK while the Jitsi Meet app seemed to functioning as - // expected in our testing. But that was to be expected because the app does - // not exercise loadURL. In order to increase the test coverage of loadURL, - // channel Universal linking through loadURL. - if ([JitsiMeetView loadURLInViews:url]) { - return YES; - } - - return [RCTLinkingManager application:application - openURL:url - sourceApplication:sourceApplication - annotation:annotation]; -} - #pragma mark Initializers - (instancetype)init { @@ -281,32 +238,6 @@ static NSMapTable *views; #pragma mark Private methods -/** - * Loads a specific {@link NSURL} in all existing {@code JitsiMeetView}s. - * - * @param url - The {@code NSURL} to load in all existing - * {@code JitsiMeetView}s. - * @return {@code YES} if the specified {@code url} was submitted for loading in - * at least one {@code JitsiMeetView}; otherwise, {@code NO}. - */ -+ (BOOL)loadURLInViews:(NSURL *)url { - BOOL handled = NO; - - if (views) { - for (NSString *externalAPIScope in views) { - JitsiMeetView *view - = [JitsiMeetView viewForExternalAPIScope:externalAPIScope]; - - if (view) { - [view loadURL:url]; - handled = YES; - } - } - } - - return handled; -} - + (instancetype)viewForExternalAPIScope:(NSString *)externalAPIScope { return [views objectForKey:externalAPIScope]; } diff --git a/react/features/app/components/App.native.js b/react/features/app/components/App.native.js index e29720df6..2388687ed 100644 --- a/react/features/app/components/App.native.js +++ b/react/features/app/components/App.native.js @@ -1,7 +1,6 @@ /* global __DEV__ */ import React from 'react'; -import { Linking } from 'react-native'; import '../../analytics'; import '../../authentication'; @@ -47,9 +46,6 @@ export class App extends AbstractApp { constructor(props) { super(props); - // Bind event handlers so they are only bound once for every instance. - this._onLinkingURL = this._onLinkingURL.bind(this); - // In the Release configuration, React Native will (intentionally) throw // an unhandled JavascriptException for an unhandled JavaScript error. // This will effectively kill the application. In accord with the Web, @@ -57,34 +53,6 @@ export class App extends AbstractApp { this._maybeDisableExceptionsManager(); } - /** - * Subscribe to notifications about activating URLs registered to be handled - * by this app. - * - * @inheritdoc - * @returns {void} - * @see https://facebook.github.io/react-native/docs/linking.html - */ - componentWillMount() { - super.componentWillMount(); - - Linking.addEventListener('url', this._onLinkingURL); - } - - /** - * Unsubscribe from notifications about activating URLs registered to be - * handled by this app. - * - * @inheritdoc - * @returns {void} - * @see https://facebook.github.io/react-native/docs/linking.html - */ - componentWillUnmount() { - Linking.removeEventListener('url', this._onLinkingURL); - - super.componentWillUnmount(); - } - /** * Attempts to disable the use of React Native * {@link ExceptionsManager#handleException} on platforms and in @@ -122,20 +90,6 @@ export class App extends AbstractApp { global.ErrorUtils.setGlobalHandler(newHandler); } } - - /** - * Notified by React's Linking API that a specific URL registered to be - * handled by this App was activated. - * - * @param {Object} event - The details of the notification/event. - * @param {string} event.url - The URL registered to be handled by this App - * which was activated. - * @private - * @returns {void} - */ - _onLinkingURL({ url }) { - this._openURL(url); - } } /**