Skip to content

Commit d4a557a

Browse files
committed
refactor: simplified setup API
It is no longer necessary to set initialProperties, and the library exports a static `application:continueUserActivity:restorationHandler:` handler. The listener is also no longer called immediately with the initial shortcut. Instead, the library now provides a `getInitialShortcut` async method to get the initial shortcut. This should make it easier to integrate with `react-navigation`'s Deep Linking. We should also write a React Navigation Example at some point, with Deep Linking setup. A migration guide needs to be written for this change. This release WILL BE A BREAKING CHANGE.
1 parent 0d2c278 commit d4a557a

File tree

6 files changed

+136
-87
lines changed

6 files changed

+136
-87
lines changed

example/App.js

+34-15
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55
* @format
66
* @flow strict-local
77
*/
8-
import type {ShortcutOptions, ShortcutData} from 'react-native-siri-shortcut';
8+
import type {
9+
ShortcutOptions,
10+
ShortcutData,
11+
ShortcutInfo,
12+
} from 'react-native-siri-shortcut';
913

1014
import React, {Component} from 'react';
1115
import {
@@ -15,15 +19,17 @@ import {
1519
Button,
1620
SafeAreaView,
1721
View,
22+
EmitterSubscription,
1823
} from 'react-native';
1924
import {
20-
SiriShortcutsEvent,
2125
donateShortcut,
2226
suggestShortcuts,
2327
clearAllShortcuts,
2428
clearShortcutsWithIdentifiers,
2529
presentShortcut,
2630
getShortcuts,
31+
addShortcutListener,
32+
getInitialShortcut,
2733
} from 'react-native-siri-shortcut';
2834
import AddToSiriButton, {
2935
SiriButtonStyles,
@@ -38,6 +44,7 @@ const opts1: ShortcutOptions = {
3844
bar: 'baz',
3945
baz: 34.5,
4046
},
47+
requiredUserInfoKeys: ['foo', 'bar', 'baz'],
4148
keywords: ['kek', 'foo', 'bar'],
4249
persistentIdentifier:
4350
'com.github.gustash.SiriShortcutsModuleExample.sayHello',
@@ -63,6 +70,8 @@ type State = {
6370
shortcuts: Array<ShortcutData>,
6471
};
6572
export default class App extends Component<void, State> {
73+
listener: ?EmitterSubscription = null;
74+
6675
state: State = {
6776
shortcutInfo: null,
6877
shortcutActivityType: null,
@@ -71,10 +80,8 @@ export default class App extends Component<void, State> {
7180
};
7281

7382
componentDidMount() {
74-
SiriShortcutsEvent.addListener(
75-
'SiriShortcutListener',
76-
this.handleSiriShortcut.bind(this),
77-
);
83+
this.handleInitialShortcut();
84+
this.listener = addShortcutListener(this.handleSiriShortcut.bind(this));
7885

7986
// This will suggest these two shortcuts so that they appear
8087
// in Settings > Siri & Search, even if they are not yet
@@ -85,7 +92,23 @@ export default class App extends Component<void, State> {
8592
this.updateShortcutList();
8693
}
8794

88-
handleSiriShortcut({userInfo, activityType}: any) {
95+
componentWillUnmount() {
96+
if (this.listener) {
97+
this.listener.remove();
98+
}
99+
}
100+
101+
async handleInitialShortcut() {
102+
const initialShortcut = await getInitialShortcut();
103+
104+
if (!initialShortcut) {
105+
return;
106+
}
107+
108+
this.handleSiriShortcut(initialShortcut);
109+
}
110+
111+
handleSiriShortcut({userInfo, activityType}: ShortcutInfo) {
89112
this.setState({
90113
shortcutInfo: userInfo,
91114
shortcutActivityType: activityType,
@@ -157,20 +180,16 @@ export default class App extends Component<void, State> {
157180
const {addToSiriStyle} = this.state;
158181

159182
const styles = Object.keys(SiriButtonStyles).map(
160-
(key) => SiriButtonStyles[key],
183+
key => SiriButtonStyles[key],
161184
);
162-
const index = styles.findIndex((style) => style === addToSiriStyle);
185+
const index = styles.findIndex(style => style === addToSiriStyle);
163186
if (index === styles.length - 1) this.setState({addToSiriStyle: styles[0]});
164187
else this.setState({addToSiriStyle: styles[index + 1]});
165188
}
166189

167190
render() {
168-
const {
169-
shortcutInfo,
170-
shortcutActivityType,
171-
addToSiriStyle,
172-
shortcuts,
173-
} = this.state;
191+
const {shortcutInfo, shortcutActivityType, addToSiriStyle, shortcuts} =
192+
this.state;
174193

175194
return (
176195
<SafeAreaView style={styles.container}>

example/ios/example/AppDelegate.mm

+2-20
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
4242
bridge.surfacePresenter = _bridgeAdapter.surfacePresenter;
4343
#endif
4444

45-
// Check if the app launched with any shortcuts
46-
BOOL launchedFromShortcut = [launchOptions objectForKey:@"UIApplicationLaunchOptionsUserActivityDictionaryKey"] != nil;
47-
// Add a boolean to the initialProperties to let the app know you got the initial shortcut
48-
NSDictionary *initialProperties = @{ @"launchedFromShortcut":@(launchedFromShortcut) };
49-
UIView *rootView = RCTAppSetupDefaultRootView(bridge,
50-
@"example",
51-
initialProperties); // Add the initial properties here
45+
UIView *rootView = RCTAppSetupDefaultRootView(bridge, @"example", nil);
5246

5347
if (@available(iOS 13.0, *)) {
5448
rootView.backgroundColor = [UIColor systemBackgroundColor];
@@ -116,19 +110,7 @@ - (BOOL)application:(UIApplication *)application
116110
continueUserActivity:(NSUserActivity *)userActivity
117111
restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler
118112
{
119-
UIViewController *viewController = self.window.rootViewController;
120-
RCTRootView *rootView = (RCTRootView *)viewController.view;
121-
122-
// If the initial properties say the app launched from a shortcut (see above), tell the library about it.
123-
if ([[rootView.appProperties objectForKey:@"launchedFromShortcut"] boolValue]) {
124-
RNSiriShortcuts.initialUserActivity = userActivity;
125-
126-
rootView.appProperties = @{ @"launchedFromShortcut": @NO };
127-
}
128-
129-
[RNSiriShortcuts shortcutReceived:userActivity];
130-
131-
return YES;
113+
return [RNSiriShortcuts application:application continueUserActivity:userActivity restorationHandler:restorationHandler];
132114
}
133115

134116
@end

index.d.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { NativeEventEmitter } from "react-native";
1+
import { EmitterSubscription, NativeEventEmitter } from "react-native";
22

33
export type ShortcutOptions = {
44
activityType: string;
@@ -28,8 +28,19 @@ export type ShortcutData = {
2828
options?: ShortcutOptions;
2929
};
3030

31+
export type ShortcutInfo = {
32+
activityType: string;
33+
userInfo?: { [key: string]: any };
34+
}
35+
36+
/** @deprecated Use `addShortcutListener` instead. */
3137
export const SiriShortcutsEvent: NativeEventEmitter;
3238

39+
export function getInitialShortcut(): Promise<ShortcutInfo | null>;
40+
41+
export type ShortcutListener = (shortcut: ShortcutInfo) => void;
42+
export function addShortcutListener(callback: ShortcutListener): EmitterSubscription;
43+
3344
export function donateShortcut(options: ShortcutOptions): void;
3445

3546
export function suggestShortcuts(options: Array<ShortcutOptions>): void;

index.js

+12-1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ export type ShortcutData = {
4444
options?: ShortcutOptions
4545
};
4646

47+
export type ShortcutInfo = {
48+
activityType: string,
49+
userInfo: ?object,
50+
}
51+
4752
const noop = () => ({});
4853
const safeCall = (func, minVersion = 12) => {
4954
if (
@@ -59,7 +64,7 @@ const safeCall = (func, minVersion = 12) => {
5964
export const SiriShortcutsEvent = Platform.select({
6065
ios: new NativeEventEmitter(RNSiriShortcuts),
6166
android: {
62-
addListener: () => {},
67+
addListener: () => ({remove: () => {}}),
6368
removeListener: () => {},
6469
removeAllListeners: () => {},
6570
removeCurrentListener: () => {},
@@ -100,3 +105,9 @@ export const presentShortcut = safeCall(
100105
);
101106

102107
export const getShortcuts = safeCall(() => RNSiriShortcuts.getShortcuts());
108+
109+
export const getInitialShortcut = safeCall(() => RNSiriShortcuts.getInitialShortcut(), 9);
110+
111+
export const addShortcutListener = (callback: (shortcut: ShortcutInfo) => void) => {
112+
return SiriShortcutsEvent.addListener("SiriShortcutListener", callback);
113+
}

ios/RNSiriShortcuts.h

+13-5
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,24 @@
99
#ifndef RNSiriShortcuts_h
1010
#define RNSiriShortcuts_h
1111

12-
#import <React/RCTBridgeModule.h>
12+
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 12000) /* __IPHONE_12_0 */
13+
#import <UIKit/UIUserActivity.h>
14+
#endif
15+
1316
#import <React/RCTEventEmitter.h>
1417

1518
NS_ASSUME_NONNULL_BEGIN
1619

17-
@interface RNSiriShortcuts : RCTEventEmitter <RCTBridgeModule>
18-
19-
@property (class, nonatomic, strong) NSUserActivity * _Nullable initialUserActivity;
20+
@interface RNSiriShortcuts : RCTEventEmitter
2021

21-
+ (void)shortcutReceived:(NSUserActivity *)activity;
22+
+ (BOOL)application:(nonnull UIApplication *)application
23+
continueUserActivity:(nonnull NSUserActivity *)userActivity
24+
restorationHandler:
25+
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 12000) /* __IPHONE_12_0 */
26+
(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> *_Nullable))restorationHandler;
27+
#else
28+
(nonnull void (^)(NSArray *_Nullable))restorationHandler;
29+
#endif
2230

2331
@end
2432

0 commit comments

Comments
 (0)