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
16 sys.path.append('scripts/gyp')
18 from app_info import AppInfo
19 from customize import VerifyAppName, CustomizeAll, \
20 ParseParameterForCompressor, ReplaceSpaceWithUnderscore
21 from dex import AddExeExtensions
22 from handle_permissions import permission_mapping_table
23 from manifest_json_parser import HandlePermissionList
24 from manifest_json_parser import ManifestJsonParser
28 if os.path.exists(path):
32 def AllArchitectures():
36 def RunCommand(command, verbose=False, shell=False):
37 """Runs the command list, print the output, and propagate its result."""
38 proc = subprocess.Popen(command, stdout=subprocess.PIPE,
39 stderr=subprocess.STDOUT, shell=shell)
41 output = proc.communicate()[0]
42 result = proc.returncode
44 print(output.decode("utf-8").strip())
46 print ('Command "%s" exited with non-zero exit code %d'
47 % (' '.join(command), result))
52 """Searches PATH for executable files with the given name, also taking
53 PATHEXT into account. Returns the first existing match, or None if no matches
55 for path in os.environ.get('PATH', '').split(os.pathsep):
56 for filename in AddExeExtensions(name):
57 full_path = os.path.join(path, filename)
58 if os.path.isfile(full_path) and os.access(full_path, os.X_OK):
64 """Find executable file with the given name
65 and maximum API level under specific path."""
67 for root, _, files in os.walk(path):
69 key = os.path.join(root, name)
70 sdk_version = os.path.basename(os.path.dirname(key))
71 str_num = re.search(r'\d+', sdk_version)
73 result[key] = int(str_num.group())
78 return max(iter(result.items()), key=operator.itemgetter(1))[0]
82 """Get the version of this python tool."""
83 version_str = 'Crosswalk app packaging tool version is '
84 file_handle = open(path, 'r')
85 src_content = file_handle.read()
86 version_nums = re.findall(r'\d+', src_content)
87 version_str += ('.').join(version_nums)
92 def ParseManifest(options):
93 parser = ManifestJsonParser(os.path.expanduser(options.manifest))
95 options.name = parser.GetAppName()
96 if not options.app_version:
97 options.app_version = parser.GetVersion()
98 if not options.app_versionCode and not options.app_versionCodeBase:
99 options.app_versionCode = 1
100 if parser.GetDescription():
101 options.description = parser.GetDescription()
102 if parser.GetPermissions():
103 options.permissions = parser.GetPermissions()
104 if parser.GetAppUrl():
105 options.app_url = parser.GetAppUrl()
106 elif parser.GetAppLocalPath():
107 options.app_local_path = parser.GetAppLocalPath()
109 print('Error: there is no app launch path defined in manifest.json.')
111 if parser.GetAppRoot():
112 options.app_root = parser.GetAppRoot()
113 options.icon_dict = parser.GetIcons()
114 if parser.GetOrientation():
115 options.orientation = parser.GetOrientation()
116 if parser.GetFullScreenFlag().lower() == 'true':
117 options.fullscreen = True
118 elif parser.GetFullScreenFlag().lower() == 'false':
119 options.fullscreen = False
123 def ParseXPK(options, out_dir):
124 cmd = ['python', 'parse_xpk.py',
125 '--file=%s' % os.path.expanduser(options.xpk),
126 '--out=%s' % out_dir]
129 print ('Use the manifest from XPK by default '
130 'when "--xpk" option is specified, and '
131 'the "--manifest" option would be ignored.')
134 if os.path.isfile(os.path.join(out_dir, 'manifest.json')):
135 options.manifest = os.path.join(out_dir, 'manifest.json')
137 print('XPK doesn\'t contain manifest file.')
141 def FindExtensionJars(root_path):
142 ''' Find all .jar files for external extensions. '''
144 if not os.path.exists(root_path):
145 return extension_jars
147 for afile in os.listdir(root_path):
148 if os.path.isdir(os.path.join(root_path, afile)):
149 base_name = os.path.basename(afile)
150 extension_jar = os.path.join(root_path, afile, base_name + '.jar')
151 if os.path.isfile(extension_jar):
152 extension_jars.append(extension_jar)
153 return extension_jars
156 # Follows the recommendation from
157 # http://software.intel.com/en-us/blogs/2012/11/12/how-to-publish-
158 # your-apps-on-google-play-for-x86-based-android-devices-using
159 def MakeVersionCode(options):
160 ''' Construct a version code'''
161 if options.app_versionCode:
162 return options.app_versionCode
164 # First digit is ABI, ARM=2, x86=6
166 if options.arch == 'arm':
168 if options.arch == 'x86':
171 if options.app_versionCodeBase:
172 b = str(options.app_versionCodeBase)
174 print('Version code base must be 7 digits or less: '
175 'versionCodeBase=%s' % (b))
177 # zero pad to 7 digits, middle digits can be used for other
178 # features, according to recommendation in URL
179 return '%s%s' % (abi, b.zfill(7))
182 def Customize(options, app_info, manifest):
183 app_info.package = options.package
184 app_info.app_name = options.name
185 app_info.android_name = ReplaceSpaceWithUnderscore(options.name)
186 if options.app_version:
187 app_info.app_version = options.app_version
188 app_info.app_versionCode = MakeVersionCode(options)
190 app_info.app_root = os.path.expanduser(options.app_root)
191 if options.enable_remote_debugging:
192 app_info.remote_debugging = '--enable-remote-debugging'
193 if options.fullscreen:
194 app_info.fullscreen_flag = '-f'
195 if options.orientation:
196 app_info.orientation = options.orientation
198 app_info.icon = '%s' % os.path.expanduser(options.icon)
199 CustomizeAll(app_info, options.description, options.icon_dict,
200 options.permissions, options.app_url, options.app_local_path,
201 options.keep_screen_on, options.extensions, manifest,
202 options.xwalk_command_line, options.compressor)
205 def Execution(options, name):
206 android_path = Which('android')
207 if android_path is None:
208 print('The "android" binary could not be found. Check your Android SDK '
209 'installation and your PATH environment variable.')
212 sdk_root_path = os.path.dirname(os.path.dirname(android_path))
215 sdk_jar_path = Find('android.jar',
216 os.path.join(sdk_root_path, 'platforms'))
218 print('Your Android SDK may be ruined, please reinstall it.')
221 level_string = os.path.basename(os.path.dirname(sdk_jar_path))
222 api_level = int(re.search(r'\d+', level_string).group())
224 print('Please install Android API level (>=14) first.')
227 if options.keystore_path:
228 key_store = os.path.expanduser(options.keystore_path)
229 if options.keystore_alias:
230 key_alias = options.keystore_alias
232 print('Please provide an alias name of the developer key.')
234 if options.keystore_passcode:
235 key_code = options.keystore_passcode
237 print('Please provide the passcode of the developer key.')
239 if options.keystore_alias_passcode:
240 key_alias_code = options.keystore_alias_passcode
242 print('--keystore-alias-passcode was not specified, '
243 'using the keystore\'s passcode as the alias keystore passcode.')
244 key_alias_code = key_code
246 print ('Use xwalk\'s keystore by default for debugging. '
247 'Please switch to your keystore when distributing it to app market.')
248 key_store = 'scripts/ant/xwalk-debug.keystore'
249 key_alias = 'xwalkdebugkey'
250 key_code = 'xwalkdebug'
251 key_alias_code = 'xwalkdebug'
253 if not os.path.exists('out'):
256 # Make sure to use ant-tasks.jar correctly.
257 # Default Android SDK names it as ant-tasks.jar
258 # Chrome third party Android SDk names it as anttasks.jar
259 ant_tasks_jar_path = os.path.join(sdk_root_path,
260 'tools', 'lib', 'ant-tasks.jar')
261 if not os.path.exists(ant_tasks_jar_path):
262 ant_tasks_jar_path = os.path.join(sdk_root_path,
263 'tools', 'lib', 'anttasks.jar')
266 for aapt_str in AddExeExtensions('aapt'):
268 aapt_path = Find(aapt_str, sdk_root_path)
269 print('Use %s in %s.' % (aapt_str, sdk_root_path))
274 print('Your Android SDK may be ruined, please reinstall it.')
277 # Check whether ant is installed.
279 cmd = ['ant', '-version']
280 RunCommand(cmd, shell=True)
281 except EnvironmentError:
282 print('Please install ant first.')
285 res_dirs = '-DADDITIONAL_RES_DIRS=\'\''
286 res_packages = '-DADDITIONAL_RES_PACKAGES=\'\''
287 res_r_text_files = '-DADDITIONAL_R_TEXT_FILES=\'\''
288 if options.mode == 'embedded':
289 # Prepare the .pak file for embedded mode.
290 pak_src_path = os.path.join('native_libs_res', 'xwalk.pak')
291 pak_des_path = os.path.join(name, 'assets', 'xwalk.pak')
292 shutil.copy(pak_src_path, pak_des_path)
294 # Prepare the icudtl.dat for embedded mode.
295 icudtl_src_path = os.path.join('native_libs_res', 'icudtl.dat')
296 icudtl_des_path = os.path.join(name, 'assets', 'icudtl.dat')
297 shutil.copy(icudtl_src_path, icudtl_des_path)
299 js_src_dir = os.path.join('native_libs_res', 'jsapi')
300 js_des_dir = os.path.join(name, 'assets', 'jsapi')
301 if os.path.exists(js_des_dir):
302 shutil.rmtree(js_des_dir)
303 shutil.copytree(js_src_dir, js_des_dir)
305 res_ui_java = os.path.join('gen', 'ui_java')
306 res_content_java = os.path.join('gen', 'content_java')
307 res_xwalk_java = os.path.join('gen', 'xwalk_core_internal_java')
308 res_dir = os.path.join('libs_res', 'xwalk_core_library')
309 res_dirs = ('-DADDITIONAL_RES_DIRS=' + res_dir)
310 res_packages = ('-DADDITIONAL_RES_PACKAGES=org.chromium.ui '
311 'org.xwalk.core.internal org.chromium.content')
312 res_r_text_files = ('-DADDITIONAL_R_TEXT_FILES='
313 + os.path.join(res_ui_java, 'java_R', 'R.txt') + ' '
314 + os.path.join(res_xwalk_java, 'java_R', 'R.txt') + ' '
315 + os.path.join(res_content_java, 'java_R', 'R.txt'))
317 resource_dir = '-DRESOURCE_DIR=' + os.path.join(name, 'res')
318 manifest_path = os.path.join(name, 'AndroidManifest.xml')
319 cmd = ['python', os.path.join('scripts', 'gyp', 'ant.py'),
320 '-DAAPT_PATH=%s' % aapt_path,
324 '-DANDROID_MANIFEST=%s' % manifest_path,
325 '-DANDROID_SDK_JAR=%s' % sdk_jar_path,
326 '-DANDROID_SDK_ROOT=%s' % sdk_root_path,
327 '-DANDROID_SDK_VERSION=%d' % api_level,
328 '-DANT_TASKS_JAR=%s' % ant_tasks_jar_path,
329 '-DLIBRARY_MANIFEST_PATHS= ',
332 '-DSTAMP=codegen.stamp',
335 os.path.join('scripts', 'ant', 'apk-codegen.xml')]
336 RunCommand(cmd, options.verbose)
338 # Check whether java is installed.
340 cmd = ['java', '-version']
341 RunCommand(cmd, shell=True)
342 except EnvironmentError:
343 print('Please install Oracle JDK first.')
346 # Compile App source code with app runtime code.
347 cmd = ['python', os.path.join('scripts', 'gyp', 'javac.py'),
348 '--output-dir=%s' % os.path.join('out', 'classes'),
350 os.path.join(os.getcwd(), 'libs', 'xwalk_app_runtime_java.jar'),
354 os.path.join(os.getcwd(), name, 'src'),
356 os.path.join(os.getcwd(), 'out', 'gen'),
358 '--stamp=compile.stam']
359 RunCommand(cmd, options.verbose)
362 asset_dir = '-DASSET_DIR=%s' % os.path.join(name, 'assets')
363 xml_path = os.path.join('scripts', 'ant', 'apk-package-resources.xml')
364 cmd = ['python', os.path.join('scripts', 'gyp', 'ant.py'),
365 '-DAAPT_PATH=%s' % aapt_path,
369 '-DANDROID_SDK_JAR=%s' % sdk_jar_path,
370 '-DANDROID_SDK_ROOT=%s' % sdk_root_path,
371 '-DANT_TASKS_JAR=%s' % ant_tasks_jar_path,
372 '-DAPK_NAME=%s' % name,
373 '-DAPP_MANIFEST_VERSION_CODE=0',
374 '-DAPP_MANIFEST_VERSION_NAME=Developer Build',
376 '-DCONFIGURATION_NAME=Release',
379 '-DSTAMP=package_resources.stamp',
383 RunCommand(cmd, options.verbose)
385 dex_path = '--dex-path=' + os.path.join(os.getcwd(), 'out', 'classes.dex')
386 app_runtime_jar = os.path.join(os.getcwd(),
387 'libs', 'xwalk_app_runtime_java.jar')
389 # Check whether external extensions are included.
390 extensions_string = 'xwalk-extensions'
391 extensions_dir = os.path.join(os.getcwd(), name, extensions_string)
392 external_extension_jars = FindExtensionJars(extensions_dir)
394 if options.mode == 'embedded':
395 input_jars.append(os.path.join(os.getcwd(), 'libs',
396 'xwalk_runtime_embedded.dex.jar'))
397 dex_command_list = ['python', os.path.join('scripts', 'gyp', 'dex.py'),
399 '--android-sdk-root=%s' % sdk_root_path,
401 os.path.join(os.getcwd(), 'out', 'classes')]
402 dex_command_list.extend(external_extension_jars)
403 dex_command_list.extend(input_jars)
404 RunCommand(dex_command_list)
406 src_dir = '-DSOURCE_DIR=' + os.path.join(name, 'src')
407 apk_path = '-DUNSIGNED_APK_PATH=' + os.path.join('out', 'app-unsigned.apk')
408 native_lib_path = '-DNATIVE_LIBS_DIR='
409 if options.mode == 'embedded':
410 if options.arch == 'x86':
411 x86_native_lib_path = os.path.join('native_libs', 'x86', 'libs',
412 'x86', 'libxwalkcore.so')
413 if os.path.isfile(x86_native_lib_path):
414 native_lib_path += os.path.join('native_libs', 'x86', 'libs')
416 print('No x86 native library has been found for creating a Crosswalk '
419 elif options.arch == 'arm':
420 arm_native_lib_path = os.path.join('native_libs', 'armeabi-v7a', 'libs',
421 'armeabi-v7a', 'libxwalkcore.so')
422 if os.path.isfile(arm_native_lib_path):
423 native_lib_path += os.path.join('native_libs', 'armeabi-v7a', 'libs')
425 print('No ARM native library has been found for creating a Crosswalk '
428 # A space is needed for Windows.
429 native_lib_path += ' '
430 cmd = ['python', 'scripts/gyp/ant.py',
431 '-DANDROID_SDK_ROOT=%s' % sdk_root_path,
432 '-DANT_TASKS_JAR=%s' % ant_tasks_jar_path,
433 '-DAPK_NAME=%s' % name,
434 '-DCONFIGURATION_NAME=Release',
441 'scripts/ant/apk-package.xml']
442 RunCommand(cmd, options.verbose)
444 # Find the path of zipalign.
445 # XWALK-2033: zipalign can be in different locations depending on Android
446 # SDK version that used ((eg. /tools, /build-tools/android-4.4W etc),).
447 # So looking up the location of zipalign here instead of hard coding.
448 # Refer to: https://codereview.chromium.org/238253015
450 for zipalign_str in AddExeExtensions('zipalign'):
452 zipalign_path = Find(zipalign_str, sdk_root_path)
454 print('Use %s in %s.' % (zipalign_str, sdk_root_path))
458 if not zipalign_path:
459 print('zipalign could not be found in your Android SDK.'
460 ' Make sure it is installed.')
462 apk_path = '--unsigned-apk-path=' + os.path.join('out', 'app-unsigned.apk')
463 final_apk_path = '--final-apk-path=' + \
464 os.path.join('out', name + '.apk')
465 cmd = ['python', 'scripts/gyp/finalize_apk.py',
466 '--zipalign-path=%s' % zipalign_path,
469 '--keystore-path=%s' % key_store,
470 '--keystore-alias=%s' % key_alias,
471 '--keystore-passcode=%s' % key_code,
472 '--keystore-alias-passcode=%s' % key_alias_code]
475 src_file = os.path.join('out', name + '.apk')
477 if options.app_version:
478 package_name += ('_' + options.app_version)
479 if options.mode == 'shared':
480 dst_file = os.path.join(options.target_dir, '%s.apk' % package_name)
481 elif options.mode == 'embedded':
482 dst_file = os.path.join(options.target_dir,
483 '%s_%s.apk' % (package_name, options.arch))
484 shutil.copyfile(src_file, dst_file)
486 if options.mode == 'embedded':
487 os.remove(pak_des_path)
490 def PrintPackageInfo(options, name, packaged_archs):
491 package_name_version = os.path.join(options.target_dir, name)
492 if options.app_version:
493 package_name_version += '_' + options.app_version
495 if len(packaged_archs) == 0:
496 print ('A non-platform specific APK for the web application "%s" was '
497 'generated successfully at\n%s.apk. It requires a shared Crosswalk '
498 'Runtime to be present.'
499 % (name, package_name_version))
502 for arch in packaged_archs:
503 print ('An APK for the web application "%s" including the Crosswalk '
504 'Runtime built for %s was generated successfully, which can be '
505 'found at\n%s_%s.apk.'
506 % (name, arch, package_name_version, arch))
508 all_archs = set(AllArchitectures())
510 if len(packaged_archs) != len(all_archs):
511 missed_archs = all_archs - set(packaged_archs)
512 print ('\n\nWARNING: ')
513 print ('This APK will only work on %s based Android devices. Consider '
514 'building for %s as well.' %
515 (', '.join(packaged_archs), ', '.join(missed_archs)))
517 print ('\n\n%d APKs were created for %s devices. '
518 % (len(all_archs), ', '.join(all_archs)))
519 print ('Please install the one that matches the processor architecture '
520 'of your device.\n\n')
521 print ('If you are going to submit this application to an application '
522 'store, please make sure you submit both packages.\nInstructions '
523 'for submitting multiple APKs to Google Play Store are available '
524 'here:\nhttps://software.intel.com/en-us/html5/articles/submitting'
525 '-multiple-crosswalk-apk-to-google-play-store')
527 def MakeApk(options, app_info, manifest):
528 Customize(options, app_info, manifest)
529 name = app_info.android_name
531 if options.mode == 'shared':
532 Execution(options, name)
533 elif options.mode == 'embedded':
535 Execution(options, name)
536 packaged_archs.append(options.arch)
538 # If the arch option is unspecified, all of available platform APKs
540 valid_archs = ['x86', 'armeabi-v7a']
541 for arch in valid_archs:
542 lib_path = os.path.join('native_libs', arch, 'libs',
543 arch, 'libxwalkcore.so')
544 if os.path.isfile(lib_path):
545 if arch.find('x86') != -1:
547 elif arch.find('arm') != -1:
549 Execution(options, name)
550 packaged_archs.append(options.arch)
552 print('Warning: failed to create package for arch "%s" '
553 'due to missing library %s' %
556 if len(packaged_archs) == 0:
557 print('No packages created, aborting')
560 PrintPackageInfo(options, name, packaged_archs)
563 parser = optparse.OptionParser()
564 parser.add_option('-v', '--version', action='store_true',
565 dest='version', default=False,
566 help='The version of this python tool.')
567 parser.add_option('--verbose', action="store_true",
568 dest='verbose', default=False,
569 help='Print debug messages.')
570 info = ('The packaging mode of the web application. The value \'shared\' '
571 'means that the runtime is shared across multiple application '
572 'instances and that the runtime needs to be distributed separately. '
573 'The value \'embedded\' means that the runtime is embedded into the '
574 'application itself and distributed along with it.'
575 'Set the default mode as \'embedded\'. For example: --mode=embedded')
576 parser.add_option('--mode', choices=('embedded', 'shared'),
577 default='embedded', help=info)
578 info = ('The target architecture of the embedded runtime. Supported values '
579 'are \'x86\' and \'arm\'. Note, if undefined, APKs for all possible '
580 'architestures will be generated.')
581 parser.add_option('--arch', choices=AllArchitectures(), help=info)
582 group = optparse.OptionGroup(parser, 'Application Source Options',
583 'This packaging tool supports 3 kinds of web application source: '
584 '1) XPK package; 2) manifest.json; 3) various command line options, '
585 'for example, \'--app-url\' for website, \'--app-root\' and '
586 '\'--app-local-path\' for local web application.')
587 info = ('The path of the XPK package. For example, --xpk=/path/to/xpk/file')
588 group.add_option('--xpk', help=info)
589 info = ('The manifest file with the detail description of the application. '
590 'For example, --manifest=/path/to/your/manifest/file')
591 group.add_option('--manifest', help=info)
592 info = ('The url of application. '
593 'This flag allows to package website as apk. For example, '
594 '--app-url=http://www.intel.com')
595 group.add_option('--app-url', help=info)
596 info = ('The root path of the web app. '
597 'This flag allows to package local web app as apk. For example, '
598 '--app-root=/root/path/of/the/web/app')
599 group.add_option('--app-root', help=info)
600 info = ('The relative path of entry file based on the value from '
601 '\'app_root\'. This flag should work with \'--app-root\' together. '
602 'For example, --app-local-path=/relative/path/of/entry/file')
603 group.add_option('--app-local-path', help=info)
604 parser.add_option_group(group)
605 group = optparse.OptionGroup(parser, 'Mandatory arguments',
606 'They are used for describing the APK information through '
607 'command line options.')
608 info = ('The apk name. For example, --name="Your Application Name"')
609 group.add_option('--name', help=info)
610 info = ('The package name. For example, '
611 '--package=com.example.YourPackage')
612 group.add_option('--package', help=info)
613 parser.add_option_group(group)
614 group = optparse.OptionGroup(parser, 'Optional arguments',
615 'They are used for various settings for applications through '
616 'command line options.')
617 info = ('The version name of the application. '
618 'For example, --app-version=1.0.0')
619 group.add_option('--app-version', help=info)
620 info = ('The version code of the application. '
621 'For example, --app-versionCode=24')
622 group.add_option('--app-versionCode', type='int', help=info)
623 info = ('The version code base of the application. Version code will '
624 'be made by adding a prefix based on architecture to the version '
625 'code base. For example, --app-versionCodeBase=24')
626 group.add_option('--app-versionCodeBase', type='int', help=info)
627 info = ('Use command lines.'
628 'Crosswalk is powered by Chromium and supports Chromium command line.'
630 '--xwalk-command-line=\'--chromium-command-1 --xwalk-command-2\'')
631 group.add_option('--xwalk-command-line', default='', help=info)
632 info = ('The description of the application. For example, '
633 '--description=YourApplicationDescription')
634 group.add_option('--description', help=info)
635 group.add_option('--enable-remote-debugging', action='store_true',
636 dest='enable_remote_debugging', default=False,
637 help='Enable remote debugging.')
638 info = ('The list of external extension paths splitted by OS separators. '
639 'The separators are \':\' , \';\' and \':\' on Linux, Windows and '
640 'Mac OS respectively. For example, '
641 '--extensions=/path/to/extension1:/path/to/extension2.')
642 group.add_option('--extensions', help=info)
643 group.add_option('-f', '--fullscreen', action='store_true',
644 dest='fullscreen', default=False,
645 help='Make application fullscreen.')
646 group.add_option('--keep-screen-on', action='store_true', default=False,
647 help='Support keeping screen on')
648 info = ('The path of application icon. '
649 'Such as: --icon=/path/to/your/customized/icon')
650 group.add_option('--icon', help=info)
651 info = ('The orientation of the web app\'s display on the device. '
652 'For example, --orientation=landscape. The default value is '
653 '\'unspecified\'. The permitted values are from Android: '
654 'http://developer.android.com/guide/topics/manifest/'
655 'activity-element.html#screen')
656 group.add_option('--orientation', help=info)
657 info = ('The list of permissions to be used by web application. For example, '
658 '--permissions=geolocation:webgl')
659 group.add_option('--permissions', help=info)
660 info = ('Packaging tool will move the output APKS to the target directory')
661 group.add_option('--target-dir', default=os.getcwd(), help=info)
662 parser.add_option_group(group)
663 group = optparse.OptionGroup(parser, 'Keystore Options',
664 'The keystore is a signature from web developer, it\'s used when '
665 'developer wants to distribute the applications.')
666 info = ('The path to the developer keystore. For example, '
667 '--keystore-path=/path/to/your/developer/keystore')
668 group.add_option('--keystore-path', help=info)
669 info = ('The alias name of keystore. For example, --keystore-alias=name')
670 group.add_option('--keystore-alias', help=info)
671 info = ('The passcode of keystore. For example, --keystore-passcode=code')
672 group.add_option('--keystore-passcode', help=info)
673 info = ('Passcode for alias\'s private key in the keystore, '
674 'For example, --keystore-alias-passcode=alias-code')
675 group.add_option('--keystore-alias-passcode', help=info)
676 info = ('Minify and obfuscate javascript and css.'
677 '--compressor: compress javascript and css.'
678 '--compressor=js: compress javascript.'
679 '--compressor=css: compress css.')
680 group.add_option('--compressor', dest='compressor', action='callback',
681 callback=ParseParameterForCompressor, type='string',
683 parser.add_option_group(group)
684 options, _ = parser.parse_args()
690 if os.path.isfile('VERSION'):
691 print(GetVersion('VERSION'))
694 parser.error('VERSION was not found, so Crosswalk\'s version could not '
699 xpk_name = os.path.splitext(os.path.basename(options.xpk))[0]
700 xpk_temp_dir = xpk_name + '_xpk'
701 ParseXPK(options, xpk_temp_dir)
703 if options.app_root and not options.manifest:
704 manifest_path = os.path.join(options.app_root, 'manifest.json')
705 if os.path.exists(manifest_path):
706 print('Using manifest.json distributed with the application.')
707 options.manifest = manifest_path
711 if not options.manifest:
712 # The checks here are really convoluted, but at the moment make_apk
713 # misbehaves any of the following conditions is true.
715 # 1) --app-url must be passed without either --app-local-path or
717 if options.app_root or options.app_local_path:
718 parser.error('You must pass either "--app-url" or "--app-local-path" '
719 'with "--app-root", but not all.')
721 # 2) --app-url is not passed but only one of --app-local-path and
723 if bool(options.app_root) != bool(options.app_local_path):
724 parser.error('You must specify both "--app-local-path" and '
726 # 3) None of --app-url, --app-local-path and --app-root are passed.
727 elif not options.app_root and not options.app_local_path:
728 parser.error('You must pass either "--app-url" or "--app-local-path" '
729 'with "--app-root".')
731 if options.permissions:
732 permission_list = options.permissions.split(':')
734 print('Warning: all supported permissions on Android port are added. '
735 'Refer to https://github.com/crosswalk-project/'
736 'crosswalk-website/wiki/Crosswalk-manifest')
737 permission_list = permission_mapping_table.keys()
738 options.permissions = HandlePermissionList(permission_list)
739 options.icon_dict = {}
742 manifest = ParseManifest(options)
743 except SystemExit as ec:
747 parser.error('An APK name is required. Please use the "--name" option.')
748 VerifyAppName(options.name)
750 if not options.package:
751 parser.error('A package name is required. Please use the "--package" '
753 VerifyAppName(options.package, 'packagename')
755 if (options.app_root and options.app_local_path and
756 not os.path.isfile(os.path.join(options.app_root,
757 options.app_local_path))):
758 print('Please make sure that the local path file of launching app '
762 if options.target_dir:
763 target_dir = os.path.abspath(os.path.expanduser(options.target_dir))
764 options.target_dir = target_dir
765 if not os.path.isdir(target_dir):
766 os.makedirs(target_dir)
769 MakeApk(options, app_info, manifest)
770 except SystemExit as ec:
771 CleanDir(app_info.android_name)
773 CleanDir(xpk_temp_dir)
778 if __name__ == '__main__':
779 sys.exit(main(sys.argv))