craft-native 0.0.91 → 0.0.92
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/dist/android/src/index.d.ts +36 -1
- package/dist/android/src/index.js +47 -0
- package/dist/android/templates/CraftBridge.kt.template +263 -31
- package/dist/android/templates/CraftNative.kt.template +26 -7
- package/dist/android/templates/MainActivity.kt.template +19 -8
- package/dist/api/mobile.d.ts +12 -2
- package/dist/cli.js +50 -3
- package/dist/index.cjs +12 -5
- package/dist/index.js +12 -5
- package/dist/ios/src/index.d.ts +1 -1
- package/dist/ios/src/index.js +1 -1
- package/dist/ios/templates/CraftApp.swift +233 -32
- package/dist/mobile.js +16 -8
- package/package.json +1 -1
|
@@ -44,7 +44,19 @@ class MainActivity : AppCompatActivity() {
|
|
|
44
44
|
|
|
45
45
|
webView = findViewById(R.id.webview)
|
|
46
46
|
craftBridge = CraftBridge(this, webView, CraftHealthConnect(this, webView))
|
|
47
|
-
|
|
47
|
+
// The link that launched the app (#215). Queued until the page's bridge
|
|
48
|
+
// is injected, then dispatched once with `initial: true`, so a page that
|
|
49
|
+
// subscribes rather than calling getInitialURL still hears it. A
|
|
50
|
+
// relaunch from Recents carries the old intent, and was not opened by it.
|
|
51
|
+
// A recreated activity restores what the bridge saved: its intent may
|
|
52
|
+
// be a later warm link that onNewIntent set.
|
|
53
|
+
if (savedInstanceState == null) {
|
|
54
|
+
val launchLink = intent.data?.toString()
|
|
55
|
+
val launchedFromHistory = intent.flags and Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY != 0
|
|
56
|
+
if (launchLink != null && !launchedFromHistory) craftBridge.receiveDeepLink(launchLink)
|
|
57
|
+
} else {
|
|
58
|
+
craftBridge.restoreDeepLinks(savedInstanceState)
|
|
59
|
+
}
|
|
48
60
|
if (savedInstanceState == null) handleIncomingShortcut(intent)
|
|
49
61
|
|
|
50
62
|
setupWebView()
|
|
@@ -150,12 +162,6 @@ class MainActivity : AppCompatActivity() {
|
|
|
150
162
|
}
|
|
151
163
|
}
|
|
152
164
|
|
|
153
|
-
private fun handleIncomingDeepLink(source: Intent?, dispatch: Boolean) {
|
|
154
|
-
val url = source?.data?.toString() ?: return
|
|
155
|
-
craftBridge.setInitialURL(url)
|
|
156
|
-
if (dispatch) craftBridge.dispatchDeepLink(url)
|
|
157
|
-
}
|
|
158
|
-
|
|
159
165
|
private fun handleIncomingShortcut(source: Intent?) {
|
|
160
166
|
source?.getStringExtra(SHORTCUT_TYPE_EXTRA)?.let(craftBridge::dispatchShortcut)
|
|
161
167
|
}
|
|
@@ -198,10 +204,15 @@ class MainActivity : AppCompatActivity() {
|
|
|
198
204
|
return (uri.scheme == "https" || localDevelopment) && origin in trustedOrigins
|
|
199
205
|
}
|
|
200
206
|
|
|
207
|
+
override fun onSaveInstanceState(outState: Bundle) {
|
|
208
|
+
super.onSaveInstanceState(outState)
|
|
209
|
+
craftBridge.saveDeepLinks(outState)
|
|
210
|
+
}
|
|
211
|
+
|
|
201
212
|
override fun onNewIntent(intent: Intent) {
|
|
202
213
|
super.onNewIntent(intent)
|
|
203
214
|
setIntent(intent)
|
|
204
|
-
|
|
215
|
+
intent.data?.toString()?.let(craftBridge::receiveDeepLink)
|
|
205
216
|
handleIncomingShortcut(intent)
|
|
206
217
|
}
|
|
207
218
|
|
package/dist/api/mobile.d.ts
CHANGED
|
@@ -550,9 +550,12 @@ export declare const share: {
|
|
|
550
550
|
/**
|
|
551
551
|
* Open native share dialog.
|
|
552
552
|
*
|
|
553
|
+
* Resolves `true` when the person shared and `false` when they dismissed the
|
|
554
|
+
* dialog, on the native bridges and in the browser alike.
|
|
555
|
+
*
|
|
553
556
|
* @param options - Share options
|
|
554
557
|
*/
|
|
555
|
-
share(options: ShareOptions): Promise<
|
|
558
|
+
share(options: ShareOptions): Promise<boolean>;
|
|
556
559
|
/**
|
|
557
560
|
* Check if sharing is available.
|
|
558
561
|
*/
|
|
@@ -670,7 +673,14 @@ export declare const keepAwake: {
|
|
|
670
673
|
};
|
|
671
674
|
export declare const deepLinks: {
|
|
672
675
|
getInitialURL(): Promise<string | null>;
|
|
673
|
-
|
|
676
|
+
/**
|
|
677
|
+
* The second argument says whether this is the link that launched the app.
|
|
678
|
+
* A page that also calls `getInitialURL()` after an await gets that link
|
|
679
|
+
* from both, and can skip it here when `initial` is true.
|
|
680
|
+
*/
|
|
681
|
+
onLink(callback: (url: string, link: {
|
|
682
|
+
initial: boolean;
|
|
683
|
+
}) => void): () => void;
|
|
674
684
|
};
|
|
675
685
|
export declare function normalizeDeepLinkURL(value: unknown): string | null;
|
|
676
686
|
export declare const network: {
|
package/dist/cli.js
CHANGED
|
@@ -1575,7 +1575,7 @@ async function open(options) {
|
|
|
1575
1575
|
await $`open ${projectPath}`;
|
|
1576
1576
|
}
|
|
1577
1577
|
function orderSimulators(devices) {
|
|
1578
|
-
return
|
|
1578
|
+
return devices.filter((device) => device.runtime.startsWith("iOS")).sort((left, right) => {
|
|
1579
1579
|
const booted = Number(right.state === "Booted") - Number(left.state === "Booted");
|
|
1580
1580
|
if (booted !== 0)
|
|
1581
1581
|
return booted;
|
|
@@ -1730,9 +1730,11 @@ var exports_src2 = {};
|
|
|
1730
1730
|
__export(exports_src2, {
|
|
1731
1731
|
syncAndroidWebAssets: () => syncAndroidWebAssets,
|
|
1732
1732
|
run: () => run2,
|
|
1733
|
+
resolveRuntimeDir: () => resolveRuntimeDir2,
|
|
1733
1734
|
renderAndroidPermissions: () => renderAndroidPermissions,
|
|
1734
1735
|
renderAndroidDeepLinks: () => renderAndroidDeepLinks,
|
|
1735
1736
|
open: () => open2,
|
|
1737
|
+
installRuntime: () => installRuntime2,
|
|
1736
1738
|
init: () => init2,
|
|
1737
1739
|
build: () => build2
|
|
1738
1740
|
});
|
|
@@ -1928,6 +1930,36 @@ function renderAndroidDeepLinks(config) {
|
|
|
1928
1930
|
</intent-filter>`).join(`
|
|
1929
1931
|
`);
|
|
1930
1932
|
}
|
|
1933
|
+
function resolveRuntimeDir2(override) {
|
|
1934
|
+
if (override === null)
|
|
1935
|
+
return null;
|
|
1936
|
+
const dir = override ?? process.env.CRAFT_ANDROID_RUNTIME;
|
|
1937
|
+
if (!dir)
|
|
1938
|
+
return null;
|
|
1939
|
+
if (!existsSync5(dir)) {
|
|
1940
|
+
const source = override === undefined ? "CRAFT_ANDROID_RUNTIME points at" : "runtimeDir is";
|
|
1941
|
+
throw new Error(`${source} ${dir}, which does not exist.`);
|
|
1942
|
+
}
|
|
1943
|
+
return dir;
|
|
1944
|
+
}
|
|
1945
|
+
function installRuntime2(output, runtimeDir) {
|
|
1946
|
+
const found = RUNTIME_ABIS.map((abi) => ({ abi, source: join3(runtimeDir, abi, "libcraft.so") })).filter((entry) => existsSync5(entry.source));
|
|
1947
|
+
if (found.length === 0) {
|
|
1948
|
+
throw new Error(`${runtimeDir} has no <abi>/libcraft.so for any of ${RUNTIME_ABIS.join(", ")}. ` + "Run `zig build build-android-all -Doptimize=ReleaseSafe` in packages/zig and point at its zig-out/android.");
|
|
1949
|
+
}
|
|
1950
|
+
if (found.length < RUNTIME_ABIS.length) {
|
|
1951
|
+
const missing = RUNTIME_ABIS.filter((abi) => !found.some((entry) => entry.abi === abi));
|
|
1952
|
+
console.warn(` \u26A0 only ${found.map((entry) => entry.abi).join(", ")} was found; ${missing.join(", ")} is missing. ` + "The app will fall back to the Kotlin shim on those devices.");
|
|
1953
|
+
}
|
|
1954
|
+
const dest = join3(output, "app/src/main/jniLibs");
|
|
1955
|
+
rmSync3(dest, { force: true, recursive: true });
|
|
1956
|
+
for (const { abi, source } of found) {
|
|
1957
|
+
const abiDir = join3(dest, abi);
|
|
1958
|
+
mkdirSync3(abiDir, { recursive: true });
|
|
1959
|
+
cpSync3(source, join3(abiDir, "libcraft.so"));
|
|
1960
|
+
}
|
|
1961
|
+
return true;
|
|
1962
|
+
}
|
|
1931
1963
|
async function init2(options) {
|
|
1932
1964
|
const { name, packageName, output } = options;
|
|
1933
1965
|
console.log(`
|
|
@@ -2147,6 +2179,11 @@ zipStorePath=wrapper/dists
|
|
|
2147
2179
|
</body>
|
|
2148
2180
|
</html>`;
|
|
2149
2181
|
writeFileSync4(join3(output, "app/src/main/assets/index.html"), placeholderHtml);
|
|
2182
|
+
const runtimeDir = resolveRuntimeDir2(options.runtimeDir);
|
|
2183
|
+
if (runtimeDir) {
|
|
2184
|
+
installRuntime2(output, runtimeDir);
|
|
2185
|
+
console.log(" Installed the Zig runtime from", runtimeDir);
|
|
2186
|
+
}
|
|
2150
2187
|
console.log("\u2705 Project initialized");
|
|
2151
2188
|
console.log("");
|
|
2152
2189
|
console.log("Next steps:");
|
|
@@ -2165,6 +2202,15 @@ async function build2(options) {
|
|
|
2165
2202
|
throw new Error(`No craft.config.json found in ${output}. Run 'craft android init' first.`);
|
|
2166
2203
|
}
|
|
2167
2204
|
const config = JSON.parse(readFileSync4(configPath, "utf-8"));
|
|
2205
|
+
if (existsSync5(join3(output, "app/src/main/jniLibs"))) {
|
|
2206
|
+
const runtimeDir = resolveRuntimeDir2(options.runtimeDir);
|
|
2207
|
+
if (runtimeDir) {
|
|
2208
|
+
installRuntime2(output, runtimeDir);
|
|
2209
|
+
console.log(" Refreshed the Zig runtime from", runtimeDir);
|
|
2210
|
+
} else {
|
|
2211
|
+
console.log(" Keeping the Zig runtime installed at init (no runtime directory configured)");
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2168
2214
|
if (devServer) {
|
|
2169
2215
|
const url = androidWebUrl(devServer, "Android dev server URL");
|
|
2170
2216
|
config.devServerURL = url.toString();
|
|
@@ -2313,7 +2359,7 @@ window.__craftRejectPendingPromises = function(message) {
|
|
|
2313
2359
|
if (entry) entry.settle(false, new Error(message || 'Android bridge closed'));
|
|
2314
2360
|
});
|
|
2315
2361
|
};
|
|
2316
|
-
`, TEMPLATES_DIR2, LOCAL_DEVELOPMENT_HOSTS, KOTLIN_KEYWORDS, DEFAULT_CONFIG2;
|
|
2362
|
+
`, TEMPLATES_DIR2, LOCAL_DEVELOPMENT_HOSTS, KOTLIN_KEYWORDS, DEFAULT_CONFIG2, RUNTIME_ABIS;
|
|
2317
2363
|
var init_src2 = __esm(() => {
|
|
2318
2364
|
({ $: $2 } = globalThis.Bun);
|
|
2319
2365
|
TEMPLATES_DIR2 = join3(dirname2(import.meta.dir), "templates");
|
|
@@ -2371,6 +2417,7 @@ var init_src2 = __esm(() => {
|
|
|
2371
2417
|
compileSdk: 36,
|
|
2372
2418
|
targetSdk: 35
|
|
2373
2419
|
};
|
|
2420
|
+
RUNTIME_ABIS = ["arm64-v8a", "x86_64"];
|
|
2374
2421
|
});
|
|
2375
2422
|
|
|
2376
2423
|
// ../../node_modules/@stacksjs/clapp/dist/index.js
|
|
@@ -4537,7 +4584,7 @@ function pinCraftNativeDependency(packagePath, craftVersion) {
|
|
|
4537
4584
|
`);
|
|
4538
4585
|
}
|
|
4539
4586
|
// package.json
|
|
4540
|
-
var version = "0.0.
|
|
4587
|
+
var version = "0.0.92";
|
|
4541
4588
|
|
|
4542
4589
|
// bin/cli.ts
|
|
4543
4590
|
var spawnedFrom = process6.env[CRAFT_CLI_SPAWN_MARKER];
|
package/dist/index.cjs
CHANGED
|
@@ -5089,11 +5089,18 @@ var share = {
|
|
|
5089
5089
|
return craft.share.share(options);
|
|
5090
5090
|
}
|
|
5091
5091
|
if (navigator.share) {
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5092
|
+
try {
|
|
5093
|
+
await navigator.share({
|
|
5094
|
+
title: options.title,
|
|
5095
|
+
text: options.text,
|
|
5096
|
+
url: options.url
|
|
5097
|
+
});
|
|
5098
|
+
return true;
|
|
5099
|
+
} catch (error) {
|
|
5100
|
+
if (error instanceof DOMException && error.name === "AbortError")
|
|
5101
|
+
return false;
|
|
5102
|
+
throw error;
|
|
5103
|
+
}
|
|
5097
5104
|
} else {
|
|
5098
5105
|
throw new Error("Share API not available");
|
|
5099
5106
|
}
|
package/dist/index.js
CHANGED
|
@@ -4850,11 +4850,18 @@ var share = {
|
|
|
4850
4850
|
return craft.share.share(options);
|
|
4851
4851
|
}
|
|
4852
4852
|
if (navigator.share) {
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4853
|
+
try {
|
|
4854
|
+
await navigator.share({
|
|
4855
|
+
title: options.title,
|
|
4856
|
+
text: options.text,
|
|
4857
|
+
url: options.url
|
|
4858
|
+
});
|
|
4859
|
+
return true;
|
|
4860
|
+
} catch (error) {
|
|
4861
|
+
if (error instanceof DOMException && error.name === "AbortError")
|
|
4862
|
+
return false;
|
|
4863
|
+
throw error;
|
|
4864
|
+
}
|
|
4858
4865
|
} else {
|
|
4859
4866
|
throw new Error("Share API not available");
|
|
4860
4867
|
}
|
package/dist/ios/src/index.d.ts
CHANGED
|
@@ -201,7 +201,7 @@ export interface SimulatorDevice {
|
|
|
201
201
|
runtime: string;
|
|
202
202
|
}
|
|
203
203
|
/**
|
|
204
|
-
* Every available simulator, newest runtime first, iPhones before iPads.
|
|
204
|
+
* Every available *iOS* simulator, newest runtime first, iPhones before iPads.
|
|
205
205
|
*
|
|
206
206
|
* Exported because the choice is worth testing without a simulator present -
|
|
207
207
|
* `pickSimulator` is the policy and this is the data it reads.
|
package/dist/ios/src/index.js
CHANGED
|
@@ -559,7 +559,7 @@ async function open(options) {
|
|
|
559
559
|
await $`open ${projectPath}`;
|
|
560
560
|
}
|
|
561
561
|
function orderSimulators(devices) {
|
|
562
|
-
return
|
|
562
|
+
return devices.filter((device) => device.runtime.startsWith("iOS")).sort((left, right) => {
|
|
563
563
|
const booted = Number(right.state === "Booted") - Number(left.state === "Booted");
|
|
564
564
|
if (booted !== 0)
|
|
565
565
|
return booted;
|