Compare commits
842 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
35dfdece12 | ||
|
|
cbed234069 | ||
|
|
81b2bccd97 | ||
|
|
89a00c02a4 | ||
|
|
40d3cdc0d6 | ||
|
|
8416c4e5e9 | ||
|
|
97ce7dd417 | ||
|
|
b32b8c89c6 | ||
|
|
fd1d3006c0 | ||
|
|
22918152cc | ||
|
|
1fcee242dc | ||
|
|
3f99c15338 | ||
|
|
f496f015b6 | ||
|
|
5e7e9d5b6c | ||
|
|
8bd4ca49a8 | ||
|
|
d33f7e08a8 | ||
|
|
d46ad592b5 | ||
|
|
eda765453b | ||
|
|
b295fc6687 | ||
|
|
0959608ab9 | ||
|
|
6db94dbb9a | ||
|
|
04a3c9d9ee | ||
|
|
db4d1f5768 | ||
|
|
81d6219663 | ||
|
|
3a1b4ffcb8 | ||
|
|
d6fe1a65eb | ||
|
|
72bbe9fdf0 | ||
|
|
d125ece9e9 | ||
|
|
ecb99c963d | ||
|
|
9738079c42 | ||
|
|
e9e27ca47c | ||
|
|
5d21fb26e6 | ||
|
|
d351e316bf | ||
|
|
dc6384d063 | ||
|
|
914e2fa35f | ||
|
|
8b96081579 | ||
|
|
f3e0623d1d | ||
|
|
abcaee24f9 | ||
|
|
8951660393 | ||
|
|
e4ecbad3cb | ||
|
|
40a740b45c | ||
|
|
9af7f506f0 | ||
|
|
9b8558dbde | ||
|
|
d28ca67edb | ||
|
|
0deaba0920 | ||
|
|
bcb10ba6da | ||
|
|
ef268e2320 | ||
|
|
d9814c5542 | ||
|
|
dd3b9dd01c | ||
|
|
1b43bc99a1 | ||
|
|
eccde6c0c0 | ||
|
|
69a2a5b551 | ||
|
|
bc9e895e25 | ||
|
|
457c5b8b3b | ||
|
|
9f1aedb56d | ||
|
|
a048aa94ec | ||
|
|
27d359bd43 | ||
|
|
456b4801af | ||
|
|
82582e5a5b | ||
|
|
18e81c4b90 | ||
|
|
bad0034e5d | ||
|
|
99d5ff7347 | ||
|
|
dc579417fe | ||
|
|
fe906dabda | ||
|
|
8ab75e7109 | ||
|
|
aa2b3d3da1 | ||
|
|
0a1b71f125 | ||
|
|
757a3685f2 | ||
|
|
fd2c3c9857 | ||
|
|
84477ff212 | ||
|
|
1d7ccaece6 | ||
|
|
ce2525d4d8 | ||
|
|
7be9e880c2 | ||
|
|
7233931681 | ||
|
|
d7e111fb71 | ||
|
|
2ac191fbb8 | ||
|
|
088140aca4 | ||
|
|
e08d0671ab | ||
|
|
7669378c6e | ||
|
|
1494082a2a | ||
|
|
233c2bd882 | ||
|
|
9c4f09a50a | ||
|
|
89d982a8e4 | ||
|
|
9d3ee3d56e | ||
|
|
44421bbc79 | ||
|
|
320558a782 | ||
|
|
9ef7ddbf20 | ||
|
|
603f994f3f | ||
|
|
ada35e0e00 | ||
|
|
fc778006ef | ||
|
|
11760afddd | ||
|
|
d78ae309f1 | ||
|
|
73fd9e4dfa | ||
|
|
fb9cf60c41 | ||
|
|
b6a329d479 | ||
|
|
70bc7b39b7 | ||
|
|
03777067cd | ||
|
|
f5271431fb | ||
|
|
c30eeee5d8 | ||
|
|
dac02bef8c | ||
|
|
32edaee3a2 | ||
|
|
ff1c58def4 | ||
|
|
f9372f5578 | ||
|
|
6afc16c33b | ||
|
|
74a3d2028f | ||
|
|
dfe468f335 | ||
|
|
4f7721b405 | ||
|
|
3abd12aee3 | ||
|
|
1c90a77325 | ||
|
|
671219ae56 | ||
|
|
78fa7374d9 | ||
|
|
c1b389ad9b | ||
|
|
5a07a51b5d | ||
|
|
824b9803d2 | ||
|
|
ab72e48431 | ||
|
|
78b7ae72c9 | ||
|
|
1151856d38 | ||
|
|
12c282ce5c | ||
|
|
0ac822c577 | ||
|
|
400282282f | ||
|
|
789c505a88 | ||
|
|
0429bb0ab8 | ||
|
|
000eb0916e | ||
|
|
4db1fecba8 | ||
|
|
013ad94af0 | ||
|
|
2ceb8030ee | ||
|
|
47ac514835 | ||
|
|
5e0c9595c3 | ||
|
|
a0747aa960 | ||
|
|
07912fdecd | ||
|
|
9a33943783 | ||
|
|
8981ddb681 | ||
|
|
7d61a79a78 | ||
|
|
afa61aeb09 | ||
|
|
bf57aa1df0 | ||
|
|
055e3bf609 | ||
|
|
b1dadaf15d | ||
|
|
9e400911f5 | ||
|
|
892b875867 | ||
|
|
8f7bc1ffbb | ||
|
|
e5506d40bc | ||
|
|
64f89c5eda | ||
|
|
1ad0665eb5 | ||
|
|
37309c23c2 | ||
|
|
8983ddbdcc | ||
|
|
d99a21eb8d | ||
|
|
f9ce1c607b | ||
|
|
847312fcf9 | ||
|
|
b770076b7f | ||
|
|
dc9413258e | ||
|
|
4b574a2863 | ||
|
|
4b3cc67353 | ||
|
|
32b72756f3 | ||
|
|
2fc86e2833 | ||
|
|
fab472859d | ||
|
|
92caa3a186 | ||
|
|
26c7a96255 | ||
|
|
e170e463fe | ||
|
|
899daa9ea7 | ||
|
|
6d334c05e9 | ||
|
|
5ac0cc51d3 | ||
|
|
f93c2b161d | ||
|
|
6b071c0fb2 | ||
|
|
d3245a43d3 | ||
|
|
90a51c2cc1 | ||
|
|
61df5e0a37 | ||
|
|
c0312f9b50 | ||
|
|
eb70f05168 | ||
|
|
505db38232 | ||
|
|
096e1e3caa | ||
|
|
b5d8b51310 | ||
|
|
c9e7201058 | ||
|
|
4bf705a3d3 | ||
|
|
ce42568721 | ||
|
|
eb956b2449 | ||
|
|
1bf4e93da1 | ||
|
|
aba0a8421b | ||
|
|
b5a58e6ca0 | ||
|
|
44aa7464e1 | ||
|
|
4ea684dd7a | ||
|
|
215b7e08f8 | ||
|
|
754911f346 | ||
|
|
9873106785 | ||
|
|
d005359f89 | ||
|
|
1ce52a2845 | ||
|
|
7e480d1ff9 | ||
|
|
85877d259c | ||
|
|
0b86db8748 | ||
|
|
bca7f62efd | ||
|
|
4953ae84cd | ||
|
|
e96a5a0b3e | ||
|
|
e4678f4709 | ||
|
|
1def13deb3 | ||
|
|
bce4283239 | ||
|
|
9ff786d021 | ||
|
|
ee14a67795 | ||
|
|
b63a2e37be | ||
|
|
84274b4259 | ||
|
|
b6bf5298e6 | ||
|
|
b0d5ffec8f | ||
|
|
09ff81c411 | ||
|
|
a0293578b1 | ||
|
|
4595403a99 | ||
|
|
0f73884c8d | ||
|
|
2e9cbdcb0d | ||
|
|
a652d892ca | ||
|
|
581252febc | ||
|
|
b27d283f21 | ||
|
|
f2d7c49acf | ||
|
|
a397a23a9c | ||
|
|
9f7e179288 | ||
|
|
ad1c3d2438 | ||
|
|
51adf81918 | ||
|
|
97718a0a25 | ||
|
|
1aaba440b5 | ||
|
|
b8f2b8948f | ||
|
|
d96d49329b | ||
|
|
4db421ca36 | ||
|
|
c3991c8164 | ||
|
|
e904bab206 | ||
|
|
500ccd8e80 | ||
|
|
7cf7311a9d | ||
|
|
0669edddae | ||
|
|
38a8d7742e | ||
|
|
32e84d2316 | ||
|
|
151b86cb7b | ||
|
|
e4c9bebe34 | ||
|
|
8d5cb00bec | ||
|
|
15530a4820 | ||
|
|
f6e56b345d | ||
|
|
56d61eb44f | ||
|
|
2103da7b9d | ||
|
|
679069729c | ||
|
|
f764448ccc | ||
|
|
e1828696f7 | ||
|
|
5b87380749 | ||
|
|
917d0dfc49 | ||
|
|
191839f764 | ||
|
|
316cf057f3 | ||
|
|
55be212594 | ||
|
|
489e63f8e7 | ||
|
|
62c081dc85 | ||
|
|
023ad9ddf8 | ||
|
|
eccf486162 | ||
|
|
a6da46a00e | ||
|
|
747d2c97cd | ||
|
|
af2969dec5 | ||
|
|
53dba8678c | ||
|
|
afdac9b413 | ||
|
|
1ad280db98 | ||
|
|
035c3ad319 | ||
|
|
c237a1c0d2 | ||
|
|
f1d093548e | ||
|
|
beab74adf5 | ||
|
|
2a49e8a931 | ||
|
|
395857c37c | ||
|
|
9a34f25edc | ||
|
|
0af02fb9ae | ||
|
|
dcff8794ad | ||
|
|
1b4f5b13f1 | ||
|
|
3950818030 | ||
|
|
d6da2ef096 | ||
|
|
455298d736 | ||
|
|
d99856c52b | ||
|
|
087ec11e6a | ||
|
|
00c0a84e4e | ||
|
|
be229b1ac6 | ||
|
|
8106981bb6 | ||
|
|
de4d7cd10d | ||
|
|
804dcac12f | ||
|
|
fb0987b824 | ||
|
|
88f50a66ff | ||
|
|
7be600d8e9 | ||
|
|
11d6b8029f | ||
|
|
f1d4c01190 | ||
|
|
c12d93e77f | ||
|
|
204130a598 | ||
|
|
dbd45d4173 | ||
|
|
7e0bfbbad2 | ||
|
|
db18e1480e | ||
|
|
9baa27508a | ||
|
|
c3267def97 | ||
|
|
390927772e | ||
|
|
a8bec4ec9c | ||
|
|
167e283450 | ||
|
|
0c3254fd48 | ||
|
|
0faf2f0461 | ||
|
|
dd6e42aacc | ||
|
|
18e5e9dcc5 | ||
|
|
c8f44ab460 | ||
|
|
ac1f9c790a | ||
|
|
7533996fac | ||
|
|
1721571012 | ||
|
|
4358a04730 | ||
|
|
c552d912a0 | ||
|
|
ad7ce085f7 | ||
|
|
828edb3a43 | ||
|
|
4cb64580fd | ||
|
|
5b2fa128a4 | ||
|
|
b7abb64661 | ||
|
|
66424b7ed5 | ||
|
|
81dafb7b3f | ||
|
|
cea81c2dc1 | ||
|
|
4b1e99ef93 | ||
|
|
83120a5bea | ||
|
|
20723896e1 | ||
|
|
aed4859642 | ||
|
|
d0ade1d190 | ||
|
|
fb8e35bb44 | ||
|
|
ce351f5c38 | ||
|
|
26ee1c4547 | ||
|
|
bf327f3916 | ||
|
|
e3dd6d8c88 | ||
|
|
137fe12c43 | ||
|
|
a2fed200fe | ||
|
|
efeeef214b | ||
|
|
37617c67f8 | ||
|
|
56f675f188 | ||
|
|
7e7dc7694c | ||
|
|
8cf8da5776 | ||
|
|
b59705bed4 | ||
|
|
3b909253bb | ||
|
|
98f90340f3 | ||
|
|
a4c9bf7d30 | ||
|
|
f459eaa5ea | ||
|
|
8d8b874c20 | ||
|
|
ccceaeaca2 | ||
|
|
076e93184b | ||
|
|
c352b296da | ||
|
|
9e04eec9dd | ||
|
|
0e19f88a04 | ||
|
|
e788e8fa0f | ||
|
|
a56c406aa3 | ||
|
|
a3457d9408 | ||
|
|
b69fed18e2 | ||
|
|
2964aea447 | ||
|
|
587488a1b1 | ||
|
|
623b394c83 | ||
|
|
e671ffdab1 | ||
|
|
92d1080b2f | ||
|
|
893c0e9b67 | ||
|
|
af60f71ea3 | ||
|
|
9a952f1004 | ||
|
|
3ec7dfff8b | ||
|
|
d30a5e0388 | ||
|
|
fcece7e189 | ||
|
|
3949d9633c | ||
|
|
62c1c5f38b | ||
|
|
56204c5748 | ||
|
|
34c163be88 | ||
|
|
11002d4a56 | ||
|
|
240f27ce97 | ||
|
|
5295be1c25 | ||
|
|
238a67af3a | ||
|
|
4382234676 | ||
|
|
8e5c93a31f | ||
|
|
0e5d72dc5d | ||
|
|
4b8069f5ec | ||
|
|
a816a48416 | ||
|
|
5415440829 | ||
|
|
9668272b80 | ||
|
|
15e19489e3 | ||
|
|
2083f683ad | ||
|
|
c3610aa43c | ||
|
|
df4fbc272a | ||
|
|
9698a995fb | ||
|
|
c1ac3aa483 | ||
|
|
311bdbd360 | ||
|
|
291f111913 | ||
|
|
95e10bdb9e | ||
|
|
c2a6dcb6bd | ||
|
|
61c4bb9888 | ||
|
|
3439746645 | ||
|
|
b10fe465ab | ||
|
|
c6b171ba95 | ||
|
|
5a17d6cd5f | ||
|
|
480af2644c | ||
|
|
ecd2e06883 | ||
|
|
4f3ae23170 | ||
|
|
7cfb33d0ef | ||
|
|
9224ab1592 | ||
|
|
a696ff37f1 | ||
|
|
931a996dab | ||
|
|
68c03090a3 | ||
|
|
98fe46757f | ||
|
|
cefd137634 | ||
|
|
6b6e887c2f | ||
|
|
20cd4f806a | ||
|
|
b92303b1c9 | ||
|
|
59d23e05b1 | ||
|
|
731a36d3a0 | ||
|
|
162fc0720e | ||
|
|
342bbaa3ae | ||
|
|
f086ef5cad | ||
|
|
56a3ee5fe6 | ||
|
|
d80d532a2a | ||
|
|
3aca14d530 | ||
|
|
aa2d3962bf | ||
|
|
f7c717e393 | ||
|
|
268fea58ee | ||
|
|
87cdc5ad1c | ||
|
|
ba140a8a84 | ||
|
|
27f1181d53 | ||
|
|
f953e6adb8 | ||
|
|
ffd14fe7d9 | ||
|
|
3206c2100d | ||
|
|
66fa12a091 | ||
|
|
b1bdf23d9c | ||
|
|
12bf07d560 | ||
|
|
132650df28 | ||
|
|
81a77949fc | ||
|
|
e597f98c62 | ||
|
|
7fbb2b195f | ||
|
|
1feaa7fed7 | ||
|
|
9b82ae19b0 | ||
|
|
9d3c13065b | ||
|
|
4859f8f759 | ||
|
|
ac284fd39c | ||
|
|
fdef0db87c | ||
|
|
e78db000c6 | ||
|
|
032ea8a8d3 | ||
|
|
fc63f66e89 | ||
|
|
832e626573 | ||
|
|
cc7d352209 | ||
|
|
ce5d9a2ee8 | ||
|
|
77c51d3ae7 | ||
|
|
53dae45430 | ||
|
|
16343ffe70 | ||
|
|
b37498d5f6 | ||
|
|
7ad16e5b0c | ||
|
|
9f41906895 | ||
|
|
2af8daff1d | ||
|
|
fbeb379f1b | ||
|
|
9577735ff7 | ||
|
|
2dcd50c11b | ||
|
|
862c223e11 | ||
|
|
7f4d5aeb0e | ||
|
|
30681eb772 | ||
|
|
52e575e1e7 | ||
|
|
890e12c306 | ||
|
|
6cbf6b7875 | ||
|
|
c255a84941 | ||
|
|
ce7d6d69d9 | ||
|
|
d5538b7076 | ||
|
|
cdfa13b265 | ||
|
|
e5efc91ef4 | ||
|
|
e31c911c30 | ||
|
|
a658ea1573 | ||
|
|
6d5b88d7b9 | ||
|
|
a986e72338 | ||
|
|
162d9b6c2e | ||
|
|
f7f49d27c5 | ||
|
|
9e3ccf4b3e | ||
|
|
6b71c2f392 | ||
|
|
0d313a3964 | ||
|
|
75a0a6752a | ||
|
|
363fc8deb5 | ||
|
|
ddac192c4a | ||
|
|
69a03c2e16 | ||
|
|
2b128b85f7 | ||
|
|
b09f973231 | ||
|
|
95815a558c | ||
|
|
879da03438 | ||
|
|
d022be547b | ||
|
|
3f83fdbfc1 | ||
|
|
949152532c | ||
|
|
215adab1f9 | ||
|
|
7ce46ed60c | ||
|
|
c32bcca67b | ||
|
|
cb442364ca | ||
|
|
6bdc01290d | ||
|
|
ac34bf1e54 | ||
|
|
6fb164d200 | ||
|
|
a5d300c6ff | ||
|
|
6eb4409a72 | ||
|
|
533677df8b | ||
|
|
8f27b2ab56 | ||
|
|
25be42d385 | ||
|
|
00f6d30e08 | ||
|
|
090822eb41 | ||
|
|
d9900a725d | ||
|
|
a10106c61a | ||
|
|
5cb01f2ae9 | ||
|
|
4c1efe7ad4 | ||
|
|
4be92f285a | ||
|
|
f9b89e98c2 | ||
|
|
be01ce03d0 | ||
|
|
f221441877 | ||
|
|
18fda7ec68 | ||
|
|
f2e8c00f49 | ||
|
|
30e8b818f5 | ||
|
|
525ce0e0ad | ||
|
|
3cd567dc95 | ||
|
|
2f7ffa3636 | ||
|
|
d99386ef1e | ||
|
|
9ae3d2c074 | ||
|
|
dd5a337a49 | ||
|
|
51e634ccb4 | ||
|
|
31b1a821ca | ||
|
|
bf13fd48ce | ||
|
|
3b99760a42 | ||
|
|
0e78dc35d8 | ||
|
|
c8bbdb23de | ||
|
|
7ee8117186 | ||
|
|
8237c41143 | ||
|
|
d52ca93ba6 | ||
|
|
8354651059 | ||
|
|
81cc3c260f | ||
|
|
4dc32e194b | ||
|
|
5a82dd5110 | ||
|
|
f20708a5e7 | ||
|
|
91cf78f183 | ||
|
|
0cde8819cf | ||
|
|
07632b0eeb | ||
|
|
4a7f825cfe | ||
|
|
0b6b068097 | ||
|
|
4bc2051f44 | ||
|
|
623b2306ca | ||
|
|
34dde53506 | ||
|
|
7a09182446 | ||
|
|
233e513860 | ||
|
|
eb8cf56e8e | ||
|
|
12a27643db | ||
|
|
c6ccde0558 | ||
|
|
16e3ebd87b | ||
|
|
94c096dd5b | ||
|
|
2e3e4ec3b2 | ||
|
|
6e222c3938 | ||
|
|
3b3bd9b6c9 | ||
|
|
4e3331ba66 | ||
|
|
7caa96abcd | ||
|
|
b2776269cf | ||
|
|
b6c5a5fc9a | ||
|
|
94943a9a84 | ||
|
|
4c1942e3fe | ||
|
|
71e72f215d | ||
|
|
58cdfd86d0 | ||
|
|
dfa66b9dd4 | ||
|
|
d56ea25816 | ||
|
|
c91b272648 | ||
|
|
ca8bb75b40 | ||
|
|
36eab713a1 | ||
|
|
7133576fe9 | ||
|
|
effffcba1d | ||
|
|
404ce8bc3e | ||
|
|
a91bd095b0 | ||
|
|
fd6a1e5ed0 | ||
|
|
7d6ac87033 | ||
|
|
8aa813b862 | ||
|
|
95aa5c9f1c | ||
|
|
4319447cb5 | ||
|
|
50ea162251 | ||
|
|
9c239804d3 | ||
|
|
a7ccb9243d | ||
|
|
320e31bb10 | ||
|
|
8b55a16986 | ||
|
|
f9b8f9a45f | ||
|
|
41125ea1e2 | ||
|
|
73219bf2d2 | ||
|
|
d6eb723b7f | ||
|
|
993d73762c | ||
|
|
48b51c451a | ||
|
|
3d191d5884 | ||
|
|
955133f173 | ||
|
|
5054b714e2 | ||
|
|
c2cafb4b45 | ||
|
|
05868b541b | ||
|
|
67f474ef42 | ||
|
|
a40424e75c | ||
|
|
cd6c0e1de9 | ||
|
|
a99c8219bd | ||
|
|
a03fdaba39 | ||
|
|
92be0033a8 | ||
|
|
6f301576eb | ||
|
|
e2b3f76a10 | ||
|
|
b934c1be6a | ||
|
|
145b50a320 | ||
|
|
a33cdc9c7b | ||
|
|
62101e85ff | ||
|
|
0a3714e5e0 | ||
|
|
86a2830d75 | ||
|
|
b277202838 | ||
|
|
a4f6d9f6e7 | ||
|
|
9300e97d2b | ||
|
|
1d4aa44d3d | ||
|
|
3792f75281 | ||
|
|
b52fcb8aa9 | ||
|
|
a14c794255 | ||
|
|
aef96e95e8 | ||
|
|
f0da63a8ff | ||
|
|
cc860804f6 | ||
|
|
f38c460588 | ||
|
|
d8a19b5565 | ||
|
|
1c5b5e2ce6 | ||
|
|
9b9c59766f | ||
|
|
fc2a202afa | ||
|
|
4b4b71ff32 | ||
|
|
9358838dab | ||
|
|
2f24e42dc1 | ||
|
|
0c12aa163e | ||
|
|
a4d9f702e4 | ||
|
|
ec47274fbd | ||
|
|
efcedabee0 | ||
|
|
25a7b66296 | ||
|
|
ac194cd34f | ||
|
|
04ccb06e3f | ||
|
|
d31ee20ba5 | ||
|
|
9b25d45b93 | ||
|
|
eca05e6bad | ||
|
|
84bf20152b | ||
|
|
d51abdd73e | ||
|
|
200e9f1a8e | ||
|
|
7dc09b4019 | ||
|
|
dbb196a17e | ||
|
|
05a95c699f | ||
|
|
9ea8b2237a | ||
|
|
9c5e340fb8 | ||
|
|
e86c2e5970 | ||
|
|
67006add53 | ||
|
|
caeb86843d | ||
|
|
1571b26a65 | ||
|
|
0f15608175 | ||
|
|
705991e5b0 | ||
|
|
b636874bd9 | ||
|
|
965e4e9b19 | ||
|
|
af77977fda | ||
|
|
e74baf188f | ||
|
|
663a71255f | ||
|
|
bdf2f22f81 | ||
|
|
79aa3e159d | ||
|
|
95118398dd | ||
|
|
4d18a8e55f | ||
|
|
3bab41f138 | ||
|
|
a8330773ca | ||
|
|
4ca2305693 | ||
|
|
f577af0886 | ||
|
|
aab47bd453 | ||
|
|
445ddd89fb | ||
|
|
6f21a96238 | ||
|
|
c47bcb2f54 | ||
|
|
b0b628ffc2 | ||
|
|
428e1bc14d | ||
|
|
d66bb84924 | ||
|
|
4ce5123a12 | ||
|
|
4b4a2e9f9e | ||
|
|
58afd0b604 | ||
|
|
4352456129 | ||
|
|
bb141a70e8 | ||
|
|
ff260c03ca | ||
|
|
96a1192474 | ||
|
|
297f862ccc | ||
|
|
c052f40ef8 | ||
|
|
98246c0e35 | ||
|
|
8ac067da89 | ||
|
|
0ffb5d253a | ||
|
|
3a9898a6a6 | ||
|
|
693ec14df5 | ||
|
|
fa189b3234 | ||
|
|
3b27cd093b | ||
|
|
141bbfb051 | ||
|
|
663a919ed1 | ||
|
|
483babe3bc | ||
|
|
6abb9da88a | ||
|
|
b407641049 | ||
|
|
d5e8807756 | ||
|
|
7e9fdb3555 | ||
|
|
32e07c22d0 | ||
|
|
d427c52aac | ||
|
|
eb623a84d5 | ||
|
|
07290277ba | ||
|
|
743541218f | ||
|
|
94de0a7ce2 | ||
|
|
36e9fb292b | ||
|
|
2661e010d9 | ||
|
|
7687becfee | ||
|
|
1641f09dc9 | ||
|
|
b42faea2eb | ||
|
|
1505673393 | ||
|
|
635a6279a9 | ||
|
|
404d3e0959 | ||
|
|
f77b20bbca | ||
|
|
1d0a1664e6 | ||
|
|
410afbf9a1 | ||
|
|
aaddfa6f3a | ||
|
|
2d9a16e857 | ||
|
|
1dcba51092 | ||
|
|
7c63b30de1 | ||
|
|
c0eae1ad52 | ||
|
|
c012b98223 | ||
|
|
559493babd | ||
|
|
990ab2c7ef | ||
|
|
437003de29 | ||
|
|
629e05b7b1 | ||
|
|
22b1959333 | ||
|
|
e98f6ae570 | ||
|
|
0b5bf0c098 | ||
|
|
1deefa48ee | ||
|
|
97008305ff | ||
|
|
1a17083e8c | ||
|
|
b6664cc859 | ||
|
|
50c4aef873 | ||
|
|
cf42d31214 | ||
|
|
00caa1c0a0 | ||
|
|
93c8ba920a | ||
|
|
8702c04d39 | ||
|
|
e595c313a1 | ||
|
|
955da2e360 | ||
|
|
04b3fc0268 | ||
|
|
105ccc81a5 | ||
|
|
c349892c5b | ||
|
|
3d4b8ce99b | ||
|
|
3571307df5 | ||
|
|
64fd87134f | ||
|
|
82bba44538 | ||
|
|
df05f3a3c0 | ||
|
|
8e31ef7be6 | ||
|
|
f4555f7c96 | ||
|
|
8408da55ea | ||
|
|
4a67dd2e28 | ||
|
|
bd806a34d8 | ||
|
|
2f7e833a79 | ||
|
|
c17503ab78 | ||
|
|
19f76d34db | ||
|
|
25c8b2fabb | ||
|
|
bfd8bf9ca4 | ||
|
|
e6adbb0e42 | ||
|
|
11fc6be328 | ||
|
|
7a5405d2ab | ||
|
|
b9a24f00ad | ||
|
|
dbfc292353 | ||
|
|
a09255b2ff | ||
|
|
9d1c72cc07 | ||
|
|
09ac30ef2e | ||
|
|
0ec8f5d283 | ||
|
|
b872df0f31 | ||
|
|
0add4af208 | ||
|
|
298cd9e065 | ||
|
|
b715d20385 | ||
|
|
79e313a0c0 | ||
|
|
9f4c75d1c2 | ||
|
|
b37492644c | ||
|
|
04a792a8c2 | ||
|
|
35ec24c3f0 | ||
|
|
9a00ccdacc | ||
|
|
61b23677d1 | ||
|
|
90037dc6cd | ||
|
|
e8d48e1f43 | ||
|
|
a2f8c9c75b | ||
|
|
5fb83e7f52 | ||
|
|
dd6bf568d1 | ||
|
|
00ee164cef | ||
|
|
448071b02d | ||
|
|
4dad9d0e37 | ||
|
|
3a2117c5d3 | ||
|
|
26a3f6ddc3 | ||
|
|
7741312673 | ||
|
|
954a1723f1 | ||
|
|
87285d94f7 | ||
|
|
d260d0c182 | ||
|
|
137eb40fab | ||
|
|
af440460e1 | ||
|
|
a5c8472a37 | ||
|
|
dfae37421d | ||
|
|
438a8d8b75 | ||
|
|
ac2034561d | ||
|
|
c42cd4233d | ||
|
|
5b2a73e3eb | ||
|
|
6f163a6ba5 | ||
|
|
cc94cc7d01 | ||
|
|
94934ae2cf | ||
|
|
e361f88501 | ||
|
|
708c042b61 | ||
|
|
600599f49e | ||
|
|
1fe7bbbbc4 | ||
|
|
f83d7a7cd1 | ||
|
|
7094047b3d | ||
|
|
11d3607688 | ||
|
|
fcae58d355 | ||
|
|
ef9ace9e65 | ||
|
|
22e4039133 | ||
|
|
4971670e56 | ||
|
|
e16cab6b9c | ||
|
|
a643c3dba6 | ||
|
|
51abf5b0a6 | ||
|
|
1cee6e309b | ||
|
|
0777a660bf | ||
|
|
5e0479e414 | ||
|
|
942c77816d | ||
|
|
8e260d5c40 | ||
|
|
7951eee8a3 | ||
|
|
be2f7d7a8a | ||
|
|
59c8e8b46e | ||
|
|
98c8b28bf3 | ||
|
|
7bb5bc01b7 | ||
|
|
1482c07ae4 | ||
|
|
adba84ae6a | ||
|
|
146e296826 | ||
|
|
28c10dba09 | ||
|
|
e646a0840d | ||
|
|
74ea6bf00a | ||
|
|
d7ad784809 | ||
|
|
642bd10dcc | ||
|
|
7c566c36f4 | ||
|
|
dbbe038939 | ||
|
|
e3430a916c | ||
|
|
ea1f041e11 | ||
|
|
0fe6d9f367 | ||
|
|
46e7359372 | ||
|
|
41cace9a96 | ||
|
|
4638331cb4 | ||
|
|
e339a7583c | ||
|
|
0b7570c9ee | ||
|
|
a85acfcfc5 | ||
|
|
3d4ccbec23 | ||
|
|
2f66ec60db | ||
|
|
f1cfe2b07b | ||
|
|
6160ca6e30 | ||
|
|
b621c3e4c4 | ||
|
|
64d2ae9ad4 | ||
|
|
39fc45b8d8 | ||
|
|
fd954adc81 | ||
|
|
8b379cbf56 | ||
|
|
59c0b04602 | ||
|
|
11b3cf3bfd | ||
|
|
9254f5a8a5 | ||
|
|
e5b68f4a3c | ||
|
|
95babc01e3 | ||
|
|
4dd792a49f | ||
|
|
207c50e500 | ||
|
|
763e34e861 | ||
|
|
b895a0c335 | ||
|
|
c5767eb545 | ||
|
|
94fb79c17f | ||
|
|
6856b02aa7 | ||
|
|
04f812c136 | ||
|
|
8783cf03b2 | ||
|
|
4e1156e083 | ||
|
|
1d6e1d416b | ||
|
|
fd02e5a07e | ||
|
|
937056fcaf | ||
|
|
41ed18684d | ||
|
|
96d4a22215 |
94
.gitattributes
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
* text eol=lf
|
||||
|
||||
# source code
|
||||
*.php text
|
||||
*.css text
|
||||
*.sass text
|
||||
*.scss text
|
||||
*.less text
|
||||
*.styl text
|
||||
*.js text
|
||||
*.coffee text
|
||||
*.json text
|
||||
*.htm text
|
||||
*.html text
|
||||
*.xml text
|
||||
*.svg text
|
||||
*.txt text
|
||||
*.ini text
|
||||
*.inc text
|
||||
*.pl text
|
||||
*.rb text
|
||||
*.py text
|
||||
*.scm text
|
||||
*.sql text
|
||||
*.sh text
|
||||
*.bat text
|
||||
|
||||
# templates
|
||||
*.ejs text
|
||||
*.hbt text
|
||||
*.jade text
|
||||
*.haml text
|
||||
*.hbs text
|
||||
*.dot text
|
||||
*.tmpl text
|
||||
*.phtml text
|
||||
|
||||
# server config
|
||||
.htaccess text
|
||||
|
||||
# git config
|
||||
.gitattributes text
|
||||
.gitignore text
|
||||
.gitconfig text
|
||||
|
||||
# code analysis config
|
||||
.jshintrc text
|
||||
.jscsrc text
|
||||
.jshintignore text
|
||||
.csslintrc text
|
||||
|
||||
# misc config
|
||||
*.yaml text
|
||||
*.yml text
|
||||
.editorconfig text
|
||||
|
||||
# build config
|
||||
*.npmignore text
|
||||
*.bowerrc text
|
||||
|
||||
# Heroku
|
||||
Procfile text
|
||||
.slugignore text
|
||||
|
||||
# Documentation
|
||||
*.md text
|
||||
LICENSE text
|
||||
AUTHORS text
|
||||
|
||||
|
||||
#
|
||||
## These files are binary and should be left untouched
|
||||
#
|
||||
|
||||
# (binary is a macro for -text -diff)
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.jpeg binary
|
||||
*.gif binary
|
||||
*.ico binary
|
||||
*.mov binary
|
||||
*.mp4 binary
|
||||
*.mp3 binary
|
||||
*.flv binary
|
||||
*.fla binary
|
||||
*.swf binary
|
||||
*.gz binary
|
||||
*.zip binary
|
||||
*.7z binary
|
||||
*.ttf binary
|
||||
*.eot binary
|
||||
*.woff binary
|
||||
*.pyc binary
|
||||
*.pdf binary
|
||||
122
.gitignore
vendored
@@ -2,23 +2,29 @@
|
||||
default.properties
|
||||
gen
|
||||
assets/www/cordova.js
|
||||
framework/assets/www/.tmp*
|
||||
local.properties
|
||||
framework/lib
|
||||
proguard.cfg
|
||||
proguard.cfg
|
||||
proguard-project.txt
|
||||
framework/bin
|
||||
framework/test/org/apache/cordova/*.class
|
||||
framework/assets/www/.DS_Store
|
||||
framework/assets/www/cordova-*.js
|
||||
framework/assets/www/phonegap-*.js
|
||||
framework/libs
|
||||
test/libs
|
||||
/framework/lib
|
||||
/framework/build
|
||||
/framework/bin
|
||||
/framework/assets/www/.DS_Store
|
||||
/framework/assets/www/cordova-*.js
|
||||
/framework/assets/www/phonegap-*.js
|
||||
/framework/libs
|
||||
/framework/javadoc-public
|
||||
/framework/javadoc-private
|
||||
/test/libs
|
||||
example
|
||||
./test
|
||||
test/bin
|
||||
test/assets/www/.tmp*
|
||||
/test/bin
|
||||
/test/assets/www/.tmp*
|
||||
/test/assets/www/cordova.js
|
||||
/test/gradle
|
||||
/test/gradlew
|
||||
/test/gradlew.bat
|
||||
/test/build
|
||||
.gradle
|
||||
tmp/**
|
||||
.metadata
|
||||
tmp/**/*
|
||||
@@ -29,6 +35,98 @@ Desktop.ini
|
||||
*.swp
|
||||
*.class
|
||||
*.jar
|
||||
!/spec/fixtures/org.test.plugins.dummyplugin/src/android/TestLib.jar
|
||||
# IntelliJ IDEA files
|
||||
*.iml
|
||||
.idea
|
||||
npm-debug.log
|
||||
/framework/build
|
||||
node_modules/jshint
|
||||
node_modules/promise-matchers
|
||||
node_modules/jasmine-node
|
||||
node_modules/rewire
|
||||
node_modules/istanbul
|
||||
node_modules/.bin/cake
|
||||
node_modules/.bin/coffee
|
||||
node_modules/.bin/escodegen
|
||||
node_modules/.bin/esgenerate
|
||||
node_modules/.bin/esparse
|
||||
node_modules/.bin/esvalidate
|
||||
node_modules/.bin/handlebars
|
||||
node_modules/.bin/istanbul
|
||||
node_modules/.bin/jasmine-node
|
||||
node_modules/.bin/js-yaml
|
||||
node_modules/.bin/jshint
|
||||
node_modules/.bin/mkdirp
|
||||
node_modules/.bin/r.js
|
||||
node_modules/.bin/r_js
|
||||
node_modules/.bin/strip-json-comments
|
||||
node_modules/.bin/uglifyjs
|
||||
node_modules/.bin/which
|
||||
node_modules/align-text/
|
||||
node_modules/amdefine/
|
||||
node_modules/argparse/
|
||||
node_modules/async/
|
||||
node_modules/camelcase/
|
||||
node_modules/center-align/
|
||||
node_modules/cli/
|
||||
node_modules/cliui/
|
||||
node_modules/coffee-script/
|
||||
node_modules/console-browserify/
|
||||
node_modules/core-util-is/
|
||||
node_modules/date-now/
|
||||
node_modules/decamelize/
|
||||
node_modules/deep-is/
|
||||
node_modules/dom-serializer/
|
||||
node_modules/domelementtype/
|
||||
node_modules/domhandler/
|
||||
node_modules/domutils/
|
||||
node_modules/entities/
|
||||
node_modules/escodegen/
|
||||
node_modules/esprima/
|
||||
node_modules/estraverse/
|
||||
node_modules/esutils/
|
||||
node_modules/exit/
|
||||
node_modules/fast-levenshtein/
|
||||
node_modules/fileset/
|
||||
node_modules/gaze/
|
||||
node_modules/growl/
|
||||
node_modules/handlebars/
|
||||
node_modules/has-flag/
|
||||
node_modules/htmlparser2/
|
||||
node_modules/is-buffer/
|
||||
node_modules/isarray/
|
||||
node_modules/isexe/
|
||||
node_modules/jasmine-growl-reporter/
|
||||
node_modules/jasmine-reporters/
|
||||
node_modules/js-yaml/
|
||||
node_modules/kind-of/
|
||||
node_modules/lazy-cache/
|
||||
node_modules/levn/
|
||||
node_modules/longest/
|
||||
node_modules/lru-cache/
|
||||
node_modules/minimist/
|
||||
node_modules/mkdirp/
|
||||
node_modules/optimist/
|
||||
node_modules/optionator/
|
||||
node_modules/prelude-ls/
|
||||
node_modules/readable-stream/
|
||||
node_modules/repeat-string/
|
||||
node_modules/requirejs/
|
||||
node_modules/resolve/
|
||||
node_modules/right-align/
|
||||
node_modules/sigmund/
|
||||
node_modules/source-map/
|
||||
node_modules/sprintf-js/
|
||||
node_modules/string_decoder/
|
||||
node_modules/strip-json-comments/
|
||||
node_modules/supports-color/
|
||||
node_modules/type-check/
|
||||
node_modules/uglify-js/
|
||||
node_modules/uglify-to-browserify/
|
||||
node_modules/walkdir/
|
||||
node_modules/which/
|
||||
node_modules/window-size/
|
||||
node_modules/wordwrap/
|
||||
node_modules/yargs/
|
||||
/coverage
|
||||
|
||||
3
.jshintignore
Normal file
@@ -0,0 +1,3 @@
|
||||
bin/node_modules/*
|
||||
bin/templates/project/*
|
||||
spec/fixtures/*
|
||||
10
.jshintrc
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"node": true
|
||||
, "bitwise": true
|
||||
, "undef": true
|
||||
, "trailing": true
|
||||
, "quotmark": true
|
||||
, "indent": 4
|
||||
, "unused": "vars"
|
||||
, "latedef": "nofunc"
|
||||
}
|
||||
6
.ratignore
Normal file
@@ -0,0 +1,6 @@
|
||||
*.properties
|
||||
bin
|
||||
gen
|
||||
proguard-project.txt
|
||||
spec
|
||||
appveyor.yml
|
||||
12
.travis.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
language: android
|
||||
sudo: false
|
||||
install:
|
||||
- npm install
|
||||
- npm install -g codecov
|
||||
- echo y | android update sdk -u --filter android-22,android-23
|
||||
script:
|
||||
- npm run jshint
|
||||
- npm run cover
|
||||
- npm run test-build
|
||||
after_script:
|
||||
- codecov
|
||||
38
CONTRIBUTING.md
Normal file
@@ -0,0 +1,38 @@
|
||||
<!--
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
#
|
||||
-->
|
||||
|
||||
# Contributing to Apache Cordova
|
||||
|
||||
Anyone can contribute to Cordova. And we need your contributions.
|
||||
|
||||
There are multiple ways to contribute: report bugs, improve the docs, and
|
||||
contribute code.
|
||||
|
||||
For instructions on this, start with the
|
||||
[contribution overview](http://cordova.apache.org/contribute/).
|
||||
|
||||
The details are explained there, but the important items are:
|
||||
- Sign and submit an Apache ICLA (Contributor License Agreement).
|
||||
- Have a Jira issue open that corresponds to your contribution.
|
||||
- Run the tests so your patch doesn't break existing functionality.
|
||||
|
||||
We look forward to your contributions!
|
||||
|
||||
116
LICENSE
@@ -187,7 +187,7 @@
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
Copyright 2015 Apache Cordova
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -199,4 +199,116 @@
|
||||
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.
|
||||
limitations under the License.
|
||||
|
||||
ADDITIONAL LICENSES:
|
||||
|
||||
================================================================================
|
||||
bin/node_modules/q
|
||||
================================================================================
|
||||
|
||||
Copyright 2009–2012 Kristopher Michael Kowal. All rights reserved.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
|
||||
================================================================================
|
||||
bin/node_modules/shelljs
|
||||
================================================================================
|
||||
Copyright (c) 2012, Artur Adib <aadib@mozilla.com>
|
||||
All rights reserved.
|
||||
|
||||
You may use this project under the terms of the New BSD license as follows:
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Artur Adib nor the
|
||||
names of the contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL ARTUR ADIB BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
================================================================================
|
||||
bin/node_modules/nopt
|
||||
================================================================================
|
||||
Copyright 2009, 2010, 2011 Isaac Z. Schlueter.
|
||||
All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
================================================================================
|
||||
bin/node_modules/which
|
||||
================================================================================
|
||||
|
||||
Copyright 2009, 2010, 2011 Isaac Z. Schlueter.
|
||||
All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
|
||||
6
NOTICE
@@ -1,5 +1,5 @@
|
||||
Apache Cordova
|
||||
Copyright 2012 The Apache Software Foundation
|
||||
Copyright 2015 The Apache Software Foundation
|
||||
|
||||
This product includes software developed at
|
||||
The Apache Software Foundation (http://www.apache.org)
|
||||
@@ -10,8 +10,6 @@ The Apache Software Foundation (http://www.apache.org)
|
||||
== in this case for the Android-specific code. ==
|
||||
=========================================================================
|
||||
|
||||
Android Code
|
||||
Copyright 2005-2008 The Android Open Source Project
|
||||
|
||||
This product includes software developed as part of
|
||||
The Android Open Source Project (http://source.android.com).
|
||||
|
||||
|
||||
73
README.md
Executable file → Normal file
@@ -7,9 +7,9 @@
|
||||
# to you 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
|
||||
@@ -18,74 +18,47 @@
|
||||
# under the License.
|
||||
#
|
||||
-->
|
||||
Cordova Android
|
||||
===
|
||||
|
||||
[](https://ci.appveyor.com/project/Humbedooh/cordova-android)
|
||||
[](https://travis-ci.org/apache/cordova-android)
|
||||
[](https://codecov.io/github/apache/cordova-android?branch=master)
|
||||
|
||||
# Cordova Android
|
||||
|
||||
Cordova Android is an Android application library that allows for Cordova-based
|
||||
projects to be built for the Android Platform. Cordova based applications are,
|
||||
at the core, applications written with web technology: HTML, CSS and JavaScript.
|
||||
at the core, applications written with web technology: HTML, CSS and JavaScript.
|
||||
|
||||
[Apache Cordova](http://cordova.io) is a project at The Apache Software Foundation (ASF).
|
||||
[Apache Cordova](https://cordova.apache.org) is a project of The Apache Software Foundation (ASF).
|
||||
|
||||
:warning: Report issues on the [Apache Cordova issue tracker](https://issues.apache.org/jira/issues/?jql=project%20%3D%20CB%20AND%20status%20in%20%28Open%2C%20%22In%20Progress%22%2C%20Reopened%29%20AND%20resolution%20%3D%20Unresolved%20AND%20component%20%3D%20%22Android%22%20ORDER%20BY%20priority%20DESC%2C%20summary%20ASC%2C%20updatedDate%20DESC)
|
||||
|
||||
|
||||
Requires
|
||||
---
|
||||
## Requires
|
||||
|
||||
- Java JDK 1.5 or greater
|
||||
- Apache ANT 1.8.0 or greater
|
||||
- Java JDK 1.6 or greater
|
||||
- Android SDK [http://developer.android.com](http://developer.android.com)
|
||||
|
||||
|
||||
Cordova Android Developer Tools
|
||||
---
|
||||
|
||||
The Cordova developer tooling is split between general tooling and project level tooling.
|
||||
## Cordova Android Developer Tools
|
||||
|
||||
General Commands
|
||||
We recommend using the [Cordova command-line tool](https://www.npmjs.com/package/cordova) to create projects and be able to easily install plugins.
|
||||
|
||||
./bin/create [path package activity] ... create the ./example app or a cordova android project
|
||||
However, the following scripts can be used instead:
|
||||
|
||||
./bin/create [path package activity] ... creates the ./example app or a cordova android project
|
||||
./bin/check_reqs ....................... checks that your environment is set up for cordova-android development
|
||||
./bin/update [path] .................... updates an existing cordova-android project to the version of the framework
|
||||
|
||||
Project Commands
|
||||
|
||||
These commands live in a generated Cordova Android project. Any interactions with the emulator require you to have an AVD defined.
|
||||
|
||||
./cordova/clean ........................ cleans the project
|
||||
./cordova/build ........................ calls `clean` then compiles the project
|
||||
./cordova/log ........................ stream device or emulate logs to stdout
|
||||
./cordova/log ........................ streams device or emulator logs to STDOUT
|
||||
./cordova/run ........................ calls `build` then deploys to a connected Android device. If no Android device is detected, will launch an emulator and deploy to it.
|
||||
./cordova/version ...................... returns the cordova-android version of the current project
|
||||
|
||||
Importing a Cordova Android Project into Eclipse
|
||||
----
|
||||
## Using Android Studio
|
||||
|
||||
1. File > New > Project...
|
||||
2. Android > Android Project
|
||||
3. Create project from existing source (point to the generated app found in tmp/android)
|
||||
4. Right click on libs/cordova.jar and add to build path
|
||||
5. Right click on the project root: Run as > Run Configurations
|
||||
6. Click on the Target tab and select Manual (this way you can choose the emulator or device to build to)
|
||||
|
||||
Building without the Tooling
|
||||
---
|
||||
Note: The Developer Tools handle this. This is only to be done if the tooling fails, or if
|
||||
you are developing directly against the framework.
|
||||
|
||||
|
||||
To create your `cordova.jar` file, run in the framework directory:
|
||||
|
||||
android update project -p . -t android-18
|
||||
ant jar
|
||||
|
||||
|
||||
Running Tests
|
||||
----
|
||||
Please see details under test/README.md.
|
||||
|
||||
Further Reading
|
||||
---
|
||||
|
||||
- [http://developer.android.com](http://developer.android.com)
|
||||
- [http://cordova.apache.org/](http://cordova.apache.org)
|
||||
- [http://wiki.apache.org/cordova/](http://wiki.apache.org/cordova/)
|
||||
1. Create a project
|
||||
2. Import it via "Non-Android Studio Project"
|
||||
|
||||
504
RELEASENOTES.md
@@ -7,9 +7,9 @@
|
||||
# to you 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
|
||||
@@ -20,33 +20,499 @@
|
||||
-->
|
||||
## Release Notes for Cordova (Android) ##
|
||||
|
||||
### 5.2.1 (Jul 11, 2016)
|
||||
* [CB-9489](https://issues.apache.org/jira/browse/CB-9489) Fixed "endless waiting for emulator" issue
|
||||
* [CB-11481](https://issues.apache.org/jira/browse/CB-11481) android-library is deprecated use com.android.library instead
|
||||
|
||||
### 5.2.0 (Jun 29, 2016)
|
||||
* [CB-11383](https://issues.apache.org/jira/browse/CB-11383) Update to gradle for using `jcenter` and correct Application plugin
|
||||
* [CB-11365](https://issues.apache.org/jira/browse/CB-11365) fixed plugin rm issue with emit being `undefined`
|
||||
* [CB-11117](https://issues.apache.org/jira/browse/CB-11117) Use `FileUpdater` to optimize prepare for **android** platform
|
||||
* [CB-10096](https://issues.apache.org/jira/browse/CB-10096) Upgrade test project to `Gradle Plugin 2.1.0`
|
||||
* [CB-11292](https://issues.apache.org/jira/browse/CB-11292) fix broken `MessageChannel` after plugins are recreated
|
||||
* [CB-11259](https://issues.apache.org/jira/browse/CB-11259) Improving build output
|
||||
* [CB-10096](https://issues.apache.org/jira/browse/CB-10096) Upgrading to `Gradle Plugin 2.1.0`
|
||||
* [CB-11198](https://issues.apache.org/jira/browse/CB-11198) Skip **android** target sdk check. This closes #303.
|
||||
* [CB-11138](https://issues.apache.org/jira/browse/CB-11138) Reuse `PluginManager` from `common` to add/rm plugins
|
||||
* [CB-11133](https://issues.apache.org/jira/browse/CB-11133) Handle **android** emulator start failure
|
||||
* [CB-11132](https://issues.apache.org/jira/browse/CB-11132) Fix Error: Cannot read property `match` of undefined in `cordova-android` `emulator.js`
|
||||
* Add simple log for package name being deployed
|
||||
* [CB-11015](https://issues.apache.org/jira/browse/CB-11015) Error adding plugin with gradle extras
|
||||
* [CB-11095](https://issues.apache.org/jira/browse/CB-11095) Fix plugin add/removal when running on `Node v.010`
|
||||
* [CB-11022](https://issues.apache.org/jira/browse/CB-11022) Duplicate www files to both destinations on plugin operations
|
||||
* [CB-10964](https://issues.apache.org/jira/browse/CB-10964) Handle `build.json` file starting with a BOM.
|
||||
* [CB-10963](https://issues.apache.org/jira/browse/CB-10963) Handle overlapping permission requests from plugins
|
||||
* [CB-8582](https://issues.apache.org/jira/browse/CB-8582) Obscure `INSTALL_FAILED_VERSION_DOWNGRADE` error when installing app
|
||||
* [CB-10862](https://issues.apache.org/jira/browse/CB-10862) Cannot set `minsdkversion`
|
||||
* [CB-10896](https://issues.apache.org/jira/browse/CB-10896) We never enabled cookies on the `WebView` proper
|
||||
* [CB-10837](https://issues.apache.org/jira/browse/CB-10837) Support platform-specific orientation on **Android**
|
||||
* [CB-10600](https://issues.apache.org/jira/browse/CB-10600) `cordova run android --release` does not use signed and zip-aligned version of `APK`
|
||||
* [CB-9710](https://issues.apache.org/jira/browse/CB-9710) Fixing issues parsing `android avd list` output for certain AVDs which resulted in them not being included in the selection process even if they are the best match.
|
||||
* [CB-10888](https://issues.apache.org/jira/browse/CB-10888) Enable coverage reports collection via codecov
|
||||
* [CB-10846](https://issues.apache.org/jira/browse/CB-10846) Add Travis and AppVeyor badges to readme
|
||||
* [CB-10846](https://issues.apache.org/jira/browse/CB-10846) Add AppVeyor configuration
|
||||
* [CB-10749](https://issues.apache.org/jira/browse/CB-10749) Use `cordova-common.CordovaLogger` in `cordova-android`
|
||||
* [CB-10673](https://issues.apache.org/jira/browse/CB-10673) fixed conflicting plugin install issue with overlapped `<source-file>` tag. Add `--force` flag.
|
||||
* [CB-8976](https://issues.apache.org/jira/browse/CB-8976) Removing the auto-version for non-Crosswalk applications
|
||||
* [CB-10768](https://issues.apache.org/jira/browse/CB-10768) Use `cordova-common.superspawn` in `GradleBuilder`
|
||||
* [CB-10729](https://issues.apache.org/jira/browse/CB-10729) Move plugin handlers tests for into platform's repo
|
||||
* [CB-10669](https://issues.apache.org/jira/browse/CB-10669) `cordova run --list` cannot find `adb`
|
||||
* [CB-10660](https://issues.apache.org/jira/browse/CB-10660) fixed the exception when removing a non-existing directory.
|
||||
|
||||
### 5.1.1 (Feb 24, 2016)
|
||||
* updated `cordova-common` dependnecy to `1.1.0`
|
||||
* [CB-10628](https://issues.apache.org/jira/browse/CB-10628) Fix `emulate android --target`
|
||||
* [CB-10618](https://issues.apache.org/jira/browse/CB-10618) Handle gradle frameworks on plugin installation/uninstallation
|
||||
* [CB-10510](https://issues.apache.org/jira/browse/CB-10510) Add an optional timeout to `emu` start script
|
||||
* [CB-10498](https://issues.apache.org/jira/browse/CB-10498) Resume event should be sticky if it has a plugin result
|
||||
* fix `HtmlNotFoundTest` so that it passes when file not found is handled correctly
|
||||
* [CB-10472](https://issues.apache.org/jira/browse/CB-10472) `NullPointerException`: `org.apache.cordova.PluginManager.onSaveInstanceState` check if `pluginManager` is `null` before using it
|
||||
* [CB-10138](https://issues.apache.org/jira/browse/CB-10138) Adds missing plugin metadata to `plugin_list` module.
|
||||
* [CB-10443](https://issues.apache.org/jira/browse/CB-10443) Pass original options instead of remaining
|
||||
* [CB-10443](https://issues.apache.org/jira/browse/CB-10443) Fix `this.root` null reference
|
||||
* [CB-10421](https://issues.apache.org/jira/browse/CB-10421) Fixes exception when calling run script with `--help` option
|
||||
* updated `.gitignore`
|
||||
* [CB-10406](https://issues.apache.org/jira/browse/CB-10406) Fixes an exception, thrown when building using Ant.
|
||||
* [CB-10157](https://issues.apache.org/jira/browse/CB-10157) Uninstall app from device/emulator only when signed apk is already installed
|
||||
|
||||
### 5.1.0 (Jan 19, 2016)
|
||||
* [CB-10386](https://issues.apache.org/jira/browse/CB-10386) Add `android.useDeprecatedNdk=true` to support `NDK` in `gradle`
|
||||
* [CB-8864](https://issues.apache.org/jira/browse/CB-8864) Fixing this to mitigate [CB-8685](https://issues.apache.org/jira/browse/CB-8685) and [CB-10104](https://issues.apache.org/jira/browse/CB-10104)
|
||||
* [CB-10105](https://issues.apache.org/jira/browse/CB-10105) Spot fix for tilde errors on paths.
|
||||
* Update theme to `Theme.DeviceDefault.NoActionBar`
|
||||
* [CB-10014](https://issues.apache.org/jira/browse/CB-10014) Set gradle `applicationId` to `package name`.
|
||||
* [CB-9949](https://issues.apache.org/jira/browse/CB-9949) Fixing menu button event not fired in **Android**
|
||||
* [CB-9479](https://issues.apache.org/jira/browse/CB-9479) Fixing the conditionals again, we should
|
||||
* [CB-8917](https://issues.apache.org/jira/browse/CB-8917) New Plugin API for passing results on resume after Activity destruction
|
||||
* [CB-9971](https://issues.apache.org/jira/browse/CB-9971) Suppress `gradlew _JAVA_OPTIONS` output during build
|
||||
* [CB-9836](https://issues.apache.org/jira/browse/CB-9836) Add `.gitattributes` to prevent `CRLF` line endings in repos
|
||||
* added node_modules back into `.gitignore`
|
||||
|
||||
### 5.0.0 (Nov 01, 2015)
|
||||
* Update CordovaWebViewEngine.java
|
||||
* [CB-9909](https://issues.apache.org/jira/browse/CB-9909) Shouldn't escape spaces in paths on Windows.
|
||||
* [CB-9870](https://issues.apache.org/jira/browse/CB-9870) updated hello world template
|
||||
* [CB-9880](https://issues.apache.org/jira/browse/CB-9880) Fixes platform update failure when upgrading from android@<4.1.0
|
||||
* [CB-9844](https://issues.apache.org/jira/browse/CB-9844) Remove old .java after renaming activity
|
||||
* [CB-9800](https://issues.apache.org/jira/browse/CB-9800) Fixing contribute link.
|
||||
* [CB-9782](https://issues.apache.org/jira/browse/CB-9782) Check in `cordova-common` dependency
|
||||
* Adds licence header to Adb to pass rat audit
|
||||
* [CB-9835](https://issues.apache.org/jira/browse/CB-9835) Downgrade `properties-parser` to prevent failures in Node < 4.x
|
||||
* [CB-9782](https://issues.apache.org/jira/browse/CB-9782) Implements PlatformApi contract for Android platform.
|
||||
* [CB-9826](https://issues.apache.org/jira/browse/CB-9826) Fixed `test-build` script on windows.
|
||||
* Refactor of the Cordova Plugin/Permissions API
|
||||
* Manually updating version to 5.0.0-dev for engine tags
|
||||
* Bump up to API level 23
|
||||
* Commiting code to handle permissions, and the special case of the Geolocation Plugin
|
||||
* [CB-9608](https://issues.apache.org/jira/browse/CB-9608) cordova-android no longer builds on Node 0.10 or below
|
||||
* [CB-9080](https://issues.apache.org/jira/browse/CB-9080) Cordova CLI run for Android versions 4.1.1 and lower throws error
|
||||
* [CB-9557](https://issues.apache.org/jira/browse/CB-9557) Fixes apk install failure when switching from debug to release build
|
||||
* [CB-9496](https://issues.apache.org/jira/browse/CB-9496) removed permissions added for crosswalk
|
||||
* [CB-9402](https://issues.apache.org/jira/browse/CB-9402) Allow to set gradle distubutionUrl via env variable CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL
|
||||
* [CB-9428](https://issues.apache.org/jira/browse/CB-9428) update script now bumps up minSdkVersion to 14 if it is less than that.
|
||||
* [CB-9430](https://issues.apache.org/jira/browse/CB-9430) Fixes check_reqs failure when javac returns an extra line
|
||||
* [CB-9172](https://issues.apache.org/jira/browse/CB-9172) Improved emulator deploy stability. This closes #188.
|
||||
* [CB-9404](https://issues.apache.org/jira/browse/CB-9404) Fixed an exception when path contained -debug or -release
|
||||
* [CB-8320](https://issues.apache.org/jira/browse/CB-8320) Setting up gradle so we can use CordovaLib as a standard Android Library
|
||||
* [CB-9185](https://issues.apache.org/jira/browse/CB-9185) Fixed an issue when unsigned apks couldn't be found.
|
||||
* [CB-9397](https://issues.apache.org/jira/browse/CB-9397) Fixes minor issues with `cordova requirements android`
|
||||
* [CB-9389](https://issues.apache.org/jira/browse/CB-9389) Fixes build/check_reqs hang
|
||||
|
||||
### Release 4.1.1 (Aug 2015) ###
|
||||
|
||||
* [CB-9428](https://issues.apache.org/jira/browse/CB-9428) update script now bumps up minSdkVersion to 14 if it is less than that
|
||||
* [CB-9430](https://issues.apache.org/jira/browse/CB-9430) Fixes check_reqs failure when javac returns an extra line
|
||||
|
||||
### Release 4.1.0 (Jul 2015) ###
|
||||
* [CB-9392](https://issues.apache.org/jira/browse/CB-9392) Fixed printing flavored versions. This closes #184.
|
||||
* [CB-9382](https://issues.apache.org/jira/browse/CB-9382) [Android] Fix KeepRunning setting when Plugin activity is showed. This closes #200
|
||||
* [CB-9391](https://issues.apache.org/jira/browse/CB-9391) Fixes cdvBuildMultipleApks option casting
|
||||
* [CB-9343](https://issues.apache.org/jira/browse/CB-9343) Split the Content-Type to obtain a clean mimetype
|
||||
* [CB-9255](https://issues.apache.org/jira/browse/CB-9255) Make getUriType case insensitive.
|
||||
* [CB-9149](https://issues.apache.org/jira/browse/CB-9149) Fixes JSHint issue introduced by 899daa9
|
||||
* [CB-9372](https://issues.apache.org/jira/browse/CB-9372) Remove unused files: 'main.js' & 'master.css'. This closes #198
|
||||
* [CB-9149](https://issues.apache.org/jira/browse/CB-9149) Make gradle alias subprojects in order to handle libs that depend on libs. This closes #182
|
||||
* Update min SDK version to 14
|
||||
* Update licenses. This closes #190
|
||||
* [CB-9185](https://issues.apache.org/jira/browse/CB-9185) Fix signed release build exception. This closes #193.
|
||||
* [CB-9286](https://issues.apache.org/jira/browse/CB-9286) Fixes build failure when ANDROID_HOME is not set.
|
||||
* [CB-9284](https://issues.apache.org/jira/browse/CB-9284) Fix for handling absolute path for keystore in build.json
|
||||
* [CB-9260](https://issues.apache.org/jira/browse/CB-9260) Install Android-22 on Travis-CI
|
||||
* Adding .ratignore file.
|
||||
* [CB-9119](https://issues.apache.org/jira/browse/CB-9119) Adding lib/retry.js for retrying promise-returning functions. Retrying 'adb install' in emulator.js because it sometimes hangs.
|
||||
* [CB-9115](https://issues.apache.org/jira/browse/CB-9115) android: Grant Lollipop permission req
|
||||
* Remove extra console message
|
||||
* [CB-8898](https://issues.apache.org/jira/browse/CB-8898) Report expected gradle location properly
|
||||
* [CB-8898](https://issues.apache.org/jira/browse/CB-8898) Fixes gradle check failure due to missing quotes
|
||||
* [CB-9080](https://issues.apache.org/jira/browse/CB-9080) -d option is not supported on Android 4.1.1 and lower, removing
|
||||
* [CB-8954](https://issues.apache.org/jira/browse/CB-8954) Adds `requirements` command support to check_reqs module
|
||||
* Update JS snapshot to version 4.1.0-dev (via coho)
|
||||
* [CB-8417](https://issues.apache.org/jira/browse/CB-8417) updated platform specific files from cordova.js repo
|
||||
* Adding tests to confirm that preferences aren't changed by Intents
|
||||
* Forgot to remove the method that copied over the intent data
|
||||
* Getting around to removing this old Intent code
|
||||
* Update JS snapshot to version 4.1.0-dev (via coho)
|
||||
* Fix CordovaPluginTest on KitKat (start-up events seem to change)
|
||||
* [CB-3360](https://issues.apache.org/jira/browse/CB-3360) Allow setting a custom User-Agent (close #162)
|
||||
* [CB-8902](https://issues.apache.org/jira/browse/CB-8902) Use immersive mode when available when going fullscreen (close #175)
|
||||
* Make BridgeMode methods public (they were always supposed to be)
|
||||
* Simplify: EncodingUtils.getBytes(str) -> str.getBytes()
|
||||
* Don't show warning when gradlew file is read-only
|
||||
* Don't show warning when prepEnv copies gradlew and it's read-only
|
||||
* Make gradle wrapper prepEnv code work even when android-sdk is read-only
|
||||
* [CB-8897](https://issues.apache.org/jira/browse/CB-8897) Delete drawable/icon.png since it duplicates drawable-mdpi/icon.png
|
||||
* Updating the template to target mininumSdkTarget=14
|
||||
* [CB-8894](https://issues.apache.org/jira/browse/CB-8894) Updating the template to target mininumSdkTarget=14
|
||||
* [CB-8891](https://issues.apache.org/jira/browse/CB-8891) Add a note about when the gradle helpers were added
|
||||
* [CB-8891](https://issues.apache.org/jira/browse/CB-8891) Add a gradle helper for retrieving config.xml preference values
|
||||
* [CB-8884](https://issues.apache.org/jira/browse/CB-8884) Delete Eclipse tweaks from create script
|
||||
* [CB-8834](https://issues.apache.org/jira/browse/CB-8834) Don't fail to install on VERSION_DOWNGRADE
|
||||
* Automated tools fail, and you have to remember all four places where this is set.
|
||||
* Update the package.json
|
||||
* [CB-9042](https://issues.apache.org/jira/browse/CB-9042) coho failed to update version, so here we are
|
||||
* CB9042 - Updating Release Notes
|
||||
* Adding tests to confirm that preferences aren't changed by Intents
|
||||
* updating existing test code
|
||||
* Forgot to remove the method that copied over the intent data
|
||||
* Getting around to removing this old Intent code
|
||||
* [CB-8834](https://issues.apache.org/jira/browse/CB-8834) Don't fail to install on VERSION_DOWNGRADE
|
||||
|
||||
### Release 4.0.2 (May 2015) ###
|
||||
|
||||
* Removed Intent Functionality from Preferences - Preferences can no longer be set by intents
|
||||
|
||||
### Release 4.0.1 (April 2015) ###
|
||||
|
||||
* Bug fixed where platform failed to install on a version downgrade
|
||||
|
||||
### Release 4.0.0 (March 2015) ###
|
||||
|
||||
This release adds significant functionality, and also introduces a number
|
||||
of breaking changes. Some of the changes to the code base will be of
|
||||
particular interest to plugin developers.
|
||||
|
||||
#### Major Changes ####
|
||||
* Support for pluggable WebViews
|
||||
* The system WebView can be replaced in your app, via a plugin
|
||||
* Core WebView functionality is encapsulated, with extension points exposed
|
||||
via interfaces
|
||||
* Support for Crosswalk to bring the modern Chromium WebView to older devices
|
||||
* Uses the pluggable WebView framework
|
||||
* You will need to add the new [cordova-crosswalk-engine](https://github.com/MobileChromeApps/cordova-crosswalk-engine) plugin
|
||||
* Splash screen functionality is now provided via plugin
|
||||
* You will need to add the new [cordova-plugin-splashscreen](https://github.com/apache/cordova-plugin-splashscreen) plugin to continue using a splash screen
|
||||
* Whitelist functionality is now provided via plugin (CB-7747)
|
||||
* The whitelist has been enhanced to be more secure and configurable
|
||||
* Setting of Content-Security-Policy is now supported by the framework (see details in plugin readme)
|
||||
* You will need to add the new [cordova-plugin-whitelist](https://github.com/apache/cordova-plugin-whitelist) plugin
|
||||
* Legacy whitelist behaviour is still available via plugin (although not recommended).
|
||||
|
||||
Changes For Plugin Developers:
|
||||
|
||||
* Develop in Android Studio
|
||||
* Android Studio is now fully supported, and recommended over Eclipse
|
||||
* Build using Gradle
|
||||
* All builds [use Gradle by default](Android%20Shell%20Tool%20Guide_building_with_gradle), instead of Ant
|
||||
* Plugins can add their own gradle build steps!
|
||||
* Plugins can depend on Maven libraries using `<framework>` tags
|
||||
* New APIs: `onStart`, `onStop`, `onConfigurationChanged`
|
||||
* `"onScrollChanged"` message removed. Use `view.getViewTreeObserver().addOnScrollChangedListener(...)` instead
|
||||
* [CB-8702](https://issues.apache.org/jira/browse/CB-8702) New API for plugins to override `shouldInterceptRequest` with a stream
|
||||
|
||||
#### Other Changes ####
|
||||
* [CB-8378](https://issues.apache.org/jira/browse/CB-8378) Removed `hidekeyboard` and `showkeyboard` events (apps should use a plugin instead)
|
||||
* [CB-8735](https://issues.apache.org/jira/browse/CB-8735) `bin/create` regex relaxed / better support for numbers
|
||||
* [CB-8699](https://issues.apache.org/jira/browse/CB-8699) Fix CordovaResourceApi `copyResource` creating zero-length files when src=uncompressed asset
|
||||
* [CB-8693](https://issues.apache.org/jira/browse/CB-8693) CordovaLib should not contain icons / splashscreens
|
||||
* [CB-8592](https://issues.apache.org/jira/browse/CB-8592) Fix NPE if lifecycle events reach CordovaWebView before `init()` has been called
|
||||
* [CB-8588](https://issues.apache.org/jira/browse/CB-8588) Add CATEGORY_BROWSABLE to intents from showWebPage openExternal=true
|
||||
* [CB-8587](https://issues.apache.org/jira/browse/CB-8587) Don't allow WebView navigations within showWebPage that are not whitelisted
|
||||
* [CB-7827](https://issues.apache.org/jira/browse/CB-7827) Add `--activity-name` for `bin/create`
|
||||
* [CB-8548](https://issues.apache.org/jira/browse/CB-8548) Use debug-signing.properties and release-signing.properties when they exist
|
||||
* [CB-8545](https://issues.apache.org/jira/browse/CB-8545) Don't add a layout as a parent of the WebView
|
||||
* [CB-7159](https://issues.apache.org/jira/browse/CB-7159) BackgroundColor not used when `<html style="opacity:0">`, nor during screen rotation
|
||||
* [CB-6630](https://issues.apache.org/jira/browse/CB-6630) Removed OkHttp from core library. It's now available as a plugin: [cordova-plugin-okhttp](https://www.npmjs.com/package/cordova-plugin-okhttp)
|
||||
|
||||
### Release 3.7.1 (January 2015) ###
|
||||
* [CB-8411](https://issues.apache.org/jira/browse/CB-8411) Initialize plugins only after `createViews()` is called (regression in 3.7.0)
|
||||
|
||||
### Release 3.7.0 (January 2015) ###
|
||||
|
||||
* [CB-8328](https://issues.apache.org/jira/browse/CB-8328) Allow plugins to handle certificate challenges (close #150)
|
||||
* [CB-8201](https://issues.apache.org/jira/browse/CB-8201) Add support for auth dialogs into Cordova Android
|
||||
* [CB-8017](https://issues.apache.org/jira/browse/CB-8017) Add support for `<input type=file>` for Lollipop
|
||||
* [CB-8143](https://issues.apache.org/jira/browse/CB-8143) Loads of gradle improvements (try it with cordova/build --gradle)
|
||||
* [CB-8329](https://issues.apache.org/jira/browse/CB-8329) Cancel outstanding ActivityResult requests when a new startActivityForResult occurs
|
||||
* [CB-8026](https://issues.apache.org/jira/browse/CB-8026) Bumping up Android Version and setting it up to allow third-party cookies. This might change later.
|
||||
* [CB-8210](https://issues.apache.org/jira/browse/CB-8210) Use PluginResult for various events from native so that content-security-policy <meta> can be used
|
||||
* [CB-8168](https://issues.apache.org/jira/browse/CB-8168) Add support for `cordova/run --list` (closes #139)
|
||||
* [CB-8176](https://issues.apache.org/jira/browse/CB-8176) Vastly better auto-detection of SDK & JDK locations
|
||||
* [CB-8079](https://issues.apache.org/jira/browse/CB-8079) Use activity class package name, but fallback to application package name when looking for splash screen drawable
|
||||
* [CB-8147](https://issues.apache.org/jira/browse/CB-8147) Have corodva/build warn about unrecognized flags rather than fail
|
||||
* [CB-7881](https://issues.apache.org/jira/browse/CB-7881) Android tooling shouldn't lock application directory
|
||||
* [CB-8112](https://issues.apache.org/jira/browse/CB-8112) Turn off mediaPlaybackRequiresUserGesture
|
||||
* [CB-6153](https://issues.apache.org/jira/browse/CB-6153) Add a preference for controlling hardware button audio stream (DefaultVolumeStream)
|
||||
* [CB-8031](https://issues.apache.org/jira/browse/CB-8031) Fix race condition that shows as ConcurrentModificationException
|
||||
* [CB-7974](https://issues.apache.org/jira/browse/CB-7974) Cancel timeout timer if view is destroyed
|
||||
* [CB-7940](https://issues.apache.org/jira/browse/CB-7940) Disable exec bridge if bridgeSecret is wrong
|
||||
* [CB-7758](https://issues.apache.org/jira/browse/CB-7758) Allow content-url-hosted pages to access the bridge
|
||||
* [CB-6511](https://issues.apache.org/jira/browse/CB-6511) Fixes build for android when app name contains unicode characters.
|
||||
* [CB-7707](https://issues.apache.org/jira/browse/CB-7707) Added multipart PluginResult
|
||||
* [CB-6837](https://issues.apache.org/jira/browse/CB-6837) Fix leaked window when hitting back button while alert being rendered
|
||||
* [CB-7674](https://issues.apache.org/jira/browse/CB-7674) Move preference activation back into onCreate()
|
||||
* [CB-7499](https://issues.apache.org/jira/browse/CB-7499) Support RTL text direction
|
||||
* [CB-7330](https://issues.apache.org/jira/browse/CB-7330) Don't run check_reqs for bin/create.
|
||||
|
||||
### 3.6.4 (Sept 30, 2014) ###
|
||||
|
||||
* Set VERSION to 3.6.4 (via coho)
|
||||
* Update JS snapshot to version 3.6.4 (via coho)
|
||||
* [CB-7634](https://issues.apache.org/jira/browse/CB-7634) Detect JAVA_HOME properly on Ubuntu
|
||||
* [CB-7579](https://issues.apache.org/jira/browse/CB-7579) Fix run script's ability to use non-arch-specific APKs
|
||||
* [CB-6511](https://issues.apache.org/jira/browse/CB-6511) Fixes build for android when app name contains unicode characters.
|
||||
* [CB-7463](https://issues.apache.org/jira/browse/CB-7463) Adding licences. I don't know what the gradle syntax is for comments, that still needs to be done.
|
||||
* [CB-7463](https://issues.apache.org/jira/browse/CB-7463) Looked at the Apache BigTop git, gradle uses C-style comments
|
||||
* [CB-7460](https://issues.apache.org/jira/browse/CB-7460) Fixing bug with KitKat where the background colour would override the CSS colours on the application
|
||||
|
||||
### 3.6.0 (Sept 2014) ###
|
||||
|
||||
* Set VERSION to 3.6.0 (via coho)
|
||||
* [CB-7410](https://issues.apache.org/jira/browse/CB-7410) fix the menu test
|
||||
* [CB-7410](https://issues.apache.org/jira/browse/CB-7410) Fix the errorUrl test
|
||||
* [CB-7410](https://issues.apache.org/jira/browse/CB-7410) Fix Basic Authentication test
|
||||
* [CB-3445](https://issues.apache.org/jira/browse/CB-3445) Allow build and run scripts to select APK by architecture
|
||||
* [CB-3445](https://issues.apache.org/jira/browse/CB-3445) Add environment variable 'BUILD_MULTIPLE_APKS' for splitting APKs based on architecture
|
||||
* [CB-3445](https://issues.apache.org/jira/browse/CB-3445) Ensure that JAR files in libs directory are included
|
||||
* [CB-7267](https://issues.apache.org/jira/browse/CB-7267) update RELEASENOTES for 3.5.1
|
||||
* [CB-7410](https://issues.apache.org/jira/browse/CB-7410) clarify the title
|
||||
* [CB-7385](https://issues.apache.org/jira/browse/CB-7385) update cordova.js for testing prior to branch/tag
|
||||
* [CB-7410](https://issues.apache.org/jira/browse/CB-7410) add whitelist entries to get iframe/GoogleMaps working
|
||||
* [CB-7291](https://issues.apache.org/jira/browse/CB-7291) propogate change in method signature to the native tests
|
||||
* [CB-7291](https://issues.apache.org/jira/browse/CB-7291) Restrict meaning of "\*" in internal whitelist to just http and https
|
||||
* [CB-7291](https://issues.apache.org/jira/browse/CB-7291) Only add file, content and data URLs to internal whitelist
|
||||
* [CB-7291](https://issues.apache.org/jira/browse/CB-7291) Add defaults to external whitelist
|
||||
* [CB-7291](https://issues.apache.org/jira/browse/CB-7291) Add external-launch-whitelist and use it for filtering intent launches
|
||||
* [CB-3445](https://issues.apache.org/jira/browse/CB-3445) Read project.properties to configure gradle libraries
|
||||
* [CB-7325](https://issues.apache.org/jira/browse/CB-7325) Fix error message in android_sdk_version.js when missing SDK on windows
|
||||
* [CB-7335](https://issues.apache.org/jira/browse/CB-7335) Add a .gitignore to android project template
|
||||
* [CB-7330](https://issues.apache.org/jira/browse/CB-7330) Fix dangling function call in last commit (broke gradle builds)
|
||||
* [CB-7330](https://issues.apache.org/jira/browse/CB-7330) Don't run "android update" during creation
|
||||
* [CB-3445](https://issues.apache.org/jira/browse/CB-3445) Add gradle support clean command (plus some code cleanup)
|
||||
* [CB-7044](https://issues.apache.org/jira/browse/CB-7044) Fix typo in prev commit causing check_reqs to always fail.
|
||||
* [CB-3445](https://issues.apache.org/jira/browse/CB-3445) Copy gradle wrapper in build instead of create
|
||||
* [CB-3445](https://issues.apache.org/jira/browse/CB-3445) Add .gradle template files for "update" as well as "create"
|
||||
* [CB-7044](https://issues.apache.org/jira/browse/CB-7044) Add JAVA_HOME when not set. Be stricter about ANDROID_HOME
|
||||
* [CB-3445](https://issues.apache.org/jira/browse/CB-3445) Speed up gradle building (incremental builds go from 10s -> 1.5s for me)
|
||||
* [CB-3445](https://issues.apache.org/jira/browse/CB-3445) android: Copy Gradle wrapper from Android SDK rather than bundling a JAR
|
||||
* [CB-3445](https://issues.apache.org/jira/browse/CB-3445) Add which to checked-in node_modules
|
||||
* [CB-3445](https://issues.apache.org/jira/browse/CB-3445) Add option to build and install with gradle
|
||||
* [CB-3445](https://issues.apache.org/jira/browse/CB-3445) Add an initial set of Gradle build scripts
|
||||
* [CB-7321](https://issues.apache.org/jira/browse/CB-7321) Don't require ant for create script
|
||||
* CB-7044, [CB-7299](https://issues.apache.org/jira/browse/CB-7299) Fix up PATH problems when possible.
|
||||
* Change in test's AndroidManifest.xml needed for the test to run properly. Forgot the manifest.
|
||||
* Change in test's AndroidManifest.xml needed for the test to run properly
|
||||
* Adding tests related to 3.5.1
|
||||
* [CB-7261](https://issues.apache.org/jira/browse/CB-7261) Fix setNativeToJsBridgeMode sometimes crashing when switching to ONLINE_EVENT
|
||||
* [CB-7265](https://issues.apache.org/jira/browse/CB-7265) Fix crash when navigating to custom protocol (introduced in 3.5.1)
|
||||
* Filter out non-launchable intents
|
||||
* Handle unsupported protocol errors in webview better
|
||||
* [CB-7238](https://issues.apache.org/jira/browse/CB-7238) I should have collapsed this, but Config.init() must go before the creation of CordovaWebView
|
||||
* [CB-7238](https://issues.apache.org/jira/browse/CB-7238) Minor band-aid to get tests running again, this has to go away before 3.6.0 is released, since this is an API change.
|
||||
* Extend whitelist to handle URLs without // chars
|
||||
* [CB-7172](https://issues.apache.org/jira/browse/CB-7172) Force window to have focus after resume
|
||||
* [CB-7159](https://issues.apache.org/jira/browse/CB-7159) Set background color of webView as well as its parent
|
||||
* [CB-7018](https://issues.apache.org/jira/browse/CB-7018) Fix setButtonPlumbedToJs never un-listening
|
||||
* Undeprecate some just-deprecated symbols in PluginManager.
|
||||
* @Deprecate methods of PluginManager that were never meant to be public
|
||||
* Move plugin instantiation and instance storing logic PluginEntry->PluginManager
|
||||
* Fix broken unit test due to missing Config.init() call
|
||||
* Update to check for Google Glass APIs
|
||||
* Fix for `android` not being in PATH check on Windows
|
||||
* Displaying error when regex does not match.
|
||||
* Fix broken compile due to previous commit :(
|
||||
* Tweak CordovaPlugin.initialize method to be less deprecated.
|
||||
* Un-deprecate CordovaActivity.init() - it's needed to tweak prefs in onCreate
|
||||
* Tweak log messages in CordovaBridge with bridgeSecret is wrong
|
||||
* Backport CordovaBridge from 4.0.x -> master
|
||||
* Update unit tests to not use most deprecated things (e.g. DroidGap)
|
||||
* Add non-String overloades for CordovaPreferences.set()
|
||||
* Make CordovaWebview resilient to init() not being called (for backwards-compatibility)
|
||||
* Add node_module licenses to LICENSE
|
||||
* Update cordova.js snapshot to work with bridge changes
|
||||
* Provide CordovaPlugin with CordovaPreferences. Add new Plugin.initialize()
|
||||
* Convert usages of Config.\* to use the non-static versions
|
||||
* Change getProperty -> prefs.get\* within CordovaActivity
|
||||
* Make CordovaUriHelper class package-private
|
||||
* Fix PluginManager.setPluginEntries not removing old entries
|
||||
* Move registration of App plugin from config.xml -> code
|
||||
* Make setWebViewClient an override instead of an overload. Delete Location-change JS->Native bridge mode (missed some of it).
|
||||
* [CB-4404](https://issues.apache.org/jira/browse/CB-4404) Revert setting android:windowSoftInputMode to "adjustPan"
|
||||
* Refactor: Use ConfigXmlParser in activity. Adds CordovaWebView.init()
|
||||
* Deprecate some convenience methods on CordovaActivity
|
||||
* Fix CordovaPreferences not correctly parsing hex values (valueOf->decode)
|
||||
* Refactor: Move url-filter information into PluginEntry.
|
||||
* Don't re-parse config.xml in onResume.
|
||||
* Move handling of Fullscreen preference to CordovaActivity
|
||||
* Delete dead code from CordovaActivity
|
||||
* Update .classpath to make Eclipse happy (just re-orders one line)
|
||||
* Delete "CB-3064: The errorUrl is..." Log message left over from debugging presumably
|
||||
* Refactor Config into ConfigXmlParser, CordovaPreferences
|
||||
* Delete Location-change JS->Native bridge mode
|
||||
* [CB-5988](https://issues.apache.org/jira/browse/CB-5988) Allow exec() only from file: or start-up URL's domain
|
||||
* [CB-6761](https://issues.apache.org/jira/browse/CB-6761) Fix native->JS bridge ceasing to fire when page changes and online is set to false and the JS loads quickly
|
||||
* Update the errorurl to no longer use intents
|
||||
* This breaks running the JUnit tests, we'll bring it back soon
|
||||
* Refactoring the URI handling on Cordova, removing dead code
|
||||
* [CB-7018](https://issues.apache.org/jira/browse/CB-7018) Clean up and deprecation of some button-related functions
|
||||
* [CB-7017](https://issues.apache.org/jira/browse/CB-7017) Fix onload=true being set on all subsequent plugins
|
||||
* [CB-5971](https://issues.apache.org/jira/browse/CB-5971) Fix package / project validation
|
||||
* [CB-5971](https://issues.apache.org/jira/browse/CB-5971) Add unit tests to cordova-android
|
||||
* [CB-5971](https://issues.apache.org/jira/browse/CB-5971) Factor out package/project name validation logic
|
||||
* Delete explicit activity.finish() in back button handling. No change in behaviour.
|
||||
* [CB-5971](https://issues.apache.org/jira/browse/CB-5971) This would have been a good first bug, too bad
|
||||
* [CB-4404](https://issues.apache.org/jira/browse/CB-4404) Changing where android:windowSoftInputMode is in the manifest so it works
|
||||
* Add documentation referencing other implementation.
|
||||
* [CB-6851](https://issues.apache.org/jira/browse/CB-6851) Deprecate WebView.sendJavascript()
|
||||
* [CB-6876](https://issues.apache.org/jira/browse/CB-6876) Show the correct executable name
|
||||
* [CB-6876](https://issues.apache.org/jira/browse/CB-6876) Fix the "print usage"
|
||||
* Trivial spelling fix in comments when reading CordovaResourceApi
|
||||
* [CB-6818](https://issues.apache.org/jira/browse/CB-6818) I want to remove this code, because Square didn't do their headers properly
|
||||
* [CB-6860](https://issues.apache.org/jira/browse/CB-6860) Add activity_name and launcher_name to AndroidManifest.xml & strings.xml
|
||||
* Add a comment to custom_rules.xml saying why we move AndroidManifest.xml
|
||||
* Remove +x from README.md
|
||||
* [CB-6784](https://issues.apache.org/jira/browse/CB-6784) Add missing licenses
|
||||
* [CB-6784](https://issues.apache.org/jira/browse/CB-6784) Add license to CONTRIBUTING.md
|
||||
* Revert "defaults.xml: Add AndroidLaunchMode preference"
|
||||
* updated RELEASENOTES
|
||||
* [CB-6315](https://issues.apache.org/jira/browse/CB-6315) Wrapping this so it runs on the UI thread
|
||||
* [CB-6723](https://issues.apache.org/jira/browse/CB-6723) Update package name for Robotium
|
||||
* [CB-6707](https://issues.apache.org/jira/browse/CB-6707) Update minSdkVersion to 10 consistently
|
||||
* [CB-5652](https://issues.apache.org/jira/browse/CB-5652) make visible cordova version
|
||||
* Update JS snapshot to version 3.6.0-dev (via coho)
|
||||
* Update JS snapshot to version 3.6.0-dev (via coho)
|
||||
* Set VERSION to 3.6.0-dev (via coho)
|
||||
|
||||
### 3.5.1 (August 2014) ###
|
||||
|
||||
This was a security update to address CVE-2014-3500, CVE-2014-3501,
|
||||
and CVE-2014-3502. For more information, see
|
||||
http://cordova.apache.org/announcements/2014/08/04/android-351.html
|
||||
|
||||
* Filter out non-launchable intents
|
||||
* Handle unsupported protocol errors in webview better
|
||||
* Update the errorurl to no longer use intents
|
||||
* Refactoring the URI handling on Cordova, removing dead code
|
||||
|
||||
### 3.5.0 (May 2014) ###
|
||||
|
||||
* OkHttp has broken headers. Updating for ASF compliance.
|
||||
* Revert accidentally removed lines from NOTICE
|
||||
* [CB-6552](https://issues.apache.org/jira/browse/CB-6552) added top level package.json
|
||||
* [CB-6491](https://issues.apache.org/jira/browse/CB-6491) add CONTRIBUTING.md
|
||||
* [CB-6543](https://issues.apache.org/jira/browse/CB-6543) Fix cordova/run failure when no custom_rules.xml available
|
||||
* defaults.xml: Add AndroidLaunchMode preference
|
||||
* Add JavaDoc for CordovaResourceApi
|
||||
* [CB-6388](https://issues.apache.org/jira/browse/CB-6388) Handle binary data correctly in LOAD_URL bridge
|
||||
* Fix [CB-6048](https://issues.apache.org/jira/browse/CB-6048) Set launchMode=singleTop so tapping app icon does not always restart app
|
||||
* Remove incorrect usage of AlertDialog.Builder.create
|
||||
* Catch uncaught exceptions in from plugins and turn them into error responses.
|
||||
* Add NOTICE file
|
||||
* [CB-6047](https://issues.apache.org/jira/browse/CB-6047) Fix online sometimes getting in a bad state on page transitions.
|
||||
* Add another convenience overload for CordovaResourceApi.copyResource
|
||||
* Update framework's .classpath to what Eclipse wants it to be.
|
||||
* README.md: `android update` to `android-19`.
|
||||
* Fix NPE when POLLING bridge mode is used.
|
||||
* Updating NOTICE to include Square for OkHttp
|
||||
* [CB-5398](https://issues.apache.org/jira/browse/CB-5398) Apply KitKat content URI fix to all content URIs
|
||||
* [CB-5398](https://issues.apache.org/jira/browse/CB-5398) Work-around for KitKat content: URLs not rendering in <img> tags
|
||||
* [CB-5908](https://issues.apache.org/jira/browse/CB-5908) add splascreen images to template
|
||||
* [CB-5395](https://issues.apache.org/jira/browse/CB-5395) Make scheme and host (but not path) case-insensitive in whitelist
|
||||
* Ignore multiple onPageFinished() callbacks & onReceivedError due to stopLoading()
|
||||
* Removing addJavascriptInterface support from all Android versions lower than 4.2 due to security vu
|
||||
* [CB-4984](https://issues.apache.org/jira/browse/CB-4984) Don't create on CordovaActivity name
|
||||
* [CB-5917](https://issues.apache.org/jira/browse/CB-5917) Add a loadUrlIntoView overload that doesn't recreate plugins.
|
||||
* Use thread pool for load timeout.
|
||||
* [CB-5715](https://issues.apache.org/jira/browse/CB-5715) For CLI, hide assets/www and res/xml/config.xml by default
|
||||
* [CB-5793](https://issues.apache.org/jira/browse/CB-5793) ant builds: Rename AndroidManifest during -post-build to avoid Eclipse detecting ant-build/
|
||||
* [CB-5889](https://issues.apache.org/jira/browse/CB-5889) Make update script find project name instead of using "null" for CordovaLib
|
||||
* [CB-5889](https://issues.apache.org/jira/browse/CB-5889) Add a message in the update script about needing to import CordovaLib when using an IDE.
|
||||
|
||||
### 3.4.0 (Feb 2014) ###
|
||||
|
||||
43 commits from 10 authors. Highlights include:
|
||||
|
||||
* Removing addJavascriptInterface support from all Android versions lower than 4.2 due to security vulnerability
|
||||
* [CB-5917](https://issues.apache.org/jira/browse/CB-5917) Add a loadUrlIntoView overload that doesn't recreate plugins.
|
||||
* [CB-5889](https://issues.apache.org/jira/browse/CB-5889) Make update script find project name instead of using "null" for CordovaLib
|
||||
* [CB-5889](https://issues.apache.org/jira/browse/CB-5889) Add a message in the update script about needing to import CordovaLib when using an IDE.
|
||||
* [CB-5793](https://issues.apache.org/jira/browse/CB-5793) Don't clean before build and change output directory to ant-build to avoid conflicts with Eclipse.
|
||||
* [CB-5803](https://issues.apache.org/jira/browse/CB-5803) Fix cordova/emulate on windows.
|
||||
* [CB-5801](https://issues.apache.org/jira/browse/CB-5801) exec->spawn in build to make sure compile errors are shown.
|
||||
* [CB-5799](https://issues.apache.org/jira/browse/CB-5799) Update version of OkHTTP to 1.3
|
||||
* [CB-4910](https://issues.apache.org/jira/browse/CB-4910) Update CLI project template to point to config.xml at the root now that it's not in www/ by default.
|
||||
* [CB-5504](https://issues.apache.org/jira/browse/CB-5504) Adding onDestroy to app plugin to deregister telephonyReceiver
|
||||
* [CB-5715](https://issues.apache.org/jira/browse/CB-5715) Add Eclipse .project file to create template. For CLI projects, it adds refs for root www/ & config.xml and hides platform versions
|
||||
* [CB-5447](https://issues.apache.org/jira/browse/CB-5447) Removed android:debuggable=“true” from project template.
|
||||
* [CB-5714](https://issues.apache.org/jira/browse/CB-5714) Fix of android build when too big output stops build with error due to buffer overflow.
|
||||
* [CB-5592](https://issues.apache.org/jira/browse/CB-5592) Set MIME type for openExternal when scheme is file:
|
||||
|
||||
### 3.3.0 (Dec 2013) ###
|
||||
|
||||
41 commits from 11 authors. Highlights include:
|
||||
|
||||
* [CB-5481](https://issues.apache.org/jira/browse/CB-5481) Fix for Cordova trying to get config.xml from the wrong namespace
|
||||
* [CB-5487](https://issues.apache.org/jira/browse/CB-5487) Enable Remote Debugging when your Android app is debuggable.
|
||||
* [CB-5445](https://issues.apache.org/jira/browse/CB-5445) Adding onScrollChanged and the ScrollEvent object
|
||||
* [CB-5422](https://issues.apache.org/jira/browse/CB-5422) Don't require JAVA_HOME to be defined
|
||||
* [CB-5490](https://issues.apache.org/jira/browse/CB-5490) Add javadoc target to ant script
|
||||
* [CB-5471](https://issues.apache.org/jira/browse/CB-5471) Deprecated DroidGap class
|
||||
* [CB-5255](https://issues.apache.org/jira/browse/CB-5255) Prefer Google API targets over android-## targets when building.
|
||||
* [CB-5232](https://issues.apache.org/jira/browse/CB-5232) Change create script to use Cordova as a Library Project instead of a .jar
|
||||
* [CB-5302](https://issues.apache.org/jira/browse/CB-5302) Massive movement to get tests working again
|
||||
* [CB-4996](https://issues.apache.org/jira/browse/CB-4996) Fix paths with spaces while launching on emulator and device
|
||||
* [CB-5209](https://issues.apache.org/jira/browse/CB-5209) Cannot build Android app if project path contains spaces
|
||||
|
||||
|
||||
### 3.2.0 (Nov 2013) ###
|
||||
|
||||
27 commits from 7 authors. Highlights include:
|
||||
|
||||
* [CB-5193](https://issues.apache.org/jira/browse/CB-5193) Fix Android WebSQL sometime throwing SECURITY_ERR.
|
||||
* [CB-5191](https://issues.apache.org/jira/browse/CB-5191) Deprecate <url-filter>
|
||||
* Updating shelljs to 0.2.6. Copy now preserves mode bits.
|
||||
* [CB-4872](https://issues.apache.org/jira/browse/CB-4872) Added android version scripts (android_sdk_version, etc)
|
||||
* [CB-5117](https://issues.apache.org/jira/browse/CB-5117) Output confirmation message if check_reqs passes.
|
||||
* [CB-5080](https://issues.apache.org/jira/browse/CB-5080) Find resources in a way that works with aapt's --rename-manifest-package
|
||||
* [CB-4527](https://issues.apache.org/jira/browse/CB-4527) Don't delete .bat files even when on non-windows platform
|
||||
* [CB-4892](https://issues.apache.org/jira/browse/CB-4892) Fix create script only escaping the first space instead of all spaces.
|
||||
|
||||
### 3.1.0 (Sept 2013) ###
|
||||
|
||||
55 commits from 9 authors. Highlights include:
|
||||
|
||||
* [CB-4817] Remove unused assets in project template.
|
||||
* [CB-4817](https://issues.apache.org/jira/browse/CB-4817) Remove unused assets in project template.
|
||||
* Fail fast in create script if package name is not com.foo.bar.
|
||||
* [CB-4782] Convert ApplicationInfo.java -> appinfo.js
|
||||
* [CB-4766] Deprecated JSONUtils.java (moved into plugins)
|
||||
* [CB-4765] Deprecated ExifHelper.java (moved into plugins)
|
||||
* [CB-4764] Deprecated DirectoryManager.java (moved into plugins)
|
||||
* [CB-4763] Deprecated FileHelper.java (moved into plugins), Move getMimeType() into CordovaResourceApi.
|
||||
* [CB-4725] Add CordovaWebView.CORDOVA_VERSION constant
|
||||
* Incremeting version check for Android 4.3 API Level 18
|
||||
* [CB-3542] rewrote cli tooling scripts in node
|
||||
* [CB-4782](https://issues.apache.org/jira/browse/CB-4782) Convert ApplicationInfo.java -> appinfo.js
|
||||
* [CB-4766](https://issues.apache.org/jira/browse/CB-4766) Deprecated JSONUtils.java (moved into plugins)
|
||||
* [CB-4765](https://issues.apache.org/jira/browse/CB-4765) Deprecated ExifHelper.java (moved into plugins)
|
||||
* [CB-4764](https://issues.apache.org/jira/browse/CB-4764) Deprecated DirectoryManager.java (moved into plugins)
|
||||
* [CB-4763](https://issues.apache.org/jira/browse/CB-4763) Deprecated FileHelper.java (moved into plugins), Move getMimeType() into CordovaResourceApi.
|
||||
* [CB-4725](https://issues.apache.org/jira/browse/CB-4725) Add CordovaWebView.CORDOVA_VERSION constant
|
||||
* Incrementing version check for Android 4.3 API Level 18
|
||||
* [CB-3542](https://issues.apache.org/jira/browse/CB-3542) rewrote cli tooling scripts in node
|
||||
* Allow CordovaChromeClient subclasses access to CordovaInterface and CordovaWebView members
|
||||
* Refactor CordovaActivity.init so that subclasses can easily override factory methods for webview objects
|
||||
* [CB-4652] Allow default project template to be overridden on create
|
||||
* [CB-4652](https://issues.apache.org/jira/browse/CB-4652) Allow default project template to be overridden on create
|
||||
* Tweak the online bridge to not send excess online events.
|
||||
* [CB-4495] Modify start-emulator script to exit immediately on a fatal emulator error.
|
||||
* [CB-4495](https://issues.apache.org/jira/browse/CB-4495) Modify start-emulator script to exit immediately on a fatal emulator error.
|
||||
* Log WebView IOExceptions only when they are not 404s
|
||||
* Use a higher threshold for slow exec() warnings when debugger is attached.
|
||||
* Fix data URI decoding in CordovaResourceApi
|
||||
* [CB-3819] Made it easier to set SplashScreen delay.
|
||||
* [CB-4013] Fixed loadUrlTimeoutValue preference.
|
||||
* [CB-3819](https://issues.apache.org/jira/browse/CB-3819) Made it easier to set SplashScreen delay.
|
||||
* [CB-4013](https://issues.apache.org/jira/browse/CB-4013) Fixed loadUrlTimeoutValue preference.
|
||||
* Upgrading project to Android 4.3
|
||||
* [CB-4198] bin/create script should be better at handling non-word characters in activity name. Patched windows script as well.
|
||||
* [CB-4198] bin/create should handle spaces in activity better.
|
||||
* [CB-4096] Implemented new unified whitelist for android
|
||||
* [CB-3384] Fix thread assertion when plugins remap URIs
|
||||
* [CB-4198](https://issues.apache.org/jira/browse/CB-4198) bin/create script should be better at handling non-word characters in activity name. Patched windows script as well.
|
||||
* [CB-4198](https://issues.apache.org/jira/browse/CB-4198) bin/create should handle spaces in activity better.
|
||||
* [CB-4096](https://issues.apache.org/jira/browse/CB-4096) Implemented new unified whitelist for android
|
||||
* [CB-3384](https://issues.apache.org/jira/browse/CB-3384) Fix thread assertion when plugins remap URIs
|
||||
|
||||
|
||||
19
appveyor.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
environment:
|
||||
matrix:
|
||||
- nodejs_version: "0.10"
|
||||
- nodejs_version: "0.12"
|
||||
- nodejs_version: "4.2"
|
||||
|
||||
install:
|
||||
# - cinst android-sdk
|
||||
# - echo y | android update sdk -u --filter android-22,android-23
|
||||
- ps: Install-Product node $env:nodejs_version
|
||||
- npm install
|
||||
|
||||
build: off
|
||||
|
||||
test_script:
|
||||
- node --version
|
||||
- npm --version
|
||||
- npm run test
|
||||
# - npm run test-build
|
||||
@@ -21,8 +21,11 @@
|
||||
|
||||
var check_reqs = require('./lib/check_reqs');
|
||||
|
||||
check_reqs.run().done(null, function(err) {
|
||||
console.log(err);
|
||||
process.exit(2);
|
||||
});
|
||||
|
||||
check_reqs.run().done(
|
||||
function success() {
|
||||
console.log('Looks like your environment fully supports cordova-android development!');
|
||||
}, function fail(err) {
|
||||
console.log(err);
|
||||
process.exit(2);
|
||||
}
|
||||
);
|
||||
|
||||
41
bin/create
@@ -19,21 +19,40 @@
|
||||
under the License.
|
||||
*/
|
||||
var path = require('path');
|
||||
var create = require('./lib/create');
|
||||
var args = process.argv;
|
||||
var ConfigParser = require('cordova-common').ConfigParser;
|
||||
var Api = require('./templates/cordova/Api');
|
||||
|
||||
// Support basic help commands
|
||||
if(args.length < 3 || (args[2] == '--help' || args[2] == '/?' || args[2] == '-h' ||
|
||||
args[2] == 'help' || args[2] == '-help' || args[2] == '/help')) {
|
||||
console.log('Usage: ' + path.relative(process.cwd(), path.join(__dirname, 'create')) + ' <path_to_new_project> <package_name> <project_name>');
|
||||
var argv = require('nopt')({
|
||||
'help' : Boolean,
|
||||
'cli' : Boolean,
|
||||
'shared' : Boolean,
|
||||
'link' : Boolean,
|
||||
'activity-name' : [String, undefined]
|
||||
}, { 'd' : '--verbose' });
|
||||
|
||||
if (argv.help || argv.argv.remain.length === 0) {
|
||||
console.log('Usage: ' + path.relative(process.cwd(), path.join(__dirname, 'create')) + ' <path_to_new_project> <package_name> <project_name> [<template_path>] [--activity-name <activity_name>] [--link]');
|
||||
console.log(' <path_to_new_project>: Path to your new Cordova Android project');
|
||||
console.log(' <package_name>: Package name, following reverse-domain style convention');
|
||||
console.log(' <project_name>: Project name');
|
||||
console.log(' <template_path>: Path to a custom application template to use');
|
||||
console.log(' --activity-name <activity_name>: Activity name');
|
||||
console.log(' --link will use the CordovaLib project directly instead of making a copy.');
|
||||
process.exit(1);
|
||||
} else {
|
||||
create.createProject(args[2], args[3], args[4], args[5]).done(null, function(err) {
|
||||
console.error(err);
|
||||
process.exit(2);
|
||||
});
|
||||
}
|
||||
|
||||
var config = new ConfigParser(path.resolve(__dirname, 'templates/project/res/xml/config.xml'));
|
||||
|
||||
if (argv.argv.remain[1]) config.setPackageName(argv.argv.remain[1]);
|
||||
if (argv.argv.remain[2]) config.setName(argv.argv.remain[2]);
|
||||
if (argv['activity-name']) config.setName(argv['activity-name']);
|
||||
|
||||
var options = {
|
||||
link: argv.link || argv.shared,
|
||||
customTemplate: argv.argv.remain[3],
|
||||
activityName: argv['activity-name']
|
||||
};
|
||||
|
||||
require('./templates/cordova/loggingHelper').adjustLoggerLevel(argv);
|
||||
|
||||
Api.createPlatform(argv.argv.remain[0], config, options).done();
|
||||
|
||||
@@ -19,21 +19,20 @@
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var shell = require('shelljs'),
|
||||
child_process = require('child_process'),
|
||||
var child_process = require('child_process'),
|
||||
Q = require('q');
|
||||
|
||||
get_highest_sdk = function(results){
|
||||
var get_highest_sdk = function(results){
|
||||
var reg = /\d+/;
|
||||
var apiLevels = [];
|
||||
for(var i=0;i<results.length;i++){
|
||||
apiLevels[i] = parseInt(results[i].match(reg)[0]);
|
||||
}
|
||||
apiLevels.sort(function(a,b){return b-a});
|
||||
apiLevels.sort(function(a,b){return b-a;});
|
||||
console.log(apiLevels[0]);
|
||||
}
|
||||
};
|
||||
|
||||
get_sdks = function() {
|
||||
var get_sdks = function() {
|
||||
var d = Q.defer();
|
||||
child_process.exec('android list targets', function(err, stdout, stderr) {
|
||||
if (err) d.reject(stderr);
|
||||
@@ -51,15 +50,15 @@ get_sdks = function() {
|
||||
|
||||
return Q();
|
||||
}, function(stderr) {
|
||||
if (stderr.match(/command\snot\sfound/)) {
|
||||
if (stderr.match(/command\snot\sfound/) || stderr.match(/'android' is not recognized/)) {
|
||||
return Q.reject(new Error('The command \"android\" failed. Make sure you have the latest Android SDK installed, and the \"android\" command (inside the tools/ folder) is added to your path.'));
|
||||
} else {
|
||||
return Q.reject(new Error('An error occurred while listing Android targets'));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.run = function() {
|
||||
return Q.all([get_sdks()]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -19,76 +19,314 @@
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var shell = require('shelljs'),
|
||||
/* jshint sub:true */
|
||||
|
||||
var shelljs = require('shelljs'),
|
||||
child_process = require('child_process'),
|
||||
Q = require('q'),
|
||||
path = require('path'),
|
||||
fs = require('fs'),
|
||||
ROOT = path.join(__dirname, '..', '..');
|
||||
var CordovaError = require('cordova-common').CordovaError;
|
||||
|
||||
// Get valid target from framework/project.properties
|
||||
module.exports.get_target = function() {
|
||||
if(fs.existsSync(path.join(ROOT, 'framework', 'project.properties'))) {
|
||||
var target = shell.grep(/target=android-[\d+]/, path.join(ROOT, 'framework', 'project.properties'));
|
||||
return target.split('=')[1].replace('\n', '').replace('\r', '').replace(' ', '');
|
||||
} else if (fs.existsSync(path.join(ROOT, 'project.properties'))) {
|
||||
// if no target found, we're probably in a project and project.properties is in ROOT.
|
||||
var target = shell.grep(/target=android-[\d+]/, path.join(ROOT, 'project.properties'));
|
||||
return target.split('=')[1].replace('\n', '').replace('\r', '').replace(' ', '');
|
||||
var isWindows = process.platform == 'win32';
|
||||
|
||||
function forgivingWhichSync(cmd) {
|
||||
try {
|
||||
return fs.realpathSync(shelljs.which(cmd));
|
||||
} catch (e) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a promise.
|
||||
module.exports.check_ant = function() {
|
||||
function tryCommand(cmd, errMsg, catchStderr) {
|
||||
var d = Q.defer();
|
||||
child_process.exec('ant -version', function(err, stdout, stderr) {
|
||||
if (err) d.reject(new Error('ERROR : executing command \'ant\', make sure you have ant installed and added to your path.'));
|
||||
else d.resolve();
|
||||
child_process.exec(cmd, function(err, stdout, stderr) {
|
||||
if (err) d.reject(new CordovaError(errMsg));
|
||||
// Sometimes it is necessary to return an stderr instead of stdout in case of success, since
|
||||
// some commands prints theirs output to stderr instead of stdout. 'javac' is the example
|
||||
else d.resolve((catchStderr ? stderr : stdout).trim());
|
||||
});
|
||||
return d.promise;
|
||||
}
|
||||
|
||||
// Get valid target from framework/project.properties
|
||||
module.exports.get_target = function() {
|
||||
function extractFromFile(filePath) {
|
||||
var target = shelljs.grep(/\btarget=/, filePath);
|
||||
if (!target) {
|
||||
throw new Error('Could not find android target within: ' + filePath);
|
||||
}
|
||||
return target.split('=')[1].trim();
|
||||
}
|
||||
if (fs.existsSync(path.join(ROOT, 'framework', 'project.properties'))) {
|
||||
return extractFromFile(path.join(ROOT, 'framework', 'project.properties'));
|
||||
}
|
||||
if (fs.existsSync(path.join(ROOT, 'project.properties'))) {
|
||||
// if no target found, we're probably in a project and project.properties is in ROOT.
|
||||
return extractFromFile(path.join(ROOT, 'project.properties'));
|
||||
}
|
||||
throw new Error('Could not find android target. File missing: ' + path.join(ROOT, 'project.properties'));
|
||||
};
|
||||
|
||||
// Returns a promise. Called only by build and clean commands.
|
||||
module.exports.check_ant = function() {
|
||||
return tryCommand('ant -version', 'Failed to run "ant -version", make sure you have ant installed and added to your PATH.')
|
||||
.then(function (output) {
|
||||
// Parse Ant version from command output
|
||||
return /version ((?:\d+\.)+(?:\d+))/i.exec(output)[1];
|
||||
});
|
||||
};
|
||||
|
||||
// Returns a promise. Called only by build and clean commands.
|
||||
module.exports.check_gradle = function() {
|
||||
var sdkDir = process.env['ANDROID_HOME'];
|
||||
if (!sdkDir)
|
||||
return Q.reject(new CordovaError('Could not find gradle wrapper within Android SDK. Could not find Android SDK directory.\n' +
|
||||
'Might need to install Android SDK or set up \'ANDROID_HOME\' env variable.'));
|
||||
|
||||
var wrapperDir = path.join(sdkDir, 'tools', 'templates', 'gradle', 'wrapper');
|
||||
if (!fs.existsSync(wrapperDir)) {
|
||||
return Q.reject(new CordovaError('Could not find gradle wrapper within Android SDK. Might need to update your Android SDK.\n' +
|
||||
'Looked here: ' + wrapperDir));
|
||||
}
|
||||
return Q.when();
|
||||
};
|
||||
|
||||
// Returns a promise.
|
||||
module.exports.check_java = function() {
|
||||
if(process.env.JAVA_HOME) {
|
||||
var d = Q.defer();
|
||||
child_process.exec('java -version', function(err, stdout, stderr) {
|
||||
if(err) d.reject(new Error('ERROR : executing command \'java\', make sure you java environment is set up. Including your JDK and JRE.' + err));
|
||||
else d.resolve();
|
||||
var javacPath = forgivingWhichSync('javac');
|
||||
var hasJavaHome = !!process.env['JAVA_HOME'];
|
||||
return Q().then(function() {
|
||||
if (hasJavaHome) {
|
||||
// Windows java installer doesn't add javac to PATH, nor set JAVA_HOME (ugh).
|
||||
if (!javacPath) {
|
||||
process.env['PATH'] += path.delimiter + path.join(process.env['JAVA_HOME'], 'bin');
|
||||
}
|
||||
} else {
|
||||
if (javacPath) {
|
||||
var msg = 'Failed to find \'JAVA_HOME\' environment variable. Try setting setting it manually.';
|
||||
// OS X has a command for finding JAVA_HOME.
|
||||
if (fs.existsSync('/usr/libexec/java_home')) {
|
||||
return tryCommand('/usr/libexec/java_home', msg)
|
||||
.then(function(stdout) {
|
||||
process.env['JAVA_HOME'] = stdout.trim();
|
||||
});
|
||||
} else {
|
||||
// See if we can derive it from javac's location.
|
||||
// fs.realpathSync is require on Ubuntu, which symplinks from /usr/bin -> JDK
|
||||
var maybeJavaHome = path.dirname(path.dirname(javacPath));
|
||||
if (fs.existsSync(path.join(maybeJavaHome, 'lib', 'tools.jar'))) {
|
||||
process.env['JAVA_HOME'] = maybeJavaHome;
|
||||
} else {
|
||||
throw new CordovaError(msg);
|
||||
}
|
||||
}
|
||||
} else if (isWindows) {
|
||||
// Try to auto-detect java in the default install paths.
|
||||
var oldSilent = shelljs.config.silent;
|
||||
shelljs.config.silent = true;
|
||||
var firstJdkDir =
|
||||
shelljs.ls(process.env['ProgramFiles'] + '\\java\\jdk*')[0] ||
|
||||
shelljs.ls('C:\\Program Files\\java\\jdk*')[0] ||
|
||||
shelljs.ls('C:\\Program Files (x86)\\java\\jdk*')[0];
|
||||
shelljs.config.silent = oldSilent;
|
||||
if (firstJdkDir) {
|
||||
// shelljs always uses / in paths.
|
||||
firstJdkDir = firstJdkDir.replace(/\//g, path.sep);
|
||||
if (!javacPath) {
|
||||
process.env['PATH'] += path.delimiter + path.join(firstJdkDir, 'bin');
|
||||
}
|
||||
process.env['JAVA_HOME'] = firstJdkDir;
|
||||
}
|
||||
}
|
||||
}
|
||||
}).then(function() {
|
||||
var msg =
|
||||
'Failed to run "javac -version", make sure that you have a JDK installed.\n' +
|
||||
'You can get it from: http://www.oracle.com/technetwork/java/javase/downloads.\n';
|
||||
if (process.env['JAVA_HOME']) {
|
||||
msg += 'Your JAVA_HOME is invalid: ' + process.env['JAVA_HOME'] + '\n';
|
||||
}
|
||||
// We use tryCommand with catchStderr = true, because
|
||||
// javac writes version info to stderr instead of stdout
|
||||
return tryCommand('javac -version', msg, true)
|
||||
.then(function (output) {
|
||||
var match = /javac ((?:\d+\.)+(?:\d+))/i.exec(output);
|
||||
return match && match[1];
|
||||
});
|
||||
});
|
||||
return d.promise;
|
||||
} else {
|
||||
return Q.reject(new Error('ERROR : Make sure JAVA_HOME is set, as well as paths to your JDK and JRE for java.'));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Returns a promise.
|
||||
module.exports.check_android = function() {
|
||||
var valid_target = this.get_target();
|
||||
var d = Q.defer();
|
||||
child_process.exec('android list targets', function(err, stdout, stderr) {
|
||||
if (err) d.reject(stderr);
|
||||
else d.resolve(stdout);
|
||||
return Q().then(function() {
|
||||
var androidCmdPath = forgivingWhichSync('android');
|
||||
var adbInPath = !!forgivingWhichSync('adb');
|
||||
var hasAndroidHome = !!process.env['ANDROID_HOME'] && fs.existsSync(process.env['ANDROID_HOME']);
|
||||
function maybeSetAndroidHome(value) {
|
||||
if (!hasAndroidHome && fs.existsSync(value)) {
|
||||
hasAndroidHome = true;
|
||||
process.env['ANDROID_HOME'] = value;
|
||||
}
|
||||
}
|
||||
if (!hasAndroidHome && !androidCmdPath) {
|
||||
if (isWindows) {
|
||||
// Android Studio 1.0 installer
|
||||
maybeSetAndroidHome(path.join(process.env['LOCALAPPDATA'], 'Android', 'sdk'));
|
||||
maybeSetAndroidHome(path.join(process.env['ProgramFiles'], 'Android', 'sdk'));
|
||||
// Android Studio pre-1.0 installer
|
||||
maybeSetAndroidHome(path.join(process.env['LOCALAPPDATA'], 'Android', 'android-studio', 'sdk'));
|
||||
maybeSetAndroidHome(path.join(process.env['ProgramFiles'], 'Android', 'android-studio', 'sdk'));
|
||||
// Stand-alone installer
|
||||
maybeSetAndroidHome(path.join(process.env['LOCALAPPDATA'], 'Android', 'android-sdk'));
|
||||
maybeSetAndroidHome(path.join(process.env['ProgramFiles'], 'Android', 'android-sdk'));
|
||||
} else if (process.platform == 'darwin') {
|
||||
// Android Studio 1.0 installer
|
||||
maybeSetAndroidHome(path.join(process.env['HOME'], 'Library', 'Android', 'sdk'));
|
||||
// Android Studio pre-1.0 installer
|
||||
maybeSetAndroidHome('/Applications/Android Studio.app/sdk');
|
||||
// Stand-alone zip file that user might think to put under /Applications
|
||||
maybeSetAndroidHome('/Applications/android-sdk-macosx');
|
||||
maybeSetAndroidHome('/Applications/android-sdk');
|
||||
}
|
||||
if (process.env['HOME']) {
|
||||
// Stand-alone zip file that user might think to put under their home directory
|
||||
maybeSetAndroidHome(path.join(process.env['HOME'], 'android-sdk-macosx'));
|
||||
maybeSetAndroidHome(path.join(process.env['HOME'], 'android-sdk'));
|
||||
}
|
||||
}
|
||||
if (hasAndroidHome && !androidCmdPath) {
|
||||
process.env['PATH'] += path.delimiter + path.join(process.env['ANDROID_HOME'], 'tools');
|
||||
}
|
||||
if (androidCmdPath && !hasAndroidHome) {
|
||||
var parentDir = path.dirname(androidCmdPath);
|
||||
var grandParentDir = path.dirname(parentDir);
|
||||
if (path.basename(parentDir) == 'tools') {
|
||||
process.env['ANDROID_HOME'] = path.dirname(parentDir);
|
||||
hasAndroidHome = true;
|
||||
} else if (fs.existsSync(path.join(grandParentDir, 'tools', 'android'))) {
|
||||
process.env['ANDROID_HOME'] = grandParentDir;
|
||||
hasAndroidHome = true;
|
||||
} else {
|
||||
throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting setting it manually.\n' +
|
||||
'Detected \'android\' command at ' + parentDir + ' but no \'tools\' directory found near.\n' +
|
||||
'Try reinstall Android SDK or update your PATH to include path to valid SDK directory.');
|
||||
}
|
||||
}
|
||||
if (hasAndroidHome && !adbInPath) {
|
||||
process.env['PATH'] += path.delimiter + path.join(process.env['ANDROID_HOME'], 'platform-tools');
|
||||
}
|
||||
if (!process.env['ANDROID_HOME']) {
|
||||
throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting setting it manually.\n' +
|
||||
'Failed to find \'android\' command in your \'PATH\'. Try update your \'PATH\' to include path to valid SDK directory.');
|
||||
}
|
||||
if (!fs.existsSync(process.env['ANDROID_HOME'])) {
|
||||
throw new CordovaError('\'ANDROID_HOME\' environment variable is set to non-existent path: ' + process.env['ANDROID_HOME'] +
|
||||
'\nTry update it manually to point to valid SDK directory.');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return d.promise.then(function(output) {
|
||||
if (!output.match(valid_target)) {
|
||||
return Q.reject(new Error('Please install Android target ' + valid_target.split('-')[1] + ' (the Android newest SDK). Make sure you have the latest Android tools installed as well. Run \"android\" from your command-line to install/update any missing SDKs or tools.'));
|
||||
module.exports.getAbsoluteAndroidCmd = function () {
|
||||
var cmd = forgivingWhichSync('android');
|
||||
if (process.platform === 'win32') {
|
||||
return '"' + cmd + '"';
|
||||
}
|
||||
return cmd.replace(/(\s)/g, '\\$1');
|
||||
};
|
||||
|
||||
module.exports.check_android_target = function(originalError) {
|
||||
// valid_target can look like:
|
||||
// android-19
|
||||
// android-L
|
||||
// Google Inc.:Google APIs:20
|
||||
// Google Inc.:Glass Development Kit Preview:20
|
||||
var valid_target = module.exports.get_target();
|
||||
var msg = 'Android SDK not found. Make sure that it is installed. If it is not at the default location, set the ANDROID_HOME environment variable.';
|
||||
return tryCommand('android list targets --compact', msg)
|
||||
.then(function(output) {
|
||||
var targets = output.split('\n');
|
||||
if (targets.indexOf(valid_target) >= 0) {
|
||||
return targets;
|
||||
}
|
||||
return Q();
|
||||
}, function(stderr) {
|
||||
if (stderr.match(/command\snot\sfound/)) {
|
||||
return Q.reject(new Error('The command \"android\" failed. Make sure you have the latest Android SDK installed, and the \"android\" command (inside the tools/ folder) is added to your path.'));
|
||||
} else {
|
||||
return Q.reject(new Error('An error occurred while listing Android targets'));
|
||||
|
||||
var androidCmd = module.exports.getAbsoluteAndroidCmd();
|
||||
var msg = 'Please install Android target: "' + valid_target + '".\n\n' +
|
||||
'Hint: Open the SDK manager by running: ' + androidCmd + '\n' +
|
||||
'You will require:\n' +
|
||||
'1. "SDK Platform" for ' + valid_target + '\n' +
|
||||
'2. "Android SDK Platform-tools (latest)\n' +
|
||||
'3. "Android SDK Build-tools" (latest)';
|
||||
if (originalError) {
|
||||
msg = originalError + '\n' + msg;
|
||||
}
|
||||
throw new CordovaError(msg);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Returns a promise.
|
||||
module.exports.run = function() {
|
||||
return Q.all([this.check_ant(), this.check_java(), this.check_android()]).then(function() {
|
||||
console.log('Looks like your environment fully supports cordova-android development!');
|
||||
return Q.all([this.check_java(), this.check_android()])
|
||||
.then(function() {
|
||||
console.log('ANDROID_HOME=' + process.env['ANDROID_HOME']);
|
||||
console.log('JAVA_HOME=' + process.env['JAVA_HOME']);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Object thar represents one of requirements for current platform.
|
||||
* @param {String} id The unique identifier for this requirements.
|
||||
* @param {String} name The name of requirements. Human-readable field.
|
||||
* @param {String} version The version of requirement installed. In some cases could be an array of strings
|
||||
* (for example, check_android_target returns an array of android targets installed)
|
||||
* @param {Boolean} installed Indicates whether the requirement is installed or not
|
||||
*/
|
||||
var Requirement = function (id, name, version, installed) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.installed = installed || false;
|
||||
this.metadata = {
|
||||
version: version,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Methods that runs all checks one by one and returns a result of checks
|
||||
* as an array of Requirement objects. This method intended to be used by cordova-lib check_reqs method
|
||||
*
|
||||
* @return Promise<Requirement[]> Array of requirements. Due to implementation, promise is always fulfilled.
|
||||
*/
|
||||
module.exports.check_all = function() {
|
||||
|
||||
var requirements = [
|
||||
new Requirement('java', 'Java JDK'),
|
||||
new Requirement('androidSdk', 'Android SDK'),
|
||||
new Requirement('androidTarget', 'Android target'),
|
||||
new Requirement('gradle', 'Gradle')
|
||||
];
|
||||
|
||||
var checkFns = [
|
||||
this.check_java,
|
||||
this.check_android,
|
||||
this.check_android_target,
|
||||
this.check_gradle
|
||||
];
|
||||
|
||||
// Then execute requirement checks one-by-one
|
||||
return checkFns.reduce(function (promise, checkFn, idx) {
|
||||
// Update each requirement with results
|
||||
var requirement = requirements[idx];
|
||||
return promise.then(checkFn)
|
||||
.then(function (version) {
|
||||
requirement.installed = true;
|
||||
requirement.metadata.version = version;
|
||||
}, function (err) {
|
||||
requirement.metadata.reason = err instanceof Error ? err.message : err;
|
||||
});
|
||||
}, Q())
|
||||
.then(function () {
|
||||
// When chain is completed, return requirements array to upstream API
|
||||
return requirements;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -18,27 +18,18 @@
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var shell = require('shelljs'),
|
||||
child_process = require('child_process'),
|
||||
Q = require('q'),
|
||||
path = require('path'),
|
||||
fs = require('fs'),
|
||||
check_reqs = require('./check_reqs'),
|
||||
ROOT = path.join(__dirname, '..', '..');
|
||||
|
||||
// Returns a promise.
|
||||
function exec(command, opt_cwd) {
|
||||
var d = Q.defer();
|
||||
try {
|
||||
child_process.exec(command, { cwd: opt_cwd }, function(err, stdout, stderr) {
|
||||
if (err) d.reject(err);
|
||||
else d.resolve(stdout);
|
||||
});
|
||||
} catch(e) {
|
||||
return Q.reject('Command error on execution: ' + command + '\n' + e);
|
||||
}
|
||||
return d.promise;
|
||||
}
|
||||
var MIN_SDK_VERSION = 14;
|
||||
|
||||
var CordovaError = require('cordova-common').CordovaError;
|
||||
var AndroidManifest = require('../templates/cordova/lib/AndroidManifest');
|
||||
|
||||
function setShellFatal(value, func) {
|
||||
var oldVal = shell.config.fatal;
|
||||
@@ -47,32 +38,102 @@ function setShellFatal(value, func) {
|
||||
shell.config.fatal = oldVal;
|
||||
}
|
||||
|
||||
// Returns a promise.
|
||||
function ensureJarIsBuilt(version, target_api) {
|
||||
var isDevVersion = /-dev$/.test(version);
|
||||
if (isDevVersion || !fs.existsSync(path.join(ROOT, 'framework', 'cordova-' + version + '.jar')) && fs.existsSync(path.join(ROOT, 'framework'))) {
|
||||
var valid_target = check_reqs.get_target();
|
||||
console.log('Building cordova-' + version + '.jar');
|
||||
// update the cordova-android framework for the desired target
|
||||
return exec('android --silent update lib-project --target "' + target_api + '" --path "' + path.join(ROOT, 'framework') + '"')
|
||||
.then(function() {
|
||||
// compile cordova.js and cordova.jar
|
||||
return exec('ant jar', path.join(ROOT, 'framework'));
|
||||
});
|
||||
}
|
||||
return Q();
|
||||
function getFrameworkDir(projectPath, shared) {
|
||||
return shared ? path.join(ROOT, 'framework') : path.join(projectPath, 'CordovaLib');
|
||||
}
|
||||
|
||||
function copyJsAndJar(projectPath, version) {
|
||||
shell.cp('-f', path.join(ROOT, 'framework', 'assets', 'www', 'cordova.js'), path.join(projectPath, 'assets', 'www', 'cordova.js'));
|
||||
function copyJsAndLibrary(projectPath, shared, projectName) {
|
||||
var nestedCordovaLibPath = getFrameworkDir(projectPath, false);
|
||||
var srcCordovaJsPath = path.join(ROOT, 'bin', 'templates', 'project', 'assets', 'www', 'cordova.js');
|
||||
shell.cp('-f', srcCordovaJsPath, path.join(projectPath, 'assets', 'www', 'cordova.js'));
|
||||
|
||||
// Copy the cordova.js file to platforms/<platform>/platform_www/
|
||||
// The www dir is nuked on each prepare so we keep cordova.js in platform_www
|
||||
shell.mkdir('-p', path.join(projectPath, 'platform_www'));
|
||||
shell.cp('-f', srcCordovaJsPath, path.join(projectPath, 'platform_www'));
|
||||
|
||||
// Copy cordova-js-src directory into platform_www directory.
|
||||
// We need these files to build cordova.js if using browserify method.
|
||||
shell.cp('-rf', path.join(ROOT, 'cordova-js-src'), path.join(projectPath, 'platform_www'));
|
||||
|
||||
// Don't fail if there are no old jars.
|
||||
setShellFatal(false, function() {
|
||||
shell.ls(path.join(projectPath, 'libs', 'cordova-*.jar')).forEach(function(oldJar) {
|
||||
console.log("Deleting " + oldJar);
|
||||
shell.rm('-f', path.join(oldJar));
|
||||
console.log('Deleting ' + oldJar);
|
||||
shell.rm('-f', oldJar);
|
||||
});
|
||||
var wasSymlink = true;
|
||||
try {
|
||||
// Delete the symlink if it was one.
|
||||
fs.unlinkSync(nestedCordovaLibPath);
|
||||
} catch (e) {
|
||||
wasSymlink = false;
|
||||
}
|
||||
// Delete old library project if it existed.
|
||||
if (shared) {
|
||||
shell.rm('-rf', nestedCordovaLibPath);
|
||||
} else if (!wasSymlink) {
|
||||
// Delete only the src, since Eclipse / Android Studio can't handle their project files being deleted.
|
||||
shell.rm('-rf', path.join(nestedCordovaLibPath, 'src'));
|
||||
}
|
||||
});
|
||||
shell.cp('-f', path.join(ROOT, 'framework', 'cordova-' + version + '.jar'), path.join(projectPath, 'libs', 'cordova-' + version + '.jar'));
|
||||
if (shared) {
|
||||
var relativeFrameworkPath = path.relative(projectPath, getFrameworkDir(projectPath, true));
|
||||
fs.symlinkSync(relativeFrameworkPath, nestedCordovaLibPath, 'dir');
|
||||
} else {
|
||||
shell.mkdir('-p', nestedCordovaLibPath);
|
||||
shell.cp('-f', path.join(ROOT, 'framework', 'AndroidManifest.xml'), nestedCordovaLibPath);
|
||||
shell.cp('-f', path.join(ROOT, 'framework', 'project.properties'), nestedCordovaLibPath);
|
||||
shell.cp('-f', path.join(ROOT, 'framework', 'build.gradle'), nestedCordovaLibPath);
|
||||
shell.cp('-f', path.join(ROOT, 'framework', 'cordova.gradle'), nestedCordovaLibPath);
|
||||
shell.cp('-r', path.join(ROOT, 'framework', 'src'), nestedCordovaLibPath);
|
||||
}
|
||||
}
|
||||
|
||||
function extractSubProjectPaths(data) {
|
||||
var ret = {};
|
||||
var r = /^\s*android\.library\.reference\.\d+=(.*)(?:\s|$)/mg;
|
||||
var m;
|
||||
while ((m = r.exec(data))) {
|
||||
ret[m[1]] = 1;
|
||||
}
|
||||
return Object.keys(ret);
|
||||
}
|
||||
|
||||
function writeProjectProperties(projectPath, target_api) {
|
||||
var dstPath = path.join(projectPath, 'project.properties');
|
||||
var templatePath = path.join(ROOT, 'bin', 'templates', 'project', 'project.properties');
|
||||
var srcPath = fs.existsSync(dstPath) ? dstPath : templatePath;
|
||||
|
||||
var data = fs.readFileSync(srcPath, 'utf8');
|
||||
data = data.replace(/^target=.*/m, 'target=' + target_api);
|
||||
var subProjects = extractSubProjectPaths(data);
|
||||
subProjects = subProjects.filter(function(p) {
|
||||
return !(/^CordovaLib$/m.exec(p) ||
|
||||
/[\\\/]cordova-android[\\\/]framework$/m.exec(p) ||
|
||||
/^(\.\.[\\\/])+framework$/m.exec(p)
|
||||
);
|
||||
});
|
||||
subProjects.unshift('CordovaLib');
|
||||
data = data.replace(/^\s*android\.library\.reference\.\d+=.*\n/mg, '');
|
||||
if (!/\n$/.exec(data)) {
|
||||
data += '\n';
|
||||
}
|
||||
for (var i = 0; i < subProjects.length; ++i) {
|
||||
data += 'android.library.reference.' + (i+1) + '=' + subProjects[i] + '\n';
|
||||
}
|
||||
fs.writeFileSync(dstPath, data);
|
||||
}
|
||||
|
||||
function prepBuildFiles(projectPath) {
|
||||
var buildModule = require(path.resolve(projectPath, 'cordova/lib/builders/builders'));
|
||||
buildModule.getBuilder('gradle').prepBuildFiles();
|
||||
}
|
||||
|
||||
function copyBuildRules(projectPath) {
|
||||
var srcDir = path.join(ROOT, 'bin', 'templates', 'project');
|
||||
|
||||
shell.cp('-f', path.join(srcDir, 'build.gradle'), projectPath);
|
||||
}
|
||||
|
||||
function copyScripts(projectPath) {
|
||||
@@ -82,115 +143,190 @@ function copyScripts(projectPath) {
|
||||
shell.rm('-rf', destScriptsDir);
|
||||
// Copy in the new ones.
|
||||
shell.cp('-r', srcScriptsDir, projectPath);
|
||||
shell.cp('-r', path.join(ROOT, 'bin', 'node_modules'), destScriptsDir);
|
||||
shell.cp(path.join(ROOT, 'bin', 'check_reqs'), path.join(destScriptsDir, 'check_reqs'));
|
||||
shell.cp('-r', path.join(ROOT, 'node_modules'), destScriptsDir);
|
||||
shell.cp(path.join(ROOT, 'bin', 'check_reqs*'), destScriptsDir);
|
||||
shell.cp(path.join(ROOT, 'bin', 'lib', 'check_reqs.js'), path.join(projectPath, 'cordova', 'lib', 'check_reqs.js'));
|
||||
shell.cp(path.join(ROOT, 'bin', 'android_sdk_version'), path.join(destScriptsDir, 'android_sdk_version'));
|
||||
shell.cp(path.join(ROOT, 'bin', 'lib', 'android_sdk_version.js'), path.join(projectPath, 'cordova', 'lib', 'android_sdk_version.js'));
|
||||
}
|
||||
|
||||
/**
|
||||
* $ create [options]
|
||||
*
|
||||
* Test whether a package name is acceptable for use as an android project.
|
||||
* Returns a promise, fulfilled if the package name is acceptable; rejected
|
||||
* otherwise.
|
||||
*/
|
||||
function validatePackageName(package_name) {
|
||||
//Make the package conform to Java package types
|
||||
//http://developer.android.com/guide/topics/manifest/manifest-element.html#package
|
||||
//Enforce underscore limitation
|
||||
var msg = 'Error validating package name. ';
|
||||
if (!/^[a-zA-Z][a-zA-Z0-9_]+(\.[a-zA-Z][a-zA-Z0-9_]*)+$/.test(package_name)) {
|
||||
return Q.reject(new CordovaError(msg + 'Package name must look like: com.company.Name'));
|
||||
}
|
||||
|
||||
//Class is a reserved word
|
||||
if(/\b[Cc]lass\b/.test(package_name)) {
|
||||
return Q.reject(new CordovaError(msg + '"class" is a reserved word'));
|
||||
}
|
||||
|
||||
return Q.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether a project name is acceptable for use as an android class.
|
||||
* Returns a promise, fulfilled if the project name is acceptable; rejected
|
||||
* otherwise.
|
||||
*/
|
||||
function validateProjectName(project_name) {
|
||||
var msg = 'Error validating project name. ';
|
||||
//Make sure there's something there
|
||||
if (project_name === '') {
|
||||
return Q.reject(new CordovaError(msg + 'Project name cannot be empty'));
|
||||
}
|
||||
|
||||
//Enforce stupid name error
|
||||
if (project_name === 'CordovaActivity') {
|
||||
return Q.reject(new CordovaError(msg + 'Project name cannot be CordovaActivity'));
|
||||
}
|
||||
|
||||
//Classes in Java don't begin with numbers
|
||||
if (/^[0-9]/.test(project_name)) {
|
||||
return Q.reject(new CordovaError(msg + 'Project name must not begin with a number'));
|
||||
}
|
||||
|
||||
return Q.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an android application with the given options.
|
||||
*
|
||||
* Options:
|
||||
* @param {String} project_path Path to the new Cordova android project.
|
||||
* @param {ConfigParser} config Instance of ConfigParser to retrieve basic
|
||||
* project properties.
|
||||
* @param {Object} [options={}] Various options
|
||||
* @param {String} [options.activityName='MainActivity'] Name for the
|
||||
* activity
|
||||
* @param {Boolean} [options.link=false] Specifies whether javascript files
|
||||
* and CordovaLib framework will be symlinked to created application.
|
||||
* @param {String} [options.customTemplate] Path to project template
|
||||
* (override)
|
||||
* @param {EventEmitter} [events] An EventEmitter instance for logging
|
||||
* events
|
||||
*
|
||||
* - `project_path` {String} Path to the new Cordova android project.
|
||||
* - `package_name`{String} Package name, following reverse-domain style convention.
|
||||
* - `project_name` {String} Project name.
|
||||
* - 'project_template_dir' {String} Path to project template (override).
|
||||
*
|
||||
* Returns a promise.
|
||||
* @return {Promise<String>} Directory where application has been created
|
||||
*/
|
||||
exports.create = function(project_path, config, options, events) {
|
||||
|
||||
exports.createProject = function(project_path, package_name, project_name, project_template_dir) {
|
||||
var VERSION = fs.readFileSync(path.join(ROOT, 'VERSION'), 'utf-8').trim();
|
||||
options = options || {};
|
||||
|
||||
// Set default values for path, package and name
|
||||
project_path = typeof project_path !== 'undefined' ? project_path : "CordovaExample";
|
||||
project_path = path.relative(process.cwd(), project_path);
|
||||
package_name = typeof package_name !== 'undefined' ? package_name : 'my.cordova.project';
|
||||
project_name = typeof project_name !== 'undefined' ? project_name : 'CordovaExample';
|
||||
project_template_dir = typeof project_template_dir !== 'undefined' ?
|
||||
project_template_dir :
|
||||
path.join(ROOT, 'bin', 'templates', 'project');
|
||||
|
||||
var safe_activity_name = project_name.replace(/\W/g, '');
|
||||
var package_as_path = package_name.replace(/\./g, path.sep);
|
||||
var activity_dir = path.join(project_path, 'src', package_as_path);
|
||||
var activity_path = path.join(activity_dir, safe_activity_name + '.java');
|
||||
var target_api = check_reqs.get_target();
|
||||
var manifest_path = path.join(project_path, 'AndroidManifest.xml');
|
||||
|
||||
project_path = path.relative(process.cwd(), (project_path || 'CordovaExample'));
|
||||
// Check if project already exists
|
||||
if(fs.existsSync(project_path)) {
|
||||
return Q.reject('Project already exists! Delete and recreate');
|
||||
return Q.reject(new CordovaError('Project already exists! Delete and recreate'));
|
||||
}
|
||||
|
||||
if (!/[a-zA-Z0-9_]+\.[a-zA-Z0-9_](.[a-zA-Z0-9_])*/.test(package_name)) {
|
||||
return Q.reject('Package name must look like: com.company.Name');
|
||||
}
|
||||
var package_name = config.packageName() || 'my.cordova.project';
|
||||
var project_name = config.name() ?
|
||||
config.name().replace(/[^\w.]/g,'_') : 'CordovaExample';
|
||||
|
||||
// Check that requirements are met and proper targets are installed
|
||||
return check_reqs.run()
|
||||
var safe_activity_name = config.android_activityName() || options.activityName || 'MainActivity';
|
||||
var target_api = check_reqs.get_target();
|
||||
|
||||
//Make the package conform to Java package types
|
||||
return validatePackageName(package_name)
|
||||
.then(function() {
|
||||
// Log the given values for the project
|
||||
console.log('Creating Cordova project for the Android platform:');
|
||||
console.log('\tPath: ' + project_path);
|
||||
console.log('\tPackage: ' + package_name);
|
||||
console.log('\tName: ' + project_name);
|
||||
console.log('\tAndroid target: ' + target_api);
|
||||
|
||||
// build from source. distro should have these files
|
||||
return ensureJarIsBuilt(VERSION, target_api);
|
||||
validateProjectName(project_name);
|
||||
}).then(function() {
|
||||
console.log('Copying template files...');
|
||||
// Log the given values for the project
|
||||
events.emit('log', 'Creating Cordova project for the Android platform:');
|
||||
events.emit('log', '\tPath: ' + project_path);
|
||||
events.emit('log', '\tPackage: ' + package_name);
|
||||
events.emit('log', '\tName: ' + project_name);
|
||||
events.emit('log', '\tActivity: ' + safe_activity_name);
|
||||
events.emit('log', '\tAndroid target: ' + target_api);
|
||||
|
||||
events.emit('verbose', 'Copying android template project to ' + project_path);
|
||||
|
||||
setShellFatal(true, function() {
|
||||
var project_template_dir = options.customTemplate || path.join(ROOT, 'bin', 'templates', 'project');
|
||||
// copy project template
|
||||
shell.cp('-r', path.join(project_template_dir, 'assets'), project_path);
|
||||
shell.cp('-r', path.join(project_template_dir, 'res'), project_path);
|
||||
shell.cp(path.join(project_template_dir, 'gitignore'), path.join(project_path, '.gitignore'));
|
||||
|
||||
// Manually create directories that would be empty within the template (since git doesn't track directories).
|
||||
shell.mkdir(path.join(project_path, 'libs'));
|
||||
|
||||
// copy cordova.js, cordova.jar and res/xml
|
||||
shell.cp('-r', path.join(ROOT, 'framework', 'res', 'xml'), path.join(project_path, 'res'));
|
||||
copyJsAndJar(project_path, VERSION);
|
||||
// copy cordova.js, cordova.jar
|
||||
copyJsAndLibrary(project_path, options.link, safe_activity_name);
|
||||
|
||||
// interpolate the activity name and package
|
||||
var packagePath = package_name.replace(/\./g, path.sep);
|
||||
var activity_dir = path.join(project_path, 'src', packagePath);
|
||||
var activity_path = path.join(activity_dir, safe_activity_name + '.java');
|
||||
shell.mkdir('-p', activity_dir);
|
||||
shell.cp('-f', path.join(project_template_dir, 'Activity.java'), activity_path);
|
||||
shell.sed('-i', /__ACTIVITY__/, safe_activity_name, activity_path);
|
||||
shell.sed('-i', /__NAME__/, project_name, path.join(project_path, 'res', 'values', 'strings.xml'));
|
||||
shell.sed('-i', /__ID__/, package_name, activity_path);
|
||||
|
||||
shell.cp('-f', path.join(project_template_dir, 'AndroidManifest.xml'), manifest_path);
|
||||
shell.sed('-i', /__ACTIVITY__/, safe_activity_name, manifest_path);
|
||||
shell.sed('-i', /__PACKAGE__/, package_name, manifest_path);
|
||||
shell.sed('-i', /__APILEVEL__/, target_api.split('-')[1], manifest_path);
|
||||
var manifest = new AndroidManifest(path.join(project_template_dir, 'AndroidManifest.xml'));
|
||||
manifest.setPackageId(package_name)
|
||||
.setTargetSdkVersion(target_api.split('-')[1])
|
||||
.getActivity().setName(safe_activity_name);
|
||||
|
||||
var manifest_path = path.join(project_path, 'AndroidManifest.xml');
|
||||
manifest.write(manifest_path);
|
||||
|
||||
copyScripts(project_path);
|
||||
copyBuildRules(project_path);
|
||||
});
|
||||
// Link it to local android install.
|
||||
console.log('Running "android update project"');
|
||||
return exec('android --silent update project --target "'+target_api+'" --path "'+ project_path+'"');
|
||||
}).then(function() {
|
||||
console.log('Project successfully created.');
|
||||
});
|
||||
writeProjectProperties(project_path, target_api);
|
||||
prepBuildFiles(project_path);
|
||||
events.emit('log', generateDoneMessage('create', options.link));
|
||||
}).thenResolve(project_path);
|
||||
};
|
||||
|
||||
function generateDoneMessage(type, link) {
|
||||
var pkg = require('../../package');
|
||||
var msg = 'Android project ' + (type == 'update' ? 'updated ' : 'created ') + 'with ' + pkg.name + '@' + pkg.version;
|
||||
if (link) {
|
||||
msg += ' and has a linked CordovaLib';
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
// Returns a promise.
|
||||
exports.updateProject = function(projectPath) {
|
||||
// Check that requirements are met and proper targets are installed
|
||||
return check_reqs.run()
|
||||
exports.update = function(projectPath, options, events) {
|
||||
options = options || {};
|
||||
|
||||
return Q()
|
||||
.then(function() {
|
||||
var version = fs.readFileSync(path.join(ROOT, 'VERSION'), 'utf-8').trim();
|
||||
|
||||
var manifest = new AndroidManifest(path.join(projectPath, 'AndroidManifest.xml'));
|
||||
|
||||
if (Number(manifest.getMinSdkVersion()) < MIN_SDK_VERSION) {
|
||||
events.emit('verbose', 'Updating minSdkVersion to ' + MIN_SDK_VERSION + ' in AndroidManifest.xml');
|
||||
manifest.setMinSdkVersion(MIN_SDK_VERSION);
|
||||
}
|
||||
|
||||
manifest.setDebuggable(false).write();
|
||||
|
||||
var projectName = manifest.getActivity().getName();
|
||||
var target_api = check_reqs.get_target();
|
||||
return ensureJarIsBuilt(version, target_api);
|
||||
}).then(function() {
|
||||
copyJsAndJar(projectPath, version);
|
||||
|
||||
copyJsAndLibrary(projectPath, options.link, projectName);
|
||||
copyScripts(projectPath);
|
||||
console.log('Android project is now at version ' + version);
|
||||
});
|
||||
copyBuildRules(projectPath);
|
||||
writeProjectProperties(projectPath, target_api);
|
||||
prepBuildFiles(projectPath);
|
||||
events.emit('log', generateDoneMessage('update', options.link));
|
||||
}).thenResolve(projectPath);
|
||||
};
|
||||
|
||||
|
||||
// For testing
|
||||
exports.validatePackageName = validatePackageName;
|
||||
exports.validateProjectName = validateProjectName;
|
||||
|
||||
1
bin/node_modules/.bin/shjs
generated
vendored
@@ -1 +0,0 @@
|
||||
../shelljs/bin/shjs
|
||||
40
bin/node_modules/q/CONTRIBUTING.md
generated
vendored
@@ -1,40 +0,0 @@
|
||||
|
||||
For pull requests:
|
||||
|
||||
- Be consistent with prevalent style and design decisions.
|
||||
- Add a Jasmine spec to `specs/q-spec.js`.
|
||||
- Use `npm test` to avoid regressions.
|
||||
- Run tests in `q-spec/run.html` in as many supported browsers as you
|
||||
can find the will to deal with.
|
||||
- Do not build minified versions; we do this each release.
|
||||
- If you would be so kind, add a note to `CHANGES.md` in an
|
||||
appropriate section:
|
||||
|
||||
- `Next Major Version` if it introduces backward incompatibilities
|
||||
to code in the wild using documented features.
|
||||
- `Next Minor Version` if it adds a new feature.
|
||||
- `Next Patch Version` if it fixes a bug.
|
||||
|
||||
For releases:
|
||||
|
||||
- Run `npm test`.
|
||||
- Run tests in `q-spec/run.html` in a representative sample of every
|
||||
browser under the sun.
|
||||
- Run `npm run cover` and make sure you're happy with the results.
|
||||
- Run `npm run minify` and be sure to commit the resulting `q.min.js`.
|
||||
- Note the Gzipped size output by the previous command, and update
|
||||
`README.md` if it has changed to 1 significant digit.
|
||||
- Stash any local changes.
|
||||
- Update `CHANGES.md` to reflect all changes in the differences
|
||||
between `HEAD` and the previous tagged version. Give credit where
|
||||
credit is due.
|
||||
- Update `README.md` to address all new, non-experimental features.
|
||||
- Update the API reference on the Wiki to reflect all non-experimental
|
||||
features.
|
||||
- Use `npm version major|minor|patch` to update `package.json`,
|
||||
commit, and tag the new version.
|
||||
- Use `npm publish` to send up a new release.
|
||||
- Send an email to the q-continuum mailing list announcing the new
|
||||
release and the notes from the change log. This helps folks
|
||||
maintaining other package ecosystems.
|
||||
|
||||
71
bin/node_modules/q/benchmark/compare-with-callbacks.js
generated
vendored
@@ -1,71 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
var Q = require("../q");
|
||||
var fs = require("fs");
|
||||
|
||||
suite("A single simple async operation", function () {
|
||||
bench("with an immediately-fulfilled promise", function (done) {
|
||||
Q().then(done);
|
||||
});
|
||||
|
||||
bench("with direct setImmediate usage", function (done) {
|
||||
setImmediate(done);
|
||||
});
|
||||
|
||||
bench("with direct setTimeout(…, 0)", function (done) {
|
||||
setTimeout(done, 0);
|
||||
});
|
||||
});
|
||||
|
||||
suite("A fs.readFile", function () {
|
||||
var denodeified = Q.denodeify(fs.readFile);
|
||||
|
||||
set("iterations", 1000);
|
||||
set("delay", 1000);
|
||||
|
||||
bench("directly, with callbacks", function (done) {
|
||||
fs.readFile(__filename, done);
|
||||
});
|
||||
|
||||
bench("with Q.nfcall", function (done) {
|
||||
Q.nfcall(fs.readFile, __filename).then(done);
|
||||
});
|
||||
|
||||
bench("with a Q.denodeify'ed version", function (done) {
|
||||
denodeified(__filename).then(done);
|
||||
});
|
||||
|
||||
bench("with manual usage of deferred.makeNodeResolver", function (done) {
|
||||
var deferred = Q.defer();
|
||||
fs.readFile(__filename, deferred.makeNodeResolver());
|
||||
deferred.promise.then(done);
|
||||
});
|
||||
});
|
||||
|
||||
suite("1000 operations in parallel", function () {
|
||||
function makeCounter(desiredCount, ultimateCallback) {
|
||||
var soFar = 0;
|
||||
return function () {
|
||||
if (++soFar === desiredCount) {
|
||||
ultimateCallback();
|
||||
}
|
||||
};
|
||||
}
|
||||
var numberOfOps = 1000;
|
||||
|
||||
bench("with immediately-fulfilled promises", function (done) {
|
||||
var counter = makeCounter(numberOfOps, done);
|
||||
|
||||
for (var i = 0; i < numberOfOps; ++i) {
|
||||
Q().then(counter);
|
||||
}
|
||||
});
|
||||
|
||||
bench("with direct setImmediate usage", function (done) {
|
||||
var counter = makeCounter(numberOfOps, done);
|
||||
|
||||
for (var i = 0; i < numberOfOps; ++i) {
|
||||
setImmediate(counter);
|
||||
}
|
||||
});
|
||||
});
|
||||
36
bin/node_modules/q/benchmark/scenarios.js
generated
vendored
@@ -1,36 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
var Q = require("../q");
|
||||
|
||||
suite("Chaining", function () {
|
||||
var numberToChain = 1000;
|
||||
|
||||
bench("Chaining many already-fulfilled promises together", function (done) {
|
||||
var currentPromise = Q();
|
||||
for (var i = 0; i < numberToChain; ++i) {
|
||||
currentPromise = currentPromise.then(function () {
|
||||
return Q();
|
||||
});
|
||||
}
|
||||
|
||||
currentPromise.then(done);
|
||||
});
|
||||
|
||||
bench("Chaining and then fulfilling the end of the chain", function (done) {
|
||||
var deferred = Q.defer();
|
||||
|
||||
var currentPromise = deferred.promise;
|
||||
for (var i = 0; i < numberToChain; ++i) {
|
||||
(function () {
|
||||
var promiseToReturn = currentPromise;
|
||||
currentPromise = Q().then(function () {
|
||||
return promiseToReturn;
|
||||
});
|
||||
}());
|
||||
}
|
||||
|
||||
currentPromise.then(done);
|
||||
|
||||
deferred.resolve();
|
||||
});
|
||||
});
|
||||
93
bin/node_modules/q/package.json
generated
vendored
48
bin/node_modules/shelljs/package.json
generated
vendored
@@ -1,33 +0,0 @@
|
||||
{
|
||||
"name": "cordova-android",
|
||||
"description": "Cordova tooling for the android platform.",
|
||||
"version": "0.0.0",
|
||||
"homepage": "http://github.com/apache/cordova-android",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://git-wip-us.apache.org/repos/asf/cordova-android.git"
|
||||
},
|
||||
"keywords": [
|
||||
"cli",
|
||||
"cordova",
|
||||
"tooling"
|
||||
],
|
||||
"engineStrict": "true",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"shelljs" : "0.2.6",
|
||||
"q": "~0.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
},
|
||||
"optionalDependencies": {
|
||||
},
|
||||
"author": {
|
||||
"name": "Benn Mapes",
|
||||
"email": "bennmapes@gmail.com"
|
||||
},
|
||||
"contributors": [
|
||||
]
|
||||
}
|
||||
10
bin/templates/cordova/.jshintrc
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"node": true
|
||||
, "bitwise": true
|
||||
, "undef": true
|
||||
, "trailing": true
|
||||
, "quotmark": true
|
||||
, "indent": 4
|
||||
, "unused": "vars"
|
||||
, "latedef": "nofunc"
|
||||
}
|
||||
349
bin/templates/cordova/Api.js
vendored
Normal file
@@ -0,0 +1,349 @@
|
||||
/**
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*/
|
||||
|
||||
var path = require('path');
|
||||
|
||||
var AndroidProject = require('./lib/AndroidProject');
|
||||
var PluginManager = require('cordova-common').PluginManager;
|
||||
|
||||
var CordovaLogger = require('cordova-common').CordovaLogger;
|
||||
var selfEvents = require('cordova-common').events;
|
||||
|
||||
var PLATFORM = 'android';
|
||||
|
||||
function setupEvents(externalEventEmitter) {
|
||||
if (externalEventEmitter) {
|
||||
// This will make the platform internal events visible outside
|
||||
selfEvents.forwardEventsTo(externalEventEmitter);
|
||||
return externalEventEmitter;
|
||||
}
|
||||
|
||||
// There is no logger if external emitter is not present,
|
||||
// so attach a console logger
|
||||
CordovaLogger.get().subscribe(selfEvents);
|
||||
return selfEvents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class, that acts as abstraction over particular platform. Encapsulates the
|
||||
* platform's properties and methods.
|
||||
*
|
||||
* Platform that implements own PlatformApi instance _should implement all
|
||||
* prototype methods_ of this class to be fully compatible with cordova-lib.
|
||||
*
|
||||
* The PlatformApi instance also should define the following field:
|
||||
*
|
||||
* * platform: String that defines a platform name.
|
||||
*/
|
||||
function Api(platform, platformRootDir, events) {
|
||||
this.platform = PLATFORM;
|
||||
this.root = path.resolve(__dirname, '..');
|
||||
|
||||
setupEvents(events);
|
||||
|
||||
var self = this;
|
||||
|
||||
this.locations = {
|
||||
root: self.root,
|
||||
www: path.join(self.root, 'assets/www'),
|
||||
platformWww: path.join(self.root, 'platform_www'),
|
||||
configXml: path.join(self.root, 'res/xml/config.xml'),
|
||||
defaultConfigXml: path.join(self.root, 'cordova/defaults.xml'),
|
||||
strings: path.join(self.root, 'res/values/strings.xml'),
|
||||
manifest: path.join(self.root, 'AndroidManifest.xml'),
|
||||
// NOTE: Due to platformApi spec we need to return relative paths here
|
||||
cordovaJs: 'bin/templates/project/assets/www/cordova.js',
|
||||
cordovaJsSrc: 'cordova-js-src'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs platform to specified directory and creates a platform project.
|
||||
*
|
||||
* @param {String} destination Destination directory, where insatll platform to
|
||||
* @param {ConfigParser} [config] ConfgiParser instance, used to retrieve
|
||||
* project creation options, such as package id and project name.
|
||||
* @param {Object} [options] An options object. The most common options are:
|
||||
* @param {String} [options.customTemplate] A path to custom template, that
|
||||
* should override the default one from platform.
|
||||
* @param {Boolean} [options.link] Flag that indicates that platform's
|
||||
* sources will be linked to installed platform instead of copying.
|
||||
* @param {EventEmitter} [events] An EventEmitter instance that will be used for
|
||||
* logging purposes. If no EventEmitter provided, all events will be logged to
|
||||
* console
|
||||
*
|
||||
* @return {Promise<PlatformApi>} Promise either fulfilled with PlatformApi
|
||||
* instance or rejected with CordovaError.
|
||||
*/
|
||||
Api.createPlatform = function (destination, config, options, events) {
|
||||
events = setupEvents(events);
|
||||
|
||||
return require('../../lib/create')
|
||||
.create(destination, config, options, events)
|
||||
.then(function (destination) {
|
||||
var PlatformApi = require(path.resolve(destination, 'cordova/Api'));
|
||||
return new PlatformApi(PLATFORM, destination, events);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates already installed platform.
|
||||
*
|
||||
* @param {String} destination Destination directory, where platform installed
|
||||
* @param {Object} [options] An options object. The most common options are:
|
||||
* @param {String} [options.customTemplate] A path to custom template, that
|
||||
* should override the default one from platform.
|
||||
* @param {Boolean} [options.link] Flag that indicates that platform's
|
||||
* sources will be linked to installed platform instead of copying.
|
||||
* @param {EventEmitter} [events] An EventEmitter instance that will be used for
|
||||
* logging purposes. If no EventEmitter provided, all events will be logged to
|
||||
* console
|
||||
*
|
||||
* @return {Promise<PlatformApi>} Promise either fulfilled with PlatformApi
|
||||
* instance or rejected with CordovaError.
|
||||
*/
|
||||
Api.updatePlatform = function (destination, options, events) {
|
||||
events = setupEvents(events);
|
||||
|
||||
return require('../../lib/create')
|
||||
.update(destination, options, events)
|
||||
.then(function (destination) {
|
||||
var PlatformApi = require(path.resolve(destination, 'cordova/Api'));
|
||||
return new PlatformApi('android', destination, events);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets a CordovaPlatform object, that represents the platform structure.
|
||||
*
|
||||
* @return {CordovaPlatform} A structure that contains the description of
|
||||
* platform's file structure and other properties of platform.
|
||||
*/
|
||||
Api.prototype.getPlatformInfo = function () {
|
||||
var result = {};
|
||||
result.locations = this.locations;
|
||||
result.root = this.root;
|
||||
result.name = this.platform;
|
||||
result.version = require('./version');
|
||||
result.projectConfig = this._config;
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates installed platform with provided www assets and new app
|
||||
* configuration. This method is required for CLI workflow and will be called
|
||||
* each time before build, so the changes, made to app configuration and www
|
||||
* code, will be applied to platform.
|
||||
*
|
||||
* @param {CordovaProject} cordovaProject A CordovaProject instance, that defines a
|
||||
* project structure and configuration, that should be applied to platform
|
||||
* (contains project's www location and ConfigParser instance for project's
|
||||
* config).
|
||||
*
|
||||
* @return {Promise} Return a promise either fulfilled, or rejected with
|
||||
* CordovaError instance.
|
||||
*/
|
||||
Api.prototype.prepare = function (cordovaProject, prepareOptions) {
|
||||
return require('./lib/prepare').prepare.call(this, cordovaProject, prepareOptions);
|
||||
};
|
||||
|
||||
/**
|
||||
* Installs a new plugin into platform. This method only copies non-www files
|
||||
* (sources, libs, etc.) to platform. It also doesn't resolves the
|
||||
* dependencies of plugin. Both of handling of www files, such as assets and
|
||||
* js-files and resolving dependencies are the responsibility of caller.
|
||||
*
|
||||
* @param {PluginInfo} plugin A PluginInfo instance that represents plugin
|
||||
* that will be installed.
|
||||
* @param {Object} installOptions An options object. Possible options below:
|
||||
* @param {Boolean} installOptions.link: Flag that specifies that plugin
|
||||
* sources will be symlinked to app's directory instead of copying (if
|
||||
* possible).
|
||||
* @param {Object} installOptions.variables An object that represents
|
||||
* variables that will be used to install plugin. See more details on plugin
|
||||
* variables in documentation:
|
||||
* https://cordova.apache.org/docs/en/4.0.0/plugin_ref_spec.md.html
|
||||
*
|
||||
* @return {Promise} Return a promise either fulfilled, or rejected with
|
||||
* CordovaError instance.
|
||||
*/
|
||||
Api.prototype.addPlugin = function (plugin, installOptions) {
|
||||
var project = AndroidProject.getProjectFile(this.root);
|
||||
|
||||
installOptions = installOptions || {};
|
||||
installOptions.variables = installOptions.variables || {};
|
||||
// Add PACKAGE_NAME variable into vars
|
||||
if (!installOptions.variables.PACKAGE_NAME) {
|
||||
installOptions.variables.PACKAGE_NAME = project.getPackageName();
|
||||
}
|
||||
|
||||
return PluginManager.get(this.platform, this.locations, project)
|
||||
.addPlugin(plugin, installOptions)
|
||||
.then(function () {
|
||||
if (plugin.getFrameworks(this.platform).length === 0) return;
|
||||
|
||||
selfEvents.emit('verbose', 'Updating build files since android plugin contained <framework>');
|
||||
require('./lib/builders/builders').getBuilder('gradle').prepBuildFiles();
|
||||
}.bind(this))
|
||||
// CB-11022 Return truthy value to prevent running prepare after
|
||||
.thenResolve(true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes an installed plugin from platform.
|
||||
*
|
||||
* Since method accepts PluginInfo instance as input parameter instead of plugin
|
||||
* id, caller shoud take care of managing/storing PluginInfo instances for
|
||||
* future uninstalls.
|
||||
*
|
||||
* @param {PluginInfo} plugin A PluginInfo instance that represents plugin
|
||||
* that will be installed.
|
||||
*
|
||||
* @return {Promise} Return a promise either fulfilled, or rejected with
|
||||
* CordovaError instance.
|
||||
*/
|
||||
Api.prototype.removePlugin = function (plugin, uninstallOptions) {
|
||||
var project = AndroidProject.getProjectFile(this.root);
|
||||
return PluginManager.get(this.platform, this.locations, project)
|
||||
.removePlugin(plugin, uninstallOptions)
|
||||
.then(function () {
|
||||
if (plugin.getFrameworks(this.platform).length === 0) return;
|
||||
|
||||
selfEvents.emit('verbose', 'Updating build files since android plugin contained <framework>');
|
||||
require('./lib/builders/builders').getBuilder('gradle').prepBuildFiles();
|
||||
}.bind(this))
|
||||
// CB-11022 Return truthy value to prevent running prepare after
|
||||
.thenResolve(true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Builds an application package for current platform.
|
||||
*
|
||||
* @param {Object} buildOptions A build options. This object's structure is
|
||||
* highly depends on platform's specific. The most common options are:
|
||||
* @param {Boolean} buildOptions.debug Indicates that packages should be
|
||||
* built with debug configuration. This is set to true by default unless the
|
||||
* 'release' option is not specified.
|
||||
* @param {Boolean} buildOptions.release Indicates that packages should be
|
||||
* built with release configuration. If not set to true, debug configuration
|
||||
* will be used.
|
||||
* @param {Boolean} buildOptions.device Specifies that built app is intended
|
||||
* to run on device
|
||||
* @param {Boolean} buildOptions.emulator: Specifies that built app is
|
||||
* intended to run on emulator
|
||||
* @param {String} buildOptions.target Specifies the device id that will be
|
||||
* used to run built application.
|
||||
* @param {Boolean} buildOptions.nobuild Indicates that this should be a
|
||||
* dry-run call, so no build artifacts will be produced.
|
||||
* @param {String[]} buildOptions.archs Specifies chip architectures which
|
||||
* app packages should be built for. List of valid architectures is depends on
|
||||
* platform.
|
||||
* @param {String} buildOptions.buildConfig The path to build configuration
|
||||
* file. The format of this file is depends on platform.
|
||||
* @param {String[]} buildOptions.argv Raw array of command-line arguments,
|
||||
* passed to `build` command. The purpose of this property is to pass a
|
||||
* platform-specific arguments, and eventually let platform define own
|
||||
* arguments processing logic.
|
||||
*
|
||||
* @return {Promise<Object[]>} A promise either fulfilled with an array of build
|
||||
* artifacts (application packages) if package was built successfully,
|
||||
* or rejected with CordovaError. The resultant build artifact objects is not
|
||||
* strictly typed and may conatin arbitrary set of fields as in sample below.
|
||||
*
|
||||
* {
|
||||
* architecture: 'x86',
|
||||
* buildType: 'debug',
|
||||
* path: '/path/to/build',
|
||||
* type: 'app'
|
||||
* }
|
||||
*
|
||||
* The return value in most cases will contain only one item but in some cases
|
||||
* there could be multiple items in output array, e.g. when multiple
|
||||
* arhcitectures is specified.
|
||||
*/
|
||||
Api.prototype.build = function (buildOptions) {
|
||||
var self = this;
|
||||
return require('./lib/check_reqs').run()
|
||||
.then(function () {
|
||||
return require('./lib/build').run.call(self, buildOptions);
|
||||
})
|
||||
.then(function (buildResults) {
|
||||
// Cast build result to array of build artifacts
|
||||
return buildResults.apkPaths.map(function (apkPath) {
|
||||
return {
|
||||
buildType: buildResults.buildType,
|
||||
buildMethod: buildResults.buildMethod,
|
||||
path: apkPath,
|
||||
type: 'apk'
|
||||
};
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Builds an application package for current platform and runs it on
|
||||
* specified/default device. If no 'device'/'emulator'/'target' options are
|
||||
* specified, then tries to run app on default device if connected, otherwise
|
||||
* runs the app on emulator.
|
||||
*
|
||||
* @param {Object} runOptions An options object. The structure is the same
|
||||
* as for build options.
|
||||
*
|
||||
* @return {Promise} A promise either fulfilled if package was built and ran
|
||||
* successfully, or rejected with CordovaError.
|
||||
*/
|
||||
Api.prototype.run = function(runOptions) {
|
||||
var self = this;
|
||||
return require('./lib/check_reqs').run()
|
||||
.then(function () {
|
||||
return require('./lib/run').run.call(self, runOptions);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Cleans out the build artifacts from platform's directory.
|
||||
*
|
||||
* @return {Promise} Return a promise either fulfilled, or rejected with
|
||||
* CordovaError.
|
||||
*/
|
||||
Api.prototype.clean = function(cleanOptions) {
|
||||
var self = this;
|
||||
return require('./lib/check_reqs').run()
|
||||
.then(function () {
|
||||
return require('./lib/build').runClean.call(self, cleanOptions);
|
||||
})
|
||||
.then(function () {
|
||||
return require('./lib/prepare').clean.call(self, cleanOptions);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Performs a requirements check for current platform. Each platform defines its
|
||||
* own set of requirements, which should be resolved before platform can be
|
||||
* built successfully.
|
||||
*
|
||||
* @return {Promise<Requirement[]>} Promise, resolved with set of Requirement
|
||||
* objects for current platform.
|
||||
*/
|
||||
Api.prototype.requirements = function() {
|
||||
return require('./lib/check_reqs').check_all();
|
||||
};
|
||||
|
||||
module.exports = Api;
|
||||
@@ -19,19 +19,32 @@
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var build = require('./lib/build'),
|
||||
reqs = require('./lib/check_reqs'),
|
||||
args = process.argv;
|
||||
var args = process.argv;
|
||||
var Api = require('./Api');
|
||||
var nopt = require('nopt');
|
||||
var path = require('path');
|
||||
|
||||
// Support basic help commands
|
||||
if(args[2] == '--help' || args[2] == '/?' || args[2] == '-h' ||
|
||||
args[2] == 'help' || args[2] == '-help' || args[2] == '/help') {
|
||||
build.help();
|
||||
} else {
|
||||
reqs.run().then(function() {
|
||||
return build.run(args[2]);
|
||||
}).done(null, function(err) {
|
||||
console.error(err);
|
||||
process.exit(2);
|
||||
});
|
||||
}
|
||||
if(['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) >= 0)
|
||||
require('./lib/build').help();
|
||||
|
||||
// Do some basic argument parsing
|
||||
var buildOpts = nopt({
|
||||
'verbose' : Boolean,
|
||||
'silent' : Boolean,
|
||||
'debug' : Boolean,
|
||||
'release' : Boolean,
|
||||
'nobuild': Boolean,
|
||||
'buildConfig' : path
|
||||
}, { 'd' : '--verbose' });
|
||||
|
||||
// Make buildOptions compatible with PlatformApi build method spec
|
||||
buildOpts.argv = buildOpts.argv.original;
|
||||
|
||||
require('./loggingHelper').adjustLoggerLevel(buildOpts);
|
||||
|
||||
new Api().build(buildOpts)
|
||||
.catch(function(err) {
|
||||
console.error(err.stack);
|
||||
process.exit(2);
|
||||
});
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
:: to you 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
|
||||
@@ -18,7 +18,7 @@
|
||||
@ECHO OFF
|
||||
SET script_path="%~dp0build"
|
||||
IF EXIST %script_path% (
|
||||
node "%script_path%" %*
|
||||
node %script_path% %*
|
||||
) ELSE (
|
||||
ECHO.
|
||||
ECHO ERROR: Could not find 'build' script in 'cordova' folder, aborting...>&2
|
||||
|
||||
@@ -19,18 +19,33 @@
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var clean = require('./lib/clean'),
|
||||
reqs = require('./lib/check_reqs'),
|
||||
args = process.argv;
|
||||
var Api = require('./Api');
|
||||
var path = require('path');
|
||||
var nopt = require('nopt');
|
||||
|
||||
// Usage support for when args are given
|
||||
if(args.length > 2) {
|
||||
clean.help();
|
||||
} else {
|
||||
reqs.run().done(function() {
|
||||
return clean.run();
|
||||
}, function(err) {
|
||||
console.error('ERROR: ' + err);
|
||||
process.exit(2);
|
||||
});
|
||||
// Support basic help commands
|
||||
if(['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) >= 0) {
|
||||
console.log('Usage: ' + path.relative(process.cwd(), process.argv[1]));
|
||||
console.log('Cleans the project directory.');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Do some basic argument parsing
|
||||
var opts = nopt({
|
||||
'verbose' : Boolean,
|
||||
'silent' : Boolean
|
||||
}, { 'd' : '--verbose' });
|
||||
|
||||
// Make buildOptions compatible with PlatformApi clean method spec
|
||||
opts.argv = opts.argv.original;
|
||||
|
||||
// Skip cleaning prepared files when not invoking via cordova CLI.
|
||||
opts.noPrepare = true;
|
||||
|
||||
require('./loggingHelper').adjustLoggerLevel(opts);
|
||||
|
||||
new Api().clean(opts)
|
||||
.catch(function(err) {
|
||||
console.error(err.stack);
|
||||
process.exit(2);
|
||||
});
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
:: to you 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
|
||||
@@ -18,7 +18,7 @@
|
||||
@ECHO OFF
|
||||
SET script_path="%~dp0clean"
|
||||
IF EXIST %script_path% (
|
||||
node "%script_path%" %*
|
||||
node %script_path% %*
|
||||
) ELSE (
|
||||
ECHO.
|
||||
ECHO ERROR: Could not find 'clean' script in 'cordova' folder, aborting...>&2
|
||||
|
||||
26
bin/templates/cordova/defaults.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
-->
|
||||
<widget xmlns = "http://www.w3.org/ns/widgets"
|
||||
id = "io.cordova.helloCordova"
|
||||
version = "2.0.0">
|
||||
|
||||
<!-- Preferences for Android -->
|
||||
<preference name="loglevel" value="DEBUG" />
|
||||
</widget>
|
||||
105
bin/templates/cordova/lib/Adb.js
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*/
|
||||
|
||||
var Q = require('q');
|
||||
var os = require('os');
|
||||
var events = require('cordova-common').events;
|
||||
var spawn = require('cordova-common').superspawn.spawn;
|
||||
var CordovaError = require('cordova-common').CordovaError;
|
||||
|
||||
var Adb = {};
|
||||
|
||||
function isDevice(line) {
|
||||
return line.match(/\w+\tdevice/) && !line.match(/emulator/);
|
||||
}
|
||||
|
||||
function isEmulator(line) {
|
||||
return line.match(/device/) && line.match(/emulator/);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists available/connected devices and emulators
|
||||
*
|
||||
* @param {Object} opts Various options
|
||||
* @param {Boolean} opts.emulators Specifies whether this method returns
|
||||
* emulators only
|
||||
*
|
||||
* @return {Promise<String[]>} list of available/connected
|
||||
* devices/emulators
|
||||
*/
|
||||
Adb.devices = function (opts) {
|
||||
return spawn('adb', ['devices'], {cwd: os.tmpdir()})
|
||||
.then(function(output) {
|
||||
return output.split('\n').filter(function (line) {
|
||||
// Filter out either real devices or emulators, depending on options
|
||||
return (line && opts && opts.emulators) ? isEmulator(line) : isDevice(line);
|
||||
}).map(function (line) {
|
||||
return line.replace(/\tdevice/, '').replace('\r', '');
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Adb.install = function (target, packagePath, opts) {
|
||||
events.emit('verbose', 'Installing apk ' + packagePath + ' on target ' + target + '...');
|
||||
var args = ['-s', target, 'install'];
|
||||
if (opts && opts.replace) args.push('-r');
|
||||
return spawn('adb', args.concat(packagePath), {cwd: os.tmpdir()})
|
||||
.then(function(output) {
|
||||
// 'adb install' seems to always returns no error, even if installation fails
|
||||
// so we catching output to detect installation failure
|
||||
if (output.match(/Failure/)) {
|
||||
if (output.match(/INSTALL_PARSE_FAILED_NO_CERTIFICATES/)) {
|
||||
output += '\n\n' + 'Sign the build using \'-- --keystore\' or \'--buildConfig\'' +
|
||||
' or sign and deploy the unsigned apk manually using Android tools.';
|
||||
} else if (output.match(/INSTALL_FAILED_VERSION_DOWNGRADE/)) {
|
||||
output += '\n\n' + 'You\'re trying to install apk with a lower versionCode that is already installed.' +
|
||||
'\nEither uninstall an app or increment the versionCode.';
|
||||
}
|
||||
|
||||
return Q.reject(new CordovaError('Failed to install apk to device: ' + output));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Adb.uninstall = function (target, packageId) {
|
||||
events.emit('verbose', 'Uninstalling package ' + packageId + ' from target ' + target + '...');
|
||||
return spawn('adb', ['-s', target, 'uninstall', packageId], {cwd: os.tmpdir()});
|
||||
};
|
||||
|
||||
Adb.shell = function (target, shellCommand) {
|
||||
events.emit('verbose', 'Running adb shell command "' + shellCommand + '" on target ' + target + '...');
|
||||
var args = ['-s', target, 'shell'];
|
||||
shellCommand = shellCommand.split(/\s+/);
|
||||
return spawn('adb', args.concat(shellCommand), {cwd: os.tmpdir()})
|
||||
.catch(function (output) {
|
||||
return Q.reject(new CordovaError('Failed to execute shell command "' +
|
||||
shellCommand + '"" on device: ' + output));
|
||||
});
|
||||
};
|
||||
|
||||
Adb.start = function (target, activityName) {
|
||||
events.emit('verbose', 'Starting application "' + activityName + '" on target ' + target + '...');
|
||||
return Adb.shell(target, 'am start -W -a android.intent.action.MAIN -n' + activityName)
|
||||
.catch(function (output) {
|
||||
return Q.reject(new CordovaError('Failed to start application "' +
|
||||
activityName + '"" on device: ' + output));
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = Adb;
|
||||
161
bin/templates/cordova/lib/AndroidManifest.js
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
/**
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*/
|
||||
|
||||
var fs = require('fs');
|
||||
var et = require('elementtree');
|
||||
var xml= require('cordova-common').xmlHelpers;
|
||||
|
||||
var DEFAULT_ORIENTATION = 'default';
|
||||
|
||||
/** Wraps an AndroidManifest file */
|
||||
function AndroidManifest(path) {
|
||||
this.path = path;
|
||||
this.doc = xml.parseElementtreeSync(path);
|
||||
if (this.doc.getroot().tag !== 'manifest') {
|
||||
throw new Error('AndroidManifest at ' + path + ' has incorrect root node name (expected "manifest")');
|
||||
}
|
||||
}
|
||||
|
||||
AndroidManifest.prototype.getVersionName = function() {
|
||||
return this.doc.getroot().attrib['android:versionName'];
|
||||
};
|
||||
|
||||
AndroidManifest.prototype.setVersionName = function(versionName) {
|
||||
this.doc.getroot().attrib['android:versionName'] = versionName;
|
||||
return this;
|
||||
};
|
||||
|
||||
AndroidManifest.prototype.getVersionCode = function() {
|
||||
return this.doc.getroot().attrib['android:versionCode'];
|
||||
};
|
||||
|
||||
AndroidManifest.prototype.setVersionCode = function(versionCode) {
|
||||
this.doc.getroot().attrib['android:versionCode'] = versionCode;
|
||||
return this;
|
||||
};
|
||||
|
||||
AndroidManifest.prototype.getPackageId = function() {
|
||||
/*jshint -W069 */
|
||||
return this.doc.getroot().attrib['package'];
|
||||
/*jshint +W069 */
|
||||
};
|
||||
|
||||
AndroidManifest.prototype.setPackageId = function(pkgId) {
|
||||
/*jshint -W069 */
|
||||
this.doc.getroot().attrib['package'] = pkgId;
|
||||
/*jshint +W069 */
|
||||
return this;
|
||||
};
|
||||
|
||||
AndroidManifest.prototype.getActivity = function() {
|
||||
var activity = this.doc.getroot().find('./application/activity');
|
||||
return {
|
||||
getName: function () {
|
||||
return activity.attrib['android:name'];
|
||||
},
|
||||
setName: function (name) {
|
||||
if (!name) {
|
||||
delete activity.attrib['android:name'];
|
||||
} else {
|
||||
activity.attrib['android:name'] = name;
|
||||
}
|
||||
return this;
|
||||
},
|
||||
getOrientation: function () {
|
||||
return activity.attrib['android:screenOrientation'];
|
||||
},
|
||||
setOrientation: function (orientation) {
|
||||
if (!orientation || orientation.toLowerCase() === DEFAULT_ORIENTATION) {
|
||||
delete activity.attrib['android:screenOrientation'];
|
||||
} else {
|
||||
activity.attrib['android:screenOrientation'] = orientation;
|
||||
}
|
||||
return this;
|
||||
},
|
||||
getLaunchMode: function () {
|
||||
return activity.attrib['android:launchMode'];
|
||||
},
|
||||
setLaunchMode: function (launchMode) {
|
||||
if (!launchMode) {
|
||||
delete activity.attrib['android:launchMode'];
|
||||
} else {
|
||||
activity.attrib['android:launchMode'] = launchMode;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
['minSdkVersion', 'maxSdkVersion', 'targetSdkVersion']
|
||||
.forEach(function(sdkPrefName) {
|
||||
// Copy variable reference to avoid closure issues
|
||||
var prefName = sdkPrefName;
|
||||
|
||||
AndroidManifest.prototype['get' + capitalize(prefName)] = function() {
|
||||
var usesSdk = this.doc.getroot().find('./uses-sdk');
|
||||
return usesSdk && usesSdk.attrib['android:' + prefName];
|
||||
};
|
||||
|
||||
AndroidManifest.prototype['set' + capitalize(prefName)] = function(prefValue) {
|
||||
var usesSdk = this.doc.getroot().find('./uses-sdk');
|
||||
|
||||
if (!usesSdk && prefValue) { // if there is no required uses-sdk element, we should create it first
|
||||
usesSdk = new et.Element('uses-sdk');
|
||||
this.doc.getroot().append(usesSdk);
|
||||
}
|
||||
|
||||
if (prefValue) {
|
||||
usesSdk.attrib['android:' + prefName] = prefValue;
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
});
|
||||
|
||||
AndroidManifest.prototype.getDebuggable = function() {
|
||||
return this.doc.getroot().find('./application').attrib['android:debuggable'] === 'true';
|
||||
};
|
||||
|
||||
AndroidManifest.prototype.setDebuggable = function(value) {
|
||||
var application = this.doc.getroot().find('./application');
|
||||
if (value) {
|
||||
application.attrib['android:debuggable'] = 'true';
|
||||
} else {
|
||||
// The default value is "false", so we can remove attribute at all.
|
||||
delete application.attrib['android:debuggable'];
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Writes manifest to disk syncronously. If filename is specified, then manifest
|
||||
* will be written to that file
|
||||
*
|
||||
* @param {String} [destPath] File to write manifest to. If omitted,
|
||||
* manifest will be written to file it has been read from.
|
||||
*/
|
||||
AndroidManifest.prototype.write = function(destPath) {
|
||||
fs.writeFileSync(destPath || this.path, this.doc.write({indent: 4}), 'utf-8');
|
||||
};
|
||||
|
||||
module.exports = AndroidManifest;
|
||||
|
||||
function capitalize (str) {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
}
|
||||
193
bin/templates/cordova/lib/AndroidProject.js
vendored
Normal file
@@ -0,0 +1,193 @@
|
||||
/**
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*/
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var properties_parser = require('properties-parser');
|
||||
var AndroidManifest = require('./AndroidManifest');
|
||||
var pluginHandlers = require('./pluginHandlers');
|
||||
|
||||
var projectFileCache = {};
|
||||
|
||||
function addToPropertyList(projectProperties, key, value) {
|
||||
var i = 1;
|
||||
while (projectProperties.get(key + '.' + i))
|
||||
i++;
|
||||
|
||||
projectProperties.set(key + '.' + i, value);
|
||||
projectProperties.dirty = true;
|
||||
}
|
||||
|
||||
function removeFromPropertyList(projectProperties, key, value) {
|
||||
var i = 1;
|
||||
var currentValue;
|
||||
while ((currentValue = projectProperties.get(key + '.' + i))) {
|
||||
if (currentValue === value) {
|
||||
while ((currentValue = projectProperties.get(key + '.' + (i + 1)))) {
|
||||
projectProperties.set(key + '.' + i, currentValue);
|
||||
i++;
|
||||
}
|
||||
projectProperties.set(key + '.' + i);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
projectProperties.dirty = true;
|
||||
}
|
||||
|
||||
function getRelativeLibraryPath (parentDir, subDir) {
|
||||
var libraryPath = path.relative(parentDir, subDir);
|
||||
return (path.sep == '\\') ? libraryPath.replace(/\\/g, '/') : libraryPath;
|
||||
}
|
||||
|
||||
function AndroidProject(projectDir) {
|
||||
this._propertiesEditors = {};
|
||||
this._subProjectDirs = {};
|
||||
this._dirty = false;
|
||||
this.projectDir = projectDir;
|
||||
this.platformWww = path.join(this.projectDir, 'platform_www');
|
||||
this.www = path.join(this.projectDir, 'assets/www');
|
||||
}
|
||||
|
||||
AndroidProject.getProjectFile = function (projectDir) {
|
||||
if (!projectFileCache[projectDir]) {
|
||||
projectFileCache[projectDir] = new AndroidProject(projectDir);
|
||||
}
|
||||
|
||||
return projectFileCache[projectDir];
|
||||
};
|
||||
|
||||
AndroidProject.purgeCache = function (projectDir) {
|
||||
if (projectDir) {
|
||||
delete projectFileCache[projectDir];
|
||||
} else {
|
||||
projectFileCache = {};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Reads the package name out of the Android Manifest file
|
||||
*
|
||||
* @param {String} projectDir The absolute path to the directory containing the project
|
||||
*
|
||||
* @return {String} The name of the package
|
||||
*/
|
||||
AndroidProject.prototype.getPackageName = function() {
|
||||
return new AndroidManifest(path.join(this.projectDir, 'AndroidManifest.xml')).getPackageId();
|
||||
};
|
||||
|
||||
AndroidProject.prototype.getCustomSubprojectRelativeDir = function(plugin_id, src) {
|
||||
// All custom subprojects are prefixed with the last portion of the package id.
|
||||
// This is to avoid collisions when opening multiple projects in Eclipse that have subprojects with the same name.
|
||||
var packageName = this.getPackageName();
|
||||
var lastDotIndex = packageName.lastIndexOf('.');
|
||||
var prefix = packageName.substring(lastDotIndex + 1);
|
||||
var subRelativeDir = path.join(plugin_id, prefix + '-' + path.basename(src));
|
||||
return subRelativeDir;
|
||||
};
|
||||
|
||||
AndroidProject.prototype.addSubProject = function(parentDir, subDir) {
|
||||
var parentProjectFile = path.resolve(parentDir, 'project.properties');
|
||||
var subProjectFile = path.resolve(subDir, 'project.properties');
|
||||
var parentProperties = this._getPropertiesFile(parentProjectFile);
|
||||
// TODO: Setting the target needs to happen only for pre-3.7.0 projects
|
||||
if (fs.existsSync(subProjectFile)) {
|
||||
var subProperties = this._getPropertiesFile(subProjectFile);
|
||||
subProperties.set('target', parentProperties.get('target'));
|
||||
subProperties.dirty = true;
|
||||
this._subProjectDirs[subDir] = true;
|
||||
}
|
||||
addToPropertyList(parentProperties, 'android.library.reference', getRelativeLibraryPath(parentDir, subDir));
|
||||
|
||||
this._dirty = true;
|
||||
};
|
||||
|
||||
AndroidProject.prototype.removeSubProject = function(parentDir, subDir) {
|
||||
var parentProjectFile = path.resolve(parentDir, 'project.properties');
|
||||
var parentProperties = this._getPropertiesFile(parentProjectFile);
|
||||
removeFromPropertyList(parentProperties, 'android.library.reference', getRelativeLibraryPath(parentDir, subDir));
|
||||
delete this._subProjectDirs[subDir];
|
||||
this._dirty = true;
|
||||
};
|
||||
|
||||
AndroidProject.prototype.addGradleReference = function(parentDir, subDir) {
|
||||
var parentProjectFile = path.resolve(parentDir, 'project.properties');
|
||||
var parentProperties = this._getPropertiesFile(parentProjectFile);
|
||||
addToPropertyList(parentProperties, 'cordova.gradle.include', getRelativeLibraryPath(parentDir, subDir));
|
||||
this._dirty = true;
|
||||
};
|
||||
|
||||
AndroidProject.prototype.removeGradleReference = function(parentDir, subDir) {
|
||||
var parentProjectFile = path.resolve(parentDir, 'project.properties');
|
||||
var parentProperties = this._getPropertiesFile(parentProjectFile);
|
||||
removeFromPropertyList(parentProperties, 'cordova.gradle.include', getRelativeLibraryPath(parentDir, subDir));
|
||||
this._dirty = true;
|
||||
};
|
||||
|
||||
AndroidProject.prototype.addSystemLibrary = function(parentDir, value) {
|
||||
var parentProjectFile = path.resolve(parentDir, 'project.properties');
|
||||
var parentProperties = this._getPropertiesFile(parentProjectFile);
|
||||
addToPropertyList(parentProperties, 'cordova.system.library', value);
|
||||
this._dirty = true;
|
||||
};
|
||||
|
||||
AndroidProject.prototype.removeSystemLibrary = function(parentDir, value) {
|
||||
var parentProjectFile = path.resolve(parentDir, 'project.properties');
|
||||
var parentProperties = this._getPropertiesFile(parentProjectFile);
|
||||
removeFromPropertyList(parentProperties, 'cordova.system.library', value);
|
||||
this._dirty = true;
|
||||
};
|
||||
|
||||
AndroidProject.prototype.write = function() {
|
||||
if (!this._dirty) {
|
||||
return;
|
||||
}
|
||||
this._dirty = false;
|
||||
|
||||
for (var filename in this._propertiesEditors) {
|
||||
var editor = this._propertiesEditors[filename];
|
||||
if (editor.dirty) {
|
||||
fs.writeFileSync(filename, editor.toString());
|
||||
editor.dirty = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
AndroidProject.prototype._getPropertiesFile = function (filename) {
|
||||
if (!this._propertiesEditors[filename]) {
|
||||
if (fs.existsSync(filename)) {
|
||||
this._propertiesEditors[filename] = properties_parser.createEditor(filename);
|
||||
} else {
|
||||
this._propertiesEditors[filename] = properties_parser.createEditor();
|
||||
}
|
||||
}
|
||||
|
||||
return this._propertiesEditors[filename];
|
||||
};
|
||||
|
||||
AndroidProject.prototype.getInstaller = function (type) {
|
||||
return pluginHandlers.getInstaller(type);
|
||||
};
|
||||
|
||||
AndroidProject.prototype.getUninstaller = function (type) {
|
||||
return pluginHandlers.getUninstaller(type);
|
||||
};
|
||||
|
||||
|
||||
module.exports = AndroidProject;
|
||||
41
bin/templates/cordova/lib/appinfo.js
vendored
@@ -1,41 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*/
|
||||
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var cachedAppInfo = null;
|
||||
|
||||
function readAppInfoFromManifest() {
|
||||
var manifestPath = path.join(__dirname, '..', '..', 'AndroidManifest.xml');
|
||||
var manifestData = fs.readFileSync(manifestPath, {encoding:'utf8'});
|
||||
var packageName = /\bpackage\s*=\s*"(.+?)"/.exec(manifestData);
|
||||
if (!packageName) throw new Error('Could not find package name within ' + manifestPath);
|
||||
var activityTag = /<activity\b[\s\S]*<\/activity>/.exec(manifestData);
|
||||
if (!activityTag) throw new Error('Could not find <activity> within ' + manifestPath);
|
||||
var activityName = /\bandroid:name\s*=\s*"(.+?)"/.exec(activityTag);
|
||||
if (!activityName) throw new Error('Could not find android:name within ' + manifestPath);
|
||||
|
||||
return packageName[1] + '/.' + activityName[1];
|
||||
}
|
||||
|
||||
exports.getActivityName = function() {
|
||||
return cachedAppInfo = cachedAppInfo || readAppInfoFromManifest();
|
||||
};
|
||||
312
bin/templates/cordova/lib/build.js
vendored
@@ -19,69 +19,283 @@
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var shell = require('shelljs'),
|
||||
exec = require('./exec'),
|
||||
Q = require('q'),
|
||||
clean = require('./clean'),
|
||||
var Q = require('q'),
|
||||
path = require('path'),
|
||||
fs = require('fs'),
|
||||
ROOT = path.join(__dirname, '..', '..');
|
||||
nopt = require('nopt');
|
||||
|
||||
var Adb = require('./Adb');
|
||||
|
||||
var builders = require('./builders/builders');
|
||||
var events = require('cordova-common').events;
|
||||
var spawn = require('cordova-common').superspawn.spawn;
|
||||
var CordovaError = require('cordova-common').CordovaError;
|
||||
|
||||
function parseOpts(options, resolvedTarget, projectRoot) {
|
||||
options = options || {};
|
||||
options.argv = nopt({
|
||||
gradle: Boolean,
|
||||
ant: Boolean,
|
||||
prepenv: Boolean,
|
||||
versionCode: String,
|
||||
minSdkVersion: String,
|
||||
gradleArg: [String, Array],
|
||||
keystore: path,
|
||||
alias: String,
|
||||
storePassword: String,
|
||||
password: String,
|
||||
keystoreType: String
|
||||
}, {}, options.argv, 0);
|
||||
|
||||
var ret = {
|
||||
buildType: options.release ? 'release' : 'debug',
|
||||
buildMethod: process.env.ANDROID_BUILD || 'gradle',
|
||||
prepEnv: options.argv.prepenv,
|
||||
arch: resolvedTarget && resolvedTarget.arch,
|
||||
extraArgs: []
|
||||
};
|
||||
|
||||
if (options.argv.ant || options.argv.gradle)
|
||||
ret.buildMethod = options.argv.ant ? 'ant' : 'gradle';
|
||||
|
||||
if (options.nobuild) ret.buildMethod = 'none';
|
||||
|
||||
if (options.argv.versionCode)
|
||||
ret.extraArgs.push('-PcdvVersionCode=' + options.argv.versionCode);
|
||||
|
||||
if (options.argv.minSdkVersion)
|
||||
ret.extraArgs.push('-PcdvMinSdkVersion=' + options.argv.minSdkVersion);
|
||||
|
||||
if (options.argv.gradleArg) {
|
||||
ret.extraArgs = ret.extraArgs.concat(options.argv.gradleArg);
|
||||
}
|
||||
|
||||
var packageArgs = {};
|
||||
|
||||
if (options.argv.keystore)
|
||||
packageArgs.keystore = path.relative(projectRoot, path.resolve(options.argv.keystore));
|
||||
|
||||
['alias','storePassword','password','keystoreType'].forEach(function (flagName) {
|
||||
if (options.argv[flagName])
|
||||
packageArgs[flagName] = options.argv[flagName];
|
||||
});
|
||||
|
||||
var buildConfig = options.buildConfig;
|
||||
|
||||
// If some values are not specified as command line arguments - use build config to supplement them.
|
||||
// Command line arguemnts have precedence over build config.
|
||||
if (buildConfig) {
|
||||
if (!fs.existsSync(buildConfig)) {
|
||||
throw new Error('Specified build config file does not exist: ' + buildConfig);
|
||||
}
|
||||
events.emit('log', 'Reading build config file: '+ path.resolve(buildConfig));
|
||||
var buildjson = fs.readFileSync(buildConfig, 'utf8');
|
||||
var config = JSON.parse(buildjson.replace(/^\ufeff/, '')); // Remove BOM
|
||||
if (config.android && config.android[ret.buildType]) {
|
||||
var androidInfo = config.android[ret.buildType];
|
||||
if(androidInfo.keystore && !packageArgs.keystore) {
|
||||
if(androidInfo.keystore.substr(0,1) === '~') {
|
||||
androidInfo.keystore = process.env.HOME + androidInfo.keystore.substr(1);
|
||||
}
|
||||
packageArgs.keystore = path.resolve(path.dirname(buildConfig), androidInfo.keystore);
|
||||
events.emit('log', 'Reading the keystore from: ' + packageArgs.keystore);
|
||||
}
|
||||
|
||||
['alias', 'storePassword', 'password','keystoreType'].forEach(function (key){
|
||||
packageArgs[key] = packageArgs[key] || androidInfo[key];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (packageArgs.keystore && packageArgs.alias) {
|
||||
ret.packageInfo = new PackageInfo(packageArgs.keystore, packageArgs.alias, packageArgs.storePassword,
|
||||
packageArgs.password, packageArgs.keystoreType);
|
||||
}
|
||||
|
||||
if(!ret.packageInfo) {
|
||||
if(Object.keys(packageArgs).length > 0) {
|
||||
events.emit('warn', '\'keystore\' and \'alias\' need to be specified to generate a signed archive.');
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Builds the project with ant.
|
||||
* Builds the project with the specifed options
|
||||
* Returns a promise.
|
||||
*/
|
||||
module.exports.run = function(build_type) {
|
||||
//default build type
|
||||
build_type = typeof build_type !== 'undefined' ? build_type : "--debug";
|
||||
var cmd;
|
||||
switch(build_type) {
|
||||
case '--debug' :
|
||||
cmd = 'ant debug -f ' + path.join(ROOT, 'build.xml');
|
||||
break;
|
||||
case '--release' :
|
||||
cmd = 'ant release -f ' + path.join(ROOT, 'build.xml');
|
||||
break;
|
||||
case '--nobuild' :
|
||||
console.log('Skipping build...');
|
||||
return Q();
|
||||
default :
|
||||
return Q.reject('Build option \'' + build_type + '\' not recognized.');
|
||||
}
|
||||
if(cmd) {
|
||||
return clean.run() // TODO: Can we stop cleaning every time and let ant build incrementally?
|
||||
module.exports.runClean = function(options) {
|
||||
var opts = parseOpts(options, null, this.root);
|
||||
var builder = builders.getBuilder(opts.buildMethod);
|
||||
return builder.prepEnv(opts)
|
||||
.then(function() {
|
||||
return builder.clean(opts);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Builds the project with the specifed options.
|
||||
*
|
||||
* @param {BuildOptions} options A set of options. See PlatformApi.build
|
||||
* method documentation for reference.
|
||||
* @param {Object} optResolvedTarget A deployment target. Used to pass
|
||||
* target architecture from upstream 'run' call. TODO: remove this option in
|
||||
* favor of setting buildOptions.archs field.
|
||||
*
|
||||
* @return {Promise<Object>} Promise, resolved with built packages
|
||||
* information.
|
||||
*/
|
||||
module.exports.run = function(options, optResolvedTarget) {
|
||||
var opts = parseOpts(options, optResolvedTarget, this.root);
|
||||
var builder = builders.getBuilder(opts.buildMethod);
|
||||
return builder.prepEnv(opts)
|
||||
.then(function() {
|
||||
if (opts.prepEnv) {
|
||||
events.emit('verbose', 'Build file successfully prepared.');
|
||||
return;
|
||||
}
|
||||
return builder.build(opts)
|
||||
.then(function() {
|
||||
return exec(cmd);
|
||||
var apkPaths = builder.findOutputApks(opts.buildType, opts.arch);
|
||||
events.emit('log', 'Built the following apk(s): \n\t' + apkPaths.join('\n\t'));
|
||||
return {
|
||||
apkPaths: apkPaths,
|
||||
buildType: opts.buildType,
|
||||
buildMethod: opts.buildMethod
|
||||
};
|
||||
});
|
||||
}
|
||||
return Q();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Gets the path to the apk file, if not such file exists then
|
||||
* the script will error out. (should we error or just return undefined?)
|
||||
* Detects the architecture of a device/emulator
|
||||
* Returns "arm" or "x86".
|
||||
*/
|
||||
module.exports.get_apk = function() {
|
||||
if(fs.existsSync(path.join(ROOT, 'bin'))) {
|
||||
var bin_files = fs.readdirSync(path.join(ROOT, 'bin'));
|
||||
for (file in bin_files) {
|
||||
if(path.extname(bin_files[file]) == '.apk') {
|
||||
return path.join(ROOT, 'bin', bin_files[file]);
|
||||
}
|
||||
module.exports.detectArchitecture = function(target) {
|
||||
function helper() {
|
||||
return Adb.shell(target, 'cat /proc/cpuinfo')
|
||||
.then(function(output) {
|
||||
return /intel/i.exec(output) ? 'x86' : 'arm';
|
||||
});
|
||||
}
|
||||
// It sometimes happens (at least on OS X), that this command will hang forever.
|
||||
// To fix it, either unplug & replug device, or restart adb server.
|
||||
return helper()
|
||||
.timeout(1000, new CordovaError('Device communication timed out. Try unplugging & replugging the device.'))
|
||||
.then(null, function(err) {
|
||||
if (/timed out/.exec('' + err)) {
|
||||
// adb kill-server doesn't seem to do the trick.
|
||||
// Could probably find a x-platform version of killall, but I'm not actually
|
||||
// sure that this scenario even happens on non-OSX machines.
|
||||
events.emit('verbose', 'adb timed out while detecting device/emulator architecture. Killing adb and trying again.');
|
||||
return spawn('killall', ['adb'])
|
||||
.then(function() {
|
||||
return helper()
|
||||
.then(null, function() {
|
||||
// The double kill is sadly often necessary, at least on mac.
|
||||
events.emit('warn', 'adb timed out a second time while detecting device/emulator architecture. Killing adb and trying again.');
|
||||
return spawn('killall', ['adb'])
|
||||
.then(function() {
|
||||
return helper()
|
||||
.then(null, function() {
|
||||
return Q.reject(new CordovaError('adb timed out a third time while detecting device/emulator architecture. Try unplugging & replugging the device.'));
|
||||
});
|
||||
});
|
||||
});
|
||||
}, function() {
|
||||
// For non-killall OS's.
|
||||
return Q.reject(err);
|
||||
});
|
||||
}
|
||||
console.error('ERROR : No .apk found in \'bin\' folder');
|
||||
process.exit(2);
|
||||
} else {
|
||||
console.error('ERROR : unable to find project bin folder, could not locate .apk');
|
||||
process.exit(2);
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.findBestApkForArchitecture = function(buildResults, arch) {
|
||||
var paths = buildResults.apkPaths.filter(function(p) {
|
||||
var apkName = path.basename(p);
|
||||
if (buildResults.buildType == 'debug') {
|
||||
return /-debug/.exec(apkName);
|
||||
}
|
||||
return !/-debug/.exec(apkName);
|
||||
});
|
||||
var archPattern = new RegExp('-' + arch);
|
||||
var hasArchPattern = /-x86|-arm/;
|
||||
for (var i = 0; i < paths.length; ++i) {
|
||||
var apkName = path.basename(paths[i]);
|
||||
if (hasArchPattern.exec(apkName)) {
|
||||
if (archPattern.exec(apkName)) {
|
||||
return paths[i];
|
||||
}
|
||||
} else {
|
||||
return paths[i];
|
||||
}
|
||||
}
|
||||
throw new Error('Could not find apk architecture: ' + arch + ' build-type: ' + buildResults.buildType);
|
||||
};
|
||||
|
||||
function PackageInfo(keystore, alias, storePassword, password, keystoreType) {
|
||||
this.keystore = {
|
||||
'name': 'key.store',
|
||||
'value': keystore
|
||||
};
|
||||
this.alias = {
|
||||
'name': 'key.alias',
|
||||
'value': alias
|
||||
};
|
||||
if (storePassword) {
|
||||
this.storePassword = {
|
||||
'name': 'key.store.password',
|
||||
'value': storePassword
|
||||
};
|
||||
}
|
||||
if (password) {
|
||||
this.password = {
|
||||
'name': 'key.alias.password',
|
||||
'value': password
|
||||
};
|
||||
}
|
||||
if (keystoreType) {
|
||||
this.keystoreType = {
|
||||
'name': 'key.store.type',
|
||||
'value': keystoreType
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
PackageInfo.prototype = {
|
||||
toProperties: function() {
|
||||
var self = this;
|
||||
var result = '';
|
||||
Object.keys(self).forEach(function(key) {
|
||||
result += self[key].name;
|
||||
result += '=';
|
||||
result += self[key].value.replace(/\\/g, '\\\\');
|
||||
result += '\n';
|
||||
});
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.help = function() {
|
||||
console.log('Usage: ' + path.relative(process.cwd(), path.join(ROOT, 'corodva', 'build')) + ' [build_type]');
|
||||
console.log('Build Types : ');
|
||||
console.log(' \'--debug\': Default build, will build project in using ant debug');
|
||||
console.log(' \'--release\': will build project using ant release');
|
||||
console.log(' \'--nobuild\': will skip build process (can be used with run command)');
|
||||
console.log('Usage: ' + path.relative(process.cwd(), path.join('../build')) + ' [flags] [Signed APK flags]');
|
||||
console.log('Flags:');
|
||||
console.log(' \'--debug\': will build project in debug mode (default)');
|
||||
console.log(' \'--release\': will build project for release');
|
||||
console.log(' \'--ant\': will build project with ant');
|
||||
console.log(' \'--gradle\': will build project with gradle (default)');
|
||||
console.log(' \'--nobuild\': will skip build process (useful when using run command)');
|
||||
console.log(' \'--prepenv\': don\'t build, but copy in build scripts where necessary');
|
||||
console.log(' \'--versionCode=#\': Override versionCode for this build. Useful for uploading multiple APKs. Requires --gradle.');
|
||||
console.log(' \'--minSdkVersion=#\': Override minSdkVersion for this build. Useful for uploading multiple APKs. Requires --gradle.');
|
||||
console.log(' \'--gradleArg=<gradle command line arg>\': Extra args to pass to the gradle command. Use one flag per arg. Ex. --gradleArg=-PcdvBuildMultipleApks=true');
|
||||
console.log('');
|
||||
console.log('Signed APK flags (overwrites debug/release-signing.proprties) :');
|
||||
console.log(' \'--keystore=<path to keystore>\': Key store used to build a signed archive. (Required)');
|
||||
console.log(' \'--alias=\': Alias for the key store. (Required)');
|
||||
console.log(' \'--storePassword=\': Password for the key store. (Optional - prompted)');
|
||||
console.log(' \'--password=\': Password for the key. (Optional - prompted)');
|
||||
console.log(' \'--keystoreType\': Type of the keystore. (Optional)');
|
||||
process.exit(0);
|
||||
}
|
||||
};
|
||||
|
||||
156
bin/templates/cordova/lib/builders/AntBuilder.js
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*/
|
||||
|
||||
var Q = require('q');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var util = require('util');
|
||||
var shell = require('shelljs');
|
||||
var spawn = require('cordova-common').superspawn.spawn;
|
||||
var CordovaError = require('cordova-common').CordovaError;
|
||||
var check_reqs = require('../check_reqs');
|
||||
|
||||
var SIGNING_PROPERTIES = '-signing.properties';
|
||||
var MARKER = 'YOUR CHANGES WILL BE ERASED!';
|
||||
var TEMPLATE =
|
||||
'# This file is automatically generated.\n' +
|
||||
'# Do not modify this file -- ' + MARKER + '\n';
|
||||
|
||||
var GenericBuilder = require('./GenericBuilder');
|
||||
|
||||
function AntBuilder (projectRoot) {
|
||||
GenericBuilder.call(this, projectRoot);
|
||||
|
||||
this.binDirs = {ant: this.binDirs.ant};
|
||||
}
|
||||
|
||||
util.inherits(AntBuilder, GenericBuilder);
|
||||
|
||||
AntBuilder.prototype.getArgs = function(cmd, opts) {
|
||||
var args = [cmd, '-f', path.join(this.root, 'build.xml')];
|
||||
// custom_rules.xml is required for incremental builds.
|
||||
if (hasCustomRules(this.root)) {
|
||||
args.push('-Dout.dir=ant-build', '-Dgen.absolute.dir=ant-gen');
|
||||
}
|
||||
if(opts.packageInfo) {
|
||||
args.push('-propertyfile=' + path.join(this.root, opts.buildType + SIGNING_PROPERTIES));
|
||||
}
|
||||
return args;
|
||||
};
|
||||
|
||||
AntBuilder.prototype.prepEnv = function(opts) {
|
||||
var self = this;
|
||||
return check_reqs.check_ant()
|
||||
.then(function() {
|
||||
// Copy in build.xml on each build so that:
|
||||
// A) we don't require the Android SDK at project creation time, and
|
||||
// B) we always use the SDK's latest version of it.
|
||||
/*jshint -W069 */
|
||||
var sdkDir = process.env['ANDROID_HOME'];
|
||||
/*jshint +W069 */
|
||||
var buildTemplate = fs.readFileSync(path.join(sdkDir, 'tools', 'lib', 'build.template'), 'utf8');
|
||||
function writeBuildXml(projectPath) {
|
||||
var newData = buildTemplate.replace('PROJECT_NAME', self.extractRealProjectNameFromManifest());
|
||||
fs.writeFileSync(path.join(projectPath, 'build.xml'), newData);
|
||||
if (!fs.existsSync(path.join(projectPath, 'local.properties'))) {
|
||||
fs.writeFileSync(path.join(projectPath, 'local.properties'), TEMPLATE);
|
||||
}
|
||||
}
|
||||
writeBuildXml(self.root);
|
||||
var propertiesObj = self.readProjectProperties();
|
||||
var subProjects = propertiesObj.libs;
|
||||
for (var i = 0; i < subProjects.length; ++i) {
|
||||
writeBuildXml(path.join(self.root, subProjects[i]));
|
||||
}
|
||||
if (propertiesObj.systemLibs.length > 0) {
|
||||
throw new CordovaError('Project contains at least one plugin that requires a system library. This is not supported with ANT. Use gradle instead.');
|
||||
}
|
||||
|
||||
var propertiesFile = opts.buildType + SIGNING_PROPERTIES;
|
||||
var propertiesFilePath = path.join(self.root, propertiesFile);
|
||||
if (opts.packageInfo) {
|
||||
fs.writeFileSync(propertiesFilePath, TEMPLATE + opts.packageInfo.toProperties());
|
||||
} else if(isAutoGenerated(propertiesFilePath)) {
|
||||
shell.rm('-f', propertiesFilePath);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Builds the project with ant.
|
||||
* Returns a promise.
|
||||
*/
|
||||
AntBuilder.prototype.build = function(opts) {
|
||||
// Without our custom_rules.xml, we need to clean before building.
|
||||
var ret = Q();
|
||||
if (!hasCustomRules(this.root)) {
|
||||
// clean will call check_ant() for us.
|
||||
ret = this.clean(opts);
|
||||
}
|
||||
|
||||
var args = this.getArgs(opts.buildType == 'debug' ? 'debug' : 'release', opts);
|
||||
return check_reqs.check_ant()
|
||||
.then(function() {
|
||||
return spawn('ant', args, {stdio: 'pipe'});
|
||||
}).progress(function (stdio){
|
||||
if (stdio.stderr) {
|
||||
process.stderr.write(stdio.stderr);
|
||||
} else {
|
||||
process.stdout.write(stdio.stdout);
|
||||
}
|
||||
}).catch(function (error) {
|
||||
if (error.toString().indexOf('Unable to resolve project target') >= 0) {
|
||||
return check_reqs.check_android_target(error).then(function() {
|
||||
// If due to some odd reason - check_android_target succeeds
|
||||
// we should still fail here.
|
||||
return Q.reject(error);
|
||||
});
|
||||
}
|
||||
return Q.reject(error);
|
||||
});
|
||||
};
|
||||
|
||||
AntBuilder.prototype.clean = function(opts) {
|
||||
var args = this.getArgs('clean', opts);
|
||||
var self = this;
|
||||
return check_reqs.check_ant()
|
||||
.then(function() {
|
||||
return spawn('ant', args, {stdio: 'inherit'});
|
||||
})
|
||||
.then(function () {
|
||||
shell.rm('-rf', path.join(self.root, 'out'));
|
||||
|
||||
['debug', 'release'].forEach(function(config) {
|
||||
var propertiesFilePath = path.join(self.root, config + SIGNING_PROPERTIES);
|
||||
if(isAutoGenerated(propertiesFilePath)){
|
||||
shell.rm('-f', propertiesFilePath);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = AntBuilder;
|
||||
|
||||
function hasCustomRules(projectRoot) {
|
||||
return fs.existsSync(path.join(projectRoot, 'custom_rules.xml'));
|
||||
}
|
||||
|
||||
function isAutoGenerated(file) {
|
||||
return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0;
|
||||
}
|
||||
147
bin/templates/cordova/lib/builders/GenericBuilder.js
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*/
|
||||
|
||||
var Q = require('q');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var shell = require('shelljs');
|
||||
var events = require('cordova-common').events;
|
||||
var CordovaError = require('cordova-common').CordovaError;
|
||||
|
||||
function GenericBuilder (projectDir) {
|
||||
this.root = projectDir || path.resolve(__dirname, '../../..');
|
||||
this.binDirs = {
|
||||
ant: path.join(this.root, hasCustomRules(this.root) ? 'ant-build' : 'bin'),
|
||||
gradle: path.join(this.root, 'build', 'outputs', 'apk')
|
||||
};
|
||||
}
|
||||
|
||||
function hasCustomRules(projectRoot) {
|
||||
return fs.existsSync(path.join(projectRoot, 'custom_rules.xml'));
|
||||
}
|
||||
|
||||
GenericBuilder.prototype.prepEnv = function() {
|
||||
return Q();
|
||||
};
|
||||
|
||||
GenericBuilder.prototype.build = function() {
|
||||
events.emit('log', 'Skipping build...');
|
||||
return Q(null);
|
||||
};
|
||||
|
||||
GenericBuilder.prototype.clean = function() {
|
||||
return Q();
|
||||
};
|
||||
|
||||
GenericBuilder.prototype.findOutputApks = function(build_type, arch) {
|
||||
var self = this;
|
||||
return Object.keys(this.binDirs)
|
||||
.reduce(function (result, builderName) {
|
||||
var binDir = self.binDirs[builderName];
|
||||
return result.concat(findOutputApksHelper(binDir, build_type, builderName === 'ant' ? null : arch));
|
||||
}, [])
|
||||
.sort(apkSorter);
|
||||
};
|
||||
|
||||
GenericBuilder.prototype.readProjectProperties = function () {
|
||||
function findAllUniq(data, r) {
|
||||
var s = {};
|
||||
var m;
|
||||
while ((m = r.exec(data))) {
|
||||
s[m[1]] = 1;
|
||||
}
|
||||
return Object.keys(s);
|
||||
}
|
||||
|
||||
var data = fs.readFileSync(path.join(this.root, 'project.properties'), 'utf8');
|
||||
return {
|
||||
libs: findAllUniq(data, /^\s*android\.library\.reference\.\d+=(.*)(?:\s|$)/mg),
|
||||
gradleIncludes: findAllUniq(data, /^\s*cordova\.gradle\.include\.\d+=(.*)(?:\s|$)/mg),
|
||||
systemLibs: findAllUniq(data, /^\s*cordova\.system\.library\.\d+=(.*)(?:\s|$)/mg)
|
||||
};
|
||||
};
|
||||
|
||||
GenericBuilder.prototype.extractRealProjectNameFromManifest = function () {
|
||||
var manifestPath = path.join(this.root, 'AndroidManifest.xml');
|
||||
var manifestData = fs.readFileSync(manifestPath, 'utf8');
|
||||
var m = /<manifest[\s\S]*?package\s*=\s*"(.*?)"/i.exec(manifestData);
|
||||
if (!m) {
|
||||
throw new CordovaError('Could not find package name in ' + manifestPath);
|
||||
}
|
||||
|
||||
var packageName=m[1];
|
||||
var lastDotIndex = packageName.lastIndexOf('.');
|
||||
return packageName.substring(lastDotIndex + 1);
|
||||
};
|
||||
|
||||
module.exports = GenericBuilder;
|
||||
|
||||
function apkSorter(fileA, fileB) {
|
||||
// De-prioritize unsigned builds
|
||||
var unsignedRE = /-unsigned/;
|
||||
if (unsignedRE.exec(fileA)) {
|
||||
return 1;
|
||||
} else if (unsignedRE.exec(fileB)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
var timeDiff = fs.statSync(fileA).mtime - fs.statSync(fileB).mtime;
|
||||
return timeDiff === 0 ? fileA.length - fileB.length : timeDiff;
|
||||
}
|
||||
|
||||
function findOutputApksHelper(dir, build_type, arch) {
|
||||
var shellSilent = shell.config.silent;
|
||||
shell.config.silent = true;
|
||||
|
||||
var ret = shell.ls(path.join(dir, '*.apk'))
|
||||
.filter(function(candidate) {
|
||||
var apkName = path.basename(candidate);
|
||||
// Need to choose between release and debug .apk.
|
||||
if (build_type === 'debug') {
|
||||
return /-debug/.exec(apkName) && !/-unaligned|-unsigned/.exec(apkName);
|
||||
}
|
||||
if (build_type === 'release') {
|
||||
return /-release/.exec(apkName) && !/-unaligned/.exec(apkName);
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.sort(apkSorter);
|
||||
|
||||
shellSilent = shellSilent;
|
||||
|
||||
if (ret.length === 0) {
|
||||
return ret;
|
||||
}
|
||||
// Assume arch-specific build if newest apk has -x86 or -arm.
|
||||
var archSpecific = !!/-x86|-arm/.exec(path.basename(ret[0]));
|
||||
// And show only arch-specific ones (or non-arch-specific)
|
||||
ret = ret.filter(function(p) {
|
||||
/*jshint -W018 */
|
||||
return !!/-x86|-arm/.exec(path.basename(p)) == archSpecific;
|
||||
/*jshint +W018 */
|
||||
});
|
||||
|
||||
if (archSpecific && ret.length > 1 && arch) {
|
||||
ret = ret.filter(function(p) {
|
||||
return path.basename(p).indexOf('-' + arch) != -1;
|
||||
});
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
241
bin/templates/cordova/lib/builders/GradleBuilder.js
vendored
Normal file
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*/
|
||||
|
||||
var Q = require('q');
|
||||
var fs = require('fs');
|
||||
var util = require('util');
|
||||
var path = require('path');
|
||||
var shell = require('shelljs');
|
||||
var spawn = require('cordova-common').superspawn.spawn;
|
||||
var CordovaError = require('cordova-common').CordovaError;
|
||||
var check_reqs = require('../check_reqs');
|
||||
|
||||
var GenericBuilder = require('./GenericBuilder');
|
||||
|
||||
var MARKER = 'YOUR CHANGES WILL BE ERASED!';
|
||||
var SIGNING_PROPERTIES = '-signing.properties';
|
||||
var TEMPLATE =
|
||||
'# This file is automatically generated.\n' +
|
||||
'# Do not modify this file -- ' + MARKER + '\n';
|
||||
|
||||
function GradleBuilder (projectRoot) {
|
||||
GenericBuilder.call(this, projectRoot);
|
||||
|
||||
this.binDirs = {gradle: this.binDirs.gradle};
|
||||
}
|
||||
|
||||
util.inherits(GradleBuilder, GenericBuilder);
|
||||
|
||||
GradleBuilder.prototype.getArgs = function(cmd, opts) {
|
||||
if (cmd == 'release') {
|
||||
cmd = 'cdvBuildRelease';
|
||||
} else if (cmd == 'debug') {
|
||||
cmd = 'cdvBuildDebug';
|
||||
}
|
||||
var args = [cmd, '-b', path.join(this.root, 'build.gradle')];
|
||||
if (opts.arch) {
|
||||
args.push('-PcdvBuildArch=' + opts.arch);
|
||||
}
|
||||
|
||||
// 10 seconds -> 6 seconds
|
||||
args.push('-Dorg.gradle.daemon=true');
|
||||
// allow NDK to be used - required by Gradle 1.5 plugin
|
||||
args.push('-Pandroid.useDeprecatedNdk=true');
|
||||
args.push.apply(args, opts.extraArgs);
|
||||
// Shaves another 100ms, but produces a "try at own risk" warning. Not worth it (yet):
|
||||
// args.push('-Dorg.gradle.parallel=true');
|
||||
return args;
|
||||
};
|
||||
|
||||
// Makes the project buildable, minus the gradle wrapper.
|
||||
GradleBuilder.prototype.prepBuildFiles = function() {
|
||||
// Update the version of build.gradle in each dependent library.
|
||||
var pluginBuildGradle = path.join(this.root, 'cordova', 'lib', 'plugin-build.gradle');
|
||||
var propertiesObj = this.readProjectProperties();
|
||||
var subProjects = propertiesObj.libs;
|
||||
for (var i = 0; i < subProjects.length; ++i) {
|
||||
if (subProjects[i] !== 'CordovaLib') {
|
||||
shell.cp('-f', pluginBuildGradle, path.join(this.root, subProjects[i], 'build.gradle'));
|
||||
}
|
||||
}
|
||||
|
||||
var name = this.extractRealProjectNameFromManifest();
|
||||
//Remove the proj.id/name- prefix from projects: https://issues.apache.org/jira/browse/CB-9149
|
||||
var settingsGradlePaths = subProjects.map(function(p){
|
||||
var realDir=p.replace(/[/\\]/g, ':');
|
||||
var libName=realDir.replace(name+'-','');
|
||||
var str='include ":'+libName+'"\n';
|
||||
if(realDir.indexOf(name+'-')!==-1)
|
||||
str+='project(":'+libName+'").projectDir = new File("'+p+'")\n';
|
||||
return str;
|
||||
});
|
||||
|
||||
// Write the settings.gradle file.
|
||||
fs.writeFileSync(path.join(this.root, 'settings.gradle'),
|
||||
'// GENERATED FILE - DO NOT EDIT\n' +
|
||||
'include ":"\n' + settingsGradlePaths.join(''));
|
||||
// Update dependencies within build.gradle.
|
||||
var buildGradle = fs.readFileSync(path.join(this.root, 'build.gradle'), 'utf8');
|
||||
var depsList = '';
|
||||
subProjects.forEach(function(p) {
|
||||
var libName=p.replace(/[/\\]/g, ':').replace(name+'-','');
|
||||
depsList += ' debugCompile project(path: "' + libName + '", configuration: "debug")\n';
|
||||
depsList += ' releaseCompile project(path: "' + libName + '", configuration: "release")\n';
|
||||
});
|
||||
// For why we do this mapping: https://issues.apache.org/jira/browse/CB-8390
|
||||
var SYSTEM_LIBRARY_MAPPINGS = [
|
||||
[/^\/?extras\/android\/support\/(.*)$/, 'com.android.support:support-$1:+'],
|
||||
[/^\/?google\/google_play_services\/libproject\/google-play-services_lib\/?$/, 'com.google.android.gms:play-services:+']
|
||||
];
|
||||
propertiesObj.systemLibs.forEach(function(p) {
|
||||
var mavenRef;
|
||||
// It's already in gradle form if it has two ':'s
|
||||
if (/:.*:/.exec(p)) {
|
||||
mavenRef = p;
|
||||
} else {
|
||||
for (var i = 0; i < SYSTEM_LIBRARY_MAPPINGS.length; ++i) {
|
||||
var pair = SYSTEM_LIBRARY_MAPPINGS[i];
|
||||
if (pair[0].exec(p)) {
|
||||
mavenRef = p.replace(pair[0], pair[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!mavenRef) {
|
||||
throw new CordovaError('Unsupported system library (does not work with gradle): ' + p);
|
||||
}
|
||||
}
|
||||
depsList += ' compile "' + mavenRef + '"\n';
|
||||
});
|
||||
buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\s\S]*(\/\/ SUB-PROJECT DEPENDENCIES END)/, '$1\n' + depsList + ' $2');
|
||||
var includeList = '';
|
||||
propertiesObj.gradleIncludes.forEach(function(includePath) {
|
||||
includeList += 'apply from: "' + includePath + '"\n';
|
||||
});
|
||||
buildGradle = buildGradle.replace(/(PLUGIN GRADLE EXTENSIONS START)[\s\S]*(\/\/ PLUGIN GRADLE EXTENSIONS END)/, '$1\n' + includeList + '$2');
|
||||
fs.writeFileSync(path.join(this.root, 'build.gradle'), buildGradle);
|
||||
};
|
||||
|
||||
GradleBuilder.prototype.prepEnv = function(opts) {
|
||||
var self = this;
|
||||
return check_reqs.check_gradle()
|
||||
.then(function() {
|
||||
return self.prepBuildFiles();
|
||||
}).then(function() {
|
||||
// Copy the gradle wrapper on each build so that:
|
||||
// A) we don't require the Android SDK at project creation time, and
|
||||
// B) we always use the SDK's latest version of it.
|
||||
// check_reqs ensures that this is set.
|
||||
/*jshint -W069 */
|
||||
var sdkDir = process.env['ANDROID_HOME'];
|
||||
/*jshint +W069 */
|
||||
var wrapperDir = path.join(sdkDir, 'tools', 'templates', 'gradle', 'wrapper');
|
||||
if (process.platform == 'win32') {
|
||||
shell.rm('-f', path.join(self.root, 'gradlew.bat'));
|
||||
shell.cp(path.join(wrapperDir, 'gradlew.bat'), self.root);
|
||||
} else {
|
||||
shell.rm('-f', path.join(self.root, 'gradlew'));
|
||||
shell.cp(path.join(wrapperDir, 'gradlew'), self.root);
|
||||
}
|
||||
shell.rm('-rf', path.join(self.root, 'gradle', 'wrapper'));
|
||||
shell.mkdir('-p', path.join(self.root, 'gradle'));
|
||||
shell.cp('-r', path.join(wrapperDir, 'gradle', 'wrapper'), path.join(self.root, 'gradle'));
|
||||
|
||||
// If the gradle distribution URL is set, make sure it points to version we want.
|
||||
// If it's not set, do nothing, assuming that we're using a future version of gradle that we don't want to mess with.
|
||||
// For some reason, using ^ and $ don't work. This does the job, though.
|
||||
var distributionUrlRegex = /distributionUrl.*zip/;
|
||||
/*jshint -W069 */
|
||||
var distributionUrl = process.env['CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL'] || 'http\\://services.gradle.org/distributions/gradle-2.13-all.zip';
|
||||
/*jshint +W069 */
|
||||
var gradleWrapperPropertiesPath = path.join(self.root, 'gradle', 'wrapper', 'gradle-wrapper.properties');
|
||||
shell.chmod('u+w', gradleWrapperPropertiesPath);
|
||||
shell.sed('-i', distributionUrlRegex, 'distributionUrl='+distributionUrl, gradleWrapperPropertiesPath);
|
||||
|
||||
var propertiesFile = opts.buildType + SIGNING_PROPERTIES;
|
||||
var propertiesFilePath = path.join(self.root, propertiesFile);
|
||||
if (opts.packageInfo) {
|
||||
fs.writeFileSync(propertiesFilePath, TEMPLATE + opts.packageInfo.toProperties());
|
||||
} else if (isAutoGenerated(propertiesFilePath)) {
|
||||
shell.rm('-f', propertiesFilePath);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Builds the project with gradle.
|
||||
* Returns a promise.
|
||||
*/
|
||||
GradleBuilder.prototype.build = function(opts) {
|
||||
var wrapper = path.join(this.root, 'gradlew');
|
||||
var args = this.getArgs(opts.buildType == 'debug' ? 'debug' : 'release', opts);
|
||||
|
||||
return spawn(wrapper, args, {stdio: 'pipe'})
|
||||
.progress(function (stdio){
|
||||
if (stdio.stderr) {
|
||||
/*
|
||||
* Workaround for the issue with Java printing some unwanted information to
|
||||
* stderr instead of stdout.
|
||||
* This function suppresses 'Picked up _JAVA_OPTIONS' message from being
|
||||
* printed to stderr. See https://issues.apache.org/jira/browse/CB-9971 for
|
||||
* explanation.
|
||||
*/
|
||||
var suppressThisLine = /^Picked up _JAVA_OPTIONS: /i.test(stdio.stderr.toString());
|
||||
if (suppressThisLine) {
|
||||
return;
|
||||
}
|
||||
process.stderr.write(stdio.stderr);
|
||||
} else {
|
||||
process.stdout.write(stdio.stdout);
|
||||
}
|
||||
}).catch(function (error) {
|
||||
if (error.toString().indexOf('failed to find target with hash string') >= 0) {
|
||||
return check_reqs.check_android_target(error).then(function() {
|
||||
// If due to some odd reason - check_android_target succeeds
|
||||
// we should still fail here.
|
||||
return Q.reject(error);
|
||||
});
|
||||
}
|
||||
return Q.reject(error);
|
||||
});
|
||||
};
|
||||
|
||||
GradleBuilder.prototype.clean = function(opts) {
|
||||
var builder = this;
|
||||
var wrapper = path.join(this.root, 'gradlew');
|
||||
var args = builder.getArgs('clean', opts);
|
||||
return Q().then(function() {
|
||||
return spawn(wrapper, args, {stdio: 'inherit'});
|
||||
})
|
||||
.then(function () {
|
||||
shell.rm('-rf', path.join(builder.root, 'out'));
|
||||
|
||||
['debug', 'release'].forEach(function(config) {
|
||||
var propertiesFilePath = path.join(builder.root, config + SIGNING_PROPERTIES);
|
||||
if(isAutoGenerated(propertiesFilePath)){
|
||||
shell.rm('-f', propertiesFilePath);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = GradleBuilder;
|
||||
|
||||
function isAutoGenerated(file) {
|
||||
return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0;
|
||||
}
|
||||
47
bin/templates/cordova/lib/builders/builders.js
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*/
|
||||
|
||||
var CordovaError = require('cordova-common').CordovaError;
|
||||
|
||||
var knownBuilders = {
|
||||
ant: 'AntBuilder',
|
||||
gradle: 'GradleBuilder',
|
||||
none: 'GenericBuilder'
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper method that instantiates and returns a builder for specified build
|
||||
* type.
|
||||
*
|
||||
* @param {String} builderType Builder name to construct and return. Must
|
||||
* be one of 'ant', 'gradle' or 'none'
|
||||
*
|
||||
* @return {Builder} A builder instance for specified build type.
|
||||
*/
|
||||
module.exports.getBuilder = function (builderType, projectRoot) {
|
||||
if (!knownBuilders[builderType])
|
||||
throw new CordovaError('Builder ' + builderType + ' is not supported.');
|
||||
|
||||
try {
|
||||
var Builder = require('./' + knownBuilders[builderType]);
|
||||
return new Builder(projectRoot);
|
||||
} catch (err) {
|
||||
throw new CordovaError('Failed to instantiate ' + knownBuilders[builderType] + ' builder: ' + err);
|
||||
}
|
||||
};
|
||||
38
bin/templates/cordova/lib/clean.js
vendored
@@ -1,38 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*/
|
||||
|
||||
var exec = require('./exec'),
|
||||
path = require('path'),
|
||||
ROOT = path.join(__dirname, '..', '..');
|
||||
|
||||
/*
|
||||
* Cleans the project using ant
|
||||
* Returns a promise.
|
||||
*/
|
||||
module.exports.run = function() {
|
||||
return exec('ant clean -f ' + path.join(ROOT, 'build.xml'));
|
||||
}
|
||||
|
||||
module.exports.help = function() {
|
||||
console.log('Usage: ' + path.relative(process.cwd(), process.argv[1]));
|
||||
console.log('Cleans the project directory.');
|
||||
process.exit(0);
|
||||
}
|
||||
132
bin/templates/cordova/lib/device.js
vendored
@@ -19,68 +19,102 @@
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var exec = require('./exec'),
|
||||
Q = require('q'),
|
||||
path = require('path'),
|
||||
build = require('./build'),
|
||||
appinfo = require('./appinfo'),
|
||||
ROOT = path.join(__dirname, '..', '..');
|
||||
var Q = require('q'),
|
||||
build = require('./build');
|
||||
var path = require('path');
|
||||
var Adb = require('./Adb');
|
||||
var AndroidManifest = require('./AndroidManifest');
|
||||
var spawn = require('cordova-common').superspawn.spawn;
|
||||
var CordovaError = require('cordova-common').CordovaError;
|
||||
var events = require('cordova-common').events;
|
||||
|
||||
/**
|
||||
* Returns a promise for the list of the device ID's found
|
||||
* @param lookHarder When true, try restarting adb if no devices are found.
|
||||
*/
|
||||
module.exports.list = function() {
|
||||
return exec('adb devices')
|
||||
.then(function(output) {
|
||||
var response = output.split('\n');
|
||||
var device_list = [];
|
||||
for (var i = 1; i < response.length; i++) {
|
||||
if (response[i].match(/\w+\tdevice/) && !response[i].match(/emulator/)) {
|
||||
device_list.push(response[i].replace(/\tdevice/, '').replace('\r', ''));
|
||||
}
|
||||
module.exports.list = function(lookHarder) {
|
||||
return Adb.devices()
|
||||
.then(function(list) {
|
||||
if (list.length === 0 && lookHarder) {
|
||||
// adb kill-server doesn't seem to do the trick.
|
||||
// Could probably find a x-platform version of killall, but I'm not actually
|
||||
// sure that this scenario even happens on non-OSX machines.
|
||||
return spawn('killall', ['adb'])
|
||||
.then(function() {
|
||||
events.emit('verbose', 'Restarting adb to see if more devices are detected.');
|
||||
return Adb.devices();
|
||||
}, function() {
|
||||
// For non-killall OS's.
|
||||
return list;
|
||||
});
|
||||
}
|
||||
return device_list;
|
||||
return list;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.resolveTarget = function(target) {
|
||||
return this.list(true)
|
||||
.then(function(device_list) {
|
||||
if (!device_list || !device_list.length) {
|
||||
return Q.reject(new CordovaError('Failed to deploy to device, no devices found.'));
|
||||
}
|
||||
// default device
|
||||
target = target || device_list[0];
|
||||
|
||||
if (device_list.indexOf(target) < 0) {
|
||||
return Q.reject('ERROR: Unable to find target \'' + target + '\'.');
|
||||
}
|
||||
|
||||
return build.detectArchitecture(target)
|
||||
.then(function(arch) {
|
||||
return { target: target, arch: arch, isEmulator: false };
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Installs a previously built application on the device
|
||||
* and launches it.
|
||||
* Returns a promise.
|
||||
*/
|
||||
module.exports.install = function(target) {
|
||||
var launchName;
|
||||
return this.list()
|
||||
.then(function(device_list) {
|
||||
if (!device_list || !device_list.length)
|
||||
return Q.reject('ERROR: Failed to deploy to device, no devices found.');
|
||||
module.exports.install = function(target, buildResults) {
|
||||
return Q().then(function() {
|
||||
if (target && typeof target == 'object') {
|
||||
return target;
|
||||
}
|
||||
return module.exports.resolveTarget(target);
|
||||
}).then(function(resolvedTarget) {
|
||||
var apk_path = build.findBestApkForArchitecture(buildResults, resolvedTarget.arch);
|
||||
var manifest = new AndroidManifest(path.join(__dirname, '../../AndroidManifest.xml'));
|
||||
var pkgName = manifest.getPackageId();
|
||||
var launchName = pkgName + '/.' + manifest.getActivity().getName();
|
||||
events.emit('log', 'Using apk: ' + apk_path);
|
||||
events.emit('log', 'Package name: ' + pkgName);
|
||||
|
||||
// default device
|
||||
target = typeof target !== 'undefined' ? target : device_list[0];
|
||||
return Adb.install(resolvedTarget.target, apk_path, {replace: true})
|
||||
.catch(function (error) {
|
||||
// CB-9557 CB-10157 only uninstall and reinstall app if the one that
|
||||
// is already installed on device was signed w/different certificate
|
||||
if (!/INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES/.test(error.toString()))
|
||||
throw error;
|
||||
|
||||
if (device_list.indexOf(target) < 0)
|
||||
return Q.reject('ERROR: Unable to find target \'' + target + '\'.');
|
||||
events.emit('warn', 'Uninstalling app from device and reinstalling it again because the ' +
|
||||
'installed app already signed with different key');
|
||||
|
||||
var apk_path = build.get_apk();
|
||||
launchName = appinfo.getActivityName();
|
||||
console.log('Installing app on device...');
|
||||
var cmd = 'adb -s ' + target + ' install -r ' + apk_path;
|
||||
return exec(cmd);
|
||||
}).then(function(output) {
|
||||
if (output.match(/Failure/)) return Q.reject('ERROR: Failed to install apk to device: ' + output);
|
||||
|
||||
//unlock screen
|
||||
var cmd = 'adb -s ' + target + ' shell input keyevent 82';
|
||||
return exec(cmd);
|
||||
}, function(err) { return Q.reject('ERROR: Failed to install apk to device: ' + err); })
|
||||
.then(function() {
|
||||
// launch the application
|
||||
console.log('Launching application...');
|
||||
var cmd = 'adb -s ' + target + ' shell am start -W -a android.intent.action.MAIN -n ' + launchName;
|
||||
return exec(cmd);
|
||||
}).then(function() {
|
||||
console.log('LANCH SUCCESS');
|
||||
}, function(err) {
|
||||
return Q.reject('ERROR: Failed to launch application on device: ' + err);
|
||||
// This promise is always resolved, even if 'adb uninstall' fails to uninstall app
|
||||
// or the app doesn't installed at all, so no error catching needed.
|
||||
return Adb.uninstall(resolvedTarget.target, pkgName)
|
||||
.then(function() {
|
||||
return Adb.install(resolvedTarget.target, apk_path, {replace: true});
|
||||
});
|
||||
})
|
||||
.then(function() {
|
||||
//unlock screen
|
||||
return Adb.shell(resolvedTarget.target, 'input keyevent 82');
|
||||
}).then(function() {
|
||||
return Adb.start(resolvedTarget.target, launchName);
|
||||
}).then(function() {
|
||||
events.emit('log', 'LAUNCH SUCCESS');
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
441
bin/templates/cordova/lib/emulator.js
vendored
@@ -19,15 +19,28 @@
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var shell = require('shelljs'),
|
||||
exec = require('./exec'),
|
||||
Q = require('q'),
|
||||
path = require('path'),
|
||||
appinfo = require('./appinfo'),
|
||||
build = require('./build'),
|
||||
ROOT = path.join(__dirname, '..', '..'),
|
||||
child_process = require('child_process'),
|
||||
new_emulator = 'cordova_emulator';
|
||||
/* jshint sub:true */
|
||||
|
||||
var retry = require('./retry');
|
||||
var build = require('./build');
|
||||
var path = require('path');
|
||||
var Adb = require('./Adb');
|
||||
var AndroidManifest = require('./AndroidManifest');
|
||||
var events = require('cordova-common').events;
|
||||
var spawn = require('cordova-common').superspawn.spawn;
|
||||
var CordovaError = require('cordova-common').CordovaError;
|
||||
|
||||
var Q = require('q');
|
||||
var os = require('os');
|
||||
var child_process = require('child_process');
|
||||
|
||||
// constants
|
||||
var ONE_SECOND = 1000; // in milliseconds
|
||||
var ONE_MINUTE = 60 * ONE_SECOND; // in milliseconds
|
||||
var INSTALL_COMMAND_TIMEOUT = 5 * ONE_MINUTE; // in milliseconds
|
||||
var NUM_INSTALL_RETRIES = 3;
|
||||
var CHECK_BOOTED_INTERVAL = 3 * ONE_SECOND; // in milliseconds
|
||||
var EXEC_KILL_SIGNAL = 'SIGKILL';
|
||||
|
||||
/**
|
||||
* Returns a Promise for a list of emulator images in the form of objects
|
||||
@@ -40,7 +53,7 @@ var shell = require('shelljs'),
|
||||
}
|
||||
*/
|
||||
module.exports.list_images = function() {
|
||||
return exec('android list avds')
|
||||
return spawn('android', ['list', 'avds'])
|
||||
.then(function(output) {
|
||||
var response = output.split('\n');
|
||||
var emulator_list = [];
|
||||
@@ -49,13 +62,18 @@ module.exports.list_images = function() {
|
||||
var img_obj = {};
|
||||
if (response[i].match(/Name:\s/)) {
|
||||
img_obj['name'] = response[i].split('Name: ')[1].replace('\r', '');
|
||||
if (response[i + 1].match(/Device:\s/)) {
|
||||
i++;
|
||||
img_obj['device'] = response[i].split('Device: ')[1].replace('\r', '');
|
||||
}
|
||||
if (response[i + 1].match(/Path:\s/)) {
|
||||
i++;
|
||||
img_obj['path'] = response[i].split('Path: ')[1].replace('\r', '');
|
||||
}
|
||||
if (response[i + 1].match(/\(API\slevel\s/)) {
|
||||
if (response[i + 1].match(/\(API\slevel\s/) || (response[i + 2] && response[i + 2].match(/\(API\slevel\s/))) {
|
||||
i++;
|
||||
img_obj['target'] = response[i].replace('\r', '');
|
||||
var secondLine = response[i + 1].match(/\(API\slevel\s/) ? response[i + 1] : '';
|
||||
img_obj['target'] = (response[i] + secondLine).split('Target: ')[1].replace('\r', '');
|
||||
}
|
||||
if (response[i + 1].match(/ABI:\s/)) {
|
||||
i++;
|
||||
@@ -76,7 +94,7 @@ module.exports.list_images = function() {
|
||||
}
|
||||
return emulator_list;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Will return the closest avd to the projects target
|
||||
@@ -84,50 +102,39 @@ module.exports.list_images = function() {
|
||||
* Returns a promise.
|
||||
*/
|
||||
module.exports.best_image = function() {
|
||||
var project_target = this.get_target().replace('android-', '');
|
||||
return this.list_images()
|
||||
.then(function(images) {
|
||||
// Just return undefined if there is no images
|
||||
if (images.length === 0) return;
|
||||
|
||||
var closest = 9999;
|
||||
var best = images[0];
|
||||
for (i in images) {
|
||||
// Loading check_reqs at run-time to avoid test-time vs run-time directory structure difference issue
|
||||
var project_target = require('./check_reqs').get_target().replace('android-', '');
|
||||
for (var i in images) {
|
||||
var target = images[i].target;
|
||||
if(target) {
|
||||
var num = target.split('(API level ')[1].replace(')', '');
|
||||
if (num == project_target) {
|
||||
return images[i];
|
||||
} else if (project_target - num < closest && project_target > num) {
|
||||
var closest = project_target - num;
|
||||
closest = project_target - num;
|
||||
best = images[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return best;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Returns a promise.
|
||||
module.exports.list_started = function() {
|
||||
return exec('adb devices')
|
||||
.then(function(output) {
|
||||
var response = output.split('\n');
|
||||
var started_emulator_list = [];
|
||||
for (var i = 1; i < response.length; i++) {
|
||||
if (response[i].match(/device/) && response[i].match(/emulator/)) {
|
||||
started_emulator_list.push(response[i].replace(/\tdevice/, '').replace('\r', ''));
|
||||
}
|
||||
}
|
||||
return started_emulator_list;
|
||||
});
|
||||
}
|
||||
|
||||
module.exports.get_target = function() {
|
||||
var target = shell.grep(/target=android-[\d+]/, path.join(ROOT, 'project.properties'));
|
||||
return target.split('=')[1].replace('\n', '').replace('\r', '').replace(' ', '');
|
||||
}
|
||||
return Adb.devices({emulators: true});
|
||||
};
|
||||
|
||||
// Returns a promise.
|
||||
module.exports.list_targets = function() {
|
||||
return exec('android list targets')
|
||||
return spawn('android', ['list', 'targets'], {cwd: os.tmpdir()})
|
||||
.then(function(output) {
|
||||
var target_out = output.split('\n');
|
||||
var targets = [];
|
||||
@@ -138,121 +145,146 @@ module.exports.list_targets = function() {
|
||||
}
|
||||
return targets;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Gets unused port for android emulator, between 5554 and 5584
|
||||
* Returns a promise.
|
||||
*/
|
||||
module.exports.get_available_port = function () {
|
||||
var self = this;
|
||||
|
||||
return self.list_started()
|
||||
.then(function (emulators) {
|
||||
for (var p = 5584; p >= 5554; p-=2) {
|
||||
if (emulators.indexOf('emulator-' + p) === -1) {
|
||||
events.emit('verbose', 'Found available port: ' + p);
|
||||
return p;
|
||||
}
|
||||
}
|
||||
throw new CordovaError('Could not find an available avd port');
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Starts an emulator with the given ID,
|
||||
* and returns the started ID of that emulator.
|
||||
* If no ID is given it will used the first image availible,
|
||||
* if no image is availible it will error out (maybe create one?).
|
||||
* If no ID is given it will use the first image available,
|
||||
* if no image is available it will error out (maybe create one?).
|
||||
* If no boot timeout is given or the value is negative it will wait forever for
|
||||
* the emulator to boot
|
||||
*
|
||||
* Returns a promise.
|
||||
*/
|
||||
module.exports.start = function(emulator_ID) {
|
||||
module.exports.start = function(emulator_ID, boot_timeout) {
|
||||
var self = this;
|
||||
var emulator_id, num_started, started_emulators;
|
||||
|
||||
return self.list_started()
|
||||
.then(function(list) {
|
||||
started_emulators = list;
|
||||
num_started = started_emulators.length;
|
||||
if (typeof emulator_ID === 'undefined') {
|
||||
return self.list_images()
|
||||
.then(function(emulator_list) {
|
||||
if (emulator_list.length > 0) {
|
||||
return self.best_image()
|
||||
.then(function(best) {
|
||||
emulator_ID = best.name;
|
||||
console.log('WARNING : no emulator specified, defaulting to ' + emulator_ID);
|
||||
return emulator_ID;
|
||||
});
|
||||
} else {
|
||||
return Q.reject('ERROR : No emulator images (avds) found, if you would like to create an\n' +
|
||||
' avd follow the instructions provided here:\n' +
|
||||
' http://developer.android.com/tools/devices/index.html\n' +
|
||||
' Or run \'android create avd --name <name> --target <targetID>\'\n' +
|
||||
' in on the command line.');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return Q(emulator_ID);
|
||||
}
|
||||
}).then(function() {
|
||||
var cmd, args;
|
||||
if(process.platform == 'win32' || process.platform == 'win64') {
|
||||
cmd = '%comspec%';
|
||||
args = ['/c', 'start', 'cmd', '/c', 'emulator', '-avd', emulator_ID];
|
||||
} else {
|
||||
cmd = 'emulator';
|
||||
args = ['-avd', emulator_ID];
|
||||
}
|
||||
var proc = child_process.spawn(cmd, args, { stdio: 'inherit', detached: true });
|
||||
proc.unref(); // Don't wait for it to finish, since the emulator will probably keep running for a long time.
|
||||
}).then(function() {
|
||||
// wait for emulator to start
|
||||
console.log('Waiting for emulator...');
|
||||
return self.wait_for_emulator(num_started);
|
||||
}).then(function(new_started) {
|
||||
if (new_started.length > 1) {
|
||||
for (i in new_started) {
|
||||
if (started_emulators.indexOf(new_started[i]) < 0) {
|
||||
emulator_id = new_started[i];
|
||||
}
|
||||
return Q().then(function() {
|
||||
if (emulator_ID) return Q(emulator_ID);
|
||||
|
||||
return self.best_image()
|
||||
.then(function(best) {
|
||||
if (best && best.name) {
|
||||
events.emit('warn', 'No emulator specified, defaulting to ' + best.name);
|
||||
return best.name;
|
||||
}
|
||||
} else {
|
||||
emulator_id = new_started[0];
|
||||
}
|
||||
if (!emulator_id) return Q.reject('ERROR : Failed to start emulator, could not find new emulator');
|
||||
|
||||
// Loading check_reqs at run-time to avoid test-time vs run-time directory structure difference issue
|
||||
var androidCmd = require('./check_reqs').getAbsoluteAndroidCmd();
|
||||
return Q.reject(new CordovaError('No emulator images (avds) found.\n' +
|
||||
'1. Download desired System Image by running: ' + androidCmd + ' sdk\n' +
|
||||
'2. Create an AVD by running: ' + androidCmd + ' avd\n' +
|
||||
'HINT: For a faster emulator, use an Intel System Image and install the HAXM device driver\n'));
|
||||
});
|
||||
}).then(function(emulatorId) {
|
||||
return self.get_available_port()
|
||||
.then(function (port) {
|
||||
var args = ['-avd', emulatorId, '-port', port];
|
||||
// Don't wait for it to finish, since the emulator will probably keep running for a long time.
|
||||
child_process
|
||||
.spawn('emulator', args, { stdio: 'inherit', detached: true })
|
||||
.unref();
|
||||
|
||||
// wait for emulator to start
|
||||
events.emit('log', 'Waiting for emulator to start...');
|
||||
return self.wait_for_emulator(port);
|
||||
});
|
||||
}).then(function(emulatorId) {
|
||||
if (!emulatorId)
|
||||
return Q.reject(new CordovaError('Failed to start emulator'));
|
||||
|
||||
//wait for emulator to boot up
|
||||
process.stdout.write('Booting up emulator (this may take a while)...');
|
||||
return self.wait_for_boot(emulator_id);
|
||||
}).then(function() {
|
||||
console.log('BOOT COMPLETE');
|
||||
|
||||
//unlock screen
|
||||
return exec('adb -s ' + emulator_id + ' shell input keyevent 82');
|
||||
}).then(function() {
|
||||
//return the new emulator id for the started emulators
|
||||
return emulator_id;
|
||||
process.stdout.write('Waiting for emulator to boot (this may take a while)...');
|
||||
return self.wait_for_boot(emulatorId, boot_timeout)
|
||||
.then(function(success) {
|
||||
if (success) {
|
||||
events.emit('log','BOOT COMPLETE');
|
||||
//unlock screen
|
||||
return Adb.shell(emulatorId, 'input keyevent 82')
|
||||
.then(function() {
|
||||
//return the new emulator id for the started emulators
|
||||
return emulatorId;
|
||||
});
|
||||
} else {
|
||||
// We timed out waiting for the boot to happen
|
||||
return null;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Waits for the new emulator to apear on the started-emulator list.
|
||||
* Returns a promise with a list of newly started emulators' IDs.
|
||||
* Waits for an emulator to boot on a given port.
|
||||
* Returns this emulator's ID in a promise.
|
||||
*/
|
||||
module.exports.wait_for_emulator = function(num_running) {
|
||||
module.exports.wait_for_emulator = function(port) {
|
||||
var self = this;
|
||||
return self.list_started()
|
||||
.then(function(new_started) {
|
||||
if (new_started.length > num_running) {
|
||||
return new_started;
|
||||
} else {
|
||||
return Q.delay(1000).then(function() {
|
||||
return self.wait_for_emulator(num_running);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
return Q().then(function() {
|
||||
var emulator_id = 'emulator-' + port;
|
||||
return Adb.shell(emulator_id, 'getprop dev.bootcomplete')
|
||||
.then(function (output) {
|
||||
if (output.indexOf('1') >= 0) {
|
||||
return emulator_id;
|
||||
}
|
||||
return self.wait_for_emulator(port);
|
||||
}, function (error) {
|
||||
if (error && error.message &&
|
||||
(error.message.indexOf('not found') > -1) ||
|
||||
error.message.indexOf('device offline') > -1) {
|
||||
// emulator not yet started, continue waiting
|
||||
return self.wait_for_emulator(port);
|
||||
} else {
|
||||
// something unexpected has happened
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Waits for the boot animation property of the emulator to switch to 'stopped'
|
||||
* Waits for the core android process of the emulator to start. Returns a
|
||||
* promise that resolves to a boolean indicating success. Not specifying a
|
||||
* time_remaining or passing a negative value will cause it to wait forever
|
||||
*/
|
||||
module.exports.wait_for_boot = function(emulator_id) {
|
||||
module.exports.wait_for_boot = function(emulator_id, time_remaining) {
|
||||
var self = this;
|
||||
return exec('adb -s ' + emulator_id + ' shell getprop init.svc.bootanim')
|
||||
return Adb.shell(emulator_id, 'ps')
|
||||
.then(function(output) {
|
||||
if (output.match(/stopped/)) {
|
||||
return;
|
||||
if (output.match(/android\.process\.acore/)) {
|
||||
return true;
|
||||
} else if (time_remaining === 0) {
|
||||
return false;
|
||||
} else {
|
||||
process.stdout.write('.');
|
||||
return Q.delay(3000).then(function() {
|
||||
return self.wait_for_boot(emulator_id);
|
||||
|
||||
// Check at regular intervals
|
||||
return Q.delay(time_remaining < CHECK_BOOTED_INTERVAL ? time_remaining : CHECK_BOOTED_INTERVAL).then(function() {
|
||||
var updated_time = time_remaining >= 0 ? Math.max(time_remaining - CHECK_BOOTED_INTERVAL, 0) : time_remaining;
|
||||
return self.wait_for_boot(emulator_id, updated_time);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Create avd
|
||||
@@ -260,28 +292,48 @@ module.exports.wait_for_boot = function(emulator_id) {
|
||||
* Returns a promise.
|
||||
*/
|
||||
module.exports.create_image = function(name, target) {
|
||||
console.log('Creating avd named ' + name);
|
||||
console.log('Creating new avd named ' + name);
|
||||
if (target) {
|
||||
return exec('android create avd --name ' + name + ' --target ' + target)
|
||||
return spawn('android', ['create', 'avd', '--name', name, '--target', target])
|
||||
.then(null, function(error) {
|
||||
console.error('ERROR : Failed to create emulator image : ');
|
||||
console.error(' Do you have the latest android targets including ' + target + '?');
|
||||
console.error(create.output);
|
||||
console.error(error);
|
||||
});
|
||||
} else {
|
||||
console.log('WARNING : Project target not found, creating avd with a different target but the project may fail to install.');
|
||||
return exec('android create avd --name ' + name + ' --target ' + this.list_targets()[0])
|
||||
return spawn('android', ['create', 'avd', '--name', name, '--target', this.list_targets()[0]])
|
||||
.then(function() {
|
||||
// TODO: This seems like another error case, even though it always happens.
|
||||
console.error('ERROR : Unable to create an avd emulator, no targets found.');
|
||||
console.error('Please insure you have targets availible by runing the "android" command');
|
||||
console.error('Ensure you have targets available by running the "android" command');
|
||||
return Q.reject();
|
||||
}, function(error) {
|
||||
console.error('ERROR : Failed to create emulator image : ');
|
||||
console.error(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.resolveTarget = function(target) {
|
||||
return this.list_started()
|
||||
.then(function(emulator_list) {
|
||||
if (emulator_list.length < 1) {
|
||||
return Q.reject('No running Android emulators found, please start an emulator before deploying your project.');
|
||||
}
|
||||
|
||||
// default emulator
|
||||
target = target || emulator_list[0];
|
||||
if (emulator_list.indexOf(target) < 0) {
|
||||
return Q.reject('Unable to find target \'' + target + '\'. Failed to deploy to emulator.');
|
||||
}
|
||||
|
||||
return build.detectArchitecture(target)
|
||||
.then(function(arch) {
|
||||
return {target:target, arch:arch, isEmulator:true};
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Installs a previously built application on the emulator and launches it.
|
||||
@@ -289,42 +341,103 @@ module.exports.create_image = function(name, target) {
|
||||
* If no started emulators are found, error out.
|
||||
* Returns a promise.
|
||||
*/
|
||||
module.exports.install = function(target) {
|
||||
var self = this;
|
||||
return this.list_started()
|
||||
.then(function(emulator_list) {
|
||||
if (emulator_list.length < 1) {
|
||||
return Q.reject('No started emulators found, please start an emultor before deploying your project.');
|
||||
module.exports.install = function(givenTarget, buildResults) {
|
||||
|
||||
var target;
|
||||
var manifest = new AndroidManifest(path.join(__dirname, '../../AndroidManifest.xml'));
|
||||
var pkgName = manifest.getPackageId();
|
||||
|
||||
// resolve the target emulator
|
||||
return Q().then(function () {
|
||||
if (givenTarget && typeof givenTarget == 'object') {
|
||||
return givenTarget;
|
||||
} else {
|
||||
return module.exports.resolveTarget(givenTarget);
|
||||
}
|
||||
|
||||
// default emulator
|
||||
target = typeof target !== 'undefined' ? target : emulator_list[0];
|
||||
if (emulator_list.indexOf(target) < 0) {
|
||||
return Q.reject('Unable to find target \'' + target + '\'. Failed to deploy to emulator.');
|
||||
}
|
||||
// set the resolved target
|
||||
}).then(function (resolvedTarget) {
|
||||
target = resolvedTarget;
|
||||
|
||||
console.log('Installing app on emulator...');
|
||||
var apk_path = build.get_apk();
|
||||
return exec('adb -s ' + target + ' install -r ' + apk_path);
|
||||
}).then(function(output) {
|
||||
if (output.match(/Failure/)) {
|
||||
return Q.reject('Failed to install apk to emulator: ' + output);
|
||||
}
|
||||
return Q();
|
||||
}, function(err) {
|
||||
return Q.reject('Failed to install apk to emulator: ' + err);
|
||||
}).then(function() {
|
||||
//unlock screen
|
||||
return exec('adb -s ' + target + ' shell input keyevent 82');
|
||||
}).then(function() {
|
||||
// launch the application
|
||||
console.log('Launching application...');
|
||||
var launchName = appinfo.getActivityName();
|
||||
cmd = 'adb -s ' + target + ' shell am start -W -a android.intent.action.MAIN -n ' + launchName;
|
||||
return exec(cmd);
|
||||
}).then(function(output) {
|
||||
console.log('LAUNCH SUCCESS');
|
||||
}, function(err) {
|
||||
return Q.reject('Failed to launch app on emulator: ' + err);
|
||||
// install the app
|
||||
}).then(function () {
|
||||
// This promise is always resolved, even if 'adb uninstall' fails to uninstall app
|
||||
// or the app doesn't installed at all, so no error catching needed.
|
||||
return Q.when()
|
||||
.then(function() {
|
||||
|
||||
var apk_path = build.findBestApkForArchitecture(buildResults, target.arch);
|
||||
var execOptions = {
|
||||
cwd: os.tmpdir(),
|
||||
timeout: INSTALL_COMMAND_TIMEOUT, // in milliseconds
|
||||
killSignal: EXEC_KILL_SIGNAL
|
||||
};
|
||||
|
||||
events.emit('log', 'Using apk: ' + apk_path);
|
||||
events.emit('log', 'Package name: ' + pkgName);
|
||||
events.emit('verbose', 'Installing app on emulator...');
|
||||
|
||||
// A special function to call adb install in specific environment w/ specific options.
|
||||
// Introduced as a part of fix for http://issues.apache.org/jira/browse/CB-9119
|
||||
// to workaround sporadic emulator hangs
|
||||
function adbInstallWithOptions(target, apk, opts) {
|
||||
events.emit('verbose', 'Installing apk ' + apk + ' on ' + target + '...');
|
||||
|
||||
var command = 'adb -s ' + target + ' install -r "' + apk + '"';
|
||||
return Q.promise(function (resolve, reject) {
|
||||
child_process.exec(command, opts, function(err, stdout, stderr) {
|
||||
if (err) reject(new CordovaError('Error executing "' + command + '": ' + stderr));
|
||||
// adb does not return an error code even if installation fails. Instead it puts a specific
|
||||
// message to stdout, so we have to use RegExp matching to detect installation failure.
|
||||
else if (/Failure/.test(stdout)) {
|
||||
if (stdout.match(/INSTALL_PARSE_FAILED_NO_CERTIFICATES/)) {
|
||||
stdout += 'Sign the build using \'-- --keystore\' or \'--buildConfig\'' +
|
||||
' or sign and deploy the unsigned apk manually using Android tools.';
|
||||
} else if (stdout.match(/INSTALL_FAILED_VERSION_DOWNGRADE/)) {
|
||||
stdout += 'You\'re trying to install apk with a lower versionCode that is already installed.' +
|
||||
'\nEither uninstall an app or increment the versionCode.';
|
||||
}
|
||||
|
||||
reject(new CordovaError('Failed to install apk to emulator: ' + stdout));
|
||||
} else resolve(stdout);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function installPromise () {
|
||||
return adbInstallWithOptions(target.target, apk_path, execOptions)
|
||||
.catch(function (error) {
|
||||
// CB-9557 CB-10157 only uninstall and reinstall app if the one that
|
||||
// is already installed on device was signed w/different certificate
|
||||
if (!/INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES/.test(error.toString()))
|
||||
throw error;
|
||||
|
||||
events.emit('warn', 'Uninstalling app from device and reinstalling it because the ' +
|
||||
'currently installed app was signed with different key');
|
||||
|
||||
// This promise is always resolved, even if 'adb uninstall' fails to uninstall app
|
||||
// or the app doesn't installed at all, so no error catching needed.
|
||||
return Adb.uninstall(target.target, pkgName)
|
||||
.then(function() {
|
||||
return adbInstallWithOptions(target.target, apk_path, execOptions);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return retry.retryPromise(NUM_INSTALL_RETRIES, installPromise)
|
||||
.then(function (output) {
|
||||
events.emit('log', 'INSTALL SUCCESS');
|
||||
});
|
||||
});
|
||||
// unlock screen
|
||||
}).then(function () {
|
||||
|
||||
events.emit('verbose', 'Unlocking screen...');
|
||||
return Adb.shell(target.target, 'input keyevent 82');
|
||||
}).then(function () {
|
||||
Adb.start(target.target, pkgName + '/.' + manifest.getActivity().getName());
|
||||
// report success or failure
|
||||
}).then(function (output) {
|
||||
events.emit('log', 'LAUNCH SUCCESS');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
43
bin/templates/cordova/lib/exec.js
vendored
@@ -1,43 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*/
|
||||
|
||||
var child_process = require('child_process'),
|
||||
Q = require('q');
|
||||
|
||||
// Takes a command and optional current working directory.
|
||||
// Returns a promise that either resolves with the stdout, or
|
||||
// rejects with an error message and the stderr.
|
||||
module.exports = function(cmd, opt_cwd) {
|
||||
var d = Q.defer();
|
||||
console.log('exec: ' + cmd);
|
||||
try {
|
||||
child_process.exec(cmd, {cwd: opt_cwd}, function(err, stdout, stderr) {
|
||||
console.log([cmd, err, stdout, stderr]);
|
||||
if (err) d.reject('Error executing "' + cmd + '": ' + stderr);
|
||||
else d.resolve(stdout);
|
||||
});
|
||||
} catch(e) {
|
||||
console.error('error caught: ' + e);
|
||||
d.reject(e);
|
||||
}
|
||||
return d.promise;
|
||||
}
|
||||
|
||||
@@ -22,12 +22,13 @@
|
||||
var devices = require('./device');
|
||||
|
||||
// Usage support for when args are given
|
||||
devices.list().done(function(device_list) {
|
||||
device_list && device_list.forEach(function(dev) {
|
||||
console.log(dev);
|
||||
require('../lib/check_reqs').check_android().then(function() {
|
||||
devices.list().done(function(device_list) {
|
||||
device_list && device_list.forEach(function(dev) {
|
||||
console.log(dev);
|
||||
});
|
||||
}, function(err) {
|
||||
console.error('ERROR: ' + err);
|
||||
process.exit(2);
|
||||
});
|
||||
}, function(err) {
|
||||
console.error('ERROR: ' + err);
|
||||
process.exit(2);
|
||||
});
|
||||
|
||||
|
||||
@@ -22,11 +22,13 @@
|
||||
var emulators = require('./emulator');
|
||||
|
||||
// Usage support for when args are given
|
||||
emulators.list_images().done(function(emulator_list) {
|
||||
emulator_list && emulator_list.forEach(function(emu) {
|
||||
console.log(emu.name);
|
||||
require('../lib/check_reqs').check_android().then(function() {
|
||||
emulators.list_images().done(function(emulator_list) {
|
||||
emulator_list && emulator_list.forEach(function(emu) {
|
||||
console.log(emu.name);
|
||||
});
|
||||
}, function(err) {
|
||||
console.error('ERROR: ' + err);
|
||||
process.exit(2);
|
||||
});
|
||||
}, function(err) {
|
||||
console.error('ERROR: ' + err);
|
||||
process.exit(2);
|
||||
});
|
||||
|
||||
@@ -22,11 +22,13 @@
|
||||
var emulators = require('./emulator');
|
||||
|
||||
// Usage support for when args are given
|
||||
emulators.list_started().done(function(emulator_list) {
|
||||
emulator_list && emulator_list.forEach(function(emu) {
|
||||
console.log(emu);
|
||||
require('../lib/check_reqs').check_android().then(function() {
|
||||
emulators.list_started().done(function(emulator_list) {
|
||||
emulator_list && emulator_list.forEach(function(emu) {
|
||||
console.log(emu);
|
||||
});
|
||||
}, function(err) {
|
||||
console.error('ERROR: ' + err);
|
||||
process.exit(2);
|
||||
});
|
||||
}, function(err) {
|
||||
console.error('ERROR: ' + err);
|
||||
process.exit(2);
|
||||
});
|
||||
|
||||
13
bin/templates/cordova/lib/log.js
vendored
@@ -19,8 +19,8 @@
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var shell = require('shelljs'),
|
||||
path = require('path'),
|
||||
var path = require('path'),
|
||||
os = require('os'),
|
||||
Q = require('q'),
|
||||
child_process = require('child_process'),
|
||||
ROOT = path.join(__dirname, '..', '..');
|
||||
@@ -30,9 +30,8 @@ var shell = require('shelljs'),
|
||||
* Returns a promise.
|
||||
*/
|
||||
module.exports.run = function() {
|
||||
var cmd = 'adb logcat | grep -v nativeGetEnabledTags';
|
||||
var d = Q.defer();
|
||||
var adb = child_process.spawn('adb', ['logcat']);
|
||||
var adb = child_process.spawn('adb', ['logcat'], {cwd: os.tmpdir()});
|
||||
|
||||
adb.stdout.on('data', function(data) {
|
||||
var lines = data ? data.toString().split('\n') : [];
|
||||
@@ -48,10 +47,10 @@ module.exports.run = function() {
|
||||
});
|
||||
|
||||
return d.promise;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.help = function() {
|
||||
console.log('Usage: ' + path.relative(process.cwd(), path.join(ROOT, 'corodva', 'log')));
|
||||
console.log('Usage: ' + path.relative(process.cwd(), path.join(ROOT, 'cordova', 'log')));
|
||||
console.log('Gives the logcat output on the command line.');
|
||||
process.exit(0);
|
||||
}
|
||||
};
|
||||
|
||||
79
bin/templates/cordova/lib/plugin-build.gradle
Normal file
@@ -0,0 +1,79 @@
|
||||
/* Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*/
|
||||
|
||||
// GENERATED FILE! DO NOT EDIT!
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
// Switch the Android Gradle plugin version requirement depending on the
|
||||
// installed version of Gradle. This dependency is documented at
|
||||
// http://tools.android.com/tech-docs/new-build-system/version-compatibility
|
||||
// and https://issues.apache.org/jira/browse/CB-8143
|
||||
if (gradle.gradleVersion >= "2.2") {
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:1.0.0+'
|
||||
}
|
||||
} else if (gradle.gradleVersion >= "2.1") {
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:0.14.0+'
|
||||
}
|
||||
} else {
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:0.12.0+'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
dependencies {
|
||||
compile fileTree(dir: 'libs', include: '*.jar')
|
||||
debugCompile project(path: ":CordovaLib", configuration: "debug")
|
||||
releaseCompile project(path: ":CordovaLib", configuration: "release")
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion cdvCompileSdkVersion
|
||||
buildToolsVersion cdvBuildToolsVersion
|
||||
publishNonDefault true
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_6
|
||||
targetCompatibility JavaVersion.VERSION_1_6
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
manifest.srcFile 'AndroidManifest.xml'
|
||||
java.srcDirs = ['src']
|
||||
resources.srcDirs = ['src']
|
||||
aidl.srcDirs = ['src']
|
||||
renderscript.srcDirs = ['src']
|
||||
res.srcDirs = ['res']
|
||||
assets.srcDirs = ['assets']
|
||||
jniLibs.srcDirs = ['libs']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (file('build-extras.gradle').exists()) {
|
||||
apply from: 'build-extras.gradle'
|
||||
}
|
||||
276
bin/templates/cordova/lib/pluginHandlers.js
vendored
Normal file
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2013 Anis Kadri
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/* jshint unused: vars */
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var shell = require('shelljs');
|
||||
var events = require('cordova-common').events;
|
||||
var CordovaError = require('cordova-common').CordovaError;
|
||||
|
||||
var handlers = {
|
||||
'source-file':{
|
||||
install:function(obj, plugin, project, options) {
|
||||
if (!obj.src) throw new CordovaError(generateAttributeError('src', 'source-file', plugin.id));
|
||||
if (!obj.targetDir) throw new CordovaError(generateAttributeError('target-dir', 'source-file', plugin.id));
|
||||
var dest = path.join(obj.targetDir, path.basename(obj.src));
|
||||
if (options && options.force) {
|
||||
copyFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link));
|
||||
} else {
|
||||
copyNewFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link));
|
||||
}
|
||||
},
|
||||
uninstall:function(obj, plugin, project, options) {
|
||||
var dest = path.join(obj.targetDir, path.basename(obj.src));
|
||||
deleteJava(project.projectDir, dest);
|
||||
}
|
||||
},
|
||||
'lib-file':{
|
||||
install:function(obj, plugin, project, options) {
|
||||
var dest = path.join('libs', path.basename(obj.src));
|
||||
copyFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link));
|
||||
},
|
||||
uninstall:function(obj, plugin, project, options) {
|
||||
var dest = path.join('libs', path.basename(obj.src));
|
||||
removeFile(project.projectDir, dest);
|
||||
}
|
||||
},
|
||||
'resource-file':{
|
||||
install:function(obj, plugin, project, options) {
|
||||
copyFile(plugin.dir, obj.src, project.projectDir, path.normalize(obj.target), !!(options && options.link));
|
||||
},
|
||||
uninstall:function(obj, plugin, project, options) {
|
||||
removeFile(project.projectDir, path.normalize(obj.target));
|
||||
}
|
||||
},
|
||||
'framework': {
|
||||
install:function(obj, plugin, project, options) {
|
||||
var src = obj.src;
|
||||
if (!src) throw new CordovaError(generateAttributeError('src', 'framework', plugin.id));
|
||||
|
||||
events.emit('verbose', 'Installing Android library: ' + src);
|
||||
var parentDir = obj.parent ? path.resolve(project.projectDir, obj.parent) : project.projectDir;
|
||||
var subDir;
|
||||
|
||||
if (obj.custom) {
|
||||
var subRelativeDir = project.getCustomSubprojectRelativeDir(plugin.id, src);
|
||||
copyNewFile(plugin.dir, src, project.projectDir, subRelativeDir, !!(options && options.link));
|
||||
subDir = path.resolve(project.projectDir, subRelativeDir);
|
||||
} else {
|
||||
obj.type = 'sys';
|
||||
subDir = src;
|
||||
}
|
||||
|
||||
if (obj.type == 'gradleReference') {
|
||||
project.addGradleReference(parentDir, subDir);
|
||||
} else if (obj.type == 'sys') {
|
||||
project.addSystemLibrary(parentDir, subDir);
|
||||
} else {
|
||||
project.addSubProject(parentDir, subDir);
|
||||
}
|
||||
},
|
||||
uninstall:function(obj, plugin, project, options) {
|
||||
var src = obj.src;
|
||||
if (!src) throw new CordovaError(generateAttributeError('src', 'framework', plugin.id));
|
||||
|
||||
events.emit('verbose', 'Uninstalling Android library: ' + src);
|
||||
var parentDir = obj.parent ? path.resolve(project.projectDir, obj.parent) : project.projectDir;
|
||||
var subDir;
|
||||
|
||||
if (obj.custom) {
|
||||
var subRelativeDir = project.getCustomSubprojectRelativeDir(plugin.id, src);
|
||||
removeFile(project.projectDir, subRelativeDir);
|
||||
subDir = path.resolve(project.projectDir, subRelativeDir);
|
||||
// If it's the last framework in the plugin, remove the parent directory.
|
||||
var parDir = path.dirname(subDir);
|
||||
if (fs.existsSync(parDir) && fs.readdirSync(parDir).length === 0) {
|
||||
fs.rmdirSync(parDir);
|
||||
}
|
||||
} else {
|
||||
obj.type = 'sys';
|
||||
subDir = src;
|
||||
}
|
||||
|
||||
if (obj.type == 'gradleReference') {
|
||||
project.removeGradleReference(parentDir, subDir);
|
||||
} else if (obj.type == 'sys') {
|
||||
project.removeSystemLibrary(parentDir, subDir);
|
||||
} else {
|
||||
project.removeSubProject(parentDir, subDir);
|
||||
}
|
||||
}
|
||||
},
|
||||
asset:{
|
||||
install:function(obj, plugin, project, options) {
|
||||
if (!obj.src) {
|
||||
throw new CordovaError(generateAttributeError('src', 'asset', plugin.id));
|
||||
}
|
||||
if (!obj.target) {
|
||||
throw new CordovaError(generateAttributeError('target', 'asset', plugin.id));
|
||||
}
|
||||
|
||||
copyFile(plugin.dir, obj.src, project.www, obj.target);
|
||||
if (options && options.usePlatformWww) {
|
||||
// CB-11022 copy file to both directories if usePlatformWww is specified
|
||||
copyFile(plugin.dir, obj.src, project.platformWww, obj.target);
|
||||
}
|
||||
},
|
||||
uninstall:function(obj, plugin, project, options) {
|
||||
var target = obj.target || obj.src;
|
||||
|
||||
if (!target) throw new CordovaError(generateAttributeError('target', 'asset', plugin.id));
|
||||
|
||||
removeFileF(path.resolve(project.www, target));
|
||||
removeFileF(path.resolve(project.www, 'plugins', plugin.id));
|
||||
if (options && options.usePlatformWww) {
|
||||
// CB-11022 remove file from both directories if usePlatformWww is specified
|
||||
removeFileF(path.resolve(project.platformWww, target));
|
||||
removeFileF(path.resolve(project.platformWww, 'plugins', plugin.id));
|
||||
}
|
||||
}
|
||||
},
|
||||
'js-module': {
|
||||
install: function (obj, plugin, project, options) {
|
||||
// Copy the plugin's files into the www directory.
|
||||
var moduleSource = path.resolve(plugin.dir, obj.src);
|
||||
var moduleName = plugin.id + '.' + (obj.name || path.basename(obj.src, path.extname (obj.src)));
|
||||
|
||||
// Read in the file, prepend the cordova.define, and write it back out.
|
||||
var scriptContent = fs.readFileSync(moduleSource, 'utf-8').replace(/^\ufeff/, ''); // Window BOM
|
||||
if (moduleSource.match(/.*\.json$/)) {
|
||||
scriptContent = 'module.exports = ' + scriptContent;
|
||||
}
|
||||
scriptContent = 'cordova.define("' + moduleName + '", function(require, exports, module) {\n' + scriptContent + '\n});\n';
|
||||
|
||||
var wwwDest = path.resolve(project.www, 'plugins', plugin.id, obj.src);
|
||||
shell.mkdir('-p', path.dirname(wwwDest));
|
||||
fs.writeFileSync(wwwDest, scriptContent, 'utf-8');
|
||||
|
||||
if (options && options.usePlatformWww) {
|
||||
// CB-11022 copy file to both directories if usePlatformWww is specified
|
||||
var platformWwwDest = path.resolve(project.platformWww, 'plugins', plugin.id, obj.src);
|
||||
shell.mkdir('-p', path.dirname(platformWwwDest));
|
||||
fs.writeFileSync(platformWwwDest, scriptContent, 'utf-8');
|
||||
}
|
||||
},
|
||||
uninstall: function (obj, plugin, project, options) {
|
||||
var pluginRelativePath = path.join('plugins', plugin.id, obj.src);
|
||||
removeFileAndParents(project.www, pluginRelativePath);
|
||||
if (options && options.usePlatformWww) {
|
||||
// CB-11022 remove file from both directories if usePlatformWww is specified
|
||||
removeFileAndParents(project.platformWww, pluginRelativePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.getInstaller = function (type) {
|
||||
if (handlers[type] && handlers[type].install) {
|
||||
return handlers[type].install;
|
||||
}
|
||||
|
||||
events.emit('verbose', '<' + type + '> is not supported for android plugins');
|
||||
};
|
||||
|
||||
module.exports.getUninstaller = function(type) {
|
||||
if (handlers[type] && handlers[type].uninstall) {
|
||||
return handlers[type].uninstall;
|
||||
}
|
||||
|
||||
events.emit('verbose', '<' + type + '> is not supported for android plugins');
|
||||
};
|
||||
|
||||
function copyFile (plugin_dir, src, project_dir, dest, link) {
|
||||
src = path.resolve(plugin_dir, src);
|
||||
if (!fs.existsSync(src)) throw new CordovaError('"' + src + '" not found!');
|
||||
|
||||
// check that src path is inside plugin directory
|
||||
var real_path = fs.realpathSync(src);
|
||||
var real_plugin_path = fs.realpathSync(plugin_dir);
|
||||
if (real_path.indexOf(real_plugin_path) !== 0)
|
||||
throw new CordovaError('File "' + src + '" is located outside the plugin directory "' + plugin_dir + '"');
|
||||
|
||||
dest = path.resolve(project_dir, dest);
|
||||
|
||||
// check that dest path is located in project directory
|
||||
if (dest.indexOf(project_dir) !== 0)
|
||||
throw new CordovaError('Destination "' + dest + '" for source file "' + src + '" is located outside the project');
|
||||
|
||||
shell.mkdir('-p', path.dirname(dest));
|
||||
|
||||
if (link) {
|
||||
fs.symlinkSync(path.relative(path.dirname(dest), src), dest);
|
||||
} else if (fs.statSync(src).isDirectory()) {
|
||||
// XXX shelljs decides to create a directory when -R|-r is used which sucks. http://goo.gl/nbsjq
|
||||
shell.cp('-Rf', src+'/*', dest);
|
||||
} else {
|
||||
shell.cp('-f', src, dest);
|
||||
}
|
||||
}
|
||||
|
||||
// Same as copy file but throws error if target exists
|
||||
function copyNewFile (plugin_dir, src, project_dir, dest, link) {
|
||||
var target_path = path.resolve(project_dir, dest);
|
||||
if (fs.existsSync(target_path))
|
||||
throw new CordovaError('"' + target_path + '" already exists!');
|
||||
|
||||
copyFile(plugin_dir, src, project_dir, dest, !!link);
|
||||
}
|
||||
|
||||
// checks if file exists and then deletes. Error if doesn't exist
|
||||
function removeFile (project_dir, src) {
|
||||
var file = path.resolve(project_dir, src);
|
||||
shell.rm('-Rf', file);
|
||||
}
|
||||
|
||||
// deletes file/directory without checking
|
||||
function removeFileF (file) {
|
||||
shell.rm('-Rf', file);
|
||||
}
|
||||
|
||||
// Sometimes we want to remove some java, and prune any unnecessary empty directories
|
||||
function deleteJava (project_dir, destFile) {
|
||||
removeFileAndParents(project_dir, destFile, 'src');
|
||||
}
|
||||
|
||||
function removeFileAndParents (baseDir, destFile, stopper) {
|
||||
stopper = stopper || '.';
|
||||
var file = path.resolve(baseDir, destFile);
|
||||
if (!fs.existsSync(file)) return;
|
||||
|
||||
removeFileF(file);
|
||||
|
||||
// check if directory is empty
|
||||
var curDir = path.dirname(file);
|
||||
|
||||
while(curDir !== path.resolve(baseDir, stopper)) {
|
||||
if(fs.existsSync(curDir) && fs.readdirSync(curDir).length === 0) {
|
||||
fs.rmdirSync(curDir);
|
||||
curDir = path.resolve(curDir, '..');
|
||||
} else {
|
||||
// directory not empty...do nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function generateAttributeError(attribute, element, id) {
|
||||
return 'Required attribute "' + attribute + '" not specified in <' + element + '> element from plugin: ' + id;
|
||||
}
|
||||
434
bin/templates/cordova/lib/prepare.js
vendored
Normal file
@@ -0,0 +1,434 @@
|
||||
/**
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*/
|
||||
|
||||
var Q = require('q');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var shell = require('shelljs');
|
||||
var events = require('cordova-common').events;
|
||||
var AndroidManifest = require('./AndroidManifest');
|
||||
var xmlHelpers = require('cordova-common').xmlHelpers;
|
||||
var CordovaError = require('cordova-common').CordovaError;
|
||||
var ConfigParser = require('cordova-common').ConfigParser;
|
||||
var FileUpdater = require('cordova-common').FileUpdater;
|
||||
var PlatformJson = require('cordova-common').PlatformJson;
|
||||
var PlatformMunger = require('cordova-common').ConfigChanges.PlatformMunger;
|
||||
var PluginInfoProvider = require('cordova-common').PluginInfoProvider;
|
||||
|
||||
module.exports.prepare = function (cordovaProject, options) {
|
||||
var self = this;
|
||||
var platformResourcesDir = path.relative(cordovaProject.root, path.join(this.locations.root, 'res'));
|
||||
|
||||
var platformJson = PlatformJson.load(this.locations.root, this.platform);
|
||||
var munger = new PlatformMunger(this.platform, this.locations.root, platformJson, new PluginInfoProvider());
|
||||
|
||||
this._config = updateConfigFilesFrom(cordovaProject.projectConfig, munger, this.locations);
|
||||
|
||||
// Update own www dir with project's www assets and plugins' assets and js-files
|
||||
return Q.when(updateWww(cordovaProject, this.locations))
|
||||
.then(function () {
|
||||
// update project according to config.xml changes.
|
||||
return updateProjectAccordingTo(self._config, self.locations);
|
||||
})
|
||||
.then(function () {
|
||||
updateIcons(cordovaProject, platformResourcesDir);
|
||||
updateSplashes(cordovaProject, platformResourcesDir);
|
||||
})
|
||||
.then(function () {
|
||||
events.emit('verbose', 'Prepared android project successfully');
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.clean = function (options) {
|
||||
// A cordovaProject isn't passed into the clean() function, because it might have
|
||||
// been called from the platform shell script rather than the CLI. Check for the
|
||||
// noPrepare option passed in by the non-CLI clean script. If that's present, or if
|
||||
// there's no config.xml found at the project root, then don't clean prepared files.
|
||||
var projectRoot = path.resolve(this.root, '../..');
|
||||
var projectConfigFile = path.join(projectRoot, 'config.xml');
|
||||
if ((options && options.noPrepare) || !fs.existsSync(projectConfigFile) ||
|
||||
!fs.existsSync(this.locations.configXml)) {
|
||||
return Q();
|
||||
}
|
||||
|
||||
var projectConfig = new ConfigParser(this.locations.configXml);
|
||||
var platformResourcesDir = path.relative(projectRoot, path.join(this.locations.root, 'res'));
|
||||
|
||||
var self = this;
|
||||
return Q().then(function () {
|
||||
cleanWww(projectRoot, self.locations);
|
||||
cleanIcons(projectRoot, projectConfig, platformResourcesDir);
|
||||
cleanSplashes(projectRoot, projectConfig, platformResourcesDir);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates config files in project based on app's config.xml and config munge,
|
||||
* generated by plugins.
|
||||
*
|
||||
* @param {ConfigParser} sourceConfig A project's configuration that will
|
||||
* be merged into platform's config.xml
|
||||
* @param {ConfigChanges} configMunger An initialized ConfigChanges instance
|
||||
* for this platform.
|
||||
* @param {Object} locations A map of locations for this platform
|
||||
*
|
||||
* @return {ConfigParser} An instance of ConfigParser, that
|
||||
* represents current project's configuration. When returned, the
|
||||
* configuration is already dumped to appropriate config.xml file.
|
||||
*/
|
||||
function updateConfigFilesFrom(sourceConfig, configMunger, locations) {
|
||||
events.emit('verbose', 'Generating platform-specific config.xml from defaults for android at ' + locations.configXml);
|
||||
|
||||
// First cleanup current config and merge project's one into own
|
||||
// Overwrite platform config.xml with defaults.xml.
|
||||
shell.cp('-f', locations.defaultConfigXml, locations.configXml);
|
||||
|
||||
// Then apply config changes from global munge to all config files
|
||||
// in project (including project's config)
|
||||
configMunger.reapply_global_munge().save_all();
|
||||
|
||||
events.emit('verbose', 'Merging project\'s config.xml into platform-specific android config.xml');
|
||||
// Merge changes from app's config.xml into platform's one
|
||||
var config = new ConfigParser(locations.configXml);
|
||||
xmlHelpers.mergeXml(sourceConfig.doc.getroot(),
|
||||
config.doc.getroot(), 'android', /*clobber=*/true);
|
||||
|
||||
config.write();
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs all file operations via the verbose event stream, indented.
|
||||
*/
|
||||
function logFileOp(message) {
|
||||
events.emit('verbose', ' ' + message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates platform 'www' directory by replacing it with contents of
|
||||
* 'platform_www' and app www. Also copies project's overrides' folder into
|
||||
* the platform 'www' folder
|
||||
*
|
||||
* @param {Object} cordovaProject An object which describes cordova project.
|
||||
* @param {Object} destinations An object that contains destination
|
||||
* paths for www files.
|
||||
*/
|
||||
function updateWww(cordovaProject, destinations) {
|
||||
var sourceDirs = [
|
||||
path.relative(cordovaProject.root, cordovaProject.locations.www),
|
||||
path.relative(cordovaProject.root, destinations.platformWww)
|
||||
];
|
||||
|
||||
// If project contains 'merges' for our platform, use them as another overrides
|
||||
var merges_path = path.join(cordovaProject.root, 'merges', 'android');
|
||||
if (fs.existsSync(merges_path)) {
|
||||
events.emit('verbose', 'Found "merges/android" folder. Copying its contents into the android project.');
|
||||
sourceDirs.push(path.join('merges', 'android'));
|
||||
}
|
||||
|
||||
var targetDir = path.relative(cordovaProject.root, destinations.www);
|
||||
events.emit(
|
||||
'verbose', 'Merging and updating files from [' + sourceDirs.join(', ') + '] to ' + targetDir);
|
||||
FileUpdater.mergeAndUpdateDir(
|
||||
sourceDirs, targetDir, { rootDir: cordovaProject.root }, logFileOp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans all files from the platform 'www' directory.
|
||||
*/
|
||||
function cleanWww(projectRoot, locations) {
|
||||
var targetDir = path.relative(projectRoot, locations.www);
|
||||
events.emit('verbose', 'Cleaning ' + targetDir);
|
||||
|
||||
// No source paths are specified, so mergeAndUpdateDir() will clear the target directory.
|
||||
FileUpdater.mergeAndUpdateDir(
|
||||
[], targetDir, { rootDir: projectRoot, all: true }, logFileOp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates project structure and AndroidManifest according to project's configuration.
|
||||
*
|
||||
* @param {ConfigParser} platformConfig A project's configuration that will
|
||||
* be used to update project
|
||||
* @param {Object} locations A map of locations for this platform
|
||||
*/
|
||||
function updateProjectAccordingTo(platformConfig, locations) {
|
||||
// Update app name by editing res/values/strings.xml
|
||||
var name = platformConfig.name();
|
||||
var strings = xmlHelpers.parseElementtreeSync(locations.strings);
|
||||
strings.find('string[@name="app_name"]').text = name;
|
||||
fs.writeFileSync(locations.strings, strings.write({indent: 4}), 'utf-8');
|
||||
events.emit('verbose', 'Wrote out android application name "' + name + '" to ' + locations.strings);
|
||||
|
||||
// Java packages cannot support dashes
|
||||
var pkg = (platformConfig.android_packageName() || platformConfig.packageName()).replace(/-/g, '_');
|
||||
|
||||
var manifest = new AndroidManifest(locations.manifest);
|
||||
var orig_pkg = manifest.getPackageId();
|
||||
|
||||
manifest.getActivity()
|
||||
.setOrientation(platformConfig.getPreference('orientation'))
|
||||
.setLaunchMode(findAndroidLaunchModePreference(platformConfig));
|
||||
|
||||
manifest.setVersionName(platformConfig.version())
|
||||
.setVersionCode(platformConfig.android_versionCode() || default_versionCode(platformConfig.version()))
|
||||
.setPackageId(pkg)
|
||||
.setMinSdkVersion(platformConfig.getPreference('android-minSdkVersion', 'android'))
|
||||
.setMaxSdkVersion(platformConfig.getPreference('android-maxSdkVersion', 'android'))
|
||||
.setTargetSdkVersion(platformConfig.getPreference('android-targetSdkVersion', 'android'))
|
||||
.write();
|
||||
|
||||
var javaPattern = path.join(locations.root, 'src', orig_pkg.replace(/\./g, '/'), '*.java');
|
||||
var java_files = shell.ls(javaPattern).filter(function(f) {
|
||||
return shell.grep(/extends\s+CordovaActivity/g, f);
|
||||
});
|
||||
|
||||
if (java_files.length === 0) {
|
||||
throw new CordovaError('No Java files found that extend CordovaActivity.');
|
||||
} else if(java_files.length > 1) {
|
||||
events.emit('log', 'Multiple candidate Java files that extend CordovaActivity found. Guessing at the first one, ' + java_files[0]);
|
||||
}
|
||||
|
||||
var destFile = path.join(locations.root, 'src', pkg.replace(/\./g, '/'), path.basename(java_files[0]));
|
||||
shell.mkdir('-p', path.dirname(destFile));
|
||||
shell.sed(/package [\w\.]*;/, 'package ' + pkg + ';', java_files[0]).to(destFile);
|
||||
events.emit('verbose', 'Wrote out Android package name "' + pkg + '" to ' + destFile);
|
||||
|
||||
if (orig_pkg !== pkg) {
|
||||
// If package was name changed we need to remove old java with main activity
|
||||
shell.rm('-Rf',java_files[0]);
|
||||
// remove any empty directories
|
||||
var currentDir = path.dirname(java_files[0]);
|
||||
var sourcesRoot = path.resolve(locations.root, 'src');
|
||||
while(currentDir !== sourcesRoot) {
|
||||
if(fs.existsSync(currentDir) && fs.readdirSync(currentDir).length === 0) {
|
||||
fs.rmdirSync(currentDir);
|
||||
currentDir = path.resolve(currentDir, '..');
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Consturct the default value for versionCode as
|
||||
// PATCH + MINOR * 100 + MAJOR * 10000
|
||||
// see http://developer.android.com/tools/publishing/versioning.html
|
||||
function default_versionCode(version) {
|
||||
var nums = version.split('-')[0].split('.');
|
||||
var versionCode = 0;
|
||||
if (+nums[0]) {
|
||||
versionCode += +nums[0] * 10000;
|
||||
}
|
||||
if (+nums[1]) {
|
||||
versionCode += +nums[1] * 100;
|
||||
}
|
||||
if (+nums[2]) {
|
||||
versionCode += +nums[2];
|
||||
}
|
||||
|
||||
events.emit('verbose', 'android-versionCode not found in config.xml. Generating a code based on version in config.xml (' + version + '): ' + versionCode);
|
||||
return versionCode;
|
||||
}
|
||||
|
||||
function getImageResourcePath(resourcesDir, density, name, sourceName) {
|
||||
if (/\.9\.png$/.test(sourceName)) {
|
||||
name = name.replace(/\.png$/, '.9.png');
|
||||
}
|
||||
var resourcePath = path.join(resourcesDir, (density ? 'drawable-' + density : 'drawable'), name);
|
||||
return resourcePath;
|
||||
}
|
||||
|
||||
function updateSplashes(cordovaProject, platformResourcesDir) {
|
||||
var resources = cordovaProject.projectConfig.getSplashScreens('android');
|
||||
|
||||
// if there are "splash" elements in config.xml
|
||||
if (resources.length === 0) {
|
||||
events.emit('verbose', 'This app does not have splash screens defined');
|
||||
return;
|
||||
}
|
||||
|
||||
var resourceMap = mapImageResources(cordovaProject.root, platformResourcesDir, 'screen.png');
|
||||
|
||||
var hadMdpi = false;
|
||||
resources.forEach(function (resource) {
|
||||
if (!resource.density) {
|
||||
return;
|
||||
}
|
||||
if (resource.density == 'mdpi') {
|
||||
hadMdpi = true;
|
||||
}
|
||||
var targetPath = getImageResourcePath(
|
||||
platformResourcesDir, resource.density, 'screen.png', path.basename(resource.src));
|
||||
resourceMap[targetPath] = resource.src;
|
||||
});
|
||||
|
||||
// There's no "default" drawable, so assume default == mdpi.
|
||||
if (!hadMdpi && resources.defaultResource) {
|
||||
var targetPath = getImageResourcePath(
|
||||
platformResourcesDir, 'mdpi', 'screen.png', path.basename(resources.defaultResource.src));
|
||||
resourceMap[targetPath] = resources.defaultResource.src;
|
||||
}
|
||||
|
||||
events.emit('verbose', 'Updating splash screens at ' + platformResourcesDir);
|
||||
FileUpdater.updatePaths(
|
||||
resourceMap, { rootDir: cordovaProject.root }, logFileOp);
|
||||
}
|
||||
|
||||
function cleanSplashes(projectRoot, projectConfig, platformResourcesDir) {
|
||||
var resources = projectConfig.getSplashScreens('android');
|
||||
if (resources.length > 0) {
|
||||
var resourceMap = mapImageResources(projectRoot, platformResourcesDir, 'screen.png');
|
||||
events.emit('verbose', 'Cleaning splash screens at ' + platformResourcesDir);
|
||||
|
||||
// No source paths are specified in the map, so updatePaths() will delete the target files.
|
||||
FileUpdater.updatePaths(
|
||||
resourceMap, { rootDir: projectRoot, all: true }, logFileOp);
|
||||
}
|
||||
}
|
||||
|
||||
function updateIcons(cordovaProject, platformResourcesDir) {
|
||||
var icons = cordovaProject.projectConfig.getIcons('android');
|
||||
|
||||
// if there are icon elements in config.xml
|
||||
if (icons.length === 0) {
|
||||
events.emit('verbose', 'This app does not have launcher icons defined');
|
||||
return;
|
||||
}
|
||||
|
||||
var resourceMap = mapImageResources(cordovaProject.root, platformResourcesDir, 'icon.png');
|
||||
|
||||
var android_icons = {};
|
||||
var default_icon;
|
||||
// http://developer.android.com/design/style/iconography.html
|
||||
var sizeToDensityMap = {
|
||||
36: 'ldpi',
|
||||
48: 'mdpi',
|
||||
72: 'hdpi',
|
||||
96: 'xhdpi',
|
||||
144: 'xxhdpi',
|
||||
192: 'xxxhdpi'
|
||||
};
|
||||
// find the best matching icon for a given density or size
|
||||
// @output android_icons
|
||||
var parseIcon = function(icon, icon_size) {
|
||||
// do I have a platform icon for that density already
|
||||
var density = icon.density || sizeToDensityMap[icon_size];
|
||||
if (!density) {
|
||||
// invalid icon defition ( or unsupported size)
|
||||
return;
|
||||
}
|
||||
var previous = android_icons[density];
|
||||
if (previous && previous.platform) {
|
||||
return;
|
||||
}
|
||||
android_icons[density] = icon;
|
||||
};
|
||||
|
||||
// iterate over all icon elements to find the default icon and call parseIcon
|
||||
for (var i=0; i<icons.length; i++) {
|
||||
var icon = icons[i];
|
||||
var size = icon.width;
|
||||
if (!size) {
|
||||
size = icon.height;
|
||||
}
|
||||
if (!size && !icon.density) {
|
||||
if (default_icon) {
|
||||
events.emit('verbose', 'Found extra default icon: ' + icon.src + ' (ignoring in favor of ' + default_icon.src + ')');
|
||||
} else {
|
||||
default_icon = icon;
|
||||
}
|
||||
} else {
|
||||
parseIcon(icon, size);
|
||||
}
|
||||
}
|
||||
|
||||
// The source paths for icons and splashes are relative to
|
||||
// project's config.xml location, so we use it as base path.
|
||||
for (var density in android_icons) {
|
||||
var targetPath = getImageResourcePath(
|
||||
platformResourcesDir, density, 'icon.png', path.basename(android_icons[density].src));
|
||||
resourceMap[targetPath] = android_icons[density].src;
|
||||
}
|
||||
|
||||
// There's no "default" drawable, so assume default == mdpi.
|
||||
if (default_icon && !android_icons.mdpi) {
|
||||
var defaultTargetPath = getImageResourcePath(
|
||||
platformResourcesDir, 'mdpi', 'icon.png', path.basename(default_icon.src));
|
||||
resourceMap[defaultTargetPath] = default_icon.src;
|
||||
}
|
||||
|
||||
events.emit('verbose', 'Updating icons at ' + platformResourcesDir);
|
||||
FileUpdater.updatePaths(
|
||||
resourceMap, { rootDir: cordovaProject.root }, logFileOp);
|
||||
}
|
||||
|
||||
function cleanIcons(projectRoot, projectConfig, platformResourcesDir) {
|
||||
var icons = projectConfig.getIcons('android');
|
||||
if (icons.length > 0) {
|
||||
var resourceMap = mapImageResources(projectRoot, platformResourcesDir, 'icon.png');
|
||||
events.emit('verbose', 'Cleaning icons at ' + platformResourcesDir);
|
||||
|
||||
// No source paths are specified in the map, so updatePaths() will delete the target files.
|
||||
FileUpdater.updatePaths(
|
||||
resourceMap, { rootDir: projectRoot, all: true }, logFileOp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a map containing resources of a specified name from all drawable folders in a directory.
|
||||
*/
|
||||
function mapImageResources(rootDir, subDir, resourceName) {
|
||||
var pathMap = {};
|
||||
shell.ls(path.join(rootDir, subDir, 'drawable-*'))
|
||||
.forEach(function (drawableFolder) {
|
||||
var imagePath = path.join(subDir, path.basename(drawableFolder), resourceName);
|
||||
pathMap[imagePath] = null;
|
||||
});
|
||||
return pathMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets and validates 'AndroidLaunchMode' prepference from config.xml. Returns
|
||||
* preference value and warns if it doesn't seems to be valid
|
||||
*
|
||||
* @param {ConfigParser} platformConfig A configParser instance for
|
||||
* platform.
|
||||
*
|
||||
* @return {String} Preference's value from config.xml or
|
||||
* default value, if there is no such preference. The default value is
|
||||
* 'singleTop'
|
||||
*/
|
||||
function findAndroidLaunchModePreference(platformConfig) {
|
||||
var launchMode = platformConfig.getPreference('AndroidLaunchMode');
|
||||
if (!launchMode) {
|
||||
// Return a default value
|
||||
return 'singleTop';
|
||||
}
|
||||
|
||||
var expectedValues = ['standard', 'singleTop', 'singleTask', 'singleInstance'];
|
||||
var valid = expectedValues.indexOf(launchMode) >= 0;
|
||||
if (!valid) {
|
||||
// Note: warn, but leave the launch mode as developer wanted, in case the list of options changes in the future
|
||||
events.emit('warn', 'Unrecognized value for AndroidLaunchMode preference: ' +
|
||||
launchMode + '. Expected values are: ' + expectedValues.join(', '));
|
||||
}
|
||||
|
||||
return launchMode;
|
||||
}
|
||||
68
bin/templates/cordova/lib/retry.js
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*/
|
||||
|
||||
/* jshint node: true */
|
||||
|
||||
'use strict';
|
||||
|
||||
var events = require('cordova-common').events;
|
||||
|
||||
/*
|
||||
* Retry a promise-returning function a number of times, propagating its
|
||||
* results on success or throwing its error on a failed final attempt.
|
||||
*
|
||||
* @arg {Number} attemts_left - The number of times to retry the passed call.
|
||||
* @arg {Function} promiseFunction - A function that returns a promise.
|
||||
* @arg {...} - Arguments to pass to promiseFunction.
|
||||
*
|
||||
* @returns {Promise}
|
||||
*/
|
||||
module.exports.retryPromise = function (attemts_left, promiseFunction) {
|
||||
|
||||
// NOTE:
|
||||
// get all trailing arguments, by skipping the first two (attemts_left and
|
||||
// promiseFunction) because they shouldn't get passed to promiseFunction
|
||||
var promiseFunctionArguments = Array.prototype.slice.call(arguments, 2);
|
||||
|
||||
return promiseFunction.apply(undefined, promiseFunctionArguments).then(
|
||||
|
||||
// on success pass results through
|
||||
function onFulfilled(value) {
|
||||
return value;
|
||||
},
|
||||
|
||||
// on rejection either retry, or throw the error
|
||||
function onRejected(error) {
|
||||
|
||||
attemts_left -= 1;
|
||||
|
||||
if (attemts_left < 1) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
events.emit('verbose', 'A retried call failed. Retrying ' + attemts_left + ' more time(s).');
|
||||
|
||||
// retry call self again with the same arguments, except attemts_left is now lower
|
||||
var fullArguments = [attemts_left, promiseFunction].concat(promiseFunctionArguments);
|
||||
return module.exports.retryPromise.apply(undefined, fullArguments);
|
||||
}
|
||||
);
|
||||
};
|
||||
184
bin/templates/cordova/lib/run.js
vendored
@@ -19,114 +19,116 @@
|
||||
under the License.
|
||||
*/
|
||||
|
||||
/* jshint loopfunc:true */
|
||||
|
||||
var path = require('path'),
|
||||
build = require('./build'),
|
||||
emulator = require('./emulator'),
|
||||
device = require('./device'),
|
||||
Q = require('q');
|
||||
Q = require('q'),
|
||||
events = require('cordova-common').events;
|
||||
|
||||
/*
|
||||
* Runs the application on a device if availible.
|
||||
* If not device is found, it will use a started emulator.
|
||||
* If no started emulators are found it will attempt to start an avd.
|
||||
* If no avds are found it will error out.
|
||||
* Returns a promise.
|
||||
*/
|
||||
module.exports.run = function(args) {
|
||||
var build_type;
|
||||
function getInstallTarget(runOptions) {
|
||||
var install_target;
|
||||
|
||||
for (var i=2; i<args.length; i++) {
|
||||
if (args[i] == '--debug') {
|
||||
build_type = '--debug';
|
||||
} else if (args[i] == '--release') {
|
||||
build_type = '--release';
|
||||
} else if (args[i] == '--nobuild') {
|
||||
build_type = '--nobuild';
|
||||
} else if (args[i] == '--device') {
|
||||
install_target = '--device';
|
||||
} else if (args[i] == '--emulator') {
|
||||
install_target = '--emulator';
|
||||
} else if (args[i].substring(0, 9) == '--target=') {
|
||||
install_target = args[i].substring(9, args[i].length);
|
||||
} else {
|
||||
console.error('ERROR : Run option \'' + args[i] + '\' not recognized.');
|
||||
process.exit(2);
|
||||
}
|
||||
if (runOptions.target) {
|
||||
install_target = runOptions.target;
|
||||
} else if (runOptions.device) {
|
||||
install_target = '--device';
|
||||
} else if (runOptions.emulator) {
|
||||
install_target = '--emulator';
|
||||
}
|
||||
|
||||
return build.run(build_type).then(function() {
|
||||
if (install_target == '--device') {
|
||||
return device.install();
|
||||
} else if (install_target == '--emulator') {
|
||||
return emulator.list_started().then(function(started) {
|
||||
var p = started && started.length > 0 ? Q() : emulator.start();
|
||||
return p.then(function() { emulator.install(); });
|
||||
});
|
||||
} else if (install_target) {
|
||||
var devices, started_emulators, avds;
|
||||
return device.list()
|
||||
.then(function(res) {
|
||||
devices = res;
|
||||
return emulator.list_started();
|
||||
}).then(function(res) {
|
||||
started_emulators = res;
|
||||
return emulator.list_images();
|
||||
}).then(function(res) {
|
||||
avds = res;
|
||||
if (devices.indexOf(install_target) > -1) {
|
||||
return device.install(install_target);
|
||||
} else if (started_emulators.indexOf(install_target) > -1) {
|
||||
return emulator.install(install_target);
|
||||
} else {
|
||||
// if target emulator isn't started, then start it.
|
||||
var emulator_ID;
|
||||
for(avd in avds) {
|
||||
if(avds[avd].name == install_target) {
|
||||
return emulator.start(install_target)
|
||||
.then(function() { emulator.install(emulator_ID); });
|
||||
}
|
||||
}
|
||||
return Q.reject('Target \'' + install_target + '\' not found, unable to run project');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// no target given, deploy to device if availible, otherwise use the emulator.
|
||||
return install_target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the application on a device if available. If no device is found, it will
|
||||
* use a started emulator. If no started emulators are found it will attempt
|
||||
* to start an avd. If no avds are found it will error out.
|
||||
*
|
||||
* @param {Object} runOptions various run/build options. See Api.js build/run
|
||||
* methods for reference.
|
||||
*
|
||||
* @return {Promise}
|
||||
*/
|
||||
module.exports.run = function(runOptions) {
|
||||
|
||||
var self = this;
|
||||
var install_target = getInstallTarget(runOptions);
|
||||
|
||||
return Q()
|
||||
.then(function() {
|
||||
if (!install_target) {
|
||||
// no target given, deploy to device if available, otherwise use the emulator.
|
||||
return device.list()
|
||||
.then(function(device_list) {
|
||||
if (device_list.length > 0) {
|
||||
console.log('WARNING : No target specified, deploying to device \'' + device_list[0] + '\'.');
|
||||
return device.install(device_list[0]);
|
||||
events.emit('warn', 'No target specified, deploying to device \'' + device_list[0] + '\'.');
|
||||
install_target = device_list[0];
|
||||
} else {
|
||||
return emulator.list_started()
|
||||
.then(function(emulator_list) {
|
||||
if (emulator_list.length > 0) {
|
||||
console.log('WARNING : No target specified, deploying to emulator \'' + emulator_list[0] + '\'.');
|
||||
return emulator.install(emulator_list[0]);
|
||||
} else {
|
||||
console.log('WARNING : No started emulators found, starting an emulator.');
|
||||
return emulator.best_image()
|
||||
.then(function(best_avd) {
|
||||
if(best_avd) {
|
||||
return emulator.start(best_avd.name)
|
||||
.then(function(emulator_ID) {
|
||||
console.log('WARNING : No target specified, deploying to emulator \'' + emulator_ID + '\'.');
|
||||
return emulator.install(emulator_ID);
|
||||
});
|
||||
} else {
|
||||
return emulator.start();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
events.emit('warn', 'No target specified and no devices found, deploying to emulator');
|
||||
install_target = '--emulator';
|
||||
}
|
||||
});
|
||||
}
|
||||
}).then(function() {
|
||||
if (install_target == '--device') {
|
||||
return device.resolveTarget(null);
|
||||
} else if (install_target == '--emulator') {
|
||||
// Give preference to any already started emulators. Else, start one.
|
||||
return emulator.list_started()
|
||||
.then(function(started) {
|
||||
return started && started.length > 0 ? started[0] : emulator.start();
|
||||
}).then(function(emulatorId) {
|
||||
return emulator.resolveTarget(emulatorId);
|
||||
});
|
||||
}
|
||||
// They specified a specific device/emulator ID.
|
||||
return device.list()
|
||||
.then(function(devices) {
|
||||
if (devices.indexOf(install_target) > -1) {
|
||||
return device.resolveTarget(install_target);
|
||||
}
|
||||
return emulator.list_started()
|
||||
.then(function(started_emulators) {
|
||||
if (started_emulators.indexOf(install_target) > -1) {
|
||||
return emulator.resolveTarget(install_target);
|
||||
}
|
||||
return emulator.list_images()
|
||||
.then(function(avds) {
|
||||
// if target emulator isn't started, then start it.
|
||||
for (var avd in avds) {
|
||||
if (avds[avd].name == install_target) {
|
||||
return emulator.start(install_target)
|
||||
.then(function(emulatorId) {
|
||||
return emulator.resolveTarget(emulatorId);
|
||||
});
|
||||
}
|
||||
}
|
||||
return Q.reject('Target \'' + install_target + '\' not found, unable to run project');
|
||||
});
|
||||
});
|
||||
});
|
||||
}).then(function(resolvedTarget) {
|
||||
// Better just call self.build, but we're doing some processing of
|
||||
// build results (according to platformApi spec) so they are in different
|
||||
// format than emulator.install expects.
|
||||
// TODO: Update emulator/device.install to handle this change
|
||||
return build.run.call(self, runOptions, resolvedTarget)
|
||||
.then(function(buildResults) {
|
||||
if (resolvedTarget.isEmulator) {
|
||||
return emulator.wait_for_boot(resolvedTarget.target)
|
||||
.then(function () {
|
||||
return emulator.install(resolvedTarget, buildResults);
|
||||
});
|
||||
}
|
||||
return device.install(resolvedTarget, buildResults);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.help = function() {
|
||||
console.log('Usage: ' + path.relative(process.cwd(), args[0]) + ' [options]');
|
||||
console.log('Usage: ' + path.relative(process.cwd(), process.argv[1]) + ' [options]');
|
||||
console.log('Build options :');
|
||||
console.log(' --debug : Builds project in debug mode');
|
||||
console.log(' --release : Builds project in release mode');
|
||||
@@ -136,4 +138,4 @@ module.exports.help = function() {
|
||||
console.log(' --emulator : Will deploy the built project to an emulator if one exists');
|
||||
console.log(' --target=<target_id> : Installs to the target with the specified id.');
|
||||
process.exit(0);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
:: to you 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
|
||||
@@ -18,7 +18,7 @@
|
||||
@ECHO OFF
|
||||
SET script_path="%~dp0log"
|
||||
IF EXIST %script_path% (
|
||||
node "%script_path%" %*
|
||||
node %script_path% %*
|
||||
) ELSE (
|
||||
ECHO.
|
||||
ECHO ERROR: Could not find 'log' script in 'cordova' folder, aborting...>&2
|
||||
|
||||
18
bin/templates/cordova/loggingHelper.js
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
var CordovaLogger = require('cordova-common').CordovaLogger;
|
||||
|
||||
module.exports = {
|
||||
adjustLoggerLevel: function (opts) {
|
||||
if (opts instanceof Array) {
|
||||
opts.silent = opts.indexOf('--silent') !== -1;
|
||||
opts.verbose = opts.indexOf('--verbose') !== -1;
|
||||
}
|
||||
|
||||
if (opts.silent) {
|
||||
CordovaLogger.get().setLevel('error');
|
||||
}
|
||||
|
||||
if (opts.verbose) {
|
||||
CordovaLogger.get().setLevel('verbose');
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -19,19 +19,35 @@
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var run = require('./lib/run'),
|
||||
reqs = require('./lib/check_reqs'),
|
||||
args = process.argv;
|
||||
var Api = require('./Api');
|
||||
var nopt = require('nopt');
|
||||
var path = require('path');
|
||||
|
||||
// Support basic help commands
|
||||
if (args[2] == '--help' || args[2] == '/?' || args[2] == '-h' ||
|
||||
args[2] == 'help' || args[2] == '-help' || args[2] == '/help') {
|
||||
run.help();
|
||||
} else {
|
||||
reqs.run().done(function() {
|
||||
return run.run(args);
|
||||
}, function(err) {
|
||||
console.error('ERROR: ' + err);
|
||||
process.exit(2);
|
||||
});
|
||||
}
|
||||
if(['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) >= 0)
|
||||
require('./lib/run').help();
|
||||
|
||||
// Do some basic argument parsing
|
||||
var runOpts = nopt({
|
||||
'verbose' : Boolean,
|
||||
'silent' : Boolean,
|
||||
'debug' : Boolean,
|
||||
'release' : Boolean,
|
||||
'nobuild': Boolean,
|
||||
'buildConfig' : path,
|
||||
'archs' : String,
|
||||
'device' : Boolean,
|
||||
'emulator': Boolean,
|
||||
'target' : String
|
||||
}, { 'd' : '--verbose' });
|
||||
|
||||
// Make runOptions compatible with PlatformApi run method spec
|
||||
runOpts.argv = runOpts.argv.remain;
|
||||
|
||||
require('./loggingHelper').adjustLoggerLevel(runOpts);
|
||||
|
||||
new Api().run(runOpts)
|
||||
.catch(function(err) {
|
||||
console.error(err, err.stack);
|
||||
process.exit(2);
|
||||
});
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
:: to you 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
|
||||
@@ -18,7 +18,7 @@
|
||||
@ECHO OFF
|
||||
SET script_path="%~dp0run"
|
||||
IF EXIST %script_path% (
|
||||
node "%script_path%" %*
|
||||
node %script_path% %*
|
||||
) ELSE (
|
||||
ECHO.
|
||||
ECHO ERROR: Could not find 'run' script in 'cordova' folder, aborting...>&2
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
*/
|
||||
|
||||
// Coho updates this line:
|
||||
var VERSION = "3.2.0-dev";
|
||||
var VERSION = "5.2.1";
|
||||
|
||||
console.log(VERSION);
|
||||
module.exports.version = VERSION;
|
||||
|
||||
if (!module.parent) {
|
||||
console.log(VERSION);
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
:: to you 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
|
||||
@@ -18,7 +18,7 @@
|
||||
@ECHO OFF
|
||||
SET script_path="%~dp0version"
|
||||
IF EXIST %script_path% (
|
||||
node "%script_path%" %*
|
||||
node %script_path% %*
|
||||
) ELSE (
|
||||
ECHO.
|
||||
ECHO ERROR: Could not find 'version' script in 'cordova' folder, aborting...>&2
|
||||
|
||||
@@ -22,16 +22,13 @@ package __ID__;
|
||||
import android.os.Bundle;
|
||||
import org.apache.cordova.*;
|
||||
|
||||
public class __ACTIVITY__ extends CordovaActivity
|
||||
public class __ACTIVITY__ extends CordovaActivity
|
||||
{
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
super.init();
|
||||
// Set by <content src="index.html" /> in config.xml
|
||||
super.loadUrl(Config.getStartUrl());
|
||||
//super.loadUrl("file:///android_asset/www/index.html")
|
||||
loadUrl(launchUrl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:windowSoftInputMode="adjustPan"
|
||||
package="__PACKAGE__" android:versionName="1.0" android:versionCode="1" android:hardwareAccelerated="true">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="__PACKAGE__" android:versionName="1.0" android:versionCode="1" android:hardwareAccelerated="true">
|
||||
<supports-screens
|
||||
android:largeScreens="true"
|
||||
android:normalScreens="true"
|
||||
@@ -31,17 +31,19 @@
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<application android:icon="@drawable/icon" android:label="@string/app_name"
|
||||
android:hardwareAccelerated="true"
|
||||
android:debuggable="true">
|
||||
<activity android:name="__ACTIVITY__" android:label="@string/app_name"
|
||||
android:theme="@android:style/Theme.Black.NoTitleBar"
|
||||
android:hardwareAccelerated="true" android:supportsRtl="true">
|
||||
<activity android:name="__ACTIVITY__"
|
||||
android:label="@string/activity_name"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@android:style/Theme.DeviceDefault.NoActionBar"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale">
|
||||
<intent-filter>
|
||||
<intent-filter android:label="@string/launcher_name">
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
<uses-sdk android:minSdkVersion="10" android:targetSdkVersion="__APILEVEL__"/>
|
||||
</manifest>
|
||||
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="__APILEVEL__"/>
|
||||
</manifest>
|
||||
|
||||
@@ -19,10 +19,20 @@
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="format-detection" content="telephone=no" />
|
||||
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
|
||||
<link rel="stylesheet" type="text/css" href="css/index.css" />
|
||||
<!--
|
||||
Customize this policy to fit your own app's needs. For more guidance, see:
|
||||
https://github.com/apache/cordova-plugin-whitelist/blob/master/README.md#content-security-policy
|
||||
Some notes:
|
||||
* gap: is required only on iOS (when using UIWebView) and is needed for JS->native communication
|
||||
* https://ssl.gstatic.com is required only on Android and is needed for TalkBack to function properly
|
||||
* Disables use of inline scripts in order to mitigate risk of XSS vulnerabilities. To change this:
|
||||
* Enable inline JS: add 'unsafe-inline' to default-src
|
||||
-->
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *">
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<meta name="msapplication-tap-highlight" content="no">
|
||||
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
|
||||
<link rel="stylesheet" type="text/css" href="css/index.css">
|
||||
<title>Hello World</title>
|
||||
</head>
|
||||
<body>
|
||||
@@ -35,8 +45,5 @@
|
||||
</div>
|
||||
<script type="text/javascript" src="cordova.js"></script>
|
||||
<script type="text/javascript" src="js/index.js"></script>
|
||||
<script type="text/javascript">
|
||||
app.initialize();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -31,7 +31,7 @@ var app = {
|
||||
// deviceready Event Handler
|
||||
//
|
||||
// The scope of 'this' is the event. In order to call the 'receivedEvent'
|
||||
// function, we must explicity call 'app.receivedEvent(...);'
|
||||
// function, we must explicitly call 'app.receivedEvent(...);'
|
||||
onDeviceReady: function() {
|
||||
app.receivedEvent('deviceready');
|
||||
},
|
||||
@@ -47,3 +47,5 @@ var app = {
|
||||
console.log('Received Event: ' + id);
|
||||
}
|
||||
};
|
||||
|
||||
app.initialize();
|
||||
@@ -1,165 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*/
|
||||
|
||||
var deviceInfo = function() {
|
||||
document.getElementById("platform").innerHTML = device.platform;
|
||||
document.getElementById("version").innerHTML = device.version;
|
||||
document.getElementById("uuid").innerHTML = device.uuid;
|
||||
document.getElementById("name").innerHTML = device.name;
|
||||
document.getElementById("width").innerHTML = screen.width;
|
||||
document.getElementById("height").innerHTML = screen.height;
|
||||
document.getElementById("colorDepth").innerHTML = screen.colorDepth;
|
||||
};
|
||||
|
||||
var getLocation = function() {
|
||||
var suc = function(p) {
|
||||
alert(p.coords.latitude + " " + p.coords.longitude);
|
||||
};
|
||||
var locFail = function() {
|
||||
};
|
||||
navigator.geolocation.getCurrentPosition(suc, locFail);
|
||||
};
|
||||
|
||||
var beep = function() {
|
||||
navigator.notification.beep(2);
|
||||
};
|
||||
|
||||
var vibrate = function() {
|
||||
navigator.notification.vibrate(0);
|
||||
};
|
||||
|
||||
function roundNumber(num) {
|
||||
var dec = 3;
|
||||
var result = Math.round(num * Math.pow(10, dec)) / Math.pow(10, dec);
|
||||
return result;
|
||||
}
|
||||
|
||||
var accelerationWatch = null;
|
||||
|
||||
function updateAcceleration(a) {
|
||||
document.getElementById('x').innerHTML = roundNumber(a.x);
|
||||
document.getElementById('y').innerHTML = roundNumber(a.y);
|
||||
document.getElementById('z').innerHTML = roundNumber(a.z);
|
||||
}
|
||||
|
||||
var toggleAccel = function() {
|
||||
if (accelerationWatch !== null) {
|
||||
navigator.accelerometer.clearWatch(accelerationWatch);
|
||||
updateAcceleration({
|
||||
x : "",
|
||||
y : "",
|
||||
z : ""
|
||||
});
|
||||
accelerationWatch = null;
|
||||
} else {
|
||||
var options = {};
|
||||
options.frequency = 1000;
|
||||
accelerationWatch = navigator.accelerometer.watchAcceleration(
|
||||
updateAcceleration, function(ex) {
|
||||
alert("accel fail (" + ex.name + ": " + ex.message + ")");
|
||||
}, options);
|
||||
}
|
||||
};
|
||||
|
||||
var preventBehavior = function(e) {
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
function dump_pic(data) {
|
||||
var viewport = document.getElementById('viewport');
|
||||
console.log(data);
|
||||
viewport.style.display = "";
|
||||
viewport.style.position = "absolute";
|
||||
viewport.style.top = "10px";
|
||||
viewport.style.left = "10px";
|
||||
document.getElementById("test_img").src = data;
|
||||
}
|
||||
|
||||
function fail(msg) {
|
||||
alert(msg);
|
||||
}
|
||||
|
||||
function show_pic() {
|
||||
navigator.camera.getPicture(dump_pic, fail, {
|
||||
quality : 50
|
||||
});
|
||||
}
|
||||
|
||||
function close() {
|
||||
var viewport = document.getElementById('viewport');
|
||||
viewport.style.position = "relative";
|
||||
viewport.style.display = "none";
|
||||
}
|
||||
|
||||
function contacts_success(contacts) {
|
||||
alert(contacts.length
|
||||
+ ' contacts returned.'
|
||||
+ (contacts[2] && contacts[2].name ? (' Third contact is ' + contacts[2].name.formatted)
|
||||
: ''));
|
||||
}
|
||||
|
||||
function get_contacts() {
|
||||
var obj = new ContactFindOptions();
|
||||
obj.filter = "";
|
||||
obj.multiple = true;
|
||||
navigator.contacts.find(
|
||||
[ "displayName", "name" ], contacts_success,
|
||||
fail, obj);
|
||||
}
|
||||
|
||||
function check_network() {
|
||||
var networkState = navigator.network.connection.type;
|
||||
|
||||
var states = {};
|
||||
states[Connection.UNKNOWN] = 'Unknown connection';
|
||||
states[Connection.ETHERNET] = 'Ethernet connection';
|
||||
states[Connection.WIFI] = 'WiFi connection';
|
||||
states[Connection.CELL_2G] = 'Cell 2G connection';
|
||||
states[Connection.CELL_3G] = 'Cell 3G connection';
|
||||
states[Connection.CELL_4G] = 'Cell 4G connection';
|
||||
states[Connection.NONE] = 'No network connection';
|
||||
|
||||
confirm('Connection type:\n ' + states[networkState]);
|
||||
}
|
||||
|
||||
var watchID = null;
|
||||
|
||||
function updateHeading(h) {
|
||||
document.getElementById('h').innerHTML = h.magneticHeading;
|
||||
}
|
||||
|
||||
function toggleCompass() {
|
||||
if (watchID !== null) {
|
||||
navigator.compass.clearWatch(watchID);
|
||||
watchID = null;
|
||||
updateHeading({ magneticHeading : "Off"});
|
||||
} else {
|
||||
var options = { frequency: 1000 };
|
||||
watchID = navigator.compass.watchHeading(updateHeading, function(e) {
|
||||
alert('Compass Error: ' + e.code);
|
||||
}, options);
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
// the next line makes it impossible to see Contacts on the HTC Evo since it
|
||||
// doesn't have a scroll button
|
||||
// document.addEventListener("touchmove", preventBehavior, false);
|
||||
document.addEventListener("deviceready", deviceInfo, true);
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*/
|
||||
|
||||
|
||||
body {
|
||||
background:#222 none repeat scroll 0 0;
|
||||
color:#666;
|
||||
font-family:Helvetica;
|
||||
font-size:72%;
|
||||
line-height:1.5em;
|
||||
margin:0;
|
||||
border-top:1px solid #393939;
|
||||
}
|
||||
|
||||
#info{
|
||||
background:#ffa;
|
||||
border: 1px solid #ffd324;
|
||||
-webkit-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
clear:both;
|
||||
margin:15px 6px 0;
|
||||
width:295px;
|
||||
padding:4px 0px 2px 10px;
|
||||
}
|
||||
|
||||
#info > h4{
|
||||
font-size:.95em;
|
||||
margin:5px 0;
|
||||
}
|
||||
|
||||
#stage.theme{
|
||||
padding-top:3px;
|
||||
}
|
||||
|
||||
/* Definition List */
|
||||
#stage.theme > dl{
|
||||
padding-top:10px;
|
||||
clear:both;
|
||||
margin:0;
|
||||
list-style-type:none;
|
||||
padding-left:10px;
|
||||
overflow:auto;
|
||||
}
|
||||
|
||||
#stage.theme > dl > dt{
|
||||
font-weight:bold;
|
||||
float:left;
|
||||
margin-left:5px;
|
||||
}
|
||||
|
||||
#stage.theme > dl > dd{
|
||||
width:45px;
|
||||
float:left;
|
||||
color:#a87;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
/* Content Styling */
|
||||
#stage.theme > h1, #stage.theme > h2, #stage.theme > p{
|
||||
margin:1em 0 .5em 13px;
|
||||
}
|
||||
|
||||
#stage.theme > h1{
|
||||
color:#eee;
|
||||
font-size:1.6em;
|
||||
text-align:center;
|
||||
margin:0;
|
||||
margin-top:15px;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
#stage.theme > h2{
|
||||
clear:both;
|
||||
margin:0;
|
||||
padding:3px;
|
||||
font-size:1em;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
/* Stage Buttons */
|
||||
#stage.theme a.btn{
|
||||
border: 1px solid #555;
|
||||
-webkit-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
text-align:center;
|
||||
display:block;
|
||||
float:left;
|
||||
background:#444;
|
||||
width:150px;
|
||||
color:#9ab;
|
||||
font-size:1.1em;
|
||||
text-decoration:none;
|
||||
padding:1.2em 0;
|
||||
margin:3px 0px 3px 5px;
|
||||
}
|
||||
#stage.theme a.btn.large{
|
||||
width:308px;
|
||||
padding:1.2em 0;
|
||||
}
|
||||
|
||||
311
bin/templates/project/build.gradle
Normal file
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*/
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
}
|
||||
|
||||
// Switch the Android Gradle plugin version requirement depending on the
|
||||
// installed version of Gradle. This dependency is documented at
|
||||
// http://tools.android.com/tech-docs/new-build-system/version-compatibility
|
||||
// and https://issues.apache.org/jira/browse/CB-8143
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.1.0'
|
||||
}
|
||||
}
|
||||
|
||||
// Allow plugins to declare Maven dependencies via build-extras.gradle.
|
||||
allprojects {
|
||||
repositories {
|
||||
mavenCentral();
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
task wrapper(type: Wrapper) {
|
||||
gradleVersion = '2.13'
|
||||
}
|
||||
|
||||
// Configuration properties. Set these via environment variables, build-extras.gradle, or gradle.properties.
|
||||
// Refer to: http://www.gradle.org/docs/current/userguide/tutorial_this_and_that.html
|
||||
ext {
|
||||
apply from: 'CordovaLib/cordova.gradle'
|
||||
// The value for android.compileSdkVersion.
|
||||
if (!project.hasProperty('cdvCompileSdkVersion')) {
|
||||
cdvCompileSdkVersion = null;
|
||||
}
|
||||
// The value for android.buildToolsVersion.
|
||||
if (!project.hasProperty('cdvBuildToolsVersion')) {
|
||||
cdvBuildToolsVersion = null;
|
||||
}
|
||||
// Sets the versionCode to the given value.
|
||||
if (!project.hasProperty('cdvVersionCode')) {
|
||||
cdvVersionCode = null
|
||||
}
|
||||
// Sets the minSdkVersion to the given value.
|
||||
if (!project.hasProperty('cdvMinSdkVersion')) {
|
||||
cdvMinSdkVersion = null
|
||||
}
|
||||
// Whether to build architecture-specific APKs.
|
||||
if (!project.hasProperty('cdvBuildMultipleApks')) {
|
||||
cdvBuildMultipleApks = null
|
||||
}
|
||||
// .properties files to use for release signing.
|
||||
if (!project.hasProperty('cdvReleaseSigningPropertiesFile')) {
|
||||
cdvReleaseSigningPropertiesFile = null
|
||||
}
|
||||
// .properties files to use for debug signing.
|
||||
if (!project.hasProperty('cdvDebugSigningPropertiesFile')) {
|
||||
cdvDebugSigningPropertiesFile = null
|
||||
}
|
||||
// Set by build.js script.
|
||||
if (!project.hasProperty('cdvBuildArch')) {
|
||||
cdvBuildArch = null
|
||||
}
|
||||
|
||||
// Plugin gradle extensions can append to this to have code run at the end.
|
||||
cdvPluginPostBuildExtras = []
|
||||
}
|
||||
|
||||
// PLUGIN GRADLE EXTENSIONS START
|
||||
// PLUGIN GRADLE EXTENSIONS END
|
||||
|
||||
def hasBuildExtras = file('build-extras.gradle').exists()
|
||||
if (hasBuildExtras) {
|
||||
apply from: 'build-extras.gradle'
|
||||
}
|
||||
|
||||
// Set property defaults after extension .gradle files.
|
||||
if (ext.cdvCompileSdkVersion == null) {
|
||||
ext.cdvCompileSdkVersion = privateHelpers.getProjectTarget()
|
||||
}
|
||||
if (ext.cdvBuildToolsVersion == null) {
|
||||
ext.cdvBuildToolsVersion = privateHelpers.findLatestInstalledBuildTools()
|
||||
}
|
||||
if (ext.cdvDebugSigningPropertiesFile == null && file('debug-signing.properties').exists()) {
|
||||
ext.cdvDebugSigningPropertiesFile = 'debug-signing.properties'
|
||||
}
|
||||
if (ext.cdvReleaseSigningPropertiesFile == null && file('release-signing.properties').exists()) {
|
||||
ext.cdvReleaseSigningPropertiesFile = 'release-signing.properties'
|
||||
}
|
||||
|
||||
// Cast to appropriate types.
|
||||
ext.cdvBuildMultipleApks = cdvBuildMultipleApks == null ? false : cdvBuildMultipleApks.toBoolean();
|
||||
ext.cdvMinSdkVersion = cdvMinSdkVersion == null ? null : Integer.parseInt('' + cdvMinSdkVersion)
|
||||
ext.cdvVersionCode = cdvVersionCode == null ? null : Integer.parseInt('' + cdvVersionCode)
|
||||
|
||||
def computeBuildTargetName(debugBuild) {
|
||||
def ret = 'assemble'
|
||||
if (cdvBuildMultipleApks && cdvBuildArch) {
|
||||
def arch = cdvBuildArch == 'arm' ? 'armv7' : cdvBuildArch
|
||||
ret += '' + arch.toUpperCase().charAt(0) + arch.substring(1);
|
||||
}
|
||||
return ret + (debugBuild ? 'Debug' : 'Release')
|
||||
}
|
||||
|
||||
// Make cdvBuild a task that depends on the debug/arch-sepecific task.
|
||||
task cdvBuildDebug
|
||||
cdvBuildDebug.dependsOn {
|
||||
return computeBuildTargetName(true)
|
||||
}
|
||||
|
||||
task cdvBuildRelease
|
||||
cdvBuildRelease.dependsOn {
|
||||
return computeBuildTargetName(false)
|
||||
}
|
||||
|
||||
task cdvPrintProps << {
|
||||
println('cdvCompileSdkVersion=' + cdvCompileSdkVersion)
|
||||
println('cdvBuildToolsVersion=' + cdvBuildToolsVersion)
|
||||
println('cdvVersionCode=' + cdvVersionCode)
|
||||
println('cdvMinSdkVersion=' + cdvMinSdkVersion)
|
||||
println('cdvBuildMultipleApks=' + cdvBuildMultipleApks)
|
||||
println('cdvReleaseSigningPropertiesFile=' + cdvReleaseSigningPropertiesFile)
|
||||
println('cdvDebugSigningPropertiesFile=' + cdvDebugSigningPropertiesFile)
|
||||
println('cdvBuildArch=' + cdvBuildArch)
|
||||
println('computedVersionCode=' + android.defaultConfig.versionCode)
|
||||
android.productFlavors.each { flavor ->
|
||||
println('computed' + flavor.name.capitalize() + 'VersionCode=' + flavor.versionCode)
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
sourceSets {
|
||||
main {
|
||||
manifest.srcFile 'AndroidManifest.xml'
|
||||
java.srcDirs = ['src']
|
||||
resources.srcDirs = ['src']
|
||||
aidl.srcDirs = ['src']
|
||||
renderscript.srcDirs = ['src']
|
||||
res.srcDirs = ['res']
|
||||
assets.srcDirs = ['assets']
|
||||
jniLibs.srcDirs = ['libs']
|
||||
}
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
versionCode cdvVersionCode ?: Integer.parseInt("" + privateHelpers.extractIntFromManifest("versionCode"))
|
||||
applicationId privateHelpers.extractStringFromManifest("package")
|
||||
|
||||
if (cdvMinSdkVersion != null) {
|
||||
minSdkVersion cdvMinSdkVersion
|
||||
}
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
abortOnError false;
|
||||
}
|
||||
|
||||
compileSdkVersion cdvCompileSdkVersion
|
||||
buildToolsVersion cdvBuildToolsVersion
|
||||
|
||||
if (Boolean.valueOf(cdvBuildMultipleApks)) {
|
||||
productFlavors {
|
||||
armv7 {
|
||||
versionCode defaultConfig.versionCode*10 + 2
|
||||
ndk {
|
||||
abiFilters "armeabi-v7a", ""
|
||||
}
|
||||
}
|
||||
x86 {
|
||||
versionCode defaultConfig.versionCode*10 + 4
|
||||
ndk {
|
||||
abiFilters "x86", ""
|
||||
}
|
||||
}
|
||||
all {
|
||||
ndk {
|
||||
abiFilters "all", ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
|
||||
ELSE NOTHING! DON'T MESS WITH THE VERSION CODE IF YOU DON'T HAVE TO!
|
||||
|
||||
else if (!cdvVersionCode) {
|
||||
def minSdkVersion = cdvMinSdkVersion ?: privateHelpers.extractIntFromManifest("minSdkVersion")
|
||||
// Vary versionCode by the two most common API levels:
|
||||
// 14 is ICS, which is the lowest API level for many apps.
|
||||
// 20 is Lollipop, which is the lowest API level for the updatable system webview.
|
||||
if (minSdkVersion >= 20) {
|
||||
defaultConfig.versionCode += 9
|
||||
} else if (minSdkVersion >= 14) {
|
||||
defaultConfig.versionCode += 8
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_6
|
||||
targetCompatibility JavaVersion.VERSION_1_6
|
||||
}
|
||||
|
||||
if (cdvReleaseSigningPropertiesFile) {
|
||||
signingConfigs {
|
||||
release {
|
||||
// These must be set or Gradle will complain (even if they are overridden).
|
||||
keyAlias = ""
|
||||
keyPassword = "__unset" // And these must be set to non-empty in order to have the signing step added to the task graph.
|
||||
storeFile = null
|
||||
storePassword = "__unset"
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
}
|
||||
addSigningProps(cdvReleaseSigningPropertiesFile, signingConfigs.release)
|
||||
}
|
||||
if (cdvDebugSigningPropertiesFile) {
|
||||
addSigningProps(cdvDebugSigningPropertiesFile, signingConfigs.debug)
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile fileTree(dir: 'libs', include: '*.jar')
|
||||
// SUB-PROJECT DEPENDENCIES START
|
||||
// SUB-PROJECT DEPENDENCIES END
|
||||
}
|
||||
|
||||
def promptForReleaseKeyPassword() {
|
||||
if (!cdvReleaseSigningPropertiesFile) {
|
||||
return;
|
||||
}
|
||||
if ('__unset'.equals(android.signingConfigs.release.storePassword)) {
|
||||
android.signingConfigs.release.storePassword = privateHelpers.promptForPassword('Enter key store password: ')
|
||||
}
|
||||
if ('__unset'.equals(android.signingConfigs.release.keyPassword)) {
|
||||
android.signingConfigs.release.keyPassword = privateHelpers.promptForPassword('Enter key password: ');
|
||||
}
|
||||
}
|
||||
|
||||
gradle.taskGraph.whenReady { taskGraph ->
|
||||
taskGraph.getAllTasks().each() { task ->
|
||||
if (task.name == 'validateReleaseSigning') {
|
||||
promptForReleaseKeyPassword()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def addSigningProps(propsFilePath, signingConfig) {
|
||||
def propsFile = file(propsFilePath)
|
||||
def props = new Properties()
|
||||
propsFile.withReader { reader ->
|
||||
props.load(reader)
|
||||
}
|
||||
|
||||
def storeFile = new File(props.get('key.store') ?: privateHelpers.ensureValueExists(propsFilePath, props, 'storeFile'))
|
||||
if (!storeFile.isAbsolute()) {
|
||||
storeFile = RelativePath.parse(true, storeFile.toString()).getFile(propsFile.getParentFile())
|
||||
}
|
||||
if (!storeFile.exists()) {
|
||||
throw new FileNotFoundException('Keystore file does not exist: ' + storeFile.getAbsolutePath())
|
||||
}
|
||||
signingConfig.keyAlias = props.get('key.alias') ?: privateHelpers.ensureValueExists(propsFilePath, props, 'keyAlias')
|
||||
signingConfig.keyPassword = props.get('keyPassword', props.get('key.alias.password', signingConfig.keyPassword))
|
||||
signingConfig.storeFile = storeFile
|
||||
signingConfig.storePassword = props.get('storePassword', props.get('key.store.password', signingConfig.storePassword))
|
||||
def storeType = props.get('storeType', props.get('key.store.type', ''))
|
||||
if (!storeType) {
|
||||
def filename = storeFile.getName().toLowerCase();
|
||||
if (filename.endsWith('.p12') || filename.endsWith('.pfx')) {
|
||||
storeType = 'pkcs12'
|
||||
} else {
|
||||
storeType = signingConfig.storeType // "jks"
|
||||
}
|
||||
}
|
||||
signingConfig.storeType = storeType
|
||||
}
|
||||
|
||||
for (def func : cdvPluginPostBuildExtras) {
|
||||
func()
|
||||
}
|
||||
|
||||
// This can be defined within build-extras.gradle as:
|
||||
// ext.postBuildExtras = { ... code here ... }
|
||||
if (hasProperty('postBuildExtras')) {
|
||||
postBuildExtras()
|
||||
}
|
||||
14
bin/templates/project/gitignore
Normal file
@@ -0,0 +1,14 @@
|
||||
# Non-project-specific build files:
|
||||
build.xml
|
||||
local.properties
|
||||
/gradlew
|
||||
/gradlew.bat
|
||||
/gradle
|
||||
# Ant builds
|
||||
ant-build
|
||||
ant-gen
|
||||
# Eclipse builds
|
||||
gen
|
||||
out
|
||||
# Gradle builds
|
||||
/build
|
||||
15
bin/templates/project/project.properties
Normal file
@@ -0,0 +1,15 @@
|
||||
# This file is automatically generated by Android Tools.
|
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||
#
|
||||
# This file must be checked in Version Control Systems.
|
||||
#
|
||||
# To customize properties used by the Ant build system edit
|
||||
# "ant.properties", and override values to adapt the script to your
|
||||
# project structure.
|
||||
#
|
||||
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
|
||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||
|
||||
android.library.reference.1=CordovaLib
|
||||
# Project target.
|
||||
target=This_gets_replaced
|
||||
BIN
bin/templates/project/res/drawable-land-hdpi/screen.png
Normal file
|
After Width: | Height: | Size: 213 KiB |
BIN
bin/templates/project/res/drawable-land-ldpi/screen.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
bin/templates/project/res/drawable-land-mdpi/screen.png
Normal file
|
After Width: | Height: | Size: 90 KiB |
BIN
bin/templates/project/res/drawable-land-xhdpi/screen.png
Normal file
|
After Width: | Height: | Size: 478 KiB |
BIN
bin/templates/project/res/drawable-port-hdpi/screen.png
Normal file
|
After Width: | Height: | Size: 217 KiB |
BIN
bin/templates/project/res/drawable-port-ldpi/screen.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
bin/templates/project/res/drawable-port-mdpi/screen.png
Normal file
|
After Width: | Height: | Size: 88 KiB |
BIN
bin/templates/project/res/drawable-port-xhdpi/screen.png
Normal file
|
After Width: | Height: | Size: 493 KiB |
|
Before Width: | Height: | Size: 7.5 KiB |
@@ -1,4 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- App label shown within list of installed apps, battery & network usage screens. -->
|
||||
<string name="app_name">__NAME__</string>
|
||||
<!-- App label shown on the launcher. -->
|
||||
<string name="launcher_name">@string/app_name</string>
|
||||
<!-- App label shown on the task switcher. -->
|
||||
<string name="activity_name">@string/launcher_name</string>
|
||||
</resources>
|
||||
|
||||
@@ -30,21 +30,29 @@
|
||||
Apache Cordova Team
|
||||
</author>
|
||||
|
||||
<access origin="*"/>
|
||||
|
||||
<!-- <content src="http://mysite.com/myapp.html" /> for external pages -->
|
||||
<content src="index.html" />
|
||||
|
||||
<!-- Whitelist docs: https://github.com/apache/cordova-plugin-whitelist -->
|
||||
<access origin="*" />
|
||||
<!-- Grant certain URLs the ability to launch external applications. This
|
||||
behaviour is set to match that of Cordova versions before 3.6.0, and
|
||||
should be reviewed before launching an application in production. It
|
||||
may be changed in the future. -->
|
||||
<allow-intent href="http://*/*" />
|
||||
<allow-intent href="https://*/*" />
|
||||
<allow-intent href="tel:*" />
|
||||
<allow-intent href="sms:*" />
|
||||
<allow-intent href="mailto:*" />
|
||||
<allow-intent href="geo:*" />
|
||||
<allow-intent href="market:*" />
|
||||
|
||||
<preference name="loglevel" value="DEBUG" />
|
||||
<!--
|
||||
<preference name="splashscreen" value="resourceName" />
|
||||
<preference name="splashscreen" value="splash" />
|
||||
<preference name="backgroundColor" value="0xFFF" />
|
||||
<preference name="loadUrlTimeoutValue" value="20000" />
|
||||
<preference name="InAppBrowserStorageEnabled" value="true" />
|
||||
<preference name="disallowOverscroll" value="true" />
|
||||
-->
|
||||
<!-- This is required for native Android hooks -->
|
||||
<feature name="App">
|
||||
<param name="android-package" value="org.apache.cordova.App" />
|
||||
</feature>
|
||||
</widget>
|
||||
23
bin/update
@@ -19,18 +19,19 @@
|
||||
under the License.
|
||||
*/
|
||||
var path = require('path');
|
||||
var args = process.argv;
|
||||
var create = require('./lib/create');
|
||||
var Api = require('./templates/cordova/Api');
|
||||
var args = require('nopt')({
|
||||
'link': Boolean,
|
||||
'shared': Boolean,
|
||||
'help': Boolean
|
||||
}, { 'd' : '--verbose' });
|
||||
|
||||
// Support basic help commands
|
||||
if(args.length < 3 || (args[2] == '--help' || args[2] == '/?' || args[2] == '-h' ||
|
||||
args[2] == 'help' || args[2] == '-help' || args[2] == '/help')) {
|
||||
console.log('Usage: ' + path.relative(process.cwd(), path.join(__dirname, 'update')) + ' <path_to_project>');
|
||||
if (args.help || args.argv.remain.length === 0) {
|
||||
console.log('Usage: ' + path.relative(process.cwd(), path.join(__dirname, 'update')) + ' <path_to_project> [--link]');
|
||||
console.log(' --link will use the CordovaLib project directly instead of making a copy.');
|
||||
process.exit(1);
|
||||
} else {
|
||||
create.updateProject(args[2]).done(null, function(err) {
|
||||
console.error(err);
|
||||
process.exit(2);
|
||||
});
|
||||
}
|
||||
|
||||
require('./templates/cordova/loggingHelper').adjustLoggerLevel(args);
|
||||
|
||||
Api.updatePlatform(args.argv.remain[0], {link: (args.link || args.shared)}).done();
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
package org.apache.cordova.test;
|
||||
/*
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
@@ -17,18 +15,22 @@ package org.apache.cordova.test;
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Exports the ExposedJsApi.java object if available, otherwise exports the PromptBasedNativeApi.
|
||||
*/
|
||||
|
||||
import org.apache.cordova.test.actions.xhr;
|
||||
var nativeApi = this._cordovaNative || require('cordova/android/promptbasednativeapi');
|
||||
var currentApi = nativeApi;
|
||||
|
||||
import android.test.ActivityInstrumentationTestCase2;
|
||||
|
||||
public class XhrTest extends ActivityInstrumentationTestCase2<xhr> {
|
||||
|
||||
public XhrTest()
|
||||
{
|
||||
super(xhr.class);
|
||||
}
|
||||
}
|
||||
module.exports = {
|
||||
get: function() { return currentApi; },
|
||||
setPreferPrompt: function(value) {
|
||||
currentApi = value ? require('cordova/android/promptbasednativeapi') : nativeApi;
|
||||
},
|
||||
// Used only by tests.
|
||||
set: function(value) {
|
||||
currentApi = value;
|
||||
}
|
||||
};
|
||||
@@ -1,6 +1,4 @@
|
||||
package org.apache.cordova.test;
|
||||
/*
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
@@ -17,18 +15,21 @@ package org.apache.cordova.test;
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements the API of ExposedJsApi.java, but uses prompt() to communicate.
|
||||
* This is used pre-JellyBean, where addJavascriptInterface() is disabled.
|
||||
*/
|
||||
|
||||
import org.apache.cordova.test.actions.lifecycle;
|
||||
|
||||
import android.test.ActivityInstrumentationTestCase2;
|
||||
|
||||
public class LifecycleTest extends ActivityInstrumentationTestCase2<lifecycle> {
|
||||
|
||||
public LifecycleTest()
|
||||
{
|
||||
super("org.apache.cordova.test",lifecycle.class);
|
||||
}
|
||||
}
|
||||
module.exports = {
|
||||
exec: function(bridgeSecret, service, action, callbackId, argsJson) {
|
||||
return prompt(argsJson, 'gap:'+JSON.stringify([bridgeSecret, service, action, callbackId]));
|
||||
},
|
||||
setNativeToJsBridgeMode: function(bridgeSecret, value) {
|
||||
prompt(value, 'gap_bridge_mode:' + bridgeSecret);
|
||||
},
|
||||
retrieveJsMessages: function(bridgeSecret, fromOnlineEvent) {
|
||||
return prompt(+fromOnlineEvent, 'gap_poll:' + bridgeSecret);
|
||||
}
|
||||
};
|
||||
283
cordova-js-src/exec.js
vendored
Normal file
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Execute a cordova command. It is up to the native side whether this action
|
||||
* is synchronous or asynchronous. The native side can return:
|
||||
* Synchronous: PluginResult object as a JSON string
|
||||
* Asynchronous: Empty string ""
|
||||
* If async, the native side will cordova.callbackSuccess or cordova.callbackError,
|
||||
* depending upon the result of the action.
|
||||
*
|
||||
* @param {Function} success The success callback
|
||||
* @param {Function} fail The fail callback
|
||||
* @param {String} service The name of the service to use
|
||||
* @param {String} action Action to be run in cordova
|
||||
* @param {String[]} [args] Zero or more arguments to pass to the method
|
||||
*/
|
||||
var cordova = require('cordova'),
|
||||
nativeApiProvider = require('cordova/android/nativeapiprovider'),
|
||||
utils = require('cordova/utils'),
|
||||
base64 = require('cordova/base64'),
|
||||
channel = require('cordova/channel'),
|
||||
jsToNativeModes = {
|
||||
PROMPT: 0,
|
||||
JS_OBJECT: 1
|
||||
},
|
||||
nativeToJsModes = {
|
||||
// Polls for messages using the JS->Native bridge.
|
||||
POLLING: 0,
|
||||
// For LOAD_URL to be viable, it would need to have a work-around for
|
||||
// the bug where the soft-keyboard gets dismissed when a message is sent.
|
||||
LOAD_URL: 1,
|
||||
// For the ONLINE_EVENT to be viable, it would need to intercept all event
|
||||
// listeners (both through addEventListener and window.ononline) as well
|
||||
// as set the navigator property itself.
|
||||
ONLINE_EVENT: 2
|
||||
},
|
||||
jsToNativeBridgeMode, // Set lazily.
|
||||
nativeToJsBridgeMode = nativeToJsModes.ONLINE_EVENT,
|
||||
pollEnabled = false,
|
||||
bridgeSecret = -1;
|
||||
|
||||
var messagesFromNative = [];
|
||||
var isProcessing = false;
|
||||
var resolvedPromise = typeof Promise == 'undefined' ? null : Promise.resolve();
|
||||
var nextTick = resolvedPromise ? function(fn) { resolvedPromise.then(fn); } : function(fn) { setTimeout(fn); };
|
||||
|
||||
function androidExec(success, fail, service, action, args) {
|
||||
if (bridgeSecret < 0) {
|
||||
// If we ever catch this firing, we'll need to queue up exec()s
|
||||
// and fire them once we get a secret. For now, I don't think
|
||||
// it's possible for exec() to be called since plugins are parsed but
|
||||
// not run until until after onNativeReady.
|
||||
throw new Error('exec() called without bridgeSecret');
|
||||
}
|
||||
// Set default bridge modes if they have not already been set.
|
||||
// By default, we use the failsafe, since addJavascriptInterface breaks too often
|
||||
if (jsToNativeBridgeMode === undefined) {
|
||||
androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
|
||||
}
|
||||
|
||||
// Process any ArrayBuffers in the args into a string.
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
if (utils.typeName(args[i]) == 'ArrayBuffer') {
|
||||
args[i] = base64.fromArrayBuffer(args[i]);
|
||||
}
|
||||
}
|
||||
|
||||
var callbackId = service + cordova.callbackId++,
|
||||
argsJson = JSON.stringify(args);
|
||||
|
||||
if (success || fail) {
|
||||
cordova.callbacks[callbackId] = {success:success, fail:fail};
|
||||
}
|
||||
|
||||
var msgs = nativeApiProvider.get().exec(bridgeSecret, service, action, callbackId, argsJson);
|
||||
// If argsJson was received by Java as null, try again with the PROMPT bridge mode.
|
||||
// This happens in rare circumstances, such as when certain Unicode characters are passed over the bridge on a Galaxy S2. See CB-2666.
|
||||
if (jsToNativeBridgeMode == jsToNativeModes.JS_OBJECT && msgs === "@Null arguments.") {
|
||||
androidExec.setJsToNativeBridgeMode(jsToNativeModes.PROMPT);
|
||||
androidExec(success, fail, service, action, args);
|
||||
androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
|
||||
} else if (msgs) {
|
||||
messagesFromNative.push(msgs);
|
||||
// Always process async to avoid exceptions messing up stack.
|
||||
nextTick(processMessages);
|
||||
}
|
||||
}
|
||||
|
||||
androidExec.init = function() {
|
||||
bridgeSecret = +prompt('', 'gap_init:' + nativeToJsBridgeMode);
|
||||
channel.onNativeReady.fire();
|
||||
};
|
||||
|
||||
function pollOnceFromOnlineEvent() {
|
||||
pollOnce(true);
|
||||
}
|
||||
|
||||
function pollOnce(opt_fromOnlineEvent) {
|
||||
if (bridgeSecret < 0) {
|
||||
// This can happen when the NativeToJsMessageQueue resets the online state on page transitions.
|
||||
// We know there's nothing to retrieve, so no need to poll.
|
||||
return;
|
||||
}
|
||||
var msgs = nativeApiProvider.get().retrieveJsMessages(bridgeSecret, !!opt_fromOnlineEvent);
|
||||
if (msgs) {
|
||||
messagesFromNative.push(msgs);
|
||||
// Process sync since we know we're already top-of-stack.
|
||||
processMessages();
|
||||
}
|
||||
}
|
||||
|
||||
function pollingTimerFunc() {
|
||||
if (pollEnabled) {
|
||||
pollOnce();
|
||||
setTimeout(pollingTimerFunc, 50);
|
||||
}
|
||||
}
|
||||
|
||||
function hookOnlineApis() {
|
||||
function proxyEvent(e) {
|
||||
cordova.fireWindowEvent(e.type);
|
||||
}
|
||||
// The network module takes care of firing online and offline events.
|
||||
// It currently fires them only on document though, so we bridge them
|
||||
// to window here (while first listening for exec()-releated online/offline
|
||||
// events).
|
||||
window.addEventListener('online', pollOnceFromOnlineEvent, false);
|
||||
window.addEventListener('offline', pollOnceFromOnlineEvent, false);
|
||||
cordova.addWindowEventHandler('online');
|
||||
cordova.addWindowEventHandler('offline');
|
||||
document.addEventListener('online', proxyEvent, false);
|
||||
document.addEventListener('offline', proxyEvent, false);
|
||||
}
|
||||
|
||||
hookOnlineApis();
|
||||
|
||||
androidExec.jsToNativeModes = jsToNativeModes;
|
||||
androidExec.nativeToJsModes = nativeToJsModes;
|
||||
|
||||
androidExec.setJsToNativeBridgeMode = function(mode) {
|
||||
if (mode == jsToNativeModes.JS_OBJECT && !window._cordovaNative) {
|
||||
mode = jsToNativeModes.PROMPT;
|
||||
}
|
||||
nativeApiProvider.setPreferPrompt(mode == jsToNativeModes.PROMPT);
|
||||
jsToNativeBridgeMode = mode;
|
||||
};
|
||||
|
||||
androidExec.setNativeToJsBridgeMode = function(mode) {
|
||||
if (mode == nativeToJsBridgeMode) {
|
||||
return;
|
||||
}
|
||||
if (nativeToJsBridgeMode == nativeToJsModes.POLLING) {
|
||||
pollEnabled = false;
|
||||
}
|
||||
|
||||
nativeToJsBridgeMode = mode;
|
||||
// Tell the native side to switch modes.
|
||||
// Otherwise, it will be set by androidExec.init()
|
||||
if (bridgeSecret >= 0) {
|
||||
nativeApiProvider.get().setNativeToJsBridgeMode(bridgeSecret, mode);
|
||||
}
|
||||
|
||||
if (mode == nativeToJsModes.POLLING) {
|
||||
pollEnabled = true;
|
||||
setTimeout(pollingTimerFunc, 1);
|
||||
}
|
||||
};
|
||||
|
||||
function buildPayload(payload, message) {
|
||||
var payloadKind = message.charAt(0);
|
||||
if (payloadKind == 's') {
|
||||
payload.push(message.slice(1));
|
||||
} else if (payloadKind == 't') {
|
||||
payload.push(true);
|
||||
} else if (payloadKind == 'f') {
|
||||
payload.push(false);
|
||||
} else if (payloadKind == 'N') {
|
||||
payload.push(null);
|
||||
} else if (payloadKind == 'n') {
|
||||
payload.push(+message.slice(1));
|
||||
} else if (payloadKind == 'A') {
|
||||
var data = message.slice(1);
|
||||
payload.push(base64.toArrayBuffer(data));
|
||||
} else if (payloadKind == 'S') {
|
||||
payload.push(window.atob(message.slice(1)));
|
||||
} else if (payloadKind == 'M') {
|
||||
var multipartMessages = message.slice(1);
|
||||
while (multipartMessages !== "") {
|
||||
var spaceIdx = multipartMessages.indexOf(' ');
|
||||
var msgLen = +multipartMessages.slice(0, spaceIdx);
|
||||
var multipartMessage = multipartMessages.substr(spaceIdx + 1, msgLen);
|
||||
multipartMessages = multipartMessages.slice(spaceIdx + msgLen + 1);
|
||||
buildPayload(payload, multipartMessage);
|
||||
}
|
||||
} else {
|
||||
payload.push(JSON.parse(message));
|
||||
}
|
||||
}
|
||||
|
||||
// Processes a single message, as encoded by NativeToJsMessageQueue.java.
|
||||
function processMessage(message) {
|
||||
var firstChar = message.charAt(0);
|
||||
if (firstChar == 'J') {
|
||||
// This is deprecated on the .java side. It doesn't work with CSP enabled.
|
||||
eval(message.slice(1));
|
||||
} else if (firstChar == 'S' || firstChar == 'F') {
|
||||
var success = firstChar == 'S';
|
||||
var keepCallback = message.charAt(1) == '1';
|
||||
var spaceIdx = message.indexOf(' ', 2);
|
||||
var status = +message.slice(2, spaceIdx);
|
||||
var nextSpaceIdx = message.indexOf(' ', spaceIdx + 1);
|
||||
var callbackId = message.slice(spaceIdx + 1, nextSpaceIdx);
|
||||
var payloadMessage = message.slice(nextSpaceIdx + 1);
|
||||
var payload = [];
|
||||
buildPayload(payload, payloadMessage);
|
||||
cordova.callbackFromNative(callbackId, success, status, payload, keepCallback);
|
||||
} else {
|
||||
console.log("processMessage failed: invalid message: " + JSON.stringify(message));
|
||||
}
|
||||
}
|
||||
|
||||
function processMessages() {
|
||||
// Check for the reentrant case.
|
||||
if (isProcessing) {
|
||||
return;
|
||||
}
|
||||
if (messagesFromNative.length === 0) {
|
||||
return;
|
||||
}
|
||||
isProcessing = true;
|
||||
try {
|
||||
var msg = popMessageFromQueue();
|
||||
// The Java side can send a * message to indicate that it
|
||||
// still has messages waiting to be retrieved.
|
||||
if (msg == '*' && messagesFromNative.length === 0) {
|
||||
nextTick(pollOnce);
|
||||
return;
|
||||
}
|
||||
processMessage(msg);
|
||||
} finally {
|
||||
isProcessing = false;
|
||||
if (messagesFromNative.length > 0) {
|
||||
nextTick(processMessages);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function popMessageFromQueue() {
|
||||
var messageBatch = messagesFromNative.shift();
|
||||
if (messageBatch == '*') {
|
||||
return '*';
|
||||
}
|
||||
|
||||
var spaceIdx = messageBatch.indexOf(' ');
|
||||
var msgLen = +messageBatch.slice(0, spaceIdx);
|
||||
var message = messageBatch.substr(spaceIdx + 1, msgLen);
|
||||
messageBatch = messageBatch.slice(spaceIdx + msgLen + 1);
|
||||
if (messageBatch) {
|
||||
messagesFromNative.unshift(messageBatch);
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
module.exports = androidExec;
|
||||
125
cordova-js-src/platform.js
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.
|
||||
*
|
||||
*/
|
||||
|
||||
// The last resume event that was received that had the result of a plugin call.
|
||||
var lastResumeEvent = null;
|
||||
|
||||
module.exports = {
|
||||
id: 'android',
|
||||
bootstrap: function() {
|
||||
var channel = require('cordova/channel'),
|
||||
cordova = require('cordova'),
|
||||
exec = require('cordova/exec'),
|
||||
modulemapper = require('cordova/modulemapper');
|
||||
|
||||
// Get the shared secret needed to use the bridge.
|
||||
exec.init();
|
||||
|
||||
// TODO: Extract this as a proper plugin.
|
||||
modulemapper.clobbers('cordova/plugin/android/app', 'navigator.app');
|
||||
|
||||
var APP_PLUGIN_NAME = Number(cordova.platformVersion.split('.')[0]) >= 4 ? 'CoreAndroid' : 'App';
|
||||
|
||||
// Inject a listener for the backbutton on the document.
|
||||
var backButtonChannel = cordova.addDocumentEventHandler('backbutton');
|
||||
backButtonChannel.onHasSubscribersChange = function() {
|
||||
// If we just attached the first handler or detached the last handler,
|
||||
// let native know we need to override the back button.
|
||||
exec(null, null, APP_PLUGIN_NAME, "overrideBackbutton", [this.numHandlers == 1]);
|
||||
};
|
||||
|
||||
// Add hardware MENU and SEARCH button handlers
|
||||
cordova.addDocumentEventHandler('menubutton');
|
||||
cordova.addDocumentEventHandler('searchbutton');
|
||||
|
||||
function bindButtonChannel(buttonName) {
|
||||
// generic button bind used for volumeup/volumedown buttons
|
||||
var volumeButtonChannel = cordova.addDocumentEventHandler(buttonName + 'button');
|
||||
volumeButtonChannel.onHasSubscribersChange = function() {
|
||||
exec(null, null, APP_PLUGIN_NAME, "overrideButton", [buttonName, this.numHandlers == 1]);
|
||||
};
|
||||
}
|
||||
// Inject a listener for the volume buttons on the document.
|
||||
bindButtonChannel('volumeup');
|
||||
bindButtonChannel('volumedown');
|
||||
|
||||
// The resume event is not "sticky", but it is possible that the event
|
||||
// will contain the result of a plugin call. We need to ensure that the
|
||||
// plugin result is delivered even after the event is fired (CB-10498)
|
||||
var cordovaAddEventListener = document.addEventListener;
|
||||
|
||||
document.addEventListener = function(evt, handler, capture) {
|
||||
cordovaAddEventListener(evt, handler, capture);
|
||||
|
||||
if (evt === 'resume' && lastResumeEvent) {
|
||||
handler(lastResumeEvent);
|
||||
}
|
||||
};
|
||||
|
||||
// Let native code know we are all done on the JS side.
|
||||
// Native code will then un-hide the WebView.
|
||||
channel.onCordovaReady.subscribe(function() {
|
||||
exec(onMessageFromNative, null, APP_PLUGIN_NAME, 'messageChannel', []);
|
||||
exec(null, null, APP_PLUGIN_NAME, "show", []);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function onMessageFromNative(msg) {
|
||||
var cordova = require('cordova');
|
||||
var action = msg.action;
|
||||
|
||||
switch (action)
|
||||
{
|
||||
// Button events
|
||||
case 'backbutton':
|
||||
case 'menubutton':
|
||||
case 'searchbutton':
|
||||
// App life cycle events
|
||||
case 'pause':
|
||||
// Volume events
|
||||
case 'volumedownbutton':
|
||||
case 'volumeupbutton':
|
||||
cordova.fireDocumentEvent(action);
|
||||
break;
|
||||
case 'resume':
|
||||
if(arguments.length > 1 && msg.pendingResult) {
|
||||
if(arguments.length === 2) {
|
||||
msg.pendingResult.result = arguments[1];
|
||||
} else {
|
||||
// The plugin returned a multipart message
|
||||
var res = [];
|
||||
for(var i = 1; i < arguments.length; i++) {
|
||||
res.push(arguments[i]);
|
||||
}
|
||||
msg.pendingResult.result = res;
|
||||
}
|
||||
|
||||
// Save the plugin result so that it can be delivered to the js
|
||||
// even if they miss the initial firing of the event
|
||||
lastResumeEvent = msg;
|
||||
}
|
||||
cordova.fireDocumentEvent(action, msg);
|
||||
break;
|
||||
default:
|
||||
throw new Error('Unknown event action ' + action);
|
||||
}
|
||||
}
|
||||
108
cordova-js-src/plugin/android/app.js
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.
|
||||
*
|
||||
*/
|
||||
|
||||
var exec = require('cordova/exec');
|
||||
var APP_PLUGIN_NAME = Number(require('cordova').platformVersion.split('.')[0]) >= 4 ? 'CoreAndroid' : 'App';
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* Clear the resource cache.
|
||||
*/
|
||||
clearCache:function() {
|
||||
exec(null, null, APP_PLUGIN_NAME, "clearCache", []);
|
||||
},
|
||||
|
||||
/**
|
||||
* Load the url into the webview or into new browser instance.
|
||||
*
|
||||
* @param url The URL to load
|
||||
* @param props Properties that can be passed in to the activity:
|
||||
* wait: int => wait msec before loading URL
|
||||
* loadingDialog: "Title,Message" => display a native loading dialog
|
||||
* loadUrlTimeoutValue: int => time in msec to wait before triggering a timeout error
|
||||
* clearHistory: boolean => clear webview history (default=false)
|
||||
* openExternal: boolean => open in a new browser (default=false)
|
||||
*
|
||||
* Example:
|
||||
* navigator.app.loadUrl("http://server/myapp/index.html", {wait:2000, loadingDialog:"Wait,Loading App", loadUrlTimeoutValue: 60000});
|
||||
*/
|
||||
loadUrl:function(url, props) {
|
||||
exec(null, null, APP_PLUGIN_NAME, "loadUrl", [url, props]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Cancel loadUrl that is waiting to be loaded.
|
||||
*/
|
||||
cancelLoadUrl:function() {
|
||||
exec(null, null, APP_PLUGIN_NAME, "cancelLoadUrl", []);
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear web history in this web view.
|
||||
* Instead of BACK button loading the previous web page, it will exit the app.
|
||||
*/
|
||||
clearHistory:function() {
|
||||
exec(null, null, APP_PLUGIN_NAME, "clearHistory", []);
|
||||
},
|
||||
|
||||
/**
|
||||
* Go to previous page displayed.
|
||||
* This is the same as pressing the backbutton on Android device.
|
||||
*/
|
||||
backHistory:function() {
|
||||
exec(null, null, APP_PLUGIN_NAME, "backHistory", []);
|
||||
},
|
||||
|
||||
/**
|
||||
* Override the default behavior of the Android back button.
|
||||
* If overridden, when the back button is pressed, the "backKeyDown" JavaScript event will be fired.
|
||||
*
|
||||
* Note: The user should not have to call this method. Instead, when the user
|
||||
* registers for the "backbutton" event, this is automatically done.
|
||||
*
|
||||
* @param override T=override, F=cancel override
|
||||
*/
|
||||
overrideBackbutton:function(override) {
|
||||
exec(null, null, APP_PLUGIN_NAME, "overrideBackbutton", [override]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Override the default behavior of the Android volume button.
|
||||
* If overridden, when the volume button is pressed, the "volume[up|down]button"
|
||||
* JavaScript event will be fired.
|
||||
*
|
||||
* Note: The user should not have to call this method. Instead, when the user
|
||||
* registers for the "volume[up|down]button" event, this is automatically done.
|
||||
*
|
||||
* @param button volumeup, volumedown
|
||||
* @param override T=override, F=cancel override
|
||||
*/
|
||||
overrideButton:function(button, override) {
|
||||
exec(null, null, APP_PLUGIN_NAME, "overrideButton", [button, override]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Exit and terminate the application.
|
||||
*/
|
||||
exitApp:function() {
|
||||
return exec(null, null, APP_PLUGIN_NAME, "exitApp", []);
|
||||
}
|
||||
};
|
||||
@@ -1,8 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="gen"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
||||
<classpathentry kind="output" path="bin/classes"/>
|
||||
</classpath>
|
||||
|
||||
4
framework/.settings/org.eclipse.jdt.core.prefs
Normal file
@@ -0,0 +1,4 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||
org.eclipse.jdt.core.compiler.source=1.6
|
||||
@@ -17,43 +17,7 @@
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:windowSoftInputMode="adjustPan"
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.apache.cordova" android:versionName="1.0" android:versionCode="1">
|
||||
<supports-screens
|
||||
android:largeScreens="true"
|
||||
android:normalScreens="true"
|
||||
android:smallScreens="true"
|
||||
android:resizeable="true"
|
||||
android:anyDensity="true"
|
||||
/>
|
||||
<!-- android:xlargeScreens="true" screen supported only after Android-9 -->
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_SMS" />
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.RECORD_VIDEO"/>
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
||||
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
||||
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
|
||||
|
||||
<uses-feature android:name="android.hardware.camera" />
|
||||
<uses-feature android:name="android.hardware.camera.autofocus" />
|
||||
|
||||
<application android:icon="@drawable/icon" android:label="@string/app_name"
|
||||
android:debuggable="true">
|
||||
<activity android:name="org.apache.cordova.DroidGap" android:label="@string/app_name"
|
||||
android:configChanges="orientation|keyboardHidden">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
<uses-sdk android:minSdkVersion="8" />
|
||||
<uses-sdk android:minSdkVersion="14" />
|
||||
</manifest>
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<script src="cordova.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
61
framework/build.gradle
Normal file
@@ -0,0 +1,61 @@
|
||||
/* Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.1.0'
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
ext {
|
||||
apply from: 'cordova.gradle'
|
||||
cdvCompileSdkVersion = privateHelpers.getProjectTarget()
|
||||
cdvBuildToolsVersion = privateHelpers.findLatestInstalledBuildTools()
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion cdvCompileSdkVersion
|
||||
buildToolsVersion cdvBuildToolsVersion
|
||||
publishNonDefault true
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_6
|
||||
targetCompatibility JavaVersion.VERSION_1_6
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
manifest.srcFile 'AndroidManifest.xml'
|
||||
java.srcDirs = ['src']
|
||||
resources.srcDirs = ['src']
|
||||
aidl.srcDirs = ['src']
|
||||
renderscript.srcDirs = ['src']
|
||||
res.srcDirs = ['res']
|
||||
assets.srcDirs = ['assets']
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -95,6 +95,13 @@
|
||||
<target name="-post-compile">
|
||||
</target>
|
||||
-->
|
||||
<target name="-pre-clean">
|
||||
<!-- delete generated javadoc -->
|
||||
<delete dir="javadoc-public" failonerror="false" />
|
||||
<delete dir="javadoc-private" failonerror="false" />
|
||||
<!-- delete generated jar -->
|
||||
<delete file="cordova-${version}.jar" failonerror="false" />
|
||||
</target>
|
||||
|
||||
<!-- Import the actual build file.
|
||||
|
||||
@@ -120,7 +127,31 @@
|
||||
that includes all JavaScript code.
|
||||
-->
|
||||
<target name="jar" depends="-compile">
|
||||
<jar jarfile="cordova-${version}.jar" basedir="bin/classes" excludes="org/apache/cordova/R.class,org/apache/cordova/R$*.class"/>
|
||||
<jar
|
||||
basedir="bin/classes"
|
||||
excludes="org/apache/cordova/R.class,org/apache/cordova/R$*.class"
|
||||
jarfile="cordova-${version}.jar" />
|
||||
</target>
|
||||
|
||||
<target name="javadoc">
|
||||
<delete dir="javadoc-public" failonerror="false" />
|
||||
<javadoc
|
||||
access="public"
|
||||
destdir="javadoc-public"
|
||||
classpath="${sdk.dir}/platforms/${target}/android.jar">
|
||||
<packageset dir="src">
|
||||
<include name="org/apache/cordova/**" />
|
||||
</packageset>
|
||||
</javadoc>
|
||||
<delete dir="javadoc-private" failonerror="false" />
|
||||
<javadoc
|
||||
access="private"
|
||||
destdir="javadoc-private"
|
||||
classpath="${sdk.dir}/platforms/${target}/android.jar">
|
||||
<packageset dir="src">
|
||||
<include name="org/apache/cordova/**" />
|
||||
</packageset>
|
||||
</javadoc>
|
||||
</target>
|
||||
|
||||
<!-- tests for Java files -->
|
||||
|
||||
201
framework/cordova.gradle
Normal file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*/
|
||||
|
||||
import java.util.regex.Pattern
|
||||
import groovy.swing.SwingBuilder
|
||||
|
||||
String doEnsureValueExists(filePath, props, key) {
|
||||
if (props.get(key) == null) {
|
||||
throw new GradleException(filePath + ': Missing key required "' + key + '"')
|
||||
}
|
||||
return props.get(key)
|
||||
}
|
||||
|
||||
String doGetProjectTarget() {
|
||||
def props = new Properties()
|
||||
file('project.properties').withReader { reader ->
|
||||
props.load(reader)
|
||||
}
|
||||
return doEnsureValueExists('project.properties', props, 'target')
|
||||
}
|
||||
|
||||
String[] getAvailableBuildTools() {
|
||||
def buildToolsDir = new File(getAndroidSdkDir(), "build-tools")
|
||||
buildToolsDir.list()
|
||||
.findAll { it ==~ /[0-9.]+/ }
|
||||
.sort { a, b -> compareVersions(b, a) }
|
||||
}
|
||||
|
||||
String doFindLatestInstalledBuildTools(String minBuildToolsVersion) {
|
||||
def availableBuildToolsVersions
|
||||
try {
|
||||
availableBuildToolsVersions = getAvailableBuildTools()
|
||||
} catch (e) {
|
||||
println "An exception occurred while trying to find the Android build tools."
|
||||
throw e
|
||||
}
|
||||
if (availableBuildToolsVersions.length > 0) {
|
||||
def highestBuildToolsVersion = availableBuildToolsVersions[0]
|
||||
if (compareVersions(highestBuildToolsVersion, minBuildToolsVersion) < 0) {
|
||||
throw new RuntimeException(
|
||||
"No usable Android build tools found. Highest installed version is " +
|
||||
highestBuildToolsVersion + "; minimum version required is " +
|
||||
minBuildToolsVersion + ".")
|
||||
}
|
||||
highestBuildToolsVersion
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
"No installed build tools found. Install the Android build tools version " +
|
||||
minBuildToolsVersion + " or higher.")
|
||||
}
|
||||
}
|
||||
|
||||
// Return the first non-zero result of subtracting version list elements
|
||||
// pairwise. If they are all identical, return the difference in length of
|
||||
// the two lists.
|
||||
int compareVersionList(Collection aParts, Collection bParts) {
|
||||
def pairs = ([aParts, bParts]).transpose()
|
||||
pairs.findResult(aParts.size()-bParts.size()) {it[0] - it[1] != 0 ? it[0] - it[1] : null}
|
||||
}
|
||||
|
||||
// Compare two version strings, such as "19.0.0" and "18.1.1.0". If all matched
|
||||
// elements are identical, the longer version is the largest by this method.
|
||||
// Examples:
|
||||
// "19.0.0" > "19"
|
||||
// "19.0.1" > "19.0.0"
|
||||
// "19.1.0" > "19.0.1"
|
||||
// "19" > "18.999.999"
|
||||
int compareVersions(String a, String b) {
|
||||
def aParts = a.tokenize('.').collect {it.toInteger()}
|
||||
def bParts = b.tokenize('.').collect {it.toInteger()}
|
||||
compareVersionList(aParts, bParts)
|
||||
}
|
||||
|
||||
String getAndroidSdkDir() {
|
||||
def rootDir = project.rootDir
|
||||
def androidSdkDir = null
|
||||
String envVar = System.getenv("ANDROID_HOME")
|
||||
def localProperties = new File(rootDir, 'local.properties')
|
||||
String systemProperty = System.getProperty("android.home")
|
||||
if (envVar != null) {
|
||||
androidSdkDir = envVar
|
||||
} else if (localProperties.exists()) {
|
||||
Properties properties = new Properties()
|
||||
localProperties.withInputStream { instr ->
|
||||
properties.load(instr)
|
||||
}
|
||||
def sdkDirProp = properties.getProperty('sdk.dir')
|
||||
if (sdkDirProp != null) {
|
||||
androidSdkDir = sdkDirProp
|
||||
} else {
|
||||
sdkDirProp = properties.getProperty('android.dir')
|
||||
if (sdkDirProp != null) {
|
||||
androidSdkDir = (new File(rootDir, sdkDirProp)).getAbsolutePath()
|
||||
}
|
||||
}
|
||||
}
|
||||
if (androidSdkDir == null && systemProperty != null) {
|
||||
androidSdkDir = systemProperty
|
||||
}
|
||||
if (androidSdkDir == null) {
|
||||
throw new RuntimeException(
|
||||
"Unable to determine Android SDK directory.")
|
||||
}
|
||||
androidSdkDir
|
||||
}
|
||||
|
||||
def doExtractIntFromManifest(name) {
|
||||
def manifestFile = file(android.sourceSets.main.manifest.srcFile)
|
||||
def pattern = Pattern.compile(name + "=\"(\\d+)\"")
|
||||
def matcher = pattern.matcher(manifestFile.getText())
|
||||
matcher.find()
|
||||
return Integer.parseInt(matcher.group(1))
|
||||
}
|
||||
|
||||
def doExtractStringFromManifest(name) {
|
||||
def manifestFile = file(android.sourceSets.main.manifest.srcFile)
|
||||
def pattern = Pattern.compile(name + "=\"(\\S+)\"")
|
||||
def matcher = pattern.matcher(manifestFile.getText())
|
||||
matcher.find()
|
||||
return matcher.group(1)
|
||||
}
|
||||
|
||||
def doPromptForPassword(msg) {
|
||||
if (System.console() == null) {
|
||||
def ret = null
|
||||
new SwingBuilder().edt {
|
||||
dialog(modal: true, title: 'Enter password', alwaysOnTop: true, resizable: false, locationRelativeTo: null, pack: true, show: true) {
|
||||
vbox {
|
||||
label(text: msg)
|
||||
def input = passwordField()
|
||||
button(defaultButton: true, text: 'OK', actionPerformed: {
|
||||
ret = input.password;
|
||||
dispose();
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ret) {
|
||||
throw new GradleException('User canceled build')
|
||||
}
|
||||
return new String(ret)
|
||||
} else {
|
||||
return System.console().readPassword('\n' + msg);
|
||||
}
|
||||
}
|
||||
|
||||
def doGetConfigXml() {
|
||||
def xml = file("res/xml/config.xml").getText()
|
||||
// Disable namespace awareness since Cordova doesn't use them properly
|
||||
return new XmlParser(false, false).parseText(xml)
|
||||
}
|
||||
|
||||
def doGetConfigPreference(name, defaultValue) {
|
||||
name = name.toLowerCase()
|
||||
def root = doGetConfigXml()
|
||||
|
||||
def ret = defaultValue
|
||||
root.preference.each { it ->
|
||||
def attrName = it.attribute("name")
|
||||
if (attrName && attrName.toLowerCase() == name) {
|
||||
ret = it.attribute("value")
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Properties exported here are visible to all plugins.
|
||||
ext {
|
||||
// These helpers are shared, but are not guaranteed to be stable / unchanged.
|
||||
privateHelpers = {}
|
||||
privateHelpers.getProjectTarget = { doGetProjectTarget() }
|
||||
privateHelpers.findLatestInstalledBuildTools = { doFindLatestInstalledBuildTools('19.1.0') }
|
||||
privateHelpers.extractIntFromManifest = { name -> doExtractIntFromManifest(name) }
|
||||
privateHelpers.extractStringFromManifest = { name -> doExtractStringFromManifest(name) }
|
||||
privateHelpers.promptForPassword = { msg -> doPromptForPassword(msg) }
|
||||
privateHelpers.ensureValueExists = { filePath, props, key -> doEnsureValueExists(filePath, props, key) }
|
||||
|
||||
// These helpers can be used by plugins / projects and will not change.
|
||||
cdvHelpers = {}
|
||||
// Returns a XmlParser for the config.xml. Added in 4.1.0.
|
||||
cdvHelpers.getConfigXml = { doGetConfigXml() }
|
||||
// Returns the value for the desired <preference>. Added in 4.1.0.
|
||||
cdvHelpers.getConfigPreference = { name, defaultValue -> doGetConfigPreference(name, defaultValue) }
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# Indicates whether an apk should be generated for each density.
|
||||
split.density=false
|
||||
# Project target.
|
||||
target=android-18
|
||||
target=android-23
|
||||
apk-configurations=
|
||||
renderscript.opt.level=O0
|
||||
android.library=true
|
||||
|
||||
|
Before Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 92 KiB |
@@ -1,29 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
<WebView android:id="@+id/appView"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_width="fill_parent"
|
||||
/>
|
||||
</LinearLayout>
|
||||