adjacent-dev-client 0.1.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/CHANGELOG.md +15 -0
- package/LICENSE +21 -0
- package/README.md +59 -0
- package/dist/android-dev.d.ts +4 -0
- package/dist/android-dev.d.ts.map +1 -0
- package/dist/android-dev.js +239 -0
- package/dist/android-dev.js.map +1 -0
- package/dist/android-wrapper.d.ts +63 -0
- package/dist/android-wrapper.d.ts.map +1 -0
- package/dist/android-wrapper.js +337 -0
- package/dist/android-wrapper.js.map +1 -0
- package/dist/android.d.ts +17 -0
- package/dist/android.d.ts.map +1 -0
- package/dist/android.js +153 -0
- package/dist/android.js.map +1 -0
- package/dist/checks.d.ts +21 -0
- package/dist/checks.d.ts.map +1 -0
- package/dist/checks.js +119 -0
- package/dist/checks.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/tunnel.d.ts +11 -0
- package/dist/tunnel.d.ts.map +1 -0
- package/dist/tunnel.js +90 -0
- package/dist/tunnel.js.map +1 -0
- package/package.json +62 -0
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { readdir, readFile, mkdir, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { ConsoleLog, fetchUtils, TwaGenerator, TwaManifest, } from "@bubblewrap/core";
|
|
6
|
+
import { runCommand } from "adjacent-cli";
|
|
7
|
+
export const ANDROID_PACKAGE_ID = "dev.adjacent.runner";
|
|
8
|
+
/**
|
|
9
|
+
* Bubblewrap pins the JDK exactly: `JdkHelper.validatePath` rejects anything
|
|
10
|
+
* whose release file is not `JAVA_VERSION="17.0`, and the Android command line
|
|
11
|
+
* tools are incompatible with newer major versions.
|
|
12
|
+
*/
|
|
13
|
+
const REQUIRED_JDK_MAJOR = "17";
|
|
14
|
+
/** Preserved across rebuilds so Gradle does not start cold every time. */
|
|
15
|
+
const PRESERVED_BUILD_ENTRIES = new Set([".gradle", "app"]);
|
|
16
|
+
export function isSupportedJdkRelease(releaseFile) {
|
|
17
|
+
return new RegExp(`JAVA_VERSION="${REQUIRED_JDK_MAJOR}(?:[."])`).test(releaseFile);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Normalises a SHA-256 certificate digest from either `apksigner` (lowercase,
|
|
21
|
+
* unseparated) or `keytool` (uppercase, colon-separated) into the colon form
|
|
22
|
+
* that a Digital Asset Links statement expects.
|
|
23
|
+
*/
|
|
24
|
+
export function parseCertificateFingerprint(output) {
|
|
25
|
+
const apksigner = /SHA-256 digest:\s*([0-9a-f]{64})/i.exec(output)?.[1];
|
|
26
|
+
if (apksigner) {
|
|
27
|
+
return (apksigner.toUpperCase().match(/.{2}/g) ?? []).join(":");
|
|
28
|
+
}
|
|
29
|
+
const keytool = /SHA256:\s*((?:[0-9A-F]{2}:){31}[0-9A-F]{2})/i.exec(output)?.[1];
|
|
30
|
+
return keytool?.toUpperCase();
|
|
31
|
+
}
|
|
32
|
+
/** Mirrors ANDROID_MANIFEST_KEY in adjacent-core, which the CLI must not import. */
|
|
33
|
+
const ANDROID_MANIFEST_KEY = "adjacent_android";
|
|
34
|
+
const CHROME_KEYS = [
|
|
35
|
+
"navigationColor",
|
|
36
|
+
"navigationColorDark",
|
|
37
|
+
"navigationDividerColor",
|
|
38
|
+
"navigationDividerColorDark",
|
|
39
|
+
"themeColorDark",
|
|
40
|
+
];
|
|
41
|
+
/**
|
|
42
|
+
* Reads the wrapper chrome Adjacent publishes alongside the web manifest.
|
|
43
|
+
*
|
|
44
|
+
* A web manifest has one `theme_color` and nothing at all for the Android
|
|
45
|
+
* navigation bar, so Bubblewrap falls back to hardcoded defaults for these five
|
|
46
|
+
* fields. Reading them from a namespaced manifest member keeps the CLI free of
|
|
47
|
+
* any dependency on the application's configuration file.
|
|
48
|
+
*/
|
|
49
|
+
export function readAndroidChrome(manifestSource) {
|
|
50
|
+
let parsed;
|
|
51
|
+
try {
|
|
52
|
+
parsed = JSON.parse(manifestSource);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return {};
|
|
56
|
+
}
|
|
57
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
58
|
+
return {};
|
|
59
|
+
const section = parsed[ANDROID_MANIFEST_KEY];
|
|
60
|
+
if (typeof section !== "object" || section === null)
|
|
61
|
+
return {};
|
|
62
|
+
const source = section;
|
|
63
|
+
const chrome = {};
|
|
64
|
+
for (const key of CHROME_KEYS) {
|
|
65
|
+
const value = source[key];
|
|
66
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
67
|
+
chrome[key] = value;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return chrome;
|
|
71
|
+
}
|
|
72
|
+
export function hashManifestSource(source) {
|
|
73
|
+
return createHash("sha256").update(source).digest("hex");
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* `TwaManifest.validate()` only checks that host, name, startUrl, and iconUrl
|
|
77
|
+
* are non-empty. These are the remaining fields that decide whether the wrapper
|
|
78
|
+
* launches fullscreen instead of falling back to a Custom Tab.
|
|
79
|
+
*/
|
|
80
|
+
/**
|
|
81
|
+
* Segments Android refuses because Java refuses them. The build fails late and
|
|
82
|
+
* unhelpfully on these, so they are named here.
|
|
83
|
+
*/
|
|
84
|
+
const JAVA_KEYWORDS = new Set([
|
|
85
|
+
"abstract", "assert", "boolean", "break", "byte", "case", "catch", "char",
|
|
86
|
+
"class", "const", "continue", "default", "do", "double", "else", "enum",
|
|
87
|
+
"extends", "final", "finally", "float", "for", "goto", "if", "implements",
|
|
88
|
+
"import", "instanceof", "int", "interface", "long", "native", "new", "package",
|
|
89
|
+
"private", "protected", "public", "return", "short", "static", "strictfp",
|
|
90
|
+
"super", "switch", "synchronized", "this", "throw", "throws", "transient",
|
|
91
|
+
"try", "void", "volatile", "while",
|
|
92
|
+
]);
|
|
93
|
+
/**
|
|
94
|
+
* Why an Android application id is invalid, or undefined when it is fine.
|
|
95
|
+
*
|
|
96
|
+
* An application id is a Java package name, which is stricter than the "letters,
|
|
97
|
+
* numbers, periods, hyphens and underscores" that documentation tends to say: a
|
|
98
|
+
* hyphen is not allowed anywhere, a segment cannot begin with a digit, and no
|
|
99
|
+
* segment may be a Java keyword. Each of those fails the Gradle build rather
|
|
100
|
+
* than the packaging step, which is a long way from the mistake.
|
|
101
|
+
*/
|
|
102
|
+
export function describePackageIdProblem(packageId) {
|
|
103
|
+
if (packageId.length === 0)
|
|
104
|
+
return "an application id is required";
|
|
105
|
+
const segments = packageId.split(".");
|
|
106
|
+
if (segments.length < 2) {
|
|
107
|
+
return `"${packageId}" needs at least two segments, such as com.example.app`;
|
|
108
|
+
}
|
|
109
|
+
for (const segment of segments) {
|
|
110
|
+
if (segment.length === 0) {
|
|
111
|
+
return `"${packageId}" has an empty segment`;
|
|
112
|
+
}
|
|
113
|
+
if (!/^[A-Za-z][A-Za-z0-9_]*$/.test(segment)) {
|
|
114
|
+
return /^[0-9]/.test(segment)
|
|
115
|
+
? `"${segment}" begins with a digit, and a segment has to begin with a letter`
|
|
116
|
+
: `"${segment}" is not a valid segment: letters, digits and underscores only, and no hyphens`;
|
|
117
|
+
}
|
|
118
|
+
if (JAVA_KEYWORDS.has(segment)) {
|
|
119
|
+
return `"${segment}" is a Java keyword, which Android cannot use as a segment`;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return undefined;
|
|
123
|
+
}
|
|
124
|
+
export function describeManifestProblems(manifest) {
|
|
125
|
+
const problems = [];
|
|
126
|
+
const packageIdProblem = describePackageIdProblem(manifest.packageId ?? "");
|
|
127
|
+
if (packageIdProblem !== undefined) {
|
|
128
|
+
problems.push(`packageId is not a valid Android application id: ${packageIdProblem}`);
|
|
129
|
+
}
|
|
130
|
+
if (!manifest.startUrl?.startsWith("/")) {
|
|
131
|
+
problems.push("startUrl must be a path relative to the origin");
|
|
132
|
+
}
|
|
133
|
+
if (!manifest.webManifestUrl) {
|
|
134
|
+
problems.push("webManifestUrl is missing, which Chrome OS and Meta Quest devices require");
|
|
135
|
+
}
|
|
136
|
+
if (manifest.display && !["standalone", "fullscreen", "fullscreen-sticky"].includes(manifest.display)) {
|
|
137
|
+
problems.push(`display "${manifest.display}" cannot launch fullscreen; use standalone or fullscreen`);
|
|
138
|
+
}
|
|
139
|
+
if (!manifest.maskableIconUrl) {
|
|
140
|
+
problems.push("no maskable icon was found, so Android will letterbox the launcher icon");
|
|
141
|
+
}
|
|
142
|
+
return problems;
|
|
143
|
+
}
|
|
144
|
+
async function assertJdk17(javaHome) {
|
|
145
|
+
const release = await readFile(join(javaHome, "release"), "utf8").catch(() => undefined);
|
|
146
|
+
if (release === undefined) {
|
|
147
|
+
throw new Error(`No JDK release file found at ${javaHome}. Point JAVA_HOME at a JDK ${REQUIRED_JDK_MAJOR} installation.`);
|
|
148
|
+
}
|
|
149
|
+
if (!isSupportedJdkRelease(release)) {
|
|
150
|
+
const found = /JAVA_VERSION="([^"]+)"/.exec(release)?.[1] ?? "an unknown version";
|
|
151
|
+
throw new Error(`The JDK at ${javaHome} is ${found}. The Android command line tools require exactly JDK ${REQUIRED_JDK_MAJOR}; newer majors are not supported.`);
|
|
152
|
+
}
|
|
153
|
+
return javaHome;
|
|
154
|
+
}
|
|
155
|
+
async function resolveJavaHome() {
|
|
156
|
+
if (process.env.JAVA_HOME) {
|
|
157
|
+
try {
|
|
158
|
+
return await assertJdk17(process.env.JAVA_HOME);
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
if (process.platform !== "darwin")
|
|
162
|
+
throw error;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (process.platform === "darwin") {
|
|
166
|
+
// Without -v this returns the machine default, which silently breaks the
|
|
167
|
+
// Gradle build as soon as a newer JDK is installed.
|
|
168
|
+
const { stdout } = await runCommand("/usr/libexec/java_home", [
|
|
169
|
+
"-v",
|
|
170
|
+
REQUIRED_JDK_MAJOR,
|
|
171
|
+
]).catch(() => {
|
|
172
|
+
throw new Error(`No JDK ${REQUIRED_JDK_MAJOR} was found. Install one, for example: brew install --cask zulu@${REQUIRED_JDK_MAJOR}`);
|
|
173
|
+
});
|
|
174
|
+
return assertJdk17(stdout);
|
|
175
|
+
}
|
|
176
|
+
throw new Error(`JAVA_HOME must point to a JDK ${REQUIRED_JDK_MAJOR} installation.`);
|
|
177
|
+
}
|
|
178
|
+
export function resolveAndroidSdk() {
|
|
179
|
+
const sdk = process.env.ANDROID_HOME ?? process.env.ANDROID_SDK_ROOT;
|
|
180
|
+
if (!sdk) {
|
|
181
|
+
throw new Error("ANDROID_HOME or ANDROID_SDK_ROOT must point to the Android SDK.");
|
|
182
|
+
}
|
|
183
|
+
if (/\s/.test(sdk)) {
|
|
184
|
+
throw new Error(`The Android SDK path must not contain spaces: ${sdk}. The Android build tools cannot resolve it.`);
|
|
185
|
+
}
|
|
186
|
+
return sdk;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Gradle fails opaquely when SDK licences have never been accepted, so this is
|
|
190
|
+
* checked up front where the fix can be spelled out.
|
|
191
|
+
*/
|
|
192
|
+
async function assertAndroidSdkLicenses(sdk) {
|
|
193
|
+
const licence = join(sdk, "licenses", "android-sdk-license");
|
|
194
|
+
const accepted = await readFile(licence, "utf8").then((contents) => contents.trim().length > 0, () => false);
|
|
195
|
+
if (!accepted) {
|
|
196
|
+
throw new Error(`The Android SDK licences have not been accepted. Run: ${join(sdk, "cmdline-tools", "latest", "bin", "sdkmanager")} --licenses`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/** Highest installed build-tools revision, which is where apksigner lives. */
|
|
200
|
+
async function resolveApksigner(sdk) {
|
|
201
|
+
const buildTools = join(sdk, "build-tools");
|
|
202
|
+
const revisions = await readdir(buildTools).catch(() => []);
|
|
203
|
+
const [newest] = revisions
|
|
204
|
+
.filter((entry) => /^\d+/.test(entry))
|
|
205
|
+
.sort((a, b) => b.localeCompare(a, undefined, { numeric: true }));
|
|
206
|
+
return newest ? join(buildTools, newest, "apksigner") : undefined;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Removes the generated project while keeping Gradle's caches, so a rebuild is
|
|
210
|
+
* incremental rather than starting from an empty directory every time.
|
|
211
|
+
*/
|
|
212
|
+
async function cleanGeneratedProject(outputRoot) {
|
|
213
|
+
const entries = await readdir(outputRoot).catch(() => undefined);
|
|
214
|
+
if (!entries) {
|
|
215
|
+
await mkdir(outputRoot, { recursive: true });
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
await Promise.all(entries
|
|
219
|
+
.filter((entry) => !PRESERVED_BUILD_ENTRIES.has(entry))
|
|
220
|
+
.map((entry) => rm(join(outputRoot, entry), { force: true, recursive: true })));
|
|
221
|
+
}
|
|
222
|
+
async function fetchManifest(manifestUrl) {
|
|
223
|
+
const response = await fetch(manifestUrl);
|
|
224
|
+
if (!response.ok) {
|
|
225
|
+
throw new Error(`Could not read ${manifestUrl}: HTTP ${response.status}`);
|
|
226
|
+
}
|
|
227
|
+
const source = await response.text();
|
|
228
|
+
return { chrome: readAndroidChrome(source), hash: hashManifestSource(source) };
|
|
229
|
+
}
|
|
230
|
+
export async function buildAndroidWrapper(projectRoot, manifestUrl) {
|
|
231
|
+
const outputRoot = join(projectRoot, ".adjacent", "android");
|
|
232
|
+
const sdk = resolveAndroidSdk();
|
|
233
|
+
const javaHome = await resolveJavaHome();
|
|
234
|
+
await assertAndroidSdkLicenses(sdk);
|
|
235
|
+
await cleanGeneratedProject(outputRoot);
|
|
236
|
+
fetchUtils.setFetchEngine("node-fetch");
|
|
237
|
+
const manifest = await fetchManifest(manifestUrl);
|
|
238
|
+
const derived = await TwaManifest.fromWebManifest(manifestUrl);
|
|
239
|
+
// Overrides are applied through the JSON form rather than onto the instance.
|
|
240
|
+
// On a TwaManifest the colour fields hold Color objects whose `hex()` is
|
|
241
|
+
// called during generation, so assigning strings to them throws; the JSON
|
|
242
|
+
// form declares them as strings and the constructor parses them back.
|
|
243
|
+
const twaManifest = new TwaManifest({
|
|
244
|
+
...derived.toJson(),
|
|
245
|
+
...manifest.chrome,
|
|
246
|
+
enableNotifications: false,
|
|
247
|
+
enableSiteSettingsShortcut: false,
|
|
248
|
+
generatorApp: "Adjacent",
|
|
249
|
+
packageId: ANDROID_PACKAGE_ID,
|
|
250
|
+
// Development wrappers are assembled as debug builds, so the release
|
|
251
|
+
// keystore Bubblewrap defaults to is never created. Point at Gradle's own.
|
|
252
|
+
signingKey: {
|
|
253
|
+
alias: "androiddebugkey",
|
|
254
|
+
path: join(homedir(), ".android", "debug.keystore"),
|
|
255
|
+
},
|
|
256
|
+
});
|
|
257
|
+
const validationError = twaManifest.validate();
|
|
258
|
+
if (validationError) {
|
|
259
|
+
throw new Error(`The web manifest is missing required fields: ${validationError}`);
|
|
260
|
+
}
|
|
261
|
+
const problems = describeManifestProblems(twaManifest);
|
|
262
|
+
if (problems.length > 0) {
|
|
263
|
+
throw new Error(`The web manifest cannot produce a fullscreen Android wrapper:\n - ${problems.join("\n - ")}`);
|
|
264
|
+
}
|
|
265
|
+
await twaManifest.saveToFile(join(outputRoot, "twa-manifest.json"));
|
|
266
|
+
await new TwaGenerator().createTwaProject(outputRoot, twaManifest, new ConsoleLog("Adjacent", false));
|
|
267
|
+
await runCommand(join(outputRoot, "gradlew"), ["assembleDebug", "--stacktrace"], {
|
|
268
|
+
cwd: outputRoot,
|
|
269
|
+
env: { ...process.env, ANDROID_HOME: sdk, JAVA_HOME: javaHome },
|
|
270
|
+
}).catch((error) => {
|
|
271
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
272
|
+
if (/licen[cs]e/i.test(message)) {
|
|
273
|
+
throw new Error(`Gradle could not build the wrapper because Android SDK licences are outstanding. Run: ${join(sdk, "cmdline-tools", "latest", "bin", "sdkmanager")} --licenses`);
|
|
274
|
+
}
|
|
275
|
+
throw error;
|
|
276
|
+
});
|
|
277
|
+
const apkPath = join(outputRoot, "app", "build", "outputs", "apk", "debug", "app-debug.apk");
|
|
278
|
+
await readFile(apkPath);
|
|
279
|
+
const state = {
|
|
280
|
+
manifestHash: manifest.hash,
|
|
281
|
+
manifestUrl,
|
|
282
|
+
packageId: ANDROID_PACKAGE_ID,
|
|
283
|
+
};
|
|
284
|
+
await writeFile(join(outputRoot, "adjacent-state.json"), `${JSON.stringify(state, null, 2)}\n`);
|
|
285
|
+
return { apkPath, packageId: ANDROID_PACKAGE_ID };
|
|
286
|
+
}
|
|
287
|
+
export async function readExistingAndroidWrapper(projectRoot, manifestUrl) {
|
|
288
|
+
const outputRoot = join(projectRoot, ".adjacent", "android");
|
|
289
|
+
const apkPath = join(outputRoot, "app", "build", "outputs", "apk", "debug", "app-debug.apk");
|
|
290
|
+
try {
|
|
291
|
+
const rawState = await readFile(join(outputRoot, "adjacent-state.json"), "utf8");
|
|
292
|
+
const state = JSON.parse(rawState);
|
|
293
|
+
if (state.manifestUrl !== manifestUrl || !state.manifestHash)
|
|
294
|
+
return undefined;
|
|
295
|
+
// The URL alone is constant across a session, so the manifest contents are
|
|
296
|
+
// compared too: renaming the app or changing its icons must rebuild.
|
|
297
|
+
if (state.manifestHash !== (await fetchManifest(manifestUrl)).hash) {
|
|
298
|
+
return undefined;
|
|
299
|
+
}
|
|
300
|
+
await readFile(apkPath);
|
|
301
|
+
return { apkPath, packageId: ANDROID_PACKAGE_ID };
|
|
302
|
+
}
|
|
303
|
+
catch {
|
|
304
|
+
return undefined;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
export async function readAndroidAssetLink(wrapper) {
|
|
308
|
+
const javaHome = await resolveJavaHome();
|
|
309
|
+
const apksigner = await resolveApksigner(resolveAndroidSdk());
|
|
310
|
+
// apksigner reads v1, v2, and v3 signatures; keytool only reads the v1 JAR
|
|
311
|
+
// signature, which Gradle stops emitting once minSdkVersion reaches 24.
|
|
312
|
+
const output = apksigner
|
|
313
|
+
? await runCommand(apksigner, ["verify", "--print-certs", wrapper.apkPath], {
|
|
314
|
+
env: { ...process.env, JAVA_HOME: javaHome },
|
|
315
|
+
}).then(({ stdout }) => stdout, () => undefined)
|
|
316
|
+
: undefined;
|
|
317
|
+
const fallback = output
|
|
318
|
+
? undefined
|
|
319
|
+
: await runCommand(join(javaHome, "bin", "keytool"), [
|
|
320
|
+
"-printcert",
|
|
321
|
+
"-jarfile",
|
|
322
|
+
wrapper.apkPath,
|
|
323
|
+
]).then(({ stdout }) => stdout);
|
|
324
|
+
const fingerprint = parseCertificateFingerprint(output ?? fallback ?? "");
|
|
325
|
+
if (!fingerprint) {
|
|
326
|
+
throw new Error(`Could not read the SHA-256 signing fingerprint from ${wrapper.apkPath}.`);
|
|
327
|
+
}
|
|
328
|
+
return { packageId: wrapper.packageId, sha256Fingerprint: fingerprint };
|
|
329
|
+
}
|
|
330
|
+
/** Backs `adj doctor`, reporting the toolchain Bubblewrap needs. */
|
|
331
|
+
export async function inspectAndroidToolchain() {
|
|
332
|
+
const androidSdk = resolveAndroidSdk();
|
|
333
|
+
const javaHome = await resolveJavaHome();
|
|
334
|
+
const licensesAccepted = await assertAndroidSdkLicenses(androidSdk).then(() => true, () => false);
|
|
335
|
+
return { androidSdk, javaHome, licensesAccepted };
|
|
336
|
+
}
|
|
337
|
+
//# sourceMappingURL=android-wrapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"android-wrapper.js","sourceRoot":"","sources":["../src/android-wrapper.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface AndroidDevice {
|
|
2
|
+
readonly serial: string;
|
|
3
|
+
readonly state: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function parseAdbDevices(output: string): AndroidDevice[];
|
|
6
|
+
export declare function resolveAdbPath(): Promise<string>;
|
|
7
|
+
export declare function selectReadyAndroidDevice(devices: readonly AndroidDevice[], requestedSerial?: string): string;
|
|
8
|
+
export declare function selectAndroidDeviceByChoice(devices: readonly AndroidDevice[], choice: string): AndroidDevice | undefined;
|
|
9
|
+
export declare function selectAndroidDevice(adb: string, requestedSerial?: string): Promise<string>;
|
|
10
|
+
export declare function prepareAndroidChrome(adb: string, serial: string, port: number): Promise<void>;
|
|
11
|
+
export declare function openAndroidChrome(adb: string, serial: string, url: string): Promise<void>;
|
|
12
|
+
export declare function installAndroidApk(adb: string, serial: string, apkPath: string): Promise<void>;
|
|
13
|
+
export declare function isAndroidPackageInstalled(adb: string, serial: string, packageId: string): Promise<boolean>;
|
|
14
|
+
export declare function openAndroidPackage(adb: string, serial: string, packageId: string): Promise<void>;
|
|
15
|
+
export declare function androidPackageLaunchArgs(serial: string, packageId: string): string[];
|
|
16
|
+
export declare function removeAndroidReverse(adb: string, serial: string, port: number): Promise<void>;
|
|
17
|
+
//# sourceMappingURL=android.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"android.d.ts","sourceRoot":"","sources":["../src/android.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAID,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,EAAE,CAY/D;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAWtD;AAED,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,SAAS,aAAa,EAAE,EACjC,eAAe,CAAC,EAAE,MAAM,GACvB,MAAM,CA2BR;AAED,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,SAAS,aAAa,EAAE,EACjC,MAAM,EAAE,MAAM,GACb,aAAa,GAAG,SAAS,CAM3B;AAgBD,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,MAAM,EACX,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,MAAM,CAAC,CAajB;AAED,wBAAsB,oBAAoB,CACxC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAgBf;AAED,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,IAAI,CAAC,CAcf;AAED,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,wBAAsB,yBAAyB,CAC7C,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC,CAWlB;AAED,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,MAAM,EAAE,CAgBV;AAED,wBAAsB,oBAAoB,CACxC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAEf"}
|
package/dist/android.js
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { access } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { runCommand } from "adjacent-cli";
|
|
4
|
+
import { selectItem } from "adjacent-cli";
|
|
5
|
+
const ADB_DEVICE_LINE = /^(.*?)\s+(bootloader|connecting|device|host|no permissions|offline|recovery|sideload|unauthorized)(?:\s|$)/;
|
|
6
|
+
export function parseAdbDevices(output) {
|
|
7
|
+
return output
|
|
8
|
+
.split("\n")
|
|
9
|
+
.slice(1)
|
|
10
|
+
.map((line) => line.trim())
|
|
11
|
+
.filter(Boolean)
|
|
12
|
+
.flatMap((line) => {
|
|
13
|
+
const match = ADB_DEVICE_LINE.exec(line);
|
|
14
|
+
if (!match)
|
|
15
|
+
return [];
|
|
16
|
+
const [, serial, state] = match;
|
|
17
|
+
return serial && state ? [{ serial, state }] : [];
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
export async function resolveAdbPath() {
|
|
21
|
+
const sdkRoot = process.env.ANDROID_HOME ?? process.env.ANDROID_SDK_ROOT;
|
|
22
|
+
if (!sdkRoot)
|
|
23
|
+
return "adb";
|
|
24
|
+
const candidate = join(sdkRoot, "platform-tools", "adb");
|
|
25
|
+
try {
|
|
26
|
+
await access(candidate);
|
|
27
|
+
return candidate;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return "adb";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export function selectReadyAndroidDevice(devices, requestedSerial) {
|
|
34
|
+
if (requestedSerial) {
|
|
35
|
+
const requested = devices.find(({ serial }) => serial === requestedSerial);
|
|
36
|
+
if (!requested) {
|
|
37
|
+
throw new Error(`Android device ${requestedSerial} is not connected.`);
|
|
38
|
+
}
|
|
39
|
+
if (requested.state !== "device") {
|
|
40
|
+
throw new Error(`Android device ${requestedSerial} is ${requested.state}. Authorize or reconnect it and try again.`);
|
|
41
|
+
}
|
|
42
|
+
return requested.serial;
|
|
43
|
+
}
|
|
44
|
+
const readyDevices = devices.filter(({ state }) => state === "device");
|
|
45
|
+
if (readyDevices.length === 0) {
|
|
46
|
+
throw new Error("No ready Android device found. Start an emulator or connect and authorize a phone, then try again.");
|
|
47
|
+
}
|
|
48
|
+
if (readyDevices.length > 1) {
|
|
49
|
+
throw new Error(`Multiple Android devices are ready. Choose one with --device: ${readyDevices.map(({ serial }) => serial).join(", ")}`);
|
|
50
|
+
}
|
|
51
|
+
return readyDevices[0].serial;
|
|
52
|
+
}
|
|
53
|
+
export function selectAndroidDeviceByChoice(devices, choice) {
|
|
54
|
+
const index = Number(choice.trim());
|
|
55
|
+
if (!Number.isInteger(index) || index < 1 || index > devices.length) {
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
return devices[index - 1];
|
|
59
|
+
}
|
|
60
|
+
async function promptForAndroidDevice(devices) {
|
|
61
|
+
const selected = await selectItem({
|
|
62
|
+
message: "Choose an Android device",
|
|
63
|
+
items: devices.map((device) => ({
|
|
64
|
+
hint: device.state,
|
|
65
|
+
label: device.serial,
|
|
66
|
+
value: device,
|
|
67
|
+
})),
|
|
68
|
+
});
|
|
69
|
+
return selectReadyAndroidDevice(devices, selected.serial);
|
|
70
|
+
}
|
|
71
|
+
export async function selectAndroidDevice(adb, requestedSerial) {
|
|
72
|
+
const { stdout } = await runCommand(adb, ["devices", "-l"]);
|
|
73
|
+
const devices = parseAdbDevices(stdout);
|
|
74
|
+
if (requestedSerial)
|
|
75
|
+
return selectReadyAndroidDevice(devices, requestedSerial);
|
|
76
|
+
if (devices.length === 0) {
|
|
77
|
+
throw new Error("No Android devices found. Start an emulator or connect a phone, then try again.");
|
|
78
|
+
}
|
|
79
|
+
if (process.stdin.isTTY && process.stdout.isTTY) {
|
|
80
|
+
return promptForAndroidDevice(devices);
|
|
81
|
+
}
|
|
82
|
+
return selectReadyAndroidDevice(devices);
|
|
83
|
+
}
|
|
84
|
+
export async function prepareAndroidChrome(adb, serial, port) {
|
|
85
|
+
const { stdout } = await runCommand(adb, [
|
|
86
|
+
"-s",
|
|
87
|
+
serial,
|
|
88
|
+
"shell",
|
|
89
|
+
"pm",
|
|
90
|
+
"list",
|
|
91
|
+
"packages",
|
|
92
|
+
"com.android.chrome",
|
|
93
|
+
]);
|
|
94
|
+
if (!stdout.split("\n").includes("package:com.android.chrome")) {
|
|
95
|
+
throw new Error("Google Chrome is not installed on the selected Android device.");
|
|
96
|
+
}
|
|
97
|
+
const target = `tcp:${port}`;
|
|
98
|
+
await runCommand(adb, ["-s", serial, "reverse", target, target]);
|
|
99
|
+
}
|
|
100
|
+
export async function openAndroidChrome(adb, serial, url) {
|
|
101
|
+
await runCommand(adb, [
|
|
102
|
+
"-s",
|
|
103
|
+
serial,
|
|
104
|
+
"shell",
|
|
105
|
+
"am",
|
|
106
|
+
"start",
|
|
107
|
+
"-W",
|
|
108
|
+
"-a",
|
|
109
|
+
"android.intent.action.VIEW",
|
|
110
|
+
"-d",
|
|
111
|
+
url,
|
|
112
|
+
"com.android.chrome",
|
|
113
|
+
]);
|
|
114
|
+
}
|
|
115
|
+
export async function installAndroidApk(adb, serial, apkPath) {
|
|
116
|
+
await runCommand(adb, ["-s", serial, "install", "-r", apkPath]);
|
|
117
|
+
}
|
|
118
|
+
export async function isAndroidPackageInstalled(adb, serial, packageId) {
|
|
119
|
+
const { stdout } = await runCommand(adb, [
|
|
120
|
+
"-s",
|
|
121
|
+
serial,
|
|
122
|
+
"shell",
|
|
123
|
+
"pm",
|
|
124
|
+
"list",
|
|
125
|
+
"packages",
|
|
126
|
+
packageId,
|
|
127
|
+
]);
|
|
128
|
+
return stdout.split("\n").includes(`package:${packageId}`);
|
|
129
|
+
}
|
|
130
|
+
export async function openAndroidPackage(adb, serial, packageId) {
|
|
131
|
+
await runCommand(adb, androidPackageLaunchArgs(serial, packageId));
|
|
132
|
+
}
|
|
133
|
+
export function androidPackageLaunchArgs(serial, packageId) {
|
|
134
|
+
return [
|
|
135
|
+
"-s",
|
|
136
|
+
serial,
|
|
137
|
+
"shell",
|
|
138
|
+
"am",
|
|
139
|
+
"start",
|
|
140
|
+
"-W",
|
|
141
|
+
"-S",
|
|
142
|
+
"-a",
|
|
143
|
+
"android.intent.action.MAIN",
|
|
144
|
+
"-c",
|
|
145
|
+
"android.intent.category.LAUNCHER",
|
|
146
|
+
"-p",
|
|
147
|
+
packageId,
|
|
148
|
+
];
|
|
149
|
+
}
|
|
150
|
+
export async function removeAndroidReverse(adb, serial, port) {
|
|
151
|
+
await runCommand(adb, ["-s", serial, "reverse", "--remove", `tcp:${port}`]);
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=android.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"android.js","sourceRoot":"","sources":["../src/android.ts"],"names":[],"mappings":"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"}
|
package/dist/checks.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type DoctorCheck } from "adjacent-cli";
|
|
2
|
+
export interface AssetLinksProblem {
|
|
3
|
+
readonly detail: string;
|
|
4
|
+
readonly remedy: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Reads a digital asset links document the way Android does, and says what is
|
|
8
|
+
* wrong with it.
|
|
9
|
+
*
|
|
10
|
+
* A wrong or unreachable one is the single most common Android fault: the app
|
|
11
|
+
* launches with a browser address bar across the top, or does not launch at
|
|
12
|
+
* all, and nothing anywhere says why. Every rule here is one that produces
|
|
13
|
+
* exactly that symptom.
|
|
14
|
+
*/
|
|
15
|
+
export declare function describeAssetLinksProblem(requested: URL, response: {
|
|
16
|
+
readonly ok: boolean;
|
|
17
|
+
readonly status: number;
|
|
18
|
+
readonly url: string;
|
|
19
|
+
}, body: string): AssetLinksProblem | undefined;
|
|
20
|
+
export declare const ANDROID_CHECKS: readonly DoctorCheck[];
|
|
21
|
+
//# sourceMappingURL=checks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checks.d.ts","sourceRoot":"","sources":["../src/checks.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAIhE,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,GAAG,EACd,QAAQ,EAAE;IAAE,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,EACjF,IAAI,EAAE,MAAM,GACX,iBAAiB,GAAG,SAAS,CA8D/B;AA2ED,eAAO,MAAM,cAAc,EAAE,SAAS,WAAW,EAIhD,CAAC"}
|