Skip to content

Commit ccce8ae

Browse files
authored
Merge branch 'main' into run-server
2 parents 44b616c + 0a593f4 commit ccce8ae

File tree

11 files changed

+81
-55
lines changed

11 files changed

+81
-55
lines changed

.changeset/smooth-views-invite.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'rock-docs': patch
3+
---
4+
5+
fix: config pages presence and positioning

.changeset/whole-tools-occur.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@rock-js/platform-android': patch
3+
---
4+
5+
feat: android aab signing

packages/platform-android/src/lib/commands/signAndroid/command.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { signAndroid } from './signAndroid.js';
33

44
export type SignFlags = {
55
verbose?: boolean;
6-
apk: string;
6+
path: string;
77
output?: string;
88
keystore?: string;
99
keystorePassword?: string;
@@ -16,8 +16,8 @@ export type SignFlags = {
1616

1717
const ARGUMENTS = [
1818
{
19-
name: 'apk',
20-
description: 'APK file path',
19+
name: 'binaryPath',
20+
description: 'Archive (apk or aab) file path',
2121
},
2222
];
2323

@@ -44,7 +44,7 @@ const OPTIONS = [
4444
},
4545
{
4646
name: '--output <string>',
47-
description: 'Path to the output APK file.',
47+
description: 'Path to the output APK/AAB file.',
4848
},
4949
{
5050
name: '--build-jsbundle',
@@ -66,9 +66,9 @@ export const registerSignCommand = (api: PluginApi) => {
6666
description: 'Sign the Android app with modified JS bundle.',
6767
args: ARGUMENTS,
6868
options: OPTIONS,
69-
action: async (apkPath, flags: SignFlags) => {
69+
action: async (binaryPath, flags: SignFlags) => {
7070
await signAndroid({
71-
apkPath,
71+
binaryPath,
7272
keystorePath: flags.keystore,
7373
keystorePassword: flags.keystorePassword,
7474
keyAlias: flags.keyAlias,

packages/platform-android/src/lib/commands/signAndroid/signAndroid.ts

Lines changed: 50 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { findAndroidBuildTool, getAndroidBuildToolsPath } from '../../paths.js';
1616
import { buildJsBundle } from './bundle.js';
1717

1818
export type SignAndroidOptions = {
19-
apkPath: string;
19+
binaryPath: string;
2020
keystorePath?: string;
2121
keystorePassword?: string;
2222
keyAlias?: string;
@@ -30,7 +30,9 @@ export type SignAndroidOptions = {
3030
export async function signAndroid(options: SignAndroidOptions) {
3131
validateOptions(options);
3232

33-
intro(`Modifying APK file`);
33+
const extension = path.extname(options.binaryPath).slice(1);
34+
35+
intro(`Modifying ${extension.toUpperCase()} file`);
3436

3537
const tempPath = getSignOutputPath();
3638
if (fs.existsSync(tempPath)) {
@@ -60,28 +62,28 @@ export async function signAndroid(options: SignAndroidOptions) {
6062
options.jsBundlePath = bundleOutputPath;
6163
}
6264

63-
// 2. Initialize temporary APK file
64-
const tempApkPath = path.join(tempPath, 'output-app.apk');
65+
// 2. Initialize temporary archive file
66+
const tempArchivePath = path.join(tempPath, `output-app.${extension}`);
6567

66-
loader.start('Initializing output APK...');
68+
loader.start(`Initializing output ${extension.toUpperCase()}...`);
6769
try {
68-
const zip = new AdmZip(options.apkPath);
70+
const zip = new AdmZip(options.binaryPath);
6971
// Remove old signature files
7072
zip.deleteFile('META-INF/*');
71-
zip.writeZip(tempApkPath);
73+
zip.writeZip(tempArchivePath);
7274
} catch (error) {
7375
throw new RockError(
74-
`Failed to initialize output APK file: ${options.outputPath}`,
76+
`Failed to initialize output file: ${options.outputPath}`,
7577
{ cause: (error as SubprocessError).stderr },
7678
);
7779
}
78-
loader.stop(`Initialized output APK.`);
80+
loader.stop(`Initialized output ${extension.toUpperCase()}`);
7981

8082
// 3. Replace JS bundle if provided
8183
if (options.jsBundlePath) {
8284
loader.start('Replacing JS bundle...');
8385
await replaceJsBundle({
84-
apkPath: tempApkPath,
86+
archivePath: tempArchivePath,
8587
jsBundlePath: options.jsBundlePath,
8688
});
8789
loader.stop(
@@ -91,32 +93,34 @@ export async function signAndroid(options: SignAndroidOptions) {
9193
);
9294
}
9395

94-
// 4. Align APK file
95-
loader.start('Aligning output APK file...');
96-
const outputApkPath = options.outputPath ?? options.apkPath;
97-
await alignApkFile(tempApkPath, outputApkPath);
96+
// 4. Align archive
97+
loader.start('Aligning output file...');
98+
const outputPath = options.outputPath ?? options.binaryPath;
99+
await alignArchiveFile(tempArchivePath, outputPath);
98100
loader.stop(
99-
`Created output APK file: ${colorLink(relativeToCwd(outputApkPath))}.`,
101+
`Created output ${extension.toUpperCase()} file: ${colorLink(relativeToCwd(outputPath))}.`,
100102
);
101103

102-
// 5. Sign APK file
103-
loader.start('Signing the APK file...');
104+
// 5. Sign archive file
105+
loader.start(`Signing the ${extension.toUpperCase()} file...`);
104106
const keystorePath = options.keystorePath ?? 'android/app/debug.keystore';
105-
await signApkFile({
106-
apkPath: outputApkPath,
107+
await signArchive({
108+
binaryPath: outputPath,
107109
keystorePath,
108110
keystorePassword: options.keystorePassword ?? 'pass:android',
109111
keyAlias: options.keyAlias,
110112
keyPassword: options.keyPassword,
111113
});
112-
loader.stop(`Signed the APK file with keystore: ${colorLink(keystorePath)}.`);
114+
loader.stop(
115+
`Signed the ${extension.toUpperCase()} file with keystore: ${colorLink(keystorePath)}.`,
116+
);
113117

114118
outro('Success 🎉.');
115119
}
116120

117121
function validateOptions(options: SignAndroidOptions) {
118-
if (!fs.existsSync(options.apkPath)) {
119-
throw new RockError(`APK file not found "${options.apkPath}"`);
122+
if (!fs.existsSync(options.binaryPath)) {
123+
throw new RockError(`File not found "${options.binaryPath}"`);
120124
}
121125

122126
if (options.buildJsBundle && options.jsBundlePath) {
@@ -131,22 +135,24 @@ function validateOptions(options: SignAndroidOptions) {
131135
}
132136

133137
type ReplaceJsBundleOptions = {
134-
apkPath: string;
138+
archivePath: string;
135139
jsBundlePath: string;
136140
};
137141

138142
async function replaceJsBundle({
139-
apkPath,
143+
archivePath,
140144
jsBundlePath,
141145
}: ReplaceJsBundleOptions) {
142146
try {
143-
const zip = new AdmZip(apkPath);
144-
zip.deleteFile('assets/index.android.bundle');
145-
zip.addLocalFile(jsBundlePath, 'assets', 'index.android.bundle');
146-
zip.writeZip(apkPath);
147+
const zip = new AdmZip(archivePath);
148+
const assetsPath = isAab(archivePath) ? 'base/assets' : 'assets';
149+
150+
zip.deleteFile(path.join(assetsPath, 'index.android.bundle'));
151+
zip.addLocalFile(jsBundlePath, assetsPath, 'index.android.bundle');
152+
zip.writeZip(archivePath);
147153
} catch (error) {
148154
throw new RockError(
149-
`Failed to replace JS bundle in destination file: ${apkPath}}`,
155+
`Failed to replace JS bundle in destination file: ${archivePath}`,
150156
{ cause: error },
151157
);
152158
}
@@ -159,7 +165,7 @@ function isSdkGTE35(versionString: string) {
159165
return match[1].localeCompare('35.0.0', undefined, { numeric: true }) >= 0;
160166
}
161167

162-
async function alignApkFile(inputApkPath: string, outputApkPath: string) {
168+
async function alignArchiveFile(inputArchivePath: string, outputPath: string) {
163169
const zipAlignPath = findAndroidBuildTool('zipalign');
164170
if (!zipAlignPath) {
165171
throw new RockError(
@@ -177,34 +183,34 @@ Please follow instructions at: https://reactnative.dev/docs/set-up-your-environm
177183
'-f', // Overwrites existing output file.
178184
'-v', // Overwrites existing output file.
179185
'4', // alignment in bytes, e.g. '4' provides 32-bit alignment
180-
inputApkPath,
181-
outputApkPath,
186+
inputArchivePath,
187+
outputPath,
182188
];
183189
try {
184190
await spawn(zipAlignPath, zipalignArgs);
185191
} catch (error) {
186192
throw new RockError(
187-
`Failed to align APK file: ${zipAlignPath} ${zipalignArgs.join(' ')}`,
193+
`Failed to align archive file: ${zipAlignPath} ${zipalignArgs.join(' ')}`,
188194
{ cause: (error as SubprocessError).stderr },
189195
);
190196
}
191197
}
192198

193-
type SignApkOptions = {
194-
apkPath: string;
199+
type SignOptions = {
200+
binaryPath: string;
195201
keystorePath: string;
196202
keystorePassword: string;
197203
keyAlias?: string;
198204
keyPassword?: string;
199205
};
200206

201-
async function signApkFile({
202-
apkPath,
207+
async function signArchive({
208+
binaryPath,
203209
keystorePath,
204210
keystorePassword,
205211
keyAlias,
206212
keyPassword,
207-
}: SignApkOptions) {
213+
}: SignOptions) {
208214
if (!fs.existsSync(keystorePath)) {
209215
throw new RockError(
210216
`Keystore file not found "${keystorePath}". Provide a valid keystore path using the "--keystore" option.`,
@@ -230,7 +236,8 @@ Please follow instructions at: https://reactnative.dev/docs/set-up-your-environm
230236
formatPassword(keystorePassword),
231237
...(keyAlias ? ['--ks-key-alias', keyAlias] : []),
232238
...(keyPassword ? ['--key-pass', formatPassword(keyPassword)] : []),
233-
apkPath,
239+
...(isAab(binaryPath) ? ['--min-sdk-version', '36'] : []),
240+
binaryPath,
234241
];
235242

236243
try {
@@ -264,3 +271,7 @@ function formatPassword(password: string) {
264271
function getSignOutputPath() {
265272
return path.join(getDotRockPath(), 'android/sign');
266273
}
274+
275+
function isAab(filePath: string): boolean {
276+
return path.extname(filePath).toLowerCase() === '.aab';
277+
}

website/src/docs/_meta.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414
"name": "getting-started",
1515
"label": "Getting Started"
1616
},
17+
{
18+
"type": "file",
19+
"name": "configuration",
20+
"label": "Configuration"
21+
},
1722
{
1823
"type": "dir",
1924
"name": "cli",

website/src/docs/cli/introduction.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -244,17 +244,17 @@ Same as for `build:android` and:
244244

245245
### `rock sign:android` Options
246246

247-
The `sign:android <binaryPath>` command signs your Android app with a keystore, producing a signed APK file ready for distribution. It allows for replacing the JS bundle with a new version.
247+
The `sign:android <binaryPath>` command signs your Android app with a keystore, producing a signed APK or AAB file ready for distribution. It allows for replacing the JS bundle with a new version.
248248

249-
| Argument | Description |
250-
| :----------- | :------------------- |
251-
| `binaryPath` | Path to the APK file |
249+
| Argument | Description |
250+
| :----------- | :-------------------------- |
251+
| `binaryPath` | Path to the APK or AAB file |
252252

253253
| Option | Description |
254254
| :----------------------------- | :---------------------------------------- |
255255
| `--keystore <string>` | Path to keystore file |
256256
| `--keystore-password <string>` | Password for keystore file |
257-
| `--output <string>` | Path to output APK file |
257+
| `--output <string>` | Path to output APK or AAB file |
258258
| `--build-jsbundle` | Build JS bundle before signing |
259259
| `--jsbundle <string>` | Path to JS bundle to apply before signing |
260260
| `--no-hermes` | Don't use Hermes for JS bundle |

website/src/docs/cli/migrating-from-community-cli.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,4 +172,4 @@ If you prefer to do it manually or encounter any issues, follow the steps below.
172172
github-token: ${{ secrets.GITHUB_TOKEN }}
173173
```
174174
175-
For more setup options see [GitHub Actions configuration](../remote-cache/configuration.md)
175+
For more setup options see [GitHub Actions configuration](../remote-cache/github-actions-setup.md)

website/src/docs/remote-cache/_meta.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
"label": "Introduction"
66
},
77
{
8-
"name": "configuration",
8+
"name": "github-actions-setup",
99
"type": "file",
10-
"label": "Configuration"
10+
"label": "Github Actions Setup"
1111
},
1212
{
1313
"name": "ios",

website/src/docs/remote-cache/android.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Android GitHub Action
22

3-
This GitHub Action allows you to build Android apps using Rock's remote build system. It supports both simulator builds for development and signed device builds for testing and release. If you haven't yet, please check the [configuration guide](./configuration.md) where you can find information on optimal workflow setup, permissions, optimizations and GitHub Personal Access Tokens.
3+
This GitHub Action allows you to build Android apps using Rock's remote build system. It supports both simulator builds for development and signed device builds for testing and release. If you haven't yet, please check the [configuration guide](./github-actions-setup.md) where you can find information on optimal workflow setup, permissions, optimizations and GitHub Personal Access Tokens.
44

55
## Development Builds For All Devices
66

File renamed without changes.

0 commit comments

Comments
 (0)