[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.
This commit is contained in:
Saúl Ibarra Corretgé 2017-08-08 13:47:20 -05:00 committed by Lyubo Marinov
parent d521deecc4
commit 205dc5f0c3
8 changed files with 25 additions and 203 deletions

View File

@ -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

View File

@ -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());
}
}
/**

View File

@ -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
* <tt>Activity.onNewIntent</tt> 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 - <tt>Intent</tt> 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

View File

@ -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

View File

@ -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<UIApplicationOpenURLOptionsKey,id> *)options {
JitsiMeetView *view = (JitsiMeetView *) self.window.rootViewController.view;
[view loadURL:url];
return YES;
}
@end

View File

@ -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;

View File

@ -18,7 +18,6 @@
#include <mach/mach_time.h>
#import <React/RCTAssert.h>
#import <React/RCTLinkingManager.h>
#import <React/RCTRootView.h>
#import "JitsiMeetView+Private.h"
@ -133,48 +132,6 @@ static NSMapTable<NSString *, JitsiMeetView *> *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<NSString *, JitsiMeetView *> *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];
}

View File

@ -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);
}
}
/**