expo-invoke 1.0.0 → 1.2.0
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/README.md +61 -3
- package/app.plugin.js +2 -0
- package/package.json +9 -5
- package/MIGRATION.md +0 -125
- package/SECURITY.md +0 -35
package/README.md
CHANGED
|
@@ -10,6 +10,9 @@ The complete native-surface-to-JS bridge for Expo. Define one intent in `app.jso
|
|
|
10
10
|
|
|
11
11
|
- [Requirements](#requirements)
|
|
12
12
|
- [Installation](#installation)
|
|
13
|
+
- [Local build](#local-build)
|
|
14
|
+
- [EAS Build (cloud)](#eas-build-cloud)
|
|
15
|
+
- [EAS Build local](#eas-build-local)
|
|
13
16
|
- [Quick Start](#quick-start)
|
|
14
17
|
- [useInvoke() — Full API](#useinvoke--full-api)
|
|
15
18
|
- [Hooks](#hooks)
|
|
@@ -59,14 +62,69 @@ The complete native-surface-to-JS bridge for Expo. Define one intent in `app.jso
|
|
|
59
62
|
npx expo install expo-invoke
|
|
60
63
|
```
|
|
61
64
|
|
|
62
|
-
Then rebuild your native app:
|
|
65
|
+
Then rebuild your native app. Choose the workflow that fits your project:
|
|
66
|
+
|
|
67
|
+
### Local build
|
|
63
68
|
|
|
64
69
|
```bash
|
|
65
|
-
npx expo prebuild
|
|
66
|
-
npx expo run:ios
|
|
70
|
+
npx expo prebuild # generates native code from your app.json
|
|
71
|
+
npx expo run:ios # build + run on simulator or device
|
|
67
72
|
npx expo run:android
|
|
68
73
|
```
|
|
69
74
|
|
|
75
|
+
### EAS Build (cloud)
|
|
76
|
+
|
|
77
|
+
expo-invoke works fully with [EAS Build](https://docs.expo.dev/build/introduction/). EAS automatically runs `expo prebuild` before each build, so the config plugin generates all Swift and Kotlin code in the cloud — no local Xcode or Android Studio required.
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# Install EAS CLI
|
|
81
|
+
npm install -g eas-cli
|
|
82
|
+
|
|
83
|
+
# Configure your project (first time only)
|
|
84
|
+
eas build:configure
|
|
85
|
+
|
|
86
|
+
# Build for both platforms
|
|
87
|
+
eas build --platform all
|
|
88
|
+
|
|
89
|
+
# Or build for a specific platform
|
|
90
|
+
eas build --platform ios
|
|
91
|
+
eas build --platform android
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
A minimal `eas.json` to get started:
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"cli": {
|
|
99
|
+
"version": ">= 10.0.0"
|
|
100
|
+
},
|
|
101
|
+
"build": {
|
|
102
|
+
"development": {
|
|
103
|
+
"developmentClient": true,
|
|
104
|
+
"distribution": "internal"
|
|
105
|
+
},
|
|
106
|
+
"preview": {
|
|
107
|
+
"distribution": "internal"
|
|
108
|
+
},
|
|
109
|
+
"production": {}
|
|
110
|
+
},
|
|
111
|
+
"submit": {
|
|
112
|
+
"production": {}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
> **Development builds:** For the fastest iteration loop during development, use `eas build --profile development` to create a [development build](https://docs.expo.dev/develop/development-builds/introduction/) — a custom Expo Go that includes your native modules including expo-invoke.
|
|
118
|
+
|
|
119
|
+
### EAS Build local
|
|
120
|
+
|
|
121
|
+
Run the EAS build pipeline locally (requires Xcode / Android Studio):
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
eas build --platform ios --local
|
|
125
|
+
eas build --platform android --local
|
|
126
|
+
```
|
|
127
|
+
|
|
70
128
|
---
|
|
71
129
|
|
|
72
130
|
## Quick Start
|
package/app.plugin.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-invoke",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "The complete native-surface-to-JS bridge for Expo. One intent config → Siri, Google Assistant, home screen widgets, Dynamic Island, app icon menus, notification actions, NFC, QR, deep links and more — all through a single useInvoke() hook.",
|
|
5
5
|
"main": "build/src/index.js",
|
|
6
6
|
"module": "build/src/index.js",
|
|
@@ -10,12 +10,15 @@
|
|
|
10
10
|
"require": "./build/src/index.js",
|
|
11
11
|
"import": "./build/src/index.js",
|
|
12
12
|
"types": "./build/src/index.d.ts"
|
|
13
|
-
}
|
|
13
|
+
},
|
|
14
|
+
"./app.plugin": "./app.plugin.js",
|
|
15
|
+
"./app.plugin.js": "./app.plugin.js"
|
|
14
16
|
},
|
|
15
17
|
"expo": {
|
|
16
18
|
"plugin": "./build/plugin/src/withInvoke"
|
|
17
19
|
},
|
|
18
20
|
"files": [
|
|
21
|
+
"app.plugin.js",
|
|
19
22
|
"build",
|
|
20
23
|
"ios",
|
|
21
24
|
"android/src",
|
|
@@ -72,19 +75,20 @@
|
|
|
72
75
|
"registry": "https://registry.npmjs.org/"
|
|
73
76
|
},
|
|
74
77
|
"peerDependencies": {
|
|
78
|
+
"@expo/config-plugins": ">=7.0.0",
|
|
75
79
|
"expo": ">=50.0.0",
|
|
76
80
|
"expo-modules-core": ">=1.12.0",
|
|
77
81
|
"react": ">=18.0.0",
|
|
78
82
|
"react-native": ">=0.73.0"
|
|
79
83
|
},
|
|
80
84
|
"peerDependenciesMeta": {
|
|
85
|
+
"@expo/config-plugins": {
|
|
86
|
+
"optional": false
|
|
87
|
+
},
|
|
81
88
|
"expo-live-activity": {
|
|
82
89
|
"optional": true
|
|
83
90
|
}
|
|
84
91
|
},
|
|
85
|
-
"dependencies": {
|
|
86
|
-
"@expo/config-plugins": "^9.0.0"
|
|
87
|
-
},
|
|
88
92
|
"devDependencies": {
|
|
89
93
|
"@types/jest": "^29.5.14",
|
|
90
94
|
"@types/node": "^20.19.41",
|
package/MIGRATION.md
DELETED
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
# Migration Guide
|
|
2
|
-
|
|
3
|
-
## From `expo-errands-assistant`
|
|
4
|
-
|
|
5
|
-
The `expo-errands-assistant` local module was hardcoded for a single Siri action with no parameters, no Android support, and no reusability. `expo-invoke` replaces it entirely.
|
|
6
|
-
|
|
7
|
-
### Step 1 — Replace the import
|
|
8
|
-
|
|
9
|
-
```diff
|
|
10
|
-
- import { useErrandsAssistant } from '../modules/expo-errands-assistant';
|
|
11
|
-
+ import { useInvokeInit, useInvoke } from 'expo-invoke';
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
### Step 2 — Replace the root-level init
|
|
15
|
-
|
|
16
|
-
```diff
|
|
17
|
-
// app/_layout.tsx
|
|
18
|
-
- useErrandsAssistant(); // old
|
|
19
|
-
+ useInvokeInit(); // new — same cold/warm start behaviour
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
### Step 3 — Replace the intent listener
|
|
23
|
-
|
|
24
|
-
```diff
|
|
25
|
-
// Before
|
|
26
|
-
- const { action } = useErrandsAssistant();
|
|
27
|
-
- if (action === 'CreateErrand') { router.push('/create'); }
|
|
28
|
-
|
|
29
|
-
// After
|
|
30
|
-
+ const { intent } = useInvoke({ intentId: 'create_errand' });
|
|
31
|
-
+ useEffect(() => { if (intent) router.push('/create'); }, [intent]);
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
### Step 4 — Move the native intent to app.json
|
|
35
|
-
|
|
36
|
-
Delete the hardcoded Swift intent file. The config plugin generates it:
|
|
37
|
-
|
|
38
|
-
```json
|
|
39
|
-
// app.json
|
|
40
|
-
{
|
|
41
|
-
"plugins": [["expo-invoke", {
|
|
42
|
-
"intents": [{
|
|
43
|
-
"id": "create_errand",
|
|
44
|
-
"title": "Create an Errand",
|
|
45
|
-
"phrases": ["Create an errand in ${applicationName}"]
|
|
46
|
-
}]
|
|
47
|
-
}]]
|
|
48
|
-
}
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
---
|
|
52
|
-
|
|
53
|
-
## From `react-native-siri-shortcut`
|
|
54
|
-
|
|
55
|
-
### Install expo-invoke
|
|
56
|
-
|
|
57
|
-
```bash
|
|
58
|
-
npx expo install expo-invoke
|
|
59
|
-
npx expo uninstall react-native-siri-shortcut
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### Replace donation calls
|
|
63
|
-
|
|
64
|
-
```diff
|
|
65
|
-
- import SiriShortcuts from 'react-native-siri-shortcut';
|
|
66
|
-
- SiriShortcuts.donateShortcut({ identifier: 'create', title: 'Create', userInfo: {} });
|
|
67
|
-
|
|
68
|
-
+ import { useDonation } from 'expo-invoke';
|
|
69
|
-
+ const { donate } = useDonation();
|
|
70
|
-
+ donate({ intentId: 'create_errand', title: 'Create an Errand' });
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
### Replace the shortcut listener
|
|
74
|
-
|
|
75
|
-
```diff
|
|
76
|
-
- import { ShortcutListener } from 'react-native-siri-shortcut';
|
|
77
|
-
- <ShortcutListener onShortcutReceived={({ identifier }) => { ... }} />
|
|
78
|
-
|
|
79
|
-
+ import { useInvoke } from 'expo-invoke';
|
|
80
|
-
+ const { intent } = useInvoke();
|
|
81
|
-
+ // intent.intentId === 'create_errand' when fired
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
---
|
|
85
|
-
|
|
86
|
-
## From `expo-siri-shortcut`
|
|
87
|
-
|
|
88
|
-
### Install expo-invoke
|
|
89
|
-
|
|
90
|
-
```bash
|
|
91
|
-
npx expo install expo-invoke
|
|
92
|
-
npx expo uninstall expo-siri-shortcut
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
### Replace the shortcut button
|
|
96
|
-
|
|
97
|
-
```diff
|
|
98
|
-
- import { SiriShortcutButton } from 'expo-siri-shortcut';
|
|
99
|
-
- <SiriShortcutButton shortcut={{ activityType: 'create', title: 'Create' }} />
|
|
100
|
-
|
|
101
|
-
+ import { AddToSiriButton } from 'expo-invoke';
|
|
102
|
-
+ <AddToSiriButton intentId="create_errand" />
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
### Replace the activity listener
|
|
106
|
-
|
|
107
|
-
The old `expo-siri-shortcut` used `NSUserActivity`. `expo-invoke` uses the modern App Intents API. Replace the app delegate hook with `useInvokeInit()` and receive via `useInvoke()`.
|
|
108
|
-
|
|
109
|
-
---
|
|
110
|
-
|
|
111
|
-
## Key Behavioural Differences
|
|
112
|
-
|
|
113
|
-
| Behaviour | Old packages | expo-invoke |
|
|
114
|
-
|---|---|---|
|
|
115
|
-
| iOS API | SiriKit (deprecated) | App Intents (iOS 16+) |
|
|
116
|
-
| Android | None | Google App Actions BII |
|
|
117
|
-
| Multi-intent | No | Yes — unlimited |
|
|
118
|
-
| Parameters | None / manual | 8 typed parameter types |
|
|
119
|
-
| Widget bridge | No | Yes — WidgetKit + AppWidgetProvider |
|
|
120
|
-
| Dynamic Island | No | Yes |
|
|
121
|
-
| Cold start TTL | None | 30s default, configurable |
|
|
122
|
-
| Intent deduplication | No | Yes (2s window) |
|
|
123
|
-
| Source attribution | No | 20 surfaces |
|
|
124
|
-
| Testing utilities | No | mockInvoke, simulateColdStart |
|
|
125
|
-
| CLI | No | validate, generate, test |
|
package/SECURITY.md
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
# Security Policy
|
|
2
|
-
|
|
3
|
-
## Supported Versions
|
|
4
|
-
|
|
5
|
-
| Version | Supported |
|
|
6
|
-
|---|---|
|
|
7
|
-
| 1.x (current) | ✓ |
|
|
8
|
-
|
|
9
|
-
## Reporting a Vulnerability
|
|
10
|
-
|
|
11
|
-
**Do not open a public GitHub issue for security vulnerabilities.**
|
|
12
|
-
|
|
13
|
-
Email: security@smarthivelabs.dev
|
|
14
|
-
|
|
15
|
-
Please include:
|
|
16
|
-
- Description of the vulnerability
|
|
17
|
-
- Steps to reproduce
|
|
18
|
-
- Affected versions
|
|
19
|
-
- Potential impact
|
|
20
|
-
|
|
21
|
-
We will acknowledge your report within 48 hours and aim to release a fix within 14 days for critical issues.
|
|
22
|
-
|
|
23
|
-
## Security Considerations for Users
|
|
24
|
-
|
|
25
|
-
### Intent ID exposure
|
|
26
|
-
Intent IDs defined in `app.json` are visible in the compiled binary. Do not use intent IDs as security boundaries. Treat them as public routing tokens.
|
|
27
|
-
|
|
28
|
-
### Deep link → intent mapping
|
|
29
|
-
Deep links that map to intents (`deepLinkPatterns` in config) process user-supplied URLs. Validate any parameters extracted from deep links before acting on them in your app.
|
|
30
|
-
|
|
31
|
-
### Widget / shared storage
|
|
32
|
-
`useWidgetData()` stores values in a shared App Group container (iOS) or SharedPreferences (Android). Do not store sensitive data (tokens, PII) using this API.
|
|
33
|
-
|
|
34
|
-
### Notification action intents
|
|
35
|
-
Notification action buttons trigger intents based on category IDs in the push payload. Ensure your push notification server validates recipient identity before sending notifications with action categories.
|