-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathindex.js
135 lines (123 loc) · 3.36 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/*
* File: index.js
* Project: aaptjs
* Description: Android Asset Packaging Tool(aapt) for Node.js
* Created By: Tao.Hu 2019-05-15
* -----
* Last Modified: 2019-05-15 11:52:33
* Modified By: Tao.Hu
* -----
*/
'use strict';
const fs = require('fs');
const util = require('util');
const path = require('path');
const access = util.promisify(fs.access);
const chmod = util.promisify(fs.chmod);
const writeFile = util.promisify(fs.writeFile);
const mkdir = util.promisify(fs.mkdir);
const execFile = util.promisify(require('child_process').execFile);
async function aapt(args) {
try {
// darwin: macOS linux win32
const aapt = path.join(__dirname, 'bin', process.platform, `aapt_64${process.platform === 'win32' ? '.exe' : ''}`);
await access(aapt, fs.constants.F_OK);
if (process.platform === 'linux' || process.platform === 'darwin') {
await chmod(aapt, '755');
}
const { stdout } = await execFile(aapt, args, { maxBuffer: 10000 * 1024 });
return stdout;
} catch (error) {
console.error('aapt error:', error.message);
throw error;
}
}
function list(filePath) {
return aapt(['l', filePath]);
}
function dump(filePath, values) {
return aapt(['d', values, filePath]);
}
function packageCmd(filePath, command) {
return aapt(['p', command, filePath]);
}
function remove(filePath, files) {
let tmpFiles = files;
if (!Array.isArray(tmpFiles)) {
tmpFiles = [tmpFiles];
}
return aapt(['r', filePath, ...tmpFiles]);
}
function add(filePath, files) {
let tmpFiles = files;
if (!Array.isArray(tmpFiles)) {
tmpFiles = [tmpFiles];
}
return aapt(['a', filePath, ...tmpFiles]);
}
function crunch(resource, outputFolder) {
let tmpResource = resource;
if (!Array.isArray(tmpResource)) {
tmpResource = [tmpResource];
}
return aapt(['c', '-S', ...tmpResource, '-C', outputFolder]);
}
function singleCrunch(inputFile, outputFile) {
return aapt(['s', '-i', inputFile, '-o', outputFile]);
}
function version() {
return aapt(['v']);
}
async function getApkInfo(filePath) {
try {
const stdout = await dump(filePath, 'badging');
const match = stdout.match(/name='([^']+)'[\s]*versionCode='(\d+)'[\s]*versionName='([^']+)/);
const matchName = stdout.match(/application: label='([^']+)'[\s]*icon='([^']+)/);
const info = {
package: match[1],
version: match[3],
name: matchName[1],
icon: matchName[2],
};
if (!info.package || !info.version) {
throw (new Error('Invalid Apk File'));
}
return info;
} catch (error) {
console.error('aapt error:', error.message);
throw error;
}
}
async function getApkAndIcon(filePath, outIconName, outIconPath = './') {
try {
if (!filePath || !outIconName) {
throw (new Error('Invalid parameter'));
}
const apkInfo = await getApkInfo(filePath);
if (apkInfo.icon) {
const { stdout } = await execFile('unzip', ['-p', filePath, apkInfo.icon], { encoding: 'buffer' });
await mkdir(outIconPath, { recursive: true });
await writeFile(`${outIconPath}/${outIconName}`, stdout);
return {
...apkInfo,
iconPath: `${outIconPath}/${outIconName}`,
};
}
} catch (error) {
console.error('aapt error:', error.message);
throw error;
}
}
module.exports = {
aapt,
list,
dump,
packageCmd,
remove,
add,
crunch,
singleCrunch,
version,
getApkInfo,
getApkAndIcon,
};