3 # Copyright (c) 2013, 2014 Intel Corporation. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file.
6 # pylint: disable=F0401
17 # get xwalk absolute path so we can run this script from any location
18 xwalk_dir = os.path.dirname(os.path.abspath(__file__))
19 sys.path.append(xwalk_dir)
21 from app_info import AppInfo
22 from customize import VerifyPackageName, CustomizeAll, \
23 ParseParameterForCompressor
24 from extension_manager import GetExtensionList, GetExtensionStatus
25 from handle_permissions import permission_mapping_table
26 from util import AllArchitectures, CleanDir, GetVersion, RunCommand, \
27 CreateAndCopyDir, GetBuildDir
28 from manifest_json_parser import HandlePermissionList
29 from manifest_json_parser import ManifestJsonParser
32 NATIVE_LIBRARY = 'libxwalkcore.so'
35 def ConvertArchNameToArchFolder(arch):
40 return arch_dict.get(arch, None)
43 def AddExeExtensions(name):
44 exts_str = os.environ.get('PATHEXT', '').lower()
45 exts = [_f for _f in exts_str.split(os.pathsep) if _f]
48 result.append(name + e)
54 """Searches PATH for executable files with the given name, also taking
55 PATHEXT into account. Returns the first existing match, or None if no matches
57 for path in os.environ.get('PATH', '').split(os.pathsep):
58 for filename in AddExeExtensions(name):
59 full_path = os.path.join(path, filename)
60 if os.path.isfile(full_path) and os.access(full_path, os.X_OK):
65 def GetAndroidApiLevel(android_path):
66 """Get Highest Android target level installed.
67 return -1 if no targets have been found.
69 target_output = RunCommand([android_path, 'list', 'target', '-c'])
70 target_regex = re.compile(r'android-(\d+)')
71 targets = [int(i) for i in target_regex.findall(target_output)]
76 def ContainsNativeLibrary(path):
77 return os.path.isfile(os.path.join(path, NATIVE_LIBRARY))
80 def ParseManifest(options):
81 parser = ManifestJsonParser(os.path.expanduser(options.manifest))
83 options.name = parser.GetAppName()
84 if not options.app_version:
85 options.app_version = parser.GetVersion()
86 if not options.app_versionCode and not options.app_versionCodeBase:
87 options.app_versionCode = 1
88 if parser.GetDescription():
89 options.description = parser.GetDescription()
90 if parser.GetPermissions():
91 options.permissions = parser.GetPermissions()
92 if parser.GetAppUrl():
93 options.app_url = parser.GetAppUrl()
94 elif parser.GetAppLocalPath():
95 options.app_local_path = parser.GetAppLocalPath()
97 print('Error: there is no app launch path defined in manifest.json.')
99 options.icon_dict = {}
100 if parser.GetAppRoot():
101 options.app_root = parser.GetAppRoot()
102 options.icon_dict = parser.GetIcons()
103 if parser.GetOrientation():
104 options.orientation = parser.GetOrientation()
105 if parser.GetFullScreenFlag().lower() == 'true':
106 options.fullscreen = True
107 elif parser.GetFullScreenFlag().lower() == 'false':
108 options.fullscreen = False
112 def ParseXPK(options, out_dir):
113 cmd = ['python', os.path.join(xwalk_dir, 'parse_xpk.py'),
114 '--file=%s' % os.path.expanduser(options.xpk),
115 '--out=%s' % out_dir]
118 print ('Use the manifest from XPK by default '
119 'when "--xpk" option is specified, and '
120 'the "--manifest" option would be ignored.')
123 if os.path.isfile(os.path.join(out_dir, 'manifest.json')):
124 options.manifest = os.path.join(out_dir, 'manifest.json')
126 print('XPK doesn\'t contain manifest file.')
130 def FindExtensionJars(root_path):
131 ''' Find all .jar files for external extensions. '''
133 if not os.path.exists(root_path):
134 return extension_jars
136 for afile in os.listdir(root_path):
137 if os.path.isdir(os.path.join(root_path, afile)):
138 base_name = os.path.basename(afile)
139 extension_jar = os.path.join(root_path, afile, base_name + '.jar')
140 if os.path.isfile(extension_jar):
141 extension_jars.append(extension_jar)
142 return extension_jars
145 # Follows the recommendation from
146 # http://software.intel.com/en-us/blogs/2012/11/12/how-to-publish-
147 # your-apps-on-google-play-for-x86-based-android-devices-using
148 def MakeVersionCode(options):
149 ''' Construct a version code'''
150 if options.app_versionCode:
151 return options.app_versionCode
153 # First digit is ABI, ARM=2, x86=6
155 if options.arch == 'arm':
157 if options.arch == 'x86':
160 if options.app_versionCodeBase:
161 b = str(options.app_versionCodeBase)
163 print('Version code base must be 7 digits or less: '
164 'versionCodeBase=%s' % (b))
166 # zero pad to 7 digits, middle digits can be used for other
167 # features, according to recommendation in URL
168 return '%s%s' % (abi, b.zfill(7))
171 def GetExtensionBinaryPathList():
172 local_extension_list = []
173 extensions_path = os.path.join(os.getcwd(), "extensions")
174 exist_extension_list = GetExtensionList(extensions_path)
175 for item in exist_extension_list:
176 build_json_path = os.path.join(extensions_path, item, "build.json")
177 with open(build_json_path) as fd:
179 if not GetExtensionStatus(item, extensions_path):
182 if data.get("binary_path", False):
183 extension_binary_path = os.path.join(extensions_path,
187 print("The extension \"%s\" doesn't exists." % item)
189 if os.path.isdir(extension_binary_path):
190 local_extension_list.append(extension_binary_path)
192 print("The extension \"%s\" doesn't exists." % item)
195 return local_extension_list
198 def Customize(options, app_info, manifest):
199 app_info.package = options.package
200 app_info.app_name = options.name
201 # 'org.xwalk.my_first_app' => 'MyFirstApp'
202 android_name = options.package.split('.')[-1].split('_')
203 app_info.android_name = ''.join([i.capitalize() for i in android_name if i])
204 if options.app_version:
205 app_info.app_version = options.app_version
206 app_info.app_versionCode = MakeVersionCode(options)
208 app_info.app_root = os.path.expanduser(options.app_root)
209 if options.enable_remote_debugging:
210 app_info.remote_debugging = '--enable-remote-debugging'
211 if options.use_animatable_view:
212 app_info.use_animatable_view = '--use-animatable-view'
213 if options.fullscreen:
214 app_info.fullscreen_flag = '-f'
215 if options.orientation:
216 app_info.orientation = options.orientation
218 app_info.icon = '%s' % os.path.expanduser(options.icon)
220 #Add local extensions to extension list.
221 extension_binary_path_list = GetExtensionBinaryPathList()
222 if len(extension_binary_path_list) > 0:
223 if options.extensions is None:
224 options.extensions = ""
226 options.extensions += os.pathsep
228 for item in extension_binary_path_list:
229 options.extensions += item
230 options.extensions += os.pathsep
231 #trim final path separator
232 options.extensions = options.extensions[0:-1]
234 CustomizeAll(app_info, options.description, options.icon_dict,
235 options.permissions, options.app_url, options.app_local_path,
236 options.keep_screen_on, options.extensions, manifest,
237 options.xwalk_command_line, options.compressor)
240 def Execution(options, name):
241 arch_string = (' ('+options.arch+')' if options.arch else '')
242 print('\nStarting application build' + arch_string)
243 app_dir = GetBuildDir(name)
244 android_path = Which('android')
245 api_level = GetAndroidApiLevel(android_path)
246 target_string = 'android-%d' % api_level
248 print (' * Checking keystore for signing')
249 if options.keystore_path:
250 key_store = os.path.expanduser(options.keystore_path)
251 if options.keystore_alias:
252 key_alias = options.keystore_alias
254 print('Please provide an alias name of the developer key.')
256 if options.keystore_passcode:
257 key_code = options.keystore_passcode
260 if options.keystore_alias_passcode:
261 key_alias_code = options.keystore_alias_passcode
263 key_alias_code = None
265 print(' No keystore provided for signing. Using xwalk\'s keystore '
266 'for debugging.\n Please use a valid keystore when '
267 'distributing to the app market.')
268 key_store = os.path.join(xwalk_dir, 'xwalk-debug.keystore')
269 key_alias = 'xwalkdebugkey'
270 key_code = 'xwalkdebug'
271 key_alias_code = 'xwalkdebug'
273 # Update android project for app and xwalk_core_library.
274 update_project_cmd = [android_path, 'update', 'project',
276 '--target', target_string,
278 if options.mode == 'embedded':
279 print(' * Updating project with xwalk_core_library')
280 RunCommand([android_path, 'update', 'lib-project',
281 '--path', os.path.join(app_dir, 'xwalk_core_library'),
282 '--target', target_string])
283 update_project_cmd.extend(['-l', 'xwalk_core_library'])
285 print(' * Updating project')
286 RunCommand(update_project_cmd)
288 # Check whether external extensions are included.
289 print(' * Checking for external extensions')
290 extensions_string = 'xwalk-extensions'
291 extensions_dir = os.path.join(app_dir, extensions_string)
292 external_extension_jars = FindExtensionJars(extensions_dir)
293 for external_extension_jar in external_extension_jars:
294 shutil.copyfile(external_extension_jar,
295 os.path.join(app_dir, 'libs',
296 os.path.basename(external_extension_jar)))
298 if options.mode == 'embedded':
299 print (' * Copying native libraries for %s' % options.arch)
300 # Remove existing native libraries in xwalk_core_library, they are probably
301 # for the last execution to make apk for another CPU arch.
302 # And then copy the native libraries for the specified arch into
303 # xwalk_core_library.
304 arch = ConvertArchNameToArchFolder(options.arch)
306 print ('Invalid CPU arch: %s.' % arch)
308 library_lib_path = os.path.join(app_dir, 'xwalk_core_library', 'libs')
309 for dir_name in os.listdir(library_lib_path):
310 lib_dir = os.path.join(library_lib_path, dir_name)
311 if ContainsNativeLibrary(lib_dir):
312 shutil.rmtree(lib_dir)
313 native_lib_path = os.path.join(app_dir, 'native_libs', arch)
314 if ContainsNativeLibrary(native_lib_path):
315 shutil.copytree(native_lib_path, os.path.join(library_lib_path, arch))
317 print('No %s native library has been found for creating a Crosswalk '
318 'embedded APK.' % arch)
321 if options.project_only:
322 print (' (Skipping apk package creation)')
326 if options.mode == 'embedded':
327 print(' * Building Android apk package with Crosswalk embedded' +
330 print(' * Building Android apk package')
331 ant_path = Which('ant')
332 ant_cmd = [ant_path, 'release', '-f', os.path.join(app_dir, 'build.xml')]
333 ant_cmd.extend(['-Dkey.store=%s' % os.path.abspath(key_store)])
334 ant_cmd.extend(['-Dkey.alias=%s' % key_alias])
336 ant_cmd.extend(['-Dkey.store.password=%s' % key_code])
338 ant_cmd.extend(['-Dkey.alias.password=%s' % key_alias_code])
340 cmd_display = ' '.join([str(item) for item in ant_cmd])
342 print('Executing:\n %s\n' % cmd_display)
344 ant_cmd.extend(['-quiet'])
345 ant_result = subprocess.call(ant_cmd)
347 print('Command "%s" exited with non-zero exit code %d'
348 % (cmd_display, ant_result))
351 src_file = os.path.join(app_dir, 'bin', '%s-release.apk' % name)
353 if options.app_version:
354 package_name += ('_' + options.app_version)
355 if options.mode == 'shared':
356 dst_file = os.path.join(options.target_dir, '%s.apk' % package_name)
357 elif options.mode == 'embedded':
358 dst_file = os.path.join(options.target_dir,
359 '%s_%s.apk' % (package_name, options.arch))
360 shutil.copyfile(src_file, dst_file)
361 print(' (Location: %s)' % dst_file)
363 def PrintPackageInfo(options, name, packaged_archs):
364 package_name_version = os.path.join(options.target_dir, name)
365 if options.app_version:
366 package_name_version += '_' + options.app_version
368 if len(packaged_archs) == 0:
369 print ('\nA non-platform specific APK for the web application "%s" was '
370 'generated successfully at:\n %s.apk.\nIt requires a shared '
371 'Crosswalk Runtime to be present.'
372 % (name, package_name_version))
375 all_archs = set(AllArchitectures())
377 if len(packaged_archs) != len(all_archs):
378 missed_archs = all_archs - set(packaged_archs)
379 print ('\nNote: This APK will only work on %s-based Android devices.'
380 ' Consider building\nfor %s as well.' %
381 (', '.join(packaged_archs), ', '.join(missed_archs)))
383 print ("\nApplication apk's were created for %d architectures (%s)." %
384 (len(all_archs), (','.join(all_archs))))
385 print ('If you submit this application to an application '
386 'store, please submit both\npackages. Instructions '
387 'for submitting multiple APKs to Google Play Store are\navailable '
389 print (' https://software.intel.com/en-us/html5/articles/submitting'
390 '-multiple-crosswalk-apk-to-google-play-store')
393 def CheckSystemRequirements():
394 ''' Check for android, ant, template dir '''
395 sys.stdout.write('Checking system requirements...')
397 # check android install
398 android_path = Which('android')
399 if android_path is None:
400 print('failed\nThe "android" binary could not be found. Check your Android '
401 'SDK installation and your PATH environment variable.')
403 if GetAndroidApiLevel(android_path) < 14:
404 print('failed\nPlease install Android API level (>=14) first.')
408 ant_path = Which('ant')
410 print('failed\nAnt could not be found. Please make sure it is installed.')
416 def MakeApk(options, app_info, manifest):
417 CheckSystemRequirements()
418 Customize(options, app_info, manifest)
419 name = app_info.android_name
420 app_dir = GetBuildDir(name)
422 if options.mode == 'shared':
423 # For shared mode, it's not necessary to use the whole xwalk core library,
424 # use xwalk_core_library_java_app_part.jar from it is enough.
425 java_app_part_jar = os.path.join(xwalk_dir, 'xwalk_core_library', 'libs',
426 'xwalk_core_library_java_app_part.jar')
427 shutil.copy(java_app_part_jar, os.path.join(app_dir, 'libs'))
428 Execution(options, name)
429 elif options.mode == 'embedded':
430 # Copy xwalk_core_library into app folder and move the native libraries
432 # When making apk for specified CPU arch, will only include the
433 # corresponding native library by copying it back into xwalk_core_library.
434 target_library_path = os.path.join(app_dir, 'xwalk_core_library')
435 shutil.copytree(os.path.join(xwalk_dir, 'xwalk_core_library'),
437 library_lib_path = os.path.join(target_library_path, 'libs')
438 native_lib_path = os.path.join(app_dir, 'native_libs')
439 os.makedirs(native_lib_path)
441 for dir_name in os.listdir(library_lib_path):
442 lib_dir = os.path.join(library_lib_path, dir_name)
443 if ContainsNativeLibrary(lib_dir):
444 shutil.move(lib_dir, os.path.join(native_lib_path, dir_name))
445 available_archs.append(dir_name)
447 Execution(options, name)
448 packaged_archs.append(options.arch)
450 # If the arch option is unspecified, all of available platform APKs
452 valid_archs = ['x86', 'armeabi-v7a']
453 for arch in valid_archs:
454 if arch in available_archs:
455 if arch.find('x86') != -1:
457 elif arch.find('arm') != -1:
459 Execution(options, name)
460 packaged_archs.append(options.arch)
462 print('Warning: failed to create package for arch "%s" '
463 'due to missing native library' % arch)
465 if len(packaged_archs) == 0:
466 print('No packages created, aborting')
469 # if project_dir, save build directory
470 if options.project_dir:
471 print ('\nCreating project directory')
472 save_dir = os.path.join(options.project_dir, name)
473 if CreateAndCopyDir(app_dir, save_dir, True):
474 print (' A project directory was created successfully in:\n %s' %
475 os.path.abspath(save_dir))
476 print (' To manually generate an APK, run the following in that '
478 print (' ant release -f build.xml')
479 print (' For more information, see:\n'
480 ' http://developer.android.com/tools/building/'
481 'building-cmdline.html')
483 print ('Error: Unable to create a project directory during the build. '
484 'Please check the directory passed in --project-dir, '
485 'available disk space, and write permission.')
487 if not options.project_only:
488 PrintPackageInfo(options, name, packaged_archs)
491 parser = optparse.OptionParser()
492 parser.add_option('-v', '--version', action='store_true',
493 dest='version', default=False,
494 help='The version of this python tool.')
495 parser.add_option('--verbose', action="store_true",
496 dest='verbose', default=False,
497 help='Print debug messages.')
498 info = ('The packaging mode of the web application. The value \'shared\' '
499 'means that the runtime is shared across multiple application '
500 'instances and that the runtime needs to be distributed separately. '
501 'The value \'embedded\' means that the runtime is embedded into the '
502 'application itself and distributed along with it.'
503 'Set the default mode as \'embedded\'. For example: --mode=embedded')
504 parser.add_option('--mode', choices=('embedded', 'shared'),
505 default='embedded', help=info)
506 info = ('The target architecture of the embedded runtime. Supported values '
507 'are \'x86\' and \'arm\'. Note, if undefined, APKs for all possible '
508 'architestures will be generated.')
509 parser.add_option('--arch', choices=AllArchitectures(), help=info)
510 group = optparse.OptionGroup(parser, 'Application Source Options',
511 'This packaging tool supports 3 kinds of web application source: '
512 '1) XPK package; 2) manifest.json; 3) various command line options, '
513 'for example, \'--app-url\' for website, \'--app-root\' and '
514 '\'--app-local-path\' for local web application.')
515 info = ('The path of the XPK package. For example, --xpk=/path/to/xpk/file')
516 group.add_option('--xpk', help=info)
517 info = ('The manifest file with the detail description of the application. '
518 'For example, --manifest=/path/to/your/manifest/file')
519 group.add_option('--manifest', help=info)
520 info = ('The url of application. '
521 'This flag allows to package website as apk. For example, '
522 '--app-url=http://www.intel.com')
523 group.add_option('--app-url', help=info)
524 info = ('The root path of the web app. '
525 'This flag allows to package local web app as apk. For example, '
526 '--app-root=/root/path/of/the/web/app')
527 group.add_option('--app-root', help=info)
528 info = ('The relative path of entry file based on the value from '
529 '\'app_root\'. This flag should work with \'--app-root\' together. '
530 'For example, --app-local-path=/relative/path/of/entry/file')
531 group.add_option('--app-local-path', help=info)
532 parser.add_option_group(group)
533 # Mandatory options group
534 group = optparse.OptionGroup(parser, 'Mandatory arguments',
535 'They are used for describing the APK information through '
536 'command line options.')
537 info = ('The apk name. For example, --name="Your Application Name"')
538 group.add_option('--name', help=info)
539 info = ('The package name. For example, '
540 '--package=com.example.YourPackage')
541 group.add_option('--package', help=info)
542 parser.add_option_group(group)
543 # Optional options group (alphabetical)
544 group = optparse.OptionGroup(parser, 'Optional arguments',
545 'They are used for various settings for applications through '
546 'command line options.')
547 info = ('The version name of the application. '
548 'For example, --app-version=1.0.0')
549 group.add_option('--app-version', help=info)
550 info = ('The version code of the application. '
551 'For example, --app-versionCode=24')
552 group.add_option('--app-versionCode', type='int', help=info)
553 info = ('The version code base of the application. Version code will '
554 'be made by adding a prefix based on architecture to the version '
555 'code base. For example, --app-versionCodeBase=24')
556 group.add_option('--app-versionCodeBase', type='int', help=info)
557 info = ('The description of the application. For example, '
558 '--description=YourApplicationDescription')
559 group.add_option('--description', help=info)
560 group.add_option('--enable-remote-debugging', action='store_true',
561 dest='enable_remote_debugging', default=False,
562 help='Enable remote debugging.')
563 group.add_option('--use-animatable-view', action='store_true',
564 dest='use_animatable_view', default=False,
565 help='Enable using animatable view (TextureView).')
566 info = ('The list of external extension paths splitted by OS separators. '
567 'The separators are \':\' , \';\' and \':\' on Linux, Windows and '
568 'Mac OS respectively. For example, '
569 '--extensions=/path/to/extension1:/path/to/extension2.')
570 group.add_option('--extensions', help=info)
571 group.add_option('-f', '--fullscreen', action='store_true',
572 dest='fullscreen', default=False,
573 help='Make application fullscreen.')
574 group.add_option('--keep-screen-on', action='store_true', default=False,
575 help='Support keeping screen on')
576 info = ('The path of application icon. '
577 'Such as: --icon=/path/to/your/customized/icon')
578 group.add_option('--icon', help=info)
579 info = ('The orientation of the web app\'s display on the device. '
580 'For example, --orientation=landscape. The default value is '
581 '\'unspecified\'. The permitted values are from Android: '
582 'http://developer.android.com/guide/topics/manifest/'
583 'activity-element.html#screen')
584 group.add_option('--orientation', help=info)
585 info = ('The list of permissions to be used by web application. For example, '
586 '--permissions=geolocation:webgl')
587 group.add_option('--permissions', help=info)
588 info = ('Create an Android project directory with Crosswalk at this location.'
589 ' (See project-only option below)')
590 group.add_option('--project-dir', help=info)
591 info = ('Must be used with project-dir option. Create an Android project '
592 'directory with Crosswalk but do not build the APK package')
593 group.add_option('--project-only', action='store_true', default=False,
594 dest='project_only', help=info)
595 info = ('Packaging tool will move the output APKs to the target directory')
596 group.add_option('--target-dir', default=os.getcwd(), help=info)
597 info = ('Use command lines.'
598 'Crosswalk is powered by Chromium and supports Chromium command line.'
600 '--xwalk-command-line=\'--chromium-command-1 --xwalk-command-2\'')
601 group.add_option('--xwalk-command-line', default='', help=info)
602 parser.add_option_group(group)
603 # Keystore options group
604 group = optparse.OptionGroup(parser, 'Keystore Options',
605 'The keystore is a signature from web developer, it\'s used when '
606 'developer wants to distribute the applications.')
607 info = ('The path to the developer keystore. For example, '
608 '--keystore-path=/path/to/your/developer/keystore')
609 group.add_option('--keystore-path', help=info)
610 info = ('The alias name of keystore. For example, --keystore-alias=name')
611 group.add_option('--keystore-alias', help=info)
612 info = ('The passcode of keystore. For example, --keystore-passcode=code')
613 group.add_option('--keystore-passcode', help=info)
614 info = ('Passcode for alias\'s private key in the keystore, '
615 'For example, --keystore-alias-passcode=alias-code')
616 group.add_option('--keystore-alias-passcode', help=info)
617 info = ('Minify and obfuscate javascript and css.'
618 '--compressor: compress javascript and css.'
619 '--compressor=js: compress javascript.'
620 '--compressor=css: compress css.')
621 group.add_option('--compressor', dest='compressor', action='callback',
622 callback=ParseParameterForCompressor, type='string',
624 parser.add_option_group(group)
625 options, _ = parser.parse_args()
631 if os.path.isfile('VERSION'):
632 print(GetVersion('VERSION'))
635 parser.error('VERSION was not found, so Crosswalk\'s version could not '
640 xpk_name = os.path.splitext(os.path.basename(options.xpk))[0]
641 xpk_temp_dir = tempfile.mkdtemp(prefix="%s-" % xpk_name + '_xpk')
642 CleanDir(xpk_temp_dir)
643 ParseXPK(options, xpk_temp_dir)
646 options.manifest = os.path.abspath(options.manifest)
647 if not os.path.isfile(options.manifest):
648 print('Error: The manifest file does not exist.')
651 if options.app_root and not options.manifest:
652 manifest_path = os.path.join(options.app_root, 'manifest.json')
653 if os.path.exists(manifest_path):
654 print('Using manifest.json distributed with the application.')
655 options.manifest = manifest_path
659 if not options.manifest:
660 # The checks here are really convoluted, but at the moment make_apk
661 # misbehaves any of the following conditions is true.
663 # 1) --app-url must be passed without either --app-local-path or
665 if options.app_root or options.app_local_path:
666 parser.error('You must pass either "--app-url" or "--app-local-path" '
667 'with "--app-root", but not all.')
669 # 2) --app-url is not passed but only one of --app-local-path and
671 if bool(options.app_root) != bool(options.app_local_path):
672 parser.error('You must specify both "--app-local-path" and '
674 # 3) None of --app-url, --app-local-path and --app-root are passed.
675 elif not options.app_root and not options.app_local_path:
676 parser.error('You must pass either "--app-url" or "--app-local-path" '
677 'with "--app-root".')
679 if options.permissions:
680 permission_list = options.permissions.split(':')
682 print('Warning: all supported permissions on Android port are added. '
683 'Refer to https://github.com/crosswalk-project/'
684 'crosswalk-website/wiki/Crosswalk-manifest')
685 permission_list = permission_mapping_table.keys()
686 options.permissions = HandlePermissionList(permission_list)
687 options.icon_dict = {}
690 manifest = ParseManifest(options)
691 except SystemExit as ec:
695 parser.error('An APK name is required. Please use the "--name" option.')
697 if not options.package:
698 parser.error('A package name is required. Please use the "--package" '
700 VerifyPackageName(options.package)
702 if (options.app_root and options.app_local_path and
703 not os.path.isfile(os.path.join(options.app_root,
704 options.app_local_path))):
705 print('Please make sure that the local path file of launching app '
709 if options.target_dir:
710 target_dir = os.path.abspath(os.path.expanduser(options.target_dir))
711 options.target_dir = target_dir
712 if not os.path.isdir(target_dir):
713 os.makedirs(target_dir)
715 if options.project_only and not options.project_dir:
716 print('\nmake_apk.py error: Option --project-only must be used '
717 'with --project-dir')
721 MakeApk(options, app_info, manifest)
722 except SystemExit as ec:
725 CleanDir(GetBuildDir(app_info.android_name))
726 CleanDir(xpk_temp_dir)
730 if __name__ == '__main__':
732 sys.exit(main(sys.argv))
733 except KeyboardInterrupt: