AndroidDeployer Scol plugin
androidDeployer.cpp
Go to the documentation of this file.
1/*
2-----------------------------------------------------------------------------
3This source file is part of OpenSpace3D
4For the latest info, see http://www.openspace3d.com
5
6Copyright (c) 2012 I-maginer
7
8This program is free software; you can redistribute it and/or modify it under
9the terms of the GNU Lesser General Public License as published by the Free Software
10Foundation; either version 2 of the License, or (at your option) any later
11version.
12
13This program is distributed in the hope that it will be useful, but WITHOUT
14ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
16
17You should have received a copy of the GNU Lesser General Public License along with
18this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19Place - Suite 330, Boston, MA 02111-1307, USA, or go to
20http://www.gnu.org/copyleft/lesser.txt
21
22-----------------------------------------------------------------------------
23*/
24
25/*
26
27 #############################################################
28 ## ======================================================= ##
29 ################### ] A N D R O I D [ ###################
30 ################### ] DEPLOYER 1.4c [ ###################
31 ## ======================================================= ##
32 ## ------------------------------------------ ##
33 ## Crafted by ##
34 ########### ] BRAIN SANDWICH, 2015 [ ###########
35 ## I-MAGINER LTD. CORP. ##
36 ## ##
37 ## ------- since 1997 ------- ##
38 ## ##
39 ## ======================================================= ##
40 ## ##
41 ## * Turbo APK generation ##
42 ## * Scol Quad Nitro SSE Zipping ##
43 ## * Android full throttle integration ##
44 ## ##
45 ## ======================================================= ##
46 #############################################################
47
48*/
49
56#include <stdlib.h>
57#include <vector>
58#include <map>
59#include <zip.h>
60#include "androidDeployer.h"
61
62//process with return content
63HANDLE g_hChildStd_OUT_Rd = NULL;
64HANDLE g_hChildStd_OUT_Wr = NULL;
65HANDLE g_hChildStd_ERR_Rd = NULL;
66HANDLE g_hChildStd_ERR_Wr = NULL;
67
68#define EXECBUFSIZE 4096
69
70PROCESS_INFORMATION CreateExecChildProcess(std::string, BOOL&);
71void ReadExecFromPipe(PROCESS_INFORMATION, std::string&, std::string&);
72
73bool execProcess(std::string cmd, std::string &output)
74{
75 SECURITY_ATTRIBUTES sa;
76 std::string err;
77
78 // Set the bInheritHandle flag so pipe handles are inherited.
79 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
80 sa.bInheritHandle = TRUE;
81 sa.lpSecurityDescriptor = NULL;
82
83 // Create a pipe for the child process's STDERR.
84 if (!CreatePipe(&g_hChildStd_ERR_Rd, &g_hChildStd_ERR_Wr, &sa, 0))
85 {
86 return false;
87 }
88
89 // Ensure the read handle to the pipe for STDERR is not inherited.
90 if (!SetHandleInformation(g_hChildStd_ERR_Rd, HANDLE_FLAG_INHERIT, 0))
91 {
92 return false;
93 }
94
95 // Create a pipe for the child process's STDOUT.
96 if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &sa, 0))
97 {
98 return false;
99 }
100
101 // Ensure the read handle to the pipe for STDOUT is not inherited
102 if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
103 {
104 return false;
105 }
106
107 // Create the child process.
108 BOOL bSuccess = FALSE;
109 PROCESS_INFORMATION piProcInfo = CreateExecChildProcess(cmd, bSuccess);
110
111 if (!bSuccess)
112 return false;
113
114 ReadExecFromPipe(piProcInfo, output, err);
115
116 //close handles explicitly.
117 // Close the handles.
118 CloseHandle(piProcInfo.hProcess);
119 CloseHandle(piProcInfo.hThread);
120
121 if (output.empty())
122 output = err;
123
124 return true;
125}
126
127// Create a child process that uses the previously created pipes
128// for STDERR and STDOUT.
129PROCESS_INFORMATION CreateExecChildProcess(std::string cmd, BOOL &bSuccess)
130{
131 PROCESS_INFORMATION piProcInfo;
132 STARTUPINFO siStartInfo;
133
134 // Set up members of the PROCESS_INFORMATION structure.
135 ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
136
137 // Set up members of the STARTUPINFO structure.
138 // This structure specifies the STDERR and STDOUT handles for redirection.
139 ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
140 siStartInfo.cb = sizeof(STARTUPINFO);
141 siStartInfo.hStdError = g_hChildStd_ERR_Wr;
142 siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
143 siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
144
145 // Create the child process.
146 bSuccess = CreateProcess(NULL,
147 (LPSTR)cmd.c_str(), // command line
148 NULL, // process security attributes
149 NULL, // primary thread security attributes
150 TRUE, // handles are inherited
151 NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, // creation flags
152 NULL, // use parent's environment
153 NULL, // use parent's current directory
154 &siStartInfo, // STARTUPINFO pointer
155 &piProcInfo); // receives PROCESS_INFORMATION
156 CloseHandle(g_hChildStd_ERR_Wr);
157 CloseHandle(g_hChildStd_OUT_Wr);
158
159 return piProcInfo;
160}
161
162// Read output from the child process's pipe for STDOUT
163// and write to the parent process's pipe for STDOUT.
164// Stop when there is no more data.
165void ReadExecFromPipe(PROCESS_INFORMATION piProcInfo, std::string &output, std::string &err)
166{
167 DWORD dwRead;
168 CHAR chBuf[EXECBUFSIZE];
169 BOOL bSuccess = FALSE;
170 output = "";
171 err = "";
172 for (;;)
173 {
174 bSuccess=ReadFile( g_hChildStd_OUT_Rd, chBuf, EXECBUFSIZE, &dwRead, NULL);
175 if( ! bSuccess || dwRead == 0 ) break;
176
177 std::string s(chBuf, dwRead);
178 output += s;
179 }
180 dwRead = 0;
181 for (;;)
182 {
183 bSuccess=ReadFile( g_hChildStd_ERR_Rd, chBuf, EXECBUFSIZE, &dwRead, NULL);
184 if( ! bSuccess || dwRead == 0 ) break;
185
186 std::string s(chBuf, dwRead);
187 err += s;
188 }
189}
190
191// add a directory and all its content to a zip archive
192void addDirToArchive(zip_t *archive, const boost::filesystem::path &srcdir, const boost::filesystem::path &inputdir)
193{
194 std::string outputdir = inputdir.generic_string().substr(srcdir.parent_path().generic_string().length() + 1);
195 if (zip_dir_add(archive, outputdir.c_str(), 0) < 0)
196 throw std::runtime_error("Failed to add directory to archive: " + std::string(zip_strerror(archive)));
197
198 boost::filesystem::directory_iterator dirIter(inputdir);
199 boost::filesystem::directory_iterator end;
200 while (dirIter != end)
201 {
202 if (boost::filesystem::is_directory(dirIter->path()))
203 addDirToArchive(archive, srcdir, dirIter->path());
204 else
205 {
206 zip_source_t *source = zip_source_file(archive, dirIter->path().generic_string().c_str(), 0, 0);
207 if (source == NULL)
208 throw std::runtime_error("Failed to add file to archive: " + std::string(zip_strerror(archive)));
209
210 std::string outputfile = outputdir + "/" + dirIter->path().filename().generic_string();
211 if (zip_file_add(archive, outputfile.c_str(), source, 0) < 0)
212 {
213 zip_source_free(source);
214 throw std::runtime_error("Failed to add file to archive: " + std::string(zip_strerror(archive)));
215 }
216 }
217 dirIter++;
218 }
219}
220
221
222// /////////////////////////////////////////////////////////////////////////////////
223// //////////////////////////////// SCOL FUNCTIONS /////////////////////////////////
224// /////////////////////////////////////////////////////////////////////////////////
225
236{
237#ifdef SCOL_DEBUG
238 MMechostr(MSKDEBUG, "_MAKEandroidUnsignedAPK\n");
239#endif
240 boost::system::error_code ec;
241
242 int imanifestPath = MMpull(m);
243 int iname = MMget(m, 0);
244
245 if (imanifestPath == NIL || iname == NIL)
246 {
247 MMechostr(MSKDEBUG, "error: manifest path or name is NIL\n");
248 MMset(m, 0, NIL);
249 return 0;
250 }
251
252 // Parse args
253 boost::filesystem::path manifestPath = MMstartstr(m, MTOP(imanifestPath));
254 boost::filesystem::path basePath = manifestPath;
255 basePath.remove_filename();
256 std::string name = MMstartstr(m, MTOP(iname));
257 std::string cmd = "";
258 std::string cmdargs = "";
259 std::string output;
260 bool result;
261
262 if (!boost::filesystem::exists(toolsPathBox.exe_aapt2Path))
263 {
264 std::string errmsg(std::string("error: ") + toolsPathBox.exe_aapt2Path.generic_string() + std::string(" doesn't exist !"));
265 MMechostr(MSKDEBUG, "_MAKEandroidUnsignedAppBundle : %s\n", errmsg.c_str());
266 MMset(m, 0, NIL);
267 return 0;
268 }
269 ProjectPathBox projectPathBox(basePath);
270
271 boost::filesystem::path unsignedAppBundle = projectPathBox.binPath / (name + ".unsigned.aab");
272
273 // remove files if exist
274 if (boost::filesystem::exists(unsignedAppBundle))
275 boost::filesystem::remove(unsignedAppBundle, ec);
276
277
278 // compile resources with aapt2
279 std::string res_arg = " -R";
280 if (boost::filesystem::exists(projectPathBox.resPath) && boost::filesystem::is_directory(projectPathBox.resPath))
281 {
282 boost::filesystem::create_directory(projectPathBox.tmpPath);
283 boost::filesystem::recursive_directory_iterator resDirIter(projectPathBox.resPath);
284 boost::filesystem::recursive_directory_iterator end;
285
286 while (resDirIter != end)
287 {
288 if (!boost::filesystem::is_directory(resDirIter->path()))
289 {
290 cmd = "\"" + toolsPathBox.exe_aapt2Path.generic_string() + "\""
291 + " compile \"" + resDirIter->path().string() + "\""
292 + " -o \"" + projectPathBox.tmpPath.generic_string() + "\"";
293 result = execProcess(cmd, output);
294 if (!result)
295 {
296 MMechostr(MSKDEBUG, "error running aapt2 compile : %s\n", output.c_str());
297 MMset(m, 0, NIL);
298 Mpushstrbloc(m, (char*)output.c_str());
299 MMpush(m, 2 * 2);
300 MBdeftab(m);
301 return 0;
302 }
303 }
304 resDirIter++;
305 }
306
307 // list compiled resources files for next step
308 boost::filesystem::directory_iterator compResDirIter(projectPathBox.tmpPath);
309 boost::filesystem::directory_iterator compResEnd;
310 while (compResDirIter != compResEnd)
311 {
312 res_arg += " \"" + compResDirIter->path().string() + "\"";
313 compResDirIter++;
314 }
315 }
316
317 // link resources with aapt2
318 cmd = "\"" + toolsPathBox.exe_aapt2Path.generic_string() + "\""
319 + " link"
320 + " --proto-format"
321 + " -o \"" + projectPathBox.projectArchive.generic_string() + "\""
322 + " -I \"" + toolsPathBox.jar_androidPath.generic_string() + "\""
323 + " --manifest \"" + projectPathBox.manifestPath.generic_string() + "\""
324 + res_arg
325 + " --auto-add-overlay";
326
327
328 MMechostr(MSKRUNTIME, "_MAKEandroidUnsignedAppBundle command: %s\n", cmd.c_str());
329 result = execProcess(cmd, output);
330 if (!result)
331 {
332 MMechostr(MSKDEBUG, "error running aapt2 link : %s\n", output.c_str());
333 MMset(m, 0, NIL);
334 Mpushstrbloc(m, (char*)output.c_str());
335 MMpush(m, 2 * 2);
336 MBdeftab(m);
337 return 0;
338 }
339
340 // add assets, dex and lib dir to archive
341 zip_t *archive;
342 zip_error_t ziperror;
343 try
344 {
345 // open archive
346 int errorp;
347 archive = zip_open(projectPathBox.projectArchive.generic_string().c_str(), 0, &errorp);
348 if (archive == NULL)
349 {
350 zip_error_init_with_code(&ziperror, errorp);
351 throw std::runtime_error("Failed to open archive " + projectPathBox.projectArchive.generic_string() + ": " + zip_error_strerror(&ziperror));
352 }
353
354 // move AndroidManifest.xml to manifest/AndroidManifest.xml
355 zip_uint64_t index = zip_name_locate(archive, "AndroidManifest.xml", 0);
356 if (index < 0 || zip_dir_add(archive, "manifest", 0) < 0 || zip_file_rename(archive, index, "manifest/AndroidManifest.xml", 0) < 0)
357 throw std::runtime_error("Failed to move manifest inside archive " + projectPathBox.projectArchive.generic_string() + ": " + zip_error_strerror(&ziperror));
358
359 // add assets, lib and dex directories to the archive
360 addDirToArchive(archive, projectPathBox.assetsPath, projectPathBox.assetsPath);
361 addDirToArchive(archive, projectPathBox.dexPath, projectPathBox.dexPath);
362 addDirToArchive(archive, projectPathBox.libPath, projectPathBox.libPath);
363 zip_close(archive);
364 }
365 catch(std::exception e)
366 {
367 if (archive != NULL)
368 zip_close(archive);
369 MMechostr(MSKDEBUG, "error packaging archive : %s\n", e.what());
370 MMset(m, 0, NIL);
371 Mpushstrbloc(m, (char*)e.what());
372 MMpush(m, 2 * 2);
373 MBdeftab(m);
374 return 0;
375 }
376
377 // create bin directory
378 boost::filesystem::create_directory(projectPathBox.binPath);
379
380 // call bundletool with its arguments
381 cmd = "\"" + toolsPathBox.exe_javacPath.generic_string() + "\" -jar \"" + toolsPathBox.jar_bundletoolPath.generic_string() + "\""
382 + " build-bundle"
383 + " --modules=\"" + projectPathBox.projectArchive.generic_string() + "\""
384 + " --output=\"" + unsignedAppBundle.generic_string() + "\"";
385
386 result = execProcess(cmd, output);
387 if (!result)
388 {
389 MMechostr(MSKDEBUG, "error running bundletool : %s\n", output.c_str());
390 MMset(m, 0, NIL);
391 Mpushstrbloc(m, (char*)output.c_str());
392 MMpush(m, 2 * 2);
393 MBdeftab(m);
394 return 0;
395 }
396
397 if (boost::filesystem::exists(unsignedAppBundle))
398 {
399 MMpull(m);
400 Mpushstrbloc(m, (char*)unsignedAppBundle.generic_string().c_str());
401 Mpushstrbloc(m, (char*)output.c_str());
402 MMpush(m, 2 * 2);
403 MBdeftab(m);
404 }
405 else
406 {
407 MMset(m, 0, NIL);
408 Mpushstrbloc(m, (char*)output.c_str());
409 MMpush(m, 2 * 2);
410 MBdeftab(m);
411 }
412
413#ifdef SCOL_DEBUG
414 MMechostr(MSKDEBUG, "end _MAKEandroidUnsignedAppBundle\n");
415#endif
416 return 0;
417}
418
429{
430#ifdef SCOL_DEBUG
431 MMechostr(MSKDEBUG, "_MAKEandroidUnsignedAPK\n");
432#endif
433
434 boost::system::error_code ec;
435 int imanifestPath = MMpull(m);
436 int iname = MMget(m, 0);
437
438 if (imanifestPath == NIL || iname == NIL)
439 {
440 MMechostr(MSKDEBUG, "error: manifest path or name is NIL\n");
441 MMset(m, 0, NIL);
442 return 0;
443 }
444
445 // Parse args
446 boost::filesystem::path manifestPath = MMstartstr(m, MTOP(imanifestPath));
447 boost::filesystem::path basePath = manifestPath;
448 basePath.remove_filename();
449 std::string name = MMstartstr(m, MTOP(iname));
450 std::string cmdargs = "";
451
452 if (!boost::filesystem::exists(toolsPathBox.exe_aaptPath))
453 {
454 std::string errmsg(std::string("error: ") + toolsPathBox.exe_aaptPath.generic_string() + std::string(" doesn't exist !"));
455 MMechostr(MSKDEBUG, "_MAKEandroidUnsignedAPK : %s\n", errmsg.c_str());
456 MMset(m, 0, NIL);
457 return 0;
458 }
459 ProjectPathBox projectPathBox(basePath);
460
461 boost::filesystem::path unsignedApk = projectPathBox.binPath / (name + ".unsigned.apk");
462
463 // remove files if exist
464 if(boost::filesystem::exists(unsignedApk))
465 boost::filesystem::remove(unsignedApk, ec);
466
467 // Pile up aapt arguments
468 cmdargs += "package";
469 cmdargs += " -M \"" + projectPathBox.manifestPath.generic_string() + "\"";
470 cmdargs += " -I \"" + toolsPathBox.jar_androidPath.generic_string() + "\"";
471 cmdargs += " -F \"" + unsignedApk.generic_string() + "\"";
472 cmdargs += " -S \"" + projectPathBox.resPath.generic_string() + "\"";
473 cmdargs += " \"" + projectPathBox.dexPath.generic_string() + "\"";
474 cmdargs += " \"" + projectPathBox.packagePath.generic_string() + "\"";
475
476 //create bin directory
477 boost::filesystem::create_directory(projectPathBox.binPath);
478
479 // Call aapt with its arguments
480 std::string cmd = "\"" + toolsPathBox.exe_aaptPath.generic_string() + "\" " + cmdargs;
481
482 MMechostr(MSKRUNTIME, "_MAKEandroidUnsignedAPK command: %s\n", cmd.c_str());
483 //int res = system(cmd.c_str());
484 //if (res != 0)
485
486 /*
487 PROCESS_INFORMATION ProcessInfoF = {0};
488 STARTUPINFO StartupInfoF = {0};
489 StartupInfoF.cb = sizeof(StartupInfoF);
490
491 if (!CreateProcess(NULL, (LPSTR)cmd.c_str(), NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, NULL, NULL, &StartupInfoF, &ProcessInfoF))
492 {
493 MMechostr(MSKDEBUG, "error running aapt : %s\n", cmd.c_str());
494 MMset(m, 0, NIL);
495 return 0;
496 }
497 WaitForSingleObject(ProcessInfoF.hProcess, INFINITE);
498 // Close the handles.
499 CloseHandle(ProcessInfoF.hProcess);
500 CloseHandle(ProcessInfoF.hThread);
501 */
502
503 std::string output;
504 bool result = execProcess(cmd, output);
505 if (!result)
506 {
507 MMechostr(MSKDEBUG, "error running aapt : %s\n", output.c_str());
508 MMset(m, 0, NIL);
509 Mpushstrbloc(m, (char*)output.c_str());
510 MMpush(m, 2*2);
511 MBdeftab (m);
512 return 0;
513 }
514
515 if (boost::filesystem::exists(unsignedApk))
516 {
517 MMpull(m);
518 Mpushstrbloc(m, (char*)unsignedApk.generic_string().c_str());
519 Mpushstrbloc(m, (char*)output.c_str());
520 MMpush(m, 2*2);
521 MBdeftab (m);
522 }
523 else
524 {
525 MMset(m, 0, NIL);
526 Mpushstrbloc(m, (char*)output.c_str());
527 MMpush(m, 2*2);
528 MBdeftab (m);
529 }
530
531#ifdef SCOL_DEBUG
532 MMechostr(MSKDEBUG, "end _MAKEandroidUnsignedAPK\n");
533#endif
534 return 0;
535}
536
549{
550#ifdef SCOL_DEBUG
551 MMechostr(MSKDEBUG, "_ENCRYPTandroidSigningKey\n");
552#endif
553 boost::system::error_code ec;
554
555 int ibundlePath = MMpull(m);
556 int ikeyAlias = MMpull(m);
557 int ikeyPassword = MMpull(m);
558 int ikeystorePath = MMget(m, 0);
559
560 if (ikeystorePath == NIL || ikeyPassword == NIL || ikeyAlias == NIL)
561 {
562 MMechostr(MSKDEBUG, "error: destination path, application name, password or key alias are NIL\n");
563 MMset(m, 0, NIL);
564 return 0;
565 }
566
567 // Parse args
568 boost::filesystem::path keystorePath = MMstartstr(m, MTOP(ikeystorePath));
569 boost::filesystem::path encryptedKeyPath = MMstartstr(m, MTOP(ibundlePath));
570 encryptedKeyPath.remove_filename();
571 encryptedKeyPath /= boost::filesystem::change_extension(keystorePath.filename(), "keystore.encrypted");
572 std::string keyPassword = MMstartstr(m, MTOP(ikeyPassword));
573 std::string keyAlias = MMstartstr(m, MTOP(ikeyAlias));
574 std::string cmd;
575
576 if (!boost::filesystem::exists(toolsPathBox.jar_pepkPath))
577 {
578 std::string errmsg(std::string("error: ") + toolsPathBox.jar_pepkPath.generic_string() + std::string(" doesn't exist !"));
579 MMechostr(MSKDEBUG, errmsg.c_str());
580 MMset(m, 0, NIL);
581 return 0;
582 }
583
584 // remove files if exist
585 if (boost::filesystem::exists(encryptedKeyPath))
586 boost::filesystem::remove(encryptedKeyPath, ec);
587
588 // test if Java is available
589 std::string output;
590 bool result = execProcess("java --version", output);
591 if (!result)
592 {
593 MMechostr(MSKDEBUG, "error : Java is not available\n");
594 MMset(m, 0, NIL);
595 Mpushstrbloc(m, "Java is not available on your computer. You must install Java in order to create and sign an Android App bundle");
596 MMpush(m, 2 * 2);
597 MBdeftab(m);
598 return 0;
599 }
600
601 // Call aapt with its arguments
602 cmd = "echo Encryption of the store key to upload to the Play Store & echo Please enter your store key password twice (the password will not appear as you type, that is the normal behaviour) & java -jar \"" + toolsPathBox.jar_pepkPath.generic_string() + "\""
603 + " --keystore=\"" + keystorePath.generic_string() + "\""
604 + " --alias=\"" + keyAlias + "\""
605 + " --output=\"" + encryptedKeyPath.generic_string() + "\""
606 + " --encryptionkey=\"eb10fe8f7c7c9df715022017b00c6471f8ba8170b13049a11e6c09ffe3056a104a3bbe4ac5a955f4ba4fe93fc8cef27558a3eb9d2a529a2092761fb833b656cd48b9de6a\""
607 + " --include-cert";
608
609 //bool result = execProcess(cmd, output);
610 //if (!result)
611 int res = system(cmd.c_str());
612 if (res != 0)
613 {
614 MMechostr(MSKRUNTIME, "_ENCRYPTandroidSigningKey : error running pepk : %s\n", output.c_str());
615 MMset(m, 0, NIL);
616 Mpushstrbloc(m, (char*)output.c_str());
617 MMpush(m, 2 * 2);
618 MBdeftab(m);
619 return 0;
620 }
621
622 if (boost::filesystem::exists(encryptedKeyPath))
623 {
624 MMpull(m);
625 Mpushstrbloc(m, (char*)encryptedKeyPath.generic_string().c_str());
626 Mpushstrbloc(m, (char*)output.c_str());
627 MMpush(m, 2 * 2);
628 MBdeftab(m);
629 }
630 else
631 {
632 MMechostr(MSKRUNTIME, "_ENCRYPTandroidSigningKey : error running pepk : %s\n", cmd.c_str());
633 MMset(m, 0, NIL);
634 Mpushstrbloc(m, (char*)output.c_str());
635 MMpush(m, 2 * 2);
636 MBdeftab(m);
637 }
638
639#ifdef SCOL_DEBUG
640 MMechostr(MSKDEBUG, "end _ENCRYPTandroidSigningKey\n");
641#endif
642 return 0;
643}
644
657{
658#ifdef SCOL_DEBUG
659 MMechostr(MSKDEBUG, "_MAKEandroidSigningKey\n");
660#endif
661 boost::system::error_code ec;
662
663 int iadditional = MMpull(m);
664 int ikeyAlias = MMpull(m);
665 int ikeyPassword = MMpull(m);
666 int ikeystorePath = MMget(m, 0);
667
668 if (ikeystorePath == NIL || ikeyPassword == NIL || ikeyAlias == NIL)
669 {
670 MMechostr(MSKDEBUG, "error: destination path, application name, password or key alias are NIL\n");
671 MMset(m, 0, NIL);
672 return 0;
673 }
674
675 // Parse args
676 boost::filesystem::path keystorePath = MMstartstr(m, MTOP(ikeystorePath));
677 std::string keyPassword = MMstartstr(m, MTOP(ikeyPassword));
678 std::string keyAlias = MMstartstr(m, MTOP(ikeyAlias));
679 std::string cmdargs = "-J-Duser.language=en ";
680
681 if (!boost::filesystem::exists(toolsPathBox.exe_keytoolPath))
682 {
683 std::string errmsg(std::string("error: ") + toolsPathBox.exe_keytoolPath.generic_string() + std::string(" doesn't exist !"));
684 MMechostr(MSKDEBUG, errmsg.c_str());
685 MMset(m, 0, NIL);
686 return 0;
687 }
688
689 // remove files if exist
690 if(boost::filesystem::exists(keystorePath))
691 boost::filesystem::remove(keystorePath, ec);
692
693 // Parse additional parameters
694 int q = 0;
695 int ikey = 0;
696 int ivalue = 0;
697 int nbData = 0;
698 std::string dname = "";
699 while(iadditional != NIL)
700 {
701 q = MMfetch(m, MTOP(iadditional), 0);
702 if (q != NIL)
703 {
704 ikey = MMfetch(m, MTOP(q), 0);
705 ivalue = MMfetch(m, MTOP(q), 1);
706 // bad parameter cancel
707 if (ikey == NIL)
708 continue;
709
710 std::string skey = MMstartstr(m, MTOP(ikey));
711 std::string svalue = "";
712 if (ivalue != NIL)
713 svalue = MMstartstr(m, MTOP(ivalue));
714
715 // Check if key is valid
716 if (!svalue.empty() && ((skey == "CN") || (skey == "OU") || (skey == "O") || (skey == "L") || (skey == "S") || (skey == "C")))
717 {
718 if (nbData != 0)
719 dname += ", ";
720
721 dname += skey + "=" + svalue;
722 nbData++;
723 }
724 }
725 iadditional = MMfetch(m, MTOP(iadditional), 1);
726 }
727
728 cmdargs += "-genkeypair";
729 cmdargs += " -validity 20000 ";
730 if (dname != "")
731 cmdargs += " -dname \"" + dname + "\"";
732 else
733 cmdargs += " -dname \"C=AQ\""; // there must be at least one dname attribute .. let's say default Country Code is Antartica.
734
735 cmdargs += " -keystore \"" + keystorePath.generic_string() + "\"";
736 cmdargs += " -storepass " + keyPassword;
737 cmdargs += " -keypass " + keyPassword;
738 cmdargs += " -alias " + keyAlias;
739 cmdargs += " -keyalg RSA";
740 cmdargs += " -keysize 2048";
741
742 // Call aapt with its arguments
743 std::string cmd = "\"" + toolsPathBox.exe_keytoolPath.generic_string() + "\" " + cmdargs;
744
745 /*
746 PROCESS_INFORMATION ProcessInfoF = {0};
747 STARTUPINFO StartupInfoF = {0};
748 StartupInfoF.cb = sizeof(StartupInfoF);
749
750 if (!CreateProcess(NULL, (LPSTR)cmd.c_str(), NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, NULL, NULL, &StartupInfoF, &ProcessInfoF))
751 {
752 MMechostr(MSKDEBUG, "error running keytool : %s\n", cmd.c_str());
753 MMset(m, 0, NIL);
754 return 0;
755 }
756 WaitForSingleObject(ProcessInfoF.hProcess, INFINITE);
757 // Close the handles.
758 CloseHandle(ProcessInfoF.hProcess);
759 CloseHandle(ProcessInfoF.hThread);
760 */
761
762 std::string output;
763 bool result = execProcess(cmd, output);
764 if (!result)
765 {
766 MMechostr(MSKRUNTIME, "_MAKEandroidSigningKey : error running keytool : %s\n", output.c_str());
767 MMset(m, 0, NIL);
768 Mpushstrbloc(m, (char*)output.c_str());
769 MMpush(m, 2*2);
770 MBdeftab (m);
771
772 MMset(m, 0, NIL);
773 return 0;
774 }
775
776 if (boost::filesystem::exists(keystorePath))
777 {
778 MMpull(m);
779 Mpushstrbloc(m, (char*)keystorePath.generic_string().c_str());
780 Mpushstrbloc(m, (char*)output.c_str());
781 MMpush(m, 2*2);
782 MBdeftab (m);
783 }
784 else
785 {
786 MMechostr(MSKRUNTIME, "_MAKEandroidSigningKey : error running keytool : %s\n", cmd.c_str());
787 MMset(m, 0, NIL);
788 Mpushstrbloc(m, (char*)output.c_str());
789 MMpush(m, 2*2);
790 MBdeftab (m);
791 }
792
793#ifdef SCOL_DEBUG
794 MMechostr(MSKDEBUG, "end _MAKEandroidSigningKey\n");
795#endif
796 return 0;
797}
798
811{
812#ifdef SCOL_DEBUG
813 MMechostr(MSKDEBUG, "_SIGNandroidAppBundle\n");
814#endif
815 boost::system::error_code ec;
816
817 int ikeyAlias = MMpull(m);
818 int ikeyPassword = MMpull(m);
819 int ikeystorePath = MMpull(m);
820 int iunsignedAppBundlepath = MMget(m, 0);
821
822 // Check args
823 if (ikeyAlias == NIL || ikeyPassword == NIL || ikeystorePath == NIL || iunsignedAppBundlepath == NIL)
824 {
825 MMechostr(MSKDEBUG, "_SIGNandroidAppBundle : error: manifest path, keystore path, key password or key alias are NIL\n");
826 MMset(m, 0, NIL);
827 return 0;
828 }
829
830 if (!boost::filesystem::exists(toolsPathBox.exe_jarsignerPath))
831 {
832 std::string errmsg(std::string("error: ") + toolsPathBox.exe_jarsignerPath.generic_string() + std::string(" doesn't exist !"));
833 MMechostr(MSKDEBUG, "_SIGNandroidAppBundle : %s\n", errmsg.c_str());
834 MMset(m, 0, NIL);
835 return 0;
836 }
837
838 // Parse args
839 boost::filesystem::path unsignedAppBundlePath = MMstartstr(m, MTOP(iunsignedAppBundlepath));
840 boost::filesystem::path keystorePath = MMstartstr(m, MTOP(ikeystorePath));
841 std::string password = MMstartstr(m, MTOP(ikeyPassword));
842 std::string alias = MMstartstr(m, MTOP(ikeyAlias));
843 std::string cmdargs = "-J-Duser.language=en ";
844
845 // Strip suffix from unsigned apk path, and make final apk paths from it
846 boost::filesystem::path appBundlePath(unsignedAppBundlePath);
847 appBundlePath = boost::filesystem::change_extension(appBundlePath, "");
848 int lastindex = appBundlePath.generic_string().find_last_of(".");
849 appBundlePath = appBundlePath.generic_string().substr(0, lastindex);
850
851 boost::filesystem::path finalAppBundlePath = appBundlePath.generic_string() + ".aab";
852
853 // remove files if exist
854 if (boost::filesystem::exists(finalAppBundlePath))
855 boost::filesystem::remove(finalAppBundlePath, ec);
856
857 cmdargs += "-tsa http://timestamp.digicert.com";
858 cmdargs += " -keystore \"" + keystorePath.generic_string() + "\"";
859 cmdargs += " -storepass " + password;
860 cmdargs += " -keypass " + password;
861 cmdargs += " -sigalg SHA1withRSA";
862 cmdargs += " -digestalg SHA1";
863 cmdargs += " -signedjar \"" + finalAppBundlePath.generic_string() + "\"";
864 cmdargs += " \"" + unsignedAppBundlePath.generic_string() + "\"";
865 cmdargs += " " + alias;
866
867 // Call jarsigner with its arguments
868 std::string cmd = "\"" + toolsPathBox.exe_jarsignerPath.generic_string() + "\" " + cmdargs;
869
870 std::string output;
871 bool result = execProcess(cmd, output);
872 if (!result || !boost::filesystem::exists(finalAppBundlePath))
873 {
874 MMechostr(MSKDEBUG, "_SIGNandroidAppBundle : error running jarsigner : %s\n", output.c_str());
875 MMset(m, 0, NIL);
876 Mpushstrbloc(m, (char*)output.c_str());
877 MMpush(m, 2 * 2);
878 MBdeftab(m);
879
880 return 0;
881 }
882
883 // remove unsigned file keep only the final one
884 if (boost::filesystem::exists(unsignedAppBundlePath))
885 boost::filesystem::remove(unsignedAppBundlePath, ec);
886
887 if (boost::filesystem::exists(finalAppBundlePath))
888 {
889 MMpull(m);
890 Mpushstrbloc(m, (char*)finalAppBundlePath.generic_string().c_str());
891 Mpushstrbloc(m, (char*)output.c_str());
892 MMpush(m, 2 * 2);
893 MBdeftab(m);
894 }
895 else
896 {
897 MMset(m, 0, NIL);
898 Mpushstrbloc(m, (char*)output.c_str());
899 MMpush(m, 2 * 2);
900 MBdeftab(m);
901 }
902
903#ifdef SCOL_DEBUG
904 MMechostr(MSKDEBUG, "end _SIGNandroidAppBundle\n");
905#endif
906 return 0;
907}
908
920int _SIGNandroidAPK(mmachine m)
921{
922#ifdef SCOL_DEBUG
923 MMechostr(MSKDEBUG, "_SIGNandroidAPK\n");
924#endif
925 boost::system::error_code ec;
926
927 int ikeyAlias = MMpull(m);
928 int ikeyPassword = MMpull(m);
929 int ikeystorePath = MMpull(m);
930 int iunsignedAPKpath = MMget(m, 0);
931
932 // Check args
933 if (ikeyAlias == NIL || ikeyPassword == NIL || ikeystorePath == NIL || iunsignedAPKpath == NIL)
934 {
935 MMechostr(MSKDEBUG, "_SIGNandroidAPK : error: manifest path, keystore path, key password or key alias are NIL\n");
936 MMset(m, 0, NIL);
937 return 0;
938 }
939
940 if (!boost::filesystem::exists(toolsPathBox.exe_jarsignerPath))
941 {
942 std::string errmsg(std::string("error: ") + toolsPathBox.exe_jarsignerPath.generic_string() + std::string(" doesn't exist !"));
943 MMechostr(MSKDEBUG, "_SIGNandroidAPK : %s\n", errmsg.c_str());
944 MMset(m, 0, NIL);
945 return 0;
946 }
947
948 // Parse args
949 boost::filesystem::path unsignedAPKPath = MMstartstr(m, MTOP(iunsignedAPKpath));
950 boost::filesystem::path keystorePath = MMstartstr(m, MTOP(ikeystorePath));
951 std::string password = MMstartstr(m, MTOP(ikeyPassword));
952 std::string alias = MMstartstr(m, MTOP(ikeyAlias));
953 std::string cmdargs = "";
954
955 // Strip suffix from unsigned apk path, and make signed and final apk paths from it
956
957 boost::filesystem::path apkPath(unsignedAPKPath);
958 apkPath = boost::filesystem::change_extension(apkPath, "");
959 int lastindex = apkPath.generic_string().find_last_of(".");
960 apkPath = apkPath.generic_string().substr(0, lastindex);
961
962 boost::filesystem::path alignedAPKPath = apkPath.generic_string() + ".aligned.apk";
963 boost::filesystem::path finalAPKPath = apkPath.generic_string() + ".apk";
964
965 // remove files if exist
966 if(boost::filesystem::exists(alignedAPKPath))
967 boost::filesystem::remove(alignedAPKPath, ec);
968
969 if(boost::filesystem::exists(finalAPKPath))
970 boost::filesystem::remove(finalAPKPath, ec);
971
972 cmdargs += "-f 4 ";
973 cmdargs += "\"" + unsignedAPKPath.generic_string() + "\" ";
974 cmdargs += "\"" + alignedAPKPath.generic_string() + "\" ";
975
976 std::string cmd = "\"" + toolsPathBox.exe_zipalignPath.generic_string() + "\" " + cmdargs;
977 //res = system(cmd.c_str());
978 //if (res != 0)
979
980 /*StartupInfoF.cb = sizeof(StartupInfoF);
981
982 if (!CreateProcess(NULL, (LPSTR)cmd.c_str(), NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, NULL, NULL, &StartupInfoF, &ProcessInfoF))
983 {
984 MMechostr(MSKDEBUG, "error running zipalign : %s\n", cmd.c_str());
985 system("cd %__LASTDIR%");
986 MMset(m, 0, NIL);
987 return 0;
988 }
989
990 WaitForSingleObject(ProcessInfoF.hProcess, INFINITE);
991 // Close the handles.
992 CloseHandle(ProcessInfoF.hProcess);
993 CloseHandle(ProcessInfoF.hThread);
994 */
995
996 std::string output;
997 bool result = execProcess(cmd, output);
998 if (!result)
999 {
1000 MMechostr(MSKDEBUG, "_SIGNandroidAPK : error running zipalign : %s\n", output.c_str());
1001 MMset(m, 0, NIL);
1002 Mpushstrbloc(m, (char*)output.c_str());
1003 MMpush(m, 2*2);
1004 MBdeftab (m);
1005 return 0;
1006 }
1007
1008 cmd = "\"" + toolsPathBox.exe_javacPath.generic_string() + "\" -jar \"" + toolsPathBox.jar_apksignerPath.generic_string() + "\""
1009 + " sign"
1010 + " --ks \"" + keystorePath.generic_string() + "\""
1011 + " --ks-pass \"pass:" + password + "\""
1012 + " --v1-signing-enabled true"
1013 + " --v2-signing-enabled true"
1014 + " --out \"" + finalAPKPath.generic_string() + "\""
1015 + " \"" + alignedAPKPath.generic_string() + "\"";
1016
1017 result = execProcess(cmd, output);
1018 if (!result)
1019 {
1020 MMechostr(MSKDEBUG, "error running apksigner : %s\n", output.c_str());
1021 MMset(m, 0, NIL);
1022 Mpushstrbloc(m, (char*)output.c_str());
1023 MMpush(m, 2 * 2);
1024 MBdeftab(m);
1025 return 0;
1026 }
1027
1028 // remove signed / unsigned file keep only the final one
1029 if(boost::filesystem::exists(unsignedAPKPath))
1030 boost::filesystem::remove(unsignedAPKPath, ec);
1031
1032 if(boost::filesystem::exists(alignedAPKPath))
1033 boost::filesystem::remove(alignedAPKPath, ec);
1034
1035 if (boost::filesystem::exists(finalAPKPath))
1036 {
1037 MMpull(m);
1038 Mpushstrbloc(m, (char*)finalAPKPath.generic_string().c_str());
1039 Mpushstrbloc(m, (char*)output.c_str());
1040 MMpush(m, 2*2);
1041 MBdeftab (m);
1042 }
1043 else
1044 {
1045 MMset(m, 0, NIL);
1046 Mpushstrbloc(m, (char*)output.c_str());
1047 MMpush(m, 2*2);
1048 MBdeftab (m);
1049 }
1050
1051#ifdef SCOL_DEBUG
1052 MMechostr(MSKDEBUG, "end _SIGNandroidAPK\n");
1053#endif
1054 return 0;
1055}
1056
1065int _INSTALLandroidAPK(mmachine m)
1066{
1067#ifdef SCOL_DEBUG
1068 MMechostr(MSKDEBUG, "_INSTALLandroidAPK\n");
1069#endif
1070
1071 int iAPKPath = MMget(m, 0);
1072
1073 if (iAPKPath == NIL)
1074 {
1075 MMechostr(MSKDEBUG, "error: APK path is NIL\n");
1076 MMset(m, 0, NIL);
1077 return 0;
1078 }
1079
1080 if (!boost::filesystem::exists(toolsPathBox.exe_adbPath))
1081 {
1082 std::string errmsg(std::string("error: ") + toolsPathBox.exe_adbPath.generic_string() + std::string(" doesn't exist !"));
1083 MMechostr(MSKDEBUG, errmsg.c_str());
1084 MMset(m, 0, NIL);
1085 return 0;
1086 }
1087
1088 boost::filesystem::path APKPath = MMstartstr(m, MTOP(iAPKPath));
1089
1090 // Call adb
1091 std::string cmd = "\"\"" + toolsPathBox.exe_adbPath.generic_string() + "\" install -r \"" + APKPath.generic_string() + "\"\"";
1092 int res = system(cmd.c_str());
1093 if (res != 0)
1094 {
1095 MMechostr(MSKDEBUG, "error running adb : %s\n", cmd.c_str());
1096 system("cd %__LASTDIR%");
1097 MMset(m, 0, NIL);
1098 return 0;
1099 }
1100
1101 MMset(m, 0, ITOM(0));
1102
1103#ifdef SCOL_DEBUG
1104 MMechostr(MSKDEBUG, "end _INSTALLandroidAPK\n");
1105#endif
1106 return 0;
1107}
1108
1116int _CHECKandroidTools(mmachine m)
1117{
1118 if (!boost::filesystem::exists(toolsPathBox.exe_aaptPath))
1119 MMpush(m, ITOM(0));
1120 else
1121 MMpush(m, ITOM(1));
1122 return 0;
1123}
1124
1125// /////////////////////////////////////////////////////////////////////////////////
1126// /////////////////////////////////////////////////////////////////////////////////
1127
1128// /////////////////////////////////////////////////////////////////////////////////
1129// //////////////////////////////////// BINDING ////////////////////////////////////
1130// /////////////////////////////////////////////////////////////////////////////////
1131
1132NativeDefinition base_android_deployer[] =
1133{
1134 { "_MAKEandroidUnsignedAppBundle", 2, "fun [S P] [P S]", _MAKEandroidUnsignedAppBundle },
1135 { "_MAKEandroidUnsignedAPK", 2, "fun [S P] [P S]", _MAKEandroidUnsignedAPK },
1136 { "_ENCRYPTandroidSigningKey", 4, "fun [P S S P] [P S]", _ENCRYPTandroidSigningKey },
1137 { "_MAKEandroidSigningKey", 4, "fun [W S S [[S S] r1]] [P S]", _MAKEandroidSigningKey },
1138 { "_SIGNandroidAppBundle", 4, "fun [P P S S] [P S]", _SIGNandroidAppBundle },
1139 { "_SIGNandroidAPK", 4, "fun [P P S S] [P S]", _SIGNandroidAPK },
1140 { "_INSTALLandroidAPK", 1, "fun [P] I", _INSTALLandroidAPK },
1141 { "_CHECKandroidTools", 0, "fun [] I", _CHECKandroidTools }
1142};
1143
1148int LoadAndroidDeployer(mmachine m)
1149{
1150 int k;
1151 MMechostr(MSKDEBUG, " > Loading Android Deployer\n");
1152 k = PKhardpak2(m, "android_deployer.pkg", sizeof(base_android_deployer) / sizeof(base_android_deployer[0]), base_android_deployer);
1153 MMechostr(MSKDEBUG, " > Successfully Loaded\n\n");
1154 return k;
1155}
1156
1157// /////////////////////////////////////////////////////////////////////////////////
1158// /////////////////////////////////////////////////////////////////////////////////
int LoadAndroidDeployer(mmachine m)
Load the packages in Scol virtual machine.
HANDLE g_hChildStd_OUT_Wr
HANDLE g_hChildStd_ERR_Rd
HANDLE g_hChildStd_ERR_Wr
bool execProcess(std::string cmd, std::string &output)
void ReadExecFromPipe(PROCESS_INFORMATION, std::string &, std::string &)
#define EXECBUFSIZE
PROCESS_INFORMATION CreateExecChildProcess(std::string, BOOL &)
void addDirToArchive(zip_t *archive, const boost::filesystem::path &srcdir, const boost::filesystem::path &inputdir)
NativeDefinition base_android_deployer[]
HANDLE g_hChildStd_OUT_Rd
ToolsPathBox toolsPathBox
boost::filesystem::path binPath
boost::filesystem::path libPath
boost::filesystem::path resPath
boost::filesystem::path packagePath
boost::filesystem::path projectArchive
boost::filesystem::path dexPath
boost::filesystem::path manifestPath
boost::filesystem::path tmpPath
boost::filesystem::path assetsPath
boost::filesystem::path exe_zipalignPath
boost::filesystem::path jar_androidPath
boost::filesystem::path exe_jarsignerPath
boost::filesystem::path exe_adbPath
boost::filesystem::path exe_aapt2Path
boost::filesystem::path jar_bundletoolPath
boost::filesystem::path jar_pepkPath
boost::filesystem::path exe_javacPath
boost::filesystem::path exe_keytoolPath
boost::filesystem::path exe_aaptPath
boost::filesystem::path jar_apksignerPath
int _CHECKandroidTools(mmachine m)
_CHECKandroidTools : This function test if the android tools are available
int _INSTALLandroidAPK(mmachine m)
_INSTALLandroidAPK : This function signs and
int _ENCRYPTandroidSigningKey(mmachine m)
_ENCRYPTandroidSigningKey : This function encrypts a signing key (.keystore) so it can be sent to the...
int _SIGNandroidAPK(mmachine m)
_SIGNandroidAPK : This function signs and zips align an APK file
int _MAKEandroidUnsignedAppBundle(mmachine m)
_MAKEandroidUnsignedAppBundle : This function creates an unsigned App Bundle from files contained in ...
int _MAKEandroidSigningKey(mmachine m)
_MAKEandroidSigningKey : This function creates a signing key (.keystore) used to sign Android APKs
int _MAKEandroidUnsignedAPK(mmachine m)
_MAKEandroidUnsignedAPK : This function creates an unsigned apk from files contained in the same fold...
int _SIGNandroidAppBundle(mmachine m)
_SIGNandroidAppBundle : This function signs and zips align an app bundle file