@expo/repack-app 0.1.10 → 0.1.11

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 CHANGED
@@ -98,3 +98,113 @@ $ bun bin/cli.js -p ios --source-app ./golden-debug-iphoneos.ipa \
98
98
  ```sh
99
99
  $ xcrun devicectl device install app --verbose --device <device-id> /path/to/sdk51onboard/repacked.ipa
100
100
  ```
101
+
102
+ ## API Documentation
103
+
104
+ ### CLI Usage
105
+
106
+ ```sh
107
+ repack-app [options] [project-root]
108
+ ```
109
+
110
+ #### Options
111
+
112
+ - `-p, --platform <platform>` (required): Platform to repack the app for (`android` or `ios`)
113
+ - `--source-app <path>` (required): Path to the source app file (APK for Android, IPA for iOS)
114
+ - `--android-build-tools-dir <path>`: Path to the Android build tools directory
115
+ - `-w, --working-directory <path>`: Path to the working directory
116
+ - `-o, --output <path>`: Path to the output artifact
117
+ - `-v, --verbose`: Enable verbose logging
118
+
119
+ #### Android-specific Options
120
+
121
+ - `--ks <path>`: Path to the keystore file
122
+ - `--ks-pass <password>`: Keystore password (default: "pass:android")
123
+ - `--ks-key-alias <alias>`: Keystore key alias
124
+ - `--ks-key-pass <password>`: Keystore key password
125
+
126
+ #### iOS-specific Options
127
+
128
+ - `--signing-identity <identity>`: Signing identity (e.g., "Apple Development: Name (Team ID)")
129
+ - `--provisioning-profile <path>`: Path to the provisioning profile
130
+
131
+ #### Bundle Options
132
+
133
+ - `--embed-bundle-assets`: Execute export:embed to embed new bundle assets
134
+ - `--bundle-assets-sourcemap-output <path>`: Generate sourcemap to the specified path (paired with --embed-bundle-assets)
135
+
136
+ ### Programmatic Usage
137
+
138
+ ```typescript
139
+ import { repackAppAndroidAsync, repackAppIosAsync } from '@expo/repack-app';
140
+
141
+ // For Android
142
+ await repackAppAndroidAsync({
143
+ platform: 'android',
144
+ projectRoot: '/path/to/project',
145
+ sourceAppPath: '/path/to/source.apk',
146
+ // Optional configurations
147
+ workingDirectory: '/path/to/working/dir',
148
+ outputPath: '/path/to/output.apk',
149
+ verbose: true,
150
+ androidSigningOptions: {
151
+ keyStorePath: '/path/to/keystore.jks',
152
+ keyStorePassword: 'password',
153
+ keyAlias: 'alias',
154
+ keyPassword: 'key-password',
155
+ },
156
+ androidBuildToolsDir: '/path/to/build-tools',
157
+ exportEmbedOptions: {
158
+ sourcemapOutput: '/path/to/sourcemap',
159
+ },
160
+ });
161
+
162
+ // For iOS
163
+ await repackAppIosAsync({
164
+ platform: 'ios',
165
+ projectRoot: '/path/to/project',
166
+ sourceAppPath: '/path/to/source.ipa',
167
+ // Optional configurations
168
+ workingDirectory: '/path/to/working/dir',
169
+ outputPath: '/path/to/output.ipa',
170
+ verbose: true,
171
+ iosSigningOptions: {
172
+ signingIdentity: 'Apple Development: Name (Team ID)',
173
+ provisioningProfile: '/path/to/profile.mobileprovision',
174
+ },
175
+ exportEmbedOptions: {
176
+ sourcemapOutput: '/path/to/sourcemap',
177
+ },
178
+ });
179
+ ```
180
+
181
+ ### Configuration Options
182
+
183
+ The following options are available when using the API programmatically:
184
+
185
+ #### Common Options
186
+
187
+ - `platform`: 'android' | 'ios' - The platform to repack the app for
188
+ - `projectRoot`: string - Path to the project root directory
189
+ - `sourceAppPath`: string - Path to the prebuilt app file (APK/IPA)
190
+ - `workingDirectory?`: string - Working directory for temporary files
191
+ - `outputPath?`: string - Path to the output app file (defaults to `projectRoot/repacked.apk` or `projectRoot/repacked.ipa`)
192
+ - `verbose?`: boolean - Enable verbose logging
193
+ - `exportEmbedOptions?`: ExportEmbedOptions - Options for embedding JS bundle
194
+ - `skipWorkingDirCleanup?`: boolean - Skip working directory cleanup
195
+ - `env?`: Record<string, string | undefined> - Environment variables
196
+ - `logger?`: Logger - Custom logger instance
197
+ - `spawnAsync?`: SpawnProcessAsync - Custom spawn process function
198
+
199
+ #### Android-specific Options
200
+
201
+ - `androidSigningOptions?`: AndroidSigningOptions - Options for signing the Android app
202
+ - `androidBuildToolsDir?`: string - Path to Android SDK build-tools directory
203
+
204
+ #### iOS-specific Options
205
+
206
+ - `iosSigningOptions?`: IosSigningOptions - Options for signing the iOS app
207
+
208
+ ### Environment Variables
209
+
210
+ - `ANDROID_SDK_ROOT`: Path to the Android SDK root directory (required for Android builds)
package/bin/cli.js CHANGED
@@ -1,3 +1,99 @@
1
- #!/usr/bin/env node
1
+ import { Command } from 'commander';
2
+ import pico from 'picocolors';
3
+ import { ConsoleLogger, repackAppAndroidAsync, repackAppIosAsync } from '../dist/index';
2
4
 
3
- import('../build/cli.js');
5
+ /**
6
+ * @import { Options } from '../dist/index'
7
+ */
8
+
9
+ const program = new Command('repack-app')
10
+ .requiredOption('-p, --platform <platform>', 'Platform to repack the app for')
11
+ .requiredOption('--source-app <path>', 'Path to the source app file')
12
+ .option('--android-build-tools-dir <path>', 'Path to the Android build tools directory')
13
+ .option('-w, --working-directory <path>', 'Path to the working directory')
14
+ .option('-o, --output <path>', 'Path to the output artifact')
15
+ // Android signing options
16
+ .option('--ks <path>', 'Path to the keystore file')
17
+ .option('--ks-pass <password>', 'Keystore password', 'pass:android')
18
+ .option('--ks-key-alias <alias>', 'Keystore key alias')
19
+ .option('--ks-key-pass <password>', 'Keystore key password')
20
+ .option('-v, --verbose', 'Enable verbose logging')
21
+ // iOS signing options
22
+ .option('--signing-identity <identity>', 'Signing identity')
23
+ .option('--provisioning-profile <path>', 'Path to the provisioning profile')
24
+ // export:embed options
25
+ .option('--embed-bundle-assets', 'Whether to execute export:embed to embed new bundle assets')
26
+ .option(
27
+ '--bundle-assets-sourcemap-output <path>',
28
+ 'Paired with --embed-bundle-assets and generate the sourcemap to the specified path'
29
+ )
30
+ // arguments
31
+ .argument('[project-root]', 'Path to the project root', process.cwd())
32
+ .version(require('../package.json').version)
33
+ .parse(process.argv);
34
+
35
+ async function runAsync() {
36
+ const logger = new ConsoleLogger();
37
+ const platform = program.opts().platform;
38
+ const projectRoot = program.processedArgs[0];
39
+
40
+ /** @type Options['exportEmbedOptions']} */
41
+ const exportEmbedOptions = program.opts().embedBundleAssets
42
+ ? {
43
+ sourcemapOutput: program.opts().bundleAssetsSourcemapOutput,
44
+ }
45
+ : undefined;
46
+
47
+ if (platform === 'android') {
48
+ const outputPath = await repackAppAndroidAsync({
49
+ platform: program.opts().platform,
50
+ projectRoot,
51
+ verbose: !!program.opts().verbose,
52
+ sourceAppPath: program.opts().sourceApp,
53
+ workingDirectory: program.opts().workingDirectory,
54
+ outputPath: program.opts().output,
55
+ exportEmbedOptions,
56
+ androidSigningOptions: {
57
+ keyStorePath: program.opts().ks,
58
+ keyStorePassword: program.opts().ksPass,
59
+ keyAlias: program.opts().ksKeyAlias,
60
+ keyPassword: program.opts().ksKeyPass,
61
+ },
62
+ androidBuildToolsDir: program.opts().androidBuildToolsDir,
63
+ logger,
64
+ });
65
+ logger.info(pico.green(`Updated APK created at ${outputPath}`));
66
+ } else if (platform === 'ios') {
67
+ /** @type Options['iosSigningOptions']} */
68
+ const iosSigningOptions =
69
+ program.opts().signingIdentity && program.opts().provisioningProfile
70
+ ? {
71
+ signingIdentity: program.opts().signingIdentity,
72
+ provisioningProfile: program.opts().provisioningProfile,
73
+ }
74
+ : undefined;
75
+ const outputPath = await repackAppIosAsync({
76
+ platform: program.opts().platform,
77
+ projectRoot,
78
+ verbose: !!program.opts().verbose,
79
+ sourceAppPath: program.opts().sourceApp,
80
+ workingDirectory: program.opts().workingDirectory,
81
+ outputPath: program.opts().output,
82
+ exportEmbedOptions,
83
+ iosSigningOptions,
84
+ logger,
85
+ });
86
+ logger.info(pico.green(`Updated IPA created at ${outputPath}`));
87
+ } else {
88
+ throw new Error(`Unsupported platform: ${platform}`);
89
+ }
90
+ }
91
+
92
+ (async () => {
93
+ try {
94
+ await runAsync();
95
+ } catch (e) {
96
+ console.error('Uncaught Error', e);
97
+ process.exit(1);
98
+ }
99
+ })();
@@ -1,143 +1,218 @@
1
- import type { ChildProcess, SpawnOptions } from 'child_process';
2
- export interface Options {
3
- /**
4
- * The platform to repack the app for.
5
- */
6
- platform: 'android' | 'ios';
7
- /**
8
- * The path to the project root directory.
9
- */
10
- projectRoot: string;
11
- /**
12
- * The prebuilt app file path that acts as a source for repacking.
13
- */
14
- sourceAppPath: string;
15
- /**
16
- * Working directory.
17
- */
18
- workingDirectory?: string;
19
- /**
20
- * The path to the output app file.
21
- * @default `projectRoot/repacked.apk` or `projectRoot/repacked.ipa`
22
- */
23
- outputPath?: string;
24
- /**
25
- * Enable verbose logging.
26
- */
27
- verbose?: boolean;
28
- /**
29
- * Whether to use the `npx export:embed` command to embed the JS bundle.
30
- */
31
- exportEmbedOptions?: ExportEmbedOptions;
32
- /**
33
- * The options for signing the android app.
34
- */
35
- androidSigningOptions?: AndroidSigningOptions;
36
- /**
37
- * The path to the Android SDK build-tools directory.
38
- * @default Try to find the latest build-tools directory in the `ANDROID_SDK_ROOT` directory.
39
- */
40
- androidBuildToolsDir?: string;
41
- /**
42
- * The options for signing the ios app.
43
- */
44
- iosSigningOptions?: IosSigningOptions;
45
- /**
46
- * Skip the working directory cleanup.
47
- */
48
- skipWorkingDirCleanup?: boolean;
49
- /**
50
- * env variables
51
- */
52
- env?: Record<string, string | undefined>;
53
- /**
54
- * Customize the logger instance.
55
- * @default `console`
56
- */
57
- logger?: Logger;
58
- /**
59
- * Customize the spawn process function.
60
- * @default `@expo/spawn-async`
61
- */
62
- spawnAsync?: SpawnProcessAsync;
63
- }
64
- export interface NormalizedOptions extends Options {
65
- workingDirectory: NonNullable<Options['workingDirectory']>;
66
- outputPath: NonNullable<Options['outputPath']>;
67
- logger: NonNullable<Options['logger']>;
68
- spawnAsync: NonNullable<Options['spawnAsync']>;
69
- }
70
- export interface AndroidSigningOptions {
71
- /**
72
- * Load private key and certificate chain from the Java
73
- * KeyStore initialized from the specified file.
74
- */
75
- keyStorePath: string;
76
- /**
77
- * KeyStore password.
78
- * The following formats are supported:
79
- * - pass:<password> password provided inline
80
- * - env:<name> password provided in the named environment variable
81
- * - file:<file> password provided in the named file, as a single line
82
- */
83
- keyStorePassword: string;
84
- /**
85
- * Alias under which the private key and certificate are stored in the KeyStore.
86
- */
87
- keyAlias?: string;
88
- /**
89
- * Password with which the private key is protected.
90
- * The following formats are supported:
91
- * - pass:<password> password provided inline
92
- * - env:<name> password provided in the named environment variable
93
- * - file:<file> password provided in the named file, as a single line
94
- */
95
- keyPassword?: string;
96
- }
97
- export interface IosSigningOptions {
98
- /**
99
- * Code signing identity.
100
- */
101
- signingIdentity: string;
102
- /**
103
- * Path to provisioning profile files.
104
- */
105
- provisioningProfile: string | Record<string, string>;
106
- /**
107
- * Provide a path to a keychain file that should be used by /usr/bin/codesign
108
- */
109
- keychainPath?: string;
110
- }
111
- /**
112
- * The options passed to the `npx export:embed` command.
113
- */
114
- export interface ExportEmbedOptions {
115
- /**
116
- * The path to the sourcemap output file.
117
- */
118
- sourcemapOutput?: string;
119
- }
120
- export interface Logger {
121
- debug(...message: any[]): void;
122
- info(...message: any[]): void;
123
- warn(...message: any[]): void;
124
- error(...message: any[]): void;
125
- time(label: string): void;
126
- timeEnd(label: string): void;
127
- }
128
- export interface SpawnProcessOptions extends SpawnOptions {
129
- }
130
- export interface SpawnProcessPromise<T> extends Promise<T> {
131
- child: ChildProcess;
132
- }
133
- export interface SpawnProcessResult {
134
- pid?: number;
135
- output: string[];
136
- stdout: string;
137
- stderr: string;
138
- status: number | null;
139
- signal: string | null;
140
- }
141
- export interface SpawnProcessAsync {
142
- (command: string, args: string[], options?: SpawnProcessOptions): SpawnProcessPromise<SpawnProcessResult>;
143
- }
1
+ import type { ChildProcess } from 'child_process';
2
+ import type { SpawnOptions } from 'child_process';
3
+
4
+ /**
5
+ * The options for signing the android app.
6
+ * @public
7
+ */
8
+ export declare interface AndroidSigningOptions {
9
+ /**
10
+ * Load private key and certificate chain from the Java
11
+ * KeyStore initialized from the specified file.
12
+ */
13
+ keyStorePath: string;
14
+ /**
15
+ * KeyStore password.
16
+ * The following formats are supported:
17
+ * - pass:<password> password provided inline
18
+ * - env:<name> password provided in the named environment variable
19
+ * - file:<file> password provided in the named file, as a single line
20
+ */
21
+ keyStorePassword: string;
22
+ /**
23
+ * Alias under which the private key and certificate are stored in the KeyStore.
24
+ */
25
+ keyAlias?: string;
26
+ /**
27
+ * Password with which the private key is protected.
28
+ * The following formats are supported:
29
+ * - pass:<password> password provided inline
30
+ * - env:<name> password provided in the named environment variable
31
+ * - file:<file> password provided in the named file, as a single line
32
+ */
33
+ keyPassword?: string;
34
+ }
35
+
36
+ /**
37
+ * The logger using [`console` API](https://nodejs.org/api/console.html).
38
+ * @public
39
+ */
40
+ export declare class ConsoleLogger implements Logger {
41
+ debug(...message: any[]): void;
42
+ info(...message: any[]): void;
43
+ warn(...message: any[]): void;
44
+ error(...message: any[]): void;
45
+ time(label: string): void;
46
+ timeEnd(label: string): void;
47
+ }
48
+
49
+ /**
50
+ * The options passed to the `npx expo export:embed` command.
51
+ * @public
52
+ */
53
+ export declare interface ExportEmbedOptions {
54
+ /**
55
+ * The path to the sourcemap output file.
56
+ */
57
+ sourcemapOutput?: string;
58
+ }
59
+
60
+ /**
61
+ * The options for signing the ios app.
62
+ * @public
63
+ */
64
+ export declare interface IosSigningOptions {
65
+ /**
66
+ * Code signing identity.
67
+ */
68
+ signingIdentity: string;
69
+ /**
70
+ * Path to provisioning profile files.
71
+ */
72
+ provisioningProfile: string | Record<string, string>;
73
+ /**
74
+ * Provide a path to a keychain file that should be used by /usr/bin/codesign
75
+ */
76
+ keychainPath?: string;
77
+ }
78
+
79
+ /**
80
+ * The logger interface.
81
+ * @internal
82
+ */
83
+ export declare interface Logger {
84
+ debug(...message: any[]): void;
85
+ info(...message: any[]): void;
86
+ warn(...message: any[]): void;
87
+ error(...message: any[]): void;
88
+ time(label: string): void;
89
+ timeEnd(label: string): void;
90
+ }
91
+
92
+ /**
93
+ * Normalized options.
94
+ * @internal
95
+ */
96
+ export declare interface NormalizedOptions extends Options {
97
+ workingDirectory: NonNullable<Options['workingDirectory']>;
98
+ outputPath: NonNullable<Options['outputPath']>;
99
+ logger: NonNullable<Options['logger']>;
100
+ spawnAsync: NonNullable<Options['spawnAsync']>;
101
+ }
102
+
103
+ /**
104
+ * The options for repacking the app.
105
+ * @public
106
+ */
107
+ export declare interface Options {
108
+ /**
109
+ * The platform to repack the app for.
110
+ */
111
+ platform: 'android' | 'ios';
112
+ /**
113
+ * The path to the project root directory.
114
+ */
115
+ projectRoot: string;
116
+ /**
117
+ * The prebuilt app file path that acts as a source for repacking.
118
+ */
119
+ sourceAppPath: string;
120
+ /**
121
+ * Working directory.
122
+ */
123
+ workingDirectory?: string;
124
+ /**
125
+ * The path to the output app file.
126
+ * @defaultValue `projectRoot/repacked.apk` or `projectRoot/repacked.ipa`
127
+ */
128
+ outputPath?: string;
129
+ /**
130
+ * Enable verbose logging.
131
+ */
132
+ verbose?: boolean;
133
+ /**
134
+ * Whether to use the `npx export:embed` command to embed the JS bundle.
135
+ */
136
+ exportEmbedOptions?: ExportEmbedOptions;
137
+ /**
138
+ * The options for signing the android app.
139
+ */
140
+ androidSigningOptions?: AndroidSigningOptions;
141
+ /**
142
+ * The path to the Android SDK build-tools directory.
143
+ * @defaultValue Try to find the latest build-tools directory in the `ANDROID_SDK_ROOT` directory.
144
+ */
145
+ androidBuildToolsDir?: string;
146
+ /**
147
+ * The options for signing the ios app.
148
+ */
149
+ iosSigningOptions?: IosSigningOptions;
150
+ /**
151
+ * Skip the working directory cleanup.
152
+ */
153
+ skipWorkingDirCleanup?: boolean;
154
+ /**
155
+ * env variables
156
+ */
157
+ env?: Record<string, string | undefined>;
158
+ /**
159
+ * Customize the logger instance.
160
+ * @defaultValue Logger instance of `ConsoleLogger`
161
+ */
162
+ logger?: Logger;
163
+ /**
164
+ * Customize the spawn process function.
165
+ * @defaultValue Use `@expo/spawn-async` to spawn the process.
166
+ */
167
+ spawnAsync?: SpawnProcessAsync;
168
+ }
169
+
170
+ /**
171
+ * Repack an Android app.
172
+ * @public
173
+ */
174
+ export declare function repackAppAndroidAsync(_options: Options): Promise<string>;
175
+
176
+ /**
177
+ * Repack an iOS app.
178
+ * @public
179
+ */
180
+ export declare function repackAppIosAsync(_options: Options): Promise<string>;
181
+
182
+ /**
183
+ * The interface for the spawn process.
184
+ * @internal
185
+ */
186
+ export declare interface SpawnProcessAsync {
187
+ (command: string, args: string[], options?: SpawnProcessOptions): SpawnProcessPromise<SpawnProcessResult>;
188
+ }
189
+
190
+ /**
191
+ * The options for the spawn process.
192
+ * @internal
193
+ */
194
+ export declare interface SpawnProcessOptions extends SpawnOptions {
195
+ }
196
+
197
+ /**
198
+ * The promise for the spawn process.
199
+ * @internal
200
+ */
201
+ export declare interface SpawnProcessPromise<T> extends Promise<T> {
202
+ child: ChildProcess;
203
+ }
204
+
205
+ /**
206
+ * The result of the spawn process.
207
+ * @internal
208
+ */
209
+ export declare interface SpawnProcessResult {
210
+ pid?: number;
211
+ output: string[];
212
+ stdout: string;
213
+ stderr: string;
214
+ status: number | null;
215
+ signal: string | null;
216
+ }
217
+
218
+ export { }