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
136
137
138
139
140
|
--!A cross-platform build utility based on Lua
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-- Copyright (C) 2015-present, Xmake Open Source Community.
--
-- @author keosu
-- @file package.lua
--
-- imports
import("core.project.depend")
import("utils.progress")
function _get_libname(android_manifest)
local libname = "libmain.so"
local manifest_xml = io.readfile(android_manifest)
if manifest_xml then
local lib_name_meta = manifest_xml:match('android:name="android.app.lib_name"%s+android:value="([^"]+)"')
if lib_name_meta then
libname = "lib" .. lib_name_meta .. ".so"
end
end
return libname
end
function _pack_resources(target, aapt, android_manifest, android_res, android_assets, android_sdkdir, android_sdk_version, tmp_path)
local resonly_apk = path.join(tmp_path, "res_only.apk")
local androidjar = path.join(android_sdkdir, "platforms", string.format("android-%s", android_sdk_version), "android.jar")
assert(os.isfile(androidjar), "%s not found", androidjar)
local aapt_argv = {"package", "-f", "-M", android_manifest, "-I", androidjar, "-F", resonly_apk}
if android_res and not os.emptydir(android_res) then
table.insert(aapt_argv, "-S")
table.insert(aapt_argv, android_res)
end
if android_assets and not os.emptydir(android_assets) then
table.insert(aapt_argv, "-A")
table.insert(aapt_argv, android_assets)
end
os.vrunv(aapt, aapt_argv)
end
function _pack_libs(target, aapt, libname, tmp_path)
os.vrunv(aapt, {"add", "res_only.apk", "lib/" .. target:arch() .."/" .. libname}, {curdir = tmp_path})
end
function _align_apk(zipalign, tmp_path)
local aligned_apk = path.join(tmp_path, "unsigned.apk")
local zipalign_argv = {"-f", "4", "res_only.apk", "unsigned.apk"}
os.vrunv(zipalign, zipalign_argv, {curdir = tmp_path})
end
function _sign_apk(apksigner, keystore, keystore_pass, final_apk, tmp_path)
local aligned_apk = path.join(tmp_path, "unsigned.apk")
if keystore == nil then
raise("keystore for signing missing; generate one via `keytool` and make it available")
elseif keystore_pass == nil then
raise("keystore_pass for signing is missing; please provide it")
end
local apksigner_argv = {"sign", "--ks", keystore, "--ks-pass", string.format("pass:%s", keystore_pass), "--out", final_apk, "--in", aligned_apk}
os.vrunv(apksigner, apksigner_argv)
end
function main(target, opt)
local conf = target:extraconf("rules", "android.native_app")
local android_sdk_version = conf.android_sdk_version
local android_manifest = conf.android_manifest
local android_res = conf.android_res
local android_assets = conf.android_assets
local keystore = conf.keystore
local keystore_pass = conf.keystore_pass
assert(android_sdk_version, "android sdk version not set")
assert(android_manifest, "android manifest not set")
if not path.is_absolute(android_manifest) then
android_manifest = path.join(target:scriptdir(), android_manifest)
end
if keystore and not path.is_absolute(keystore) then
keystore = path.join(target:scriptdir(), keystore)
end
if android_res and not path.is_absolute(android_res) then
android_res = path.join(target:scriptdir(), android_res)
end
if android_assets and not path.is_absolute(android_assets) then
android_assets = path.join(target:scriptdir(), android_assets)
end
local final_apk = path.join(target:targetdir(), target:basename() .. ".apk")
-- add dependencies
local depfiles = {target:targetfile(), android_manifest, keystore}
if android_res and os.isdir(android_res) then
table.join2(depfiles, os.files(path.join(android_res, "**")))
end
if android_assets and os.isdir(android_assets) then
table.join2(depfiles, os.files(path.join(android_assets, "**")))
end
depend.on_changed(function ()
progress.show(opt.progress, "${color.build.target}packing.apk %s", final_apk)
local tmp_path = path.join(target:autogendir(), "packing")
os.tryrm(tmp_path)
os.mkdir(tmp_path)
os.mkdir(path.join(tmp_path, "lib"))
os.mkdir(path.join(tmp_path, "lib", target:arch()))
-- copy the target library
local libname = _get_libname(android_manifest)
local libfile = path.join(tmp_path, "lib", target:arch(), libname)
os.cp(target:targetfile(), libfile)
-- get android tool path
local android_sdkdir = target:toolchain("ndk"):config("android_sdk")
local android_build_toolver = target:toolchain("ndk"):config("build_toolver")
local sdk_tool_path = path.join(android_sdkdir, "build-tools", android_build_toolver)
local aapt = path.join(sdk_tool_path, "aapt" .. (is_host("windows") and ".exe" or ""))
local zipalign = path.join(sdk_tool_path, "zipalign" .. (is_host("windows") and ".exe" or ""))
local apksigner = path.join(sdk_tool_path, "apksigner" .. (is_host("windows") and ".bat" or ""))
_pack_resources(target, aapt, android_manifest, android_res, android_assets, android_sdkdir, android_sdk_version, tmp_path)
_pack_libs(target, aapt, libname, tmp_path)
_align_apk(zipalign, tmp_path)
_sign_apk(apksigner, keystore, keystore_pass, final_apk, tmp_path)
end, {dependfile = target:dependfile(final_apk), files = depfiles, values = {android_sdk_version, keystore_pass}})
end
|