expo-invoke 1.0.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/MIGRATION.md +125 -0
- package/README.md +942 -0
- package/SECURITY.md +35 -0
- package/android/build.gradle +42 -0
- package/android/src/main/java/expo/modules/invoke/AppActionsHandler.kt +74 -0
- package/android/src/main/java/expo/modules/invoke/ExpoInvokeModule.kt +135 -0
- package/android/src/main/java/expo/modules/invoke/QuickTileService.kt +63 -0
- package/android/src/main/java/expo/modules/invoke/ShortcutsHelper.kt +72 -0
- package/build/cli/commands/generate.d.ts +1 -0
- package/build/cli/commands/generate.js +119 -0
- package/build/cli/commands/generate.js.map +1 -0
- package/build/cli/commands/test.d.ts +1 -0
- package/build/cli/commands/test.js +53 -0
- package/build/cli/commands/test.js.map +1 -0
- package/build/cli/commands/validate.d.ts +1 -0
- package/build/cli/commands/validate.js +116 -0
- package/build/cli/commands/validate.js.map +1 -0
- package/build/cli/index.d.ts +2 -0
- package/build/cli/index.js +37 -0
- package/build/cli/index.js.map +1 -0
- package/build/plugin/android/withAndroidInvoke.d.ts +8 -0
- package/build/plugin/android/withAndroidInvoke.js +106 -0
- package/build/plugin/android/withAndroidInvoke.js.map +1 -0
- package/build/plugin/codegen/generateActionsXml.d.ts +2 -0
- package/build/plugin/codegen/generateActionsXml.js +69 -0
- package/build/plugin/codegen/generateActionsXml.js.map +1 -0
- package/build/plugin/codegen/generateShortcutsXml.d.ts +2 -0
- package/build/plugin/codegen/generateShortcutsXml.js +45 -0
- package/build/plugin/codegen/generateShortcutsXml.js.map +1 -0
- package/build/plugin/codegen/generateSwiftIntents.d.ts +2 -0
- package/build/plugin/codegen/generateSwiftIntents.js +129 -0
- package/build/plugin/codegen/generateSwiftIntents.js.map +1 -0
- package/build/plugin/ios/withIOSInvoke.d.ts +9 -0
- package/build/plugin/ios/withIOSInvoke.js +83 -0
- package/build/plugin/ios/withIOSInvoke.js.map +1 -0
- package/build/plugin/src/withInvoke.d.ts +16 -0
- package/build/plugin/src/withInvoke.js +13 -0
- package/build/plugin/src/withInvoke.js.map +1 -0
- package/build/src/components/AddToSiriButton.d.ts +18 -0
- package/build/src/components/AddToSiriButton.d.ts.map +1 -0
- package/build/src/components/AddToSiriButton.js +35 -0
- package/build/src/components/AddToSiriButton.js.map +1 -0
- package/build/src/components/InvokeDebugger.d.ts +12 -0
- package/build/src/components/InvokeDebugger.d.ts.map +1 -0
- package/build/src/components/InvokeDebugger.js +122 -0
- package/build/src/components/InvokeDebugger.js.map +1 -0
- package/build/src/components/ShortcutChip.d.ts +20 -0
- package/build/src/components/ShortcutChip.d.ts.map +1 -0
- package/build/src/components/ShortcutChip.js +44 -0
- package/build/src/components/ShortcutChip.js.map +1 -0
- package/build/src/hooks/useAddToSiri.d.ts +9 -0
- package/build/src/hooks/useAddToSiri.d.ts.map +1 -0
- package/build/src/hooks/useAddToSiri.js +15 -0
- package/build/src/hooks/useAddToSiri.js.map +1 -0
- package/build/src/hooks/useDonation.d.ts +26 -0
- package/build/src/hooks/useDonation.d.ts.map +1 -0
- package/build/src/hooks/useDonation.js +21 -0
- package/build/src/hooks/useDonation.js.map +1 -0
- package/build/src/hooks/useFocusFilter.d.ts +11 -0
- package/build/src/hooks/useFocusFilter.d.ts.map +1 -0
- package/build/src/hooks/useFocusFilter.js +24 -0
- package/build/src/hooks/useFocusFilter.js.map +1 -0
- package/build/src/hooks/useHandoff.d.ts +29 -0
- package/build/src/hooks/useHandoff.d.ts.map +1 -0
- package/build/src/hooks/useHandoff.js +27 -0
- package/build/src/hooks/useHandoff.js.map +1 -0
- package/build/src/hooks/useInvoke.d.ts +43 -0
- package/build/src/hooks/useInvoke.d.ts.map +1 -0
- package/build/src/hooks/useInvoke.js +70 -0
- package/build/src/hooks/useInvoke.js.map +1 -0
- package/build/src/hooks/useInvokeAnalytics.d.ts +23 -0
- package/build/src/hooks/useInvokeAnalytics.d.ts.map +1 -0
- package/build/src/hooks/useInvokeAnalytics.js +27 -0
- package/build/src/hooks/useInvokeAnalytics.js.map +1 -0
- package/build/src/hooks/useInvokeHistory.d.ts +11 -0
- package/build/src/hooks/useInvokeHistory.d.ts.map +1 -0
- package/build/src/hooks/useInvokeHistory.js +26 -0
- package/build/src/hooks/useInvokeHistory.js.map +1 -0
- package/build/src/hooks/useInvokeInit.d.ts +16 -0
- package/build/src/hooks/useInvokeInit.d.ts.map +1 -0
- package/build/src/hooks/useInvokeInit.js +32 -0
- package/build/src/hooks/useInvokeInit.js.map +1 -0
- package/build/src/hooks/useLiveActivityIntent.d.ts +21 -0
- package/build/src/hooks/useLiveActivityIntent.d.ts.map +1 -0
- package/build/src/hooks/useLiveActivityIntent.js +9 -0
- package/build/src/hooks/useLiveActivityIntent.js.map +1 -0
- package/build/src/hooks/useQuickTile.d.ts +23 -0
- package/build/src/hooks/useQuickTile.d.ts.map +1 -0
- package/build/src/hooks/useQuickTile.js +15 -0
- package/build/src/hooks/useQuickTile.js.map +1 -0
- package/build/src/hooks/useShortcuts.d.ts +25 -0
- package/build/src/hooks/useShortcuts.d.ts.map +1 -0
- package/build/src/hooks/useShortcuts.js +23 -0
- package/build/src/hooks/useShortcuts.js.map +1 -0
- package/build/src/hooks/useSpotlight.d.ts +23 -0
- package/build/src/hooks/useSpotlight.d.ts.map +1 -0
- package/build/src/hooks/useSpotlight.js +13 -0
- package/build/src/hooks/useSpotlight.js.map +1 -0
- package/build/src/hooks/useWidgetData.d.ts +20 -0
- package/build/src/hooks/useWidgetData.d.ts.map +1 -0
- package/build/src/hooks/useWidgetData.js +12 -0
- package/build/src/hooks/useWidgetData.js.map +1 -0
- package/build/src/index.d.ts +32 -0
- package/build/src/index.d.ts.map +1 -0
- package/build/src/index.js +27 -0
- package/build/src/index.js.map +1 -0
- package/build/src/module.d.ts +25 -0
- package/build/src/module.d.ts.map +1 -0
- package/build/src/module.js +102 -0
- package/build/src/module.js.map +1 -0
- package/build/src/types/index.d.ts +156 -0
- package/build/src/types/index.d.ts.map +1 -0
- package/build/src/types/index.js +4 -0
- package/build/src/types/index.js.map +1 -0
- package/build/src/utils/actionStore.d.ts +6 -0
- package/build/src/utils/actionStore.d.ts.map +1 -0
- package/build/src/utils/actionStore.js +32 -0
- package/build/src/utils/actionStore.js.map +1 -0
- package/build/src/utils/analytics.d.ts +12 -0
- package/build/src/utils/analytics.d.ts.map +1 -0
- package/build/src/utils/analytics.js +29 -0
- package/build/src/utils/analytics.js.map +1 -0
- package/build/src/utils/testing.d.ts +39 -0
- package/build/src/utils/testing.d.ts.map +1 -0
- package/build/src/utils/testing.js +58 -0
- package/build/src/utils/testing.js.map +1 -0
- package/build/src/utils/validation.d.ts +11 -0
- package/build/src/utils/validation.d.ts.map +1 -0
- package/build/src/utils/validation.js +128 -0
- package/build/src/utils/validation.js.map +1 -0
- package/expo-module.config.json +9 -0
- package/ios/Focus/FocusFilterManager.swift +19 -0
- package/ios/Intents/BaseInvokeIntent.swift +42 -0
- package/ios/Intents/HandoffManager.swift +49 -0
- package/ios/Intents/InvokeActionStore.swift +21 -0
- package/ios/Intents/InvokeParameterTypes.swift +142 -0
- package/ios/LiveActivity/LiveActivityIntentBridge.swift +44 -0
- package/ios/Module/ExpoInvokeModule.swift +170 -0
- package/ios/Notifications/NotificationActionHandler.swift +80 -0
- package/ios/Shortcuts/DonationManager.swift +44 -0
- package/ios/Shortcuts/ShortcutsManager.swift +32 -0
- package/ios/Shortcuts/SpotlightManager.swift +48 -0
- package/ios/Widget/WidgetManager.swift +19 -0
- package/package.json +111 -0
package/SECURITY.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
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.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
apply plugin: 'com.android.library'
|
|
2
|
+
apply plugin: 'kotlin-android'
|
|
3
|
+
|
|
4
|
+
android {
|
|
5
|
+
namespace "expo.modules.invoke"
|
|
6
|
+
compileSdkVersion safeExtGet("compileSdkVersion", 34)
|
|
7
|
+
|
|
8
|
+
compileOptions {
|
|
9
|
+
sourceCompatibility JavaVersion.VERSION_11
|
|
10
|
+
targetCompatibility JavaVersion.VERSION_11
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
kotlinOptions {
|
|
14
|
+
jvmTarget = JavaVersion.VERSION_11.majorVersion
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
defaultConfig {
|
|
18
|
+
minSdkVersion safeExtGet("minSdkVersion", 24)
|
|
19
|
+
targetSdkVersion safeExtGet("targetSdkVersion", 34)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
sourceSets {
|
|
23
|
+
main {
|
|
24
|
+
java.srcDirs += 'src/main/java'
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
repositories {
|
|
30
|
+
mavenCentral()
|
|
31
|
+
google()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
dependencies {
|
|
35
|
+
implementation project(':expo-modules-core')
|
|
36
|
+
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${kotlinVersion}"
|
|
37
|
+
implementation "androidx.core:core-ktx:1.12.0"
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
def safeExtGet(prop, fallback) {
|
|
41
|
+
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
|
42
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
package expo.modules.invoke
|
|
2
|
+
|
|
3
|
+
import android.content.Intent
|
|
4
|
+
import android.content.SharedPreferences
|
|
5
|
+
import android.net.Uri
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Handles incoming Android Intents from Google App Actions and deep links.
|
|
9
|
+
*
|
|
10
|
+
* Google App Actions fire as ACTION_VIEW intents with a deep link URL.
|
|
11
|
+
* The intentId is encoded as either:
|
|
12
|
+
* - A path segment: myapp://invoke/create_errand?param=value
|
|
13
|
+
* - A query param: myapp://open?intentId=create_errand¶m=value
|
|
14
|
+
*/
|
|
15
|
+
object AppActionsHandler {
|
|
16
|
+
|
|
17
|
+
private val INVOKE_ACTIONS = setOf(
|
|
18
|
+
Intent.ACTION_VIEW,
|
|
19
|
+
Intent.ACTION_MAIN,
|
|
20
|
+
"com.google.android.gms.actions.SEARCH_ACTION",
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
fun handleIntent(intent: Intent, prefs: SharedPreferences): String? {
|
|
24
|
+
if (intent.action !in INVOKE_ACTIONS) return null
|
|
25
|
+
val uri = intent.data ?: return null
|
|
26
|
+
return parseUri(uri, prefs)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
private fun parseUri(uri: Uri, prefs: SharedPreferences): String? {
|
|
30
|
+
// Extract intentId from path or query param
|
|
31
|
+
val intentId = uri.getQueryParameter("intentId")
|
|
32
|
+
?: extractIntentIdFromPath(uri)
|
|
33
|
+
?: return null
|
|
34
|
+
|
|
35
|
+
val parameters = mutableMapOf<String, Any>()
|
|
36
|
+
|
|
37
|
+
for (key in uri.queryParameterNames) {
|
|
38
|
+
if (key == "intentId") continue
|
|
39
|
+
val value = uri.getQueryParameter(key) ?: continue
|
|
40
|
+
parameters[key] = coerceParam(key, value)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
val source = when {
|
|
44
|
+
uri.host?.contains("google") == true -> "google"
|
|
45
|
+
else -> "deep_link"
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
ExpoInvokeModule.writePendingIntent(prefs, intentId, source, parameters)
|
|
49
|
+
|
|
50
|
+
return prefs.getString("pendingIntent", null)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private fun extractIntentIdFromPath(uri: Uri): String? {
|
|
54
|
+
// e.g. myapp://invoke/create_errand → "create_errand"
|
|
55
|
+
val segments = uri.pathSegments
|
|
56
|
+
return if (segments.size >= 2 && segments[0] == "invoke") {
|
|
57
|
+
segments[1]
|
|
58
|
+
} else if (segments.size == 1) {
|
|
59
|
+
segments[0].takeIf { it.isNotBlank() }
|
|
60
|
+
} else {
|
|
61
|
+
null
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
private fun coerceParam(key: String, value: String): Any {
|
|
66
|
+
// Attempt numeric coercion for common numeric keys
|
|
67
|
+
value.toDoubleOrNull()?.let { return it }
|
|
68
|
+
if (value.equals("true", ignoreCase = true)) return true
|
|
69
|
+
if (value.equals("false", ignoreCase = true)) return false
|
|
70
|
+
|
|
71
|
+
// Location: "lat,lng" or JSON object — keep as string; JS side parses
|
|
72
|
+
return value
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
package expo.modules.invoke
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.content.Intent
|
|
5
|
+
import android.content.SharedPreferences
|
|
6
|
+
import expo.modules.kotlin.modules.Module
|
|
7
|
+
import expo.modules.kotlin.modules.ModuleDefinition
|
|
8
|
+
import org.json.JSONObject
|
|
9
|
+
|
|
10
|
+
private const val PREFS_NAME = "expo.invoke"
|
|
11
|
+
private const val KEY_PENDING_INTENT = "pendingIntent"
|
|
12
|
+
private const val KEY_CONFIG = "config"
|
|
13
|
+
private const val KEY_SHORTCUTS = "shortcuts"
|
|
14
|
+
private const val DEFAULT_TTL_MS = 30_000L
|
|
15
|
+
|
|
16
|
+
class ExpoInvokeModule : Module() {
|
|
17
|
+
|
|
18
|
+
private val prefs: SharedPreferences
|
|
19
|
+
get() = appContext.reactContext!!.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
|
20
|
+
|
|
21
|
+
override fun definition() = ModuleDefinition {
|
|
22
|
+
Name("ExpoInvoke")
|
|
23
|
+
|
|
24
|
+
Events("onIntent")
|
|
25
|
+
|
|
26
|
+
// ── configure ────────────────────────────────────────────────────────────
|
|
27
|
+
Function("configure") { configJson: String ->
|
|
28
|
+
prefs.edit().putString(KEY_CONFIG, configJson).apply()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// ── getInitialIntent ─────────────────────────────────────────────────────
|
|
32
|
+
Function("getInitialIntent") {
|
|
33
|
+
consumePendingIntent(prefs)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// ── Donations (no-op on Android — Google handles via App Actions) ────────
|
|
37
|
+
Function("donateAction") { _: String -> Unit }
|
|
38
|
+
Function("deleteAction") { _: String -> Unit }
|
|
39
|
+
Function("deleteAllActions") { Unit }
|
|
40
|
+
|
|
41
|
+
// ── Dynamic shortcuts ─────────────────────────────────────────────────────
|
|
42
|
+
Function("setDynamicShortcuts") { json: String ->
|
|
43
|
+
prefs.edit().putString(KEY_SHORTCUTS, json).apply()
|
|
44
|
+
ShortcutsHelper.setDynamicShortcuts(appContext.reactContext!!, json)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
Function("getDynamicShortcuts") {
|
|
48
|
+
prefs.getString(KEY_SHORTCUTS, "[]") ?: "[]"
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
Function("clearDynamicShortcuts") {
|
|
52
|
+
prefs.edit().remove(KEY_SHORTCUTS).apply()
|
|
53
|
+
ShortcutsHelper.clearDynamicShortcuts(appContext.reactContext!!)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ── Spotlight — no-op on Android ─────────────────────────────────────────
|
|
57
|
+
Function("indexSpotlightItems") { _: String -> Unit }
|
|
58
|
+
Function("deindexSpotlightItems") { _: List<String> -> Unit }
|
|
59
|
+
|
|
60
|
+
// ── Widget data (SharedPreferences — readable by AppWidgetProvider) ──────
|
|
61
|
+
Function("setWidgetData") { key: String, value: String ->
|
|
62
|
+
prefs.edit().putString("widget.$key", value).apply()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
Function("getWidgetData") { key: String ->
|
|
66
|
+
prefs.getString("widget.$key", null)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ── Quick tile ────────────────────────────────────────────────────────────
|
|
70
|
+
Function("updateQuickTile") { state: String, label: String ->
|
|
71
|
+
QuickTileService.pendingState = state
|
|
72
|
+
QuickTileService.pendingLabel = label
|
|
73
|
+
QuickTileService.requestUpdate(appContext.reactContext!!)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// ── Handoff — no-op on Android ────────────────────────────────────────────
|
|
77
|
+
Function("advertiseHandoff") { _: String, _: String -> Unit }
|
|
78
|
+
Function("stopHandoff") { Unit }
|
|
79
|
+
|
|
80
|
+
// ── Live Activity — no-op on Android ─────────────────────────────────────
|
|
81
|
+
Function("setLiveActivityIntent") { _: String, _: String -> Unit }
|
|
82
|
+
|
|
83
|
+
// ── Add to Siri — no-op on Android ───────────────────────────────────────
|
|
84
|
+
Function("addIntentToSiri") { _: String -> Unit }
|
|
85
|
+
|
|
86
|
+
// ── Focus mode — no-op on Android ────────────────────────────────────────
|
|
87
|
+
Function("getFocusMode") { null as String? }
|
|
88
|
+
|
|
89
|
+
// ── Warm start ────────────────────────────────────────────────────────────
|
|
90
|
+
OnActivityEntersForeground {
|
|
91
|
+
val json = consumePendingIntent(prefs) ?: return@OnActivityEntersForeground
|
|
92
|
+
sendEvent("onIntent", mapOf("json" to json))
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ── New intent (App Actions / deep links fire here) ───────────────────────
|
|
96
|
+
OnNewIntent { intent ->
|
|
97
|
+
val json = AppActionsHandler.handleIntent(intent, prefs) ?: return@OnNewIntent
|
|
98
|
+
sendEvent("onIntent", mapOf("json" to json))
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
companion object {
|
|
103
|
+
fun writePendingIntent(
|
|
104
|
+
prefs: SharedPreferences,
|
|
105
|
+
intentId: String,
|
|
106
|
+
source: String = "google",
|
|
107
|
+
parameters: Map<String, Any> = emptyMap(),
|
|
108
|
+
) {
|
|
109
|
+
val payload = JSONObject().apply {
|
|
110
|
+
put("intentId", intentId)
|
|
111
|
+
put("source", source)
|
|
112
|
+
put("timestamp", System.currentTimeMillis().toDouble())
|
|
113
|
+
val params = JSONObject()
|
|
114
|
+
parameters.forEach { (k, v) -> params.put(k, v) }
|
|
115
|
+
put("parameters", params)
|
|
116
|
+
}
|
|
117
|
+
prefs.edit().putString(KEY_PENDING_INTENT, payload.toString()).apply()
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
fun consumePendingIntent(prefs: SharedPreferences): String? {
|
|
121
|
+
val json = prefs.getString(KEY_PENDING_INTENT, null) ?: return null
|
|
122
|
+
prefs.edit().remove(KEY_PENDING_INTENT).apply()
|
|
123
|
+
|
|
124
|
+
return try {
|
|
125
|
+
val obj = JSONObject(json)
|
|
126
|
+
val tsMs = obj.optDouble("timestamp", 0.0)
|
|
127
|
+
val ttl = obj.optDouble("_ttl", DEFAULT_TTL_MS.toDouble())
|
|
128
|
+
val ageMs = System.currentTimeMillis() - tsMs
|
|
129
|
+
if (ageMs < ttl) json else null
|
|
130
|
+
} catch (_: Exception) {
|
|
131
|
+
null
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
package expo.modules.invoke
|
|
2
|
+
|
|
3
|
+
import android.annotation.TargetApi
|
|
4
|
+
import android.content.ComponentName
|
|
5
|
+
import android.content.Context
|
|
6
|
+
import android.content.SharedPreferences
|
|
7
|
+
import android.os.Build
|
|
8
|
+
import android.service.quicksettings.Tile
|
|
9
|
+
import android.service.quicksettings.TileService
|
|
10
|
+
import androidx.core.content.getSystemService
|
|
11
|
+
|
|
12
|
+
@TargetApi(Build.VERSION_CODES.N)
|
|
13
|
+
class QuickTileService : TileService() {
|
|
14
|
+
|
|
15
|
+
override fun onStartListening() {
|
|
16
|
+
super.onStartListening()
|
|
17
|
+
applyPendingState()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
override fun onClick() {
|
|
21
|
+
super.onClick()
|
|
22
|
+
// Write a pending intent so the app fires it when opened
|
|
23
|
+
val prefs = getSharedPreferences("expo.invoke", MODE_PRIVATE)
|
|
24
|
+
val intentId = prefs.getString("quickTileIntentId", null) ?: return
|
|
25
|
+
ExpoInvokeModule.writePendingIntent(prefs, intentId, "quick_tile")
|
|
26
|
+
// Launch the app
|
|
27
|
+
startActivityAndCollapse(
|
|
28
|
+
packageManager.getLaunchIntentForPackage(packageName)?.apply {
|
|
29
|
+
addFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
30
|
+
}
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
private fun applyPendingState() {
|
|
35
|
+
val tile = qsTile ?: return
|
|
36
|
+
val state = pendingState
|
|
37
|
+
val label = pendingLabel
|
|
38
|
+
|
|
39
|
+
tile.state = when (state) {
|
|
40
|
+
"active" -> Tile.STATE_ACTIVE
|
|
41
|
+
"inactive" -> Tile.STATE_INACTIVE
|
|
42
|
+
else -> Tile.STATE_UNAVAILABLE
|
|
43
|
+
}
|
|
44
|
+
if (label.isNotBlank()) {
|
|
45
|
+
tile.label = label
|
|
46
|
+
}
|
|
47
|
+
tile.updateTile()
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
companion object {
|
|
51
|
+
@Volatile var pendingState: String = "inactive"
|
|
52
|
+
@Volatile var pendingLabel: String = ""
|
|
53
|
+
|
|
54
|
+
fun requestUpdate(context: Context) {
|
|
55
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
56
|
+
requestListeningState(
|
|
57
|
+
context,
|
|
58
|
+
ComponentName(context, QuickTileService::class.java)
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
package expo.modules.invoke
|
|
2
|
+
|
|
3
|
+
import android.annotation.TargetApi
|
|
4
|
+
import android.content.Context
|
|
5
|
+
import android.content.pm.ShortcutInfo
|
|
6
|
+
import android.content.pm.ShortcutManager
|
|
7
|
+
import android.graphics.drawable.Icon
|
|
8
|
+
import android.os.Build
|
|
9
|
+
import androidx.core.content.getSystemService
|
|
10
|
+
import org.json.JSONArray
|
|
11
|
+
import org.json.JSONObject
|
|
12
|
+
|
|
13
|
+
object ShortcutsHelper {
|
|
14
|
+
|
|
15
|
+
@TargetApi(Build.VERSION_CODES.N_MR1)
|
|
16
|
+
fun setDynamicShortcuts(context: Context, json: String) {
|
|
17
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) return
|
|
18
|
+
val manager = context.getSystemService<ShortcutManager>() ?: return
|
|
19
|
+
|
|
20
|
+
val shortcuts = parseShortcuts(context, json)
|
|
21
|
+
manager.dynamicShortcuts = shortcuts.take(manager.maxShortcutCountPerActivity)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@TargetApi(Build.VERSION_CODES.N_MR1)
|
|
25
|
+
fun clearDynamicShortcuts(context: Context) {
|
|
26
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) return
|
|
27
|
+
context.getSystemService<ShortcutManager>()?.removeAllDynamicShortcuts()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@TargetApi(Build.VERSION_CODES.N_MR1)
|
|
31
|
+
private fun parseShortcuts(context: Context, json: String): List<ShortcutInfo> {
|
|
32
|
+
val arr = JSONArray(json)
|
|
33
|
+
val result = mutableListOf<ShortcutInfo>()
|
|
34
|
+
|
|
35
|
+
for (i in 0 until arr.length()) {
|
|
36
|
+
val obj = arr.getJSONObject(i)
|
|
37
|
+
val id = obj.getString("id")
|
|
38
|
+
val title = obj.getString("title")
|
|
39
|
+
val subtitle = obj.optString("subtitle", "")
|
|
40
|
+
val intentId = obj.optString("intentId", id)
|
|
41
|
+
|
|
42
|
+
val launchIntent = context.packageManager
|
|
43
|
+
.getLaunchIntentForPackage(context.packageName)
|
|
44
|
+
?.apply {
|
|
45
|
+
action = "expo.invoke.SHORTCUT"
|
|
46
|
+
putExtra("intentId", intentId)
|
|
47
|
+
// Encode optional parameters
|
|
48
|
+
if (obj.has("parameters")) {
|
|
49
|
+
putExtra("parameters", obj.getJSONObject("parameters").toString())
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
?: continue
|
|
53
|
+
|
|
54
|
+
val builder = ShortcutInfo.Builder(context, id)
|
|
55
|
+
.setShortLabel(title.take(10))
|
|
56
|
+
.setLongLabel(if (subtitle.isNotEmpty()) subtitle.take(25) else title.take(25))
|
|
57
|
+
.setIntent(launchIntent)
|
|
58
|
+
|
|
59
|
+
// Use adaptive icon from the app launcher icon
|
|
60
|
+
try {
|
|
61
|
+
val iconRes = context.resources.getIdentifier("ic_launcher", "mipmap", context.packageName)
|
|
62
|
+
if (iconRes != 0) {
|
|
63
|
+
builder.setIcon(Icon.createWithResource(context, iconRes))
|
|
64
|
+
}
|
|
65
|
+
} catch (_: Exception) { /* icon is optional */ }
|
|
66
|
+
|
|
67
|
+
result.add(builder.build())
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return result
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runGenerate(args: string[]): void;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.runGenerate = runGenerate;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
function toPascalCase(id) {
|
|
40
|
+
return id.split(/[_\s-]+/).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join('');
|
|
41
|
+
}
|
|
42
|
+
function tsParamType(param) {
|
|
43
|
+
switch (param.type) {
|
|
44
|
+
case 'text': return 'string';
|
|
45
|
+
case 'number': return 'number';
|
|
46
|
+
case 'boolean': return 'boolean';
|
|
47
|
+
case 'date': return 'number'; // timestamp ms
|
|
48
|
+
case 'location': return '{ latitude: number; longitude: number; name?: string }';
|
|
49
|
+
case 'person': return '{ displayName?: string; phoneNumber?: string; emailAddress?: string }';
|
|
50
|
+
case 'enum': return param.options.map((o) => `"${o.id}"`).join(' | ') || 'string';
|
|
51
|
+
case 'array':
|
|
52
|
+
switch (param.itemType) {
|
|
53
|
+
case 'text': return 'string[]';
|
|
54
|
+
case 'number': return 'number[]';
|
|
55
|
+
case 'location': return '{ latitude: number; longitude: number; name?: string }[]';
|
|
56
|
+
default: return 'unknown[]';
|
|
57
|
+
}
|
|
58
|
+
default: return 'unknown';
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function generateParamsInterface(intent) {
|
|
62
|
+
var _a;
|
|
63
|
+
const params = (_a = intent.parameters) !== null && _a !== void 0 ? _a : [];
|
|
64
|
+
if (params.length === 0)
|
|
65
|
+
return ' parameters: Record<string, never>;';
|
|
66
|
+
const fields = params.map((p) => {
|
|
67
|
+
const opt = p.optional ? '?' : '';
|
|
68
|
+
return ` ${p.name}${opt}: ${tsParamType(p)};`;
|
|
69
|
+
}).join('\n');
|
|
70
|
+
return ` parameters: {\n${fields}\n };`;
|
|
71
|
+
}
|
|
72
|
+
function loadConfig(cwd) {
|
|
73
|
+
var _a, _b, _c;
|
|
74
|
+
const appJsonPath = path.join(cwd, 'app.json');
|
|
75
|
+
if (!fs.existsSync(appJsonPath)) {
|
|
76
|
+
console.error('❌ app.json not found in', cwd);
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
const raw = JSON.parse(fs.readFileSync(appJsonPath, 'utf8'));
|
|
80
|
+
const plugins = (_c = (_b = (_a = raw === null || raw === void 0 ? void 0 : raw.expo) === null || _a === void 0 ? void 0 : _a.plugins) !== null && _b !== void 0 ? _b : raw === null || raw === void 0 ? void 0 : raw.plugins) !== null && _c !== void 0 ? _c : [];
|
|
81
|
+
for (const plugin of plugins) {
|
|
82
|
+
if (Array.isArray(plugin) && plugin[0] === 'expo-invoke') {
|
|
83
|
+
return plugin[1];
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
console.error('❌ expo-invoke plugin not found in app.json');
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
function runGenerate(args) {
|
|
90
|
+
var _a;
|
|
91
|
+
const cwd = (_a = args[0]) !== null && _a !== void 0 ? _a : process.cwd();
|
|
92
|
+
const outputPath = path.join(cwd, 'invoke-types.d.ts');
|
|
93
|
+
const config = loadConfig(cwd);
|
|
94
|
+
if (!config) {
|
|
95
|
+
process.exit(1);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const intentIds = config.intents.map((i) => `"${i.id}"`).join(' | ');
|
|
99
|
+
const intentTypes = config.intents.map((intent) => {
|
|
100
|
+
const name = `${toPascalCase(intent.id)}Intent`;
|
|
101
|
+
return `export interface ${name} extends ResolvedIntent {
|
|
102
|
+
intentId: "${intent.id}";
|
|
103
|
+
${generateParamsInterface(intent)}
|
|
104
|
+
}`;
|
|
105
|
+
}).join('\n\n');
|
|
106
|
+
const output = `// AUTO-GENERATED by expo-invoke. Run \`npx expo-invoke generate\` to refresh.
|
|
107
|
+
import type { ResolvedIntent } from "expo-invoke";
|
|
108
|
+
|
|
109
|
+
export type InvokeIntentId = ${intentIds};
|
|
110
|
+
|
|
111
|
+
${intentTypes}
|
|
112
|
+
|
|
113
|
+
export type AnyInvokeIntent =
|
|
114
|
+
${config.intents.map((i) => `${toPascalCase(i.id)}Intent`).join('\n | ')};
|
|
115
|
+
`;
|
|
116
|
+
fs.writeFileSync(outputPath, output, 'utf8');
|
|
117
|
+
console.log('✅ Generated', outputPath);
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=generate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate.js","sourceRoot":"","sources":["../../../cli/commands/generate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runTest(args: string[]): void;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.runTest = runTest;
|
|
37
|
+
const child_process_1 = require("child_process");
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
function runTest(args) {
|
|
40
|
+
var _a;
|
|
41
|
+
const cwd = (_a = args[0]) !== null && _a !== void 0 ? _a : process.cwd();
|
|
42
|
+
const jestBin = path.join(__dirname, '..', '..', 'node_modules', '.bin', 'jest');
|
|
43
|
+
try {
|
|
44
|
+
(0, child_process_1.execSync)(`node "${jestBin}" --passWithNoTests`, {
|
|
45
|
+
cwd,
|
|
46
|
+
stdio: 'inherit',
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test.js","sourceRoot":"","sources":["../../../cli/commands/test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGA,0BAYC;AAfD,iDAAyC;AACzC,2CAA6B;AAE7B,SAAgB,OAAO,CAAC,IAAc;;IACpC,MAAM,GAAG,GAAG,MAAA,IAAI,CAAC,CAAC,CAAC,mCAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACrC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAEjF,IAAI,CAAC;QACH,IAAA,wBAAQ,EAAC,SAAS,OAAO,qBAAqB,EAAE;YAC9C,GAAG;YACH,KAAK,EAAE,SAAS;SACjB,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runValidate(args: string[]): void;
|