def build_xcode_project(args): """调用方法: python ~/apk-builder/xcode_builder.py -a ipa --ipa SDK_V5 -p FLGamePlatformDemo -s FLGamePlatformDemoRelease --clean 工作步骤: 1. XCode项目打包 2. 重命名ipa为 %(ipa_name)s_v%(code_ver)s_r%(repo_ver)s_b%(build_num)s.ipa 例如: SDK_V5_v5.1.56_r168988_b62.jar 3. create ota plist """ # 1. build xcode project and export ipa Command.xcodebuild_ipa(project=args.project + '.xcodeproj', scheme=args.scheme, export=args.export, plist=args.plist, is_clean=args.clean, dry_run=args.dry_run) print 'ipa file name:', args.ipa_name # 2. rename ipa_name = '%(ipa_name)s_v%(code_ver)s_r%(repo_ver)s_b%(build_num)s.ipa' % { 'ipa_name': args.ipa_name, 'code_ver': read_version_from_project(), 'repo_ver': Command.git_ver('..', do_update=False) if args.git else Command.svn_ver('..', do_update=False), 'build_num': os.environ.get('BUILD_NUMBER') } rename_cmd = 'mv %(export_path)s/%(scheme_name)s.ipa %(export_path)s/%(ipa_name)s' % { 'scheme_name': args.scheme, 'export_path': args.export, 'ipa_name': ipa_name } (cost, out, err) = Command.excute(rename_cmd, args.dry_run) if len(err) == 0: logging.info('mission done for building [%s]' % ipa_name) else: logging.error('mission failed for building [%s]' % ipa_name) # 3. create ota plist # cp ipa to nginx root path rename_cmd = 'cp %(export_path)s/%(ipa_name)s %(root_path)s' % { 'export_path': args.export, 'ipa_name': ipa_name, 'root_path': args.root_path } (cost, out, err) = Command.excute(rename_cmd, args.dry_run) plistBuddy = PlistBuddy(args.root_path, ipa_name) # create plist plistBuddy.create_ota_plist(os.path.join(args.ipa_url, ipa_name), os.path.join(args.ipa_url, 'icon.png')) # create update links to plist plistBuddy.update_index_html(args.ipa_name, args.ipa_url)
def merge_plugin_and_build_apk(args): """Excute Help: python apk_builder.py -c apk -s /data/game_apks/g103_3 -ch qh -c command type, must be apk -s read source code from this directory -ch witch channel plugin merge to source lftp -c 'open -e "pget -n 4 games/qzgs_201_08211523.rar" sdk:[email protected]' wget https://github.com/dryes/rarlinux/raw/master/rarlinux-5.2.1.tar.gz 操作逻辑说明: 1. init: 初始化工程目录,删除存在的工程目录 2. copy: 复制项目代码到工程目录 3. clean: 清理工程目录中的默认插件代码 4. merge: 把指定插件拷贝到工程目录 5. update: 更新versionName和versionCode 6. build: 打包 7. save: 拷贝到指定目录 - 工作目录 1. sdk-u3d-plugins:根据apk_builder.py路径,从而确定plugins路径; 2. 工程目录(apk_dir, 执行ant release的目录):当前执行命令的路径下的build_<plugin name>目录,即 os.getcwd()/build_<plugin name> - 渠道打包命名规则 应用名称_渠道编码-应用目录名-插件版本号.apk 应用举例:g20_exit/g20_noexit 插件举例:p23 - 对应的git revision """ Command.set_log_level(logging.DEBUG) status = 'init' game_dir = args.src channel = args.channel apk_dir = os.path.join(os.getcwd(), 'build_%s' % channel) plugin_dir = sys.path[0] logging.info('[%s] running_dir = %s, plugin_dir = %s, building_dir = %s' % (status, os.getcwd(), plugin_dir, apk_dir)) revision = Command.git_ver(plugin_dir) if len(revision) == 0: print 'revision missing' logging.warn('revision missing') if os.path.exists(apk_dir): print 'apk_dir exists, you should delete before build.' return -1 apk_name = channel + '-' + os.path.basename(game_dir) # 拷贝母包 status = 'copy' (cost, out, err) = Command.excute('cp -R %s %s' % (game_dir, apk_dir), args.dry_run) logging.info('[%s] from_dir = %s, to_dir = %s' % (status, game_dir, apk_dir)) # 母包初始化 logging.info('[clean] Clean and Init Project...') clean_and_init_project(apk_dir) # cp channel keystore & ant.properties logging.info('[merge] Add build config for channel[%s] to Project...' % channel) keystore = os.path.join(plugin_dir, 'keys.%s/%s.keystore' % (args.app, channel)) ant_p = os.path.join(plugin_dir, 'keys.%s/ant_%s.properties' % (args.app, channel)) if os.path.exists(keystore) and os.path.exists(ant_p): (cost, out, err) = Command.excute('cp %s %s' % (keystore, apk_dir), args.dry_run) (cost, out, err) = Command.excute('cp %s %s/ant.properties' % (ant_p, apk_dir), args.dry_run) (cost, out, err) = Command.excute( 'cp -Rv %s/plugin_%s/* %s' % (plugin_dir, channel, apk_dir), args.dry_run) # change versionCode&versionName in AndroidManifest.xml cmd = '''sed -i.bak -r '{s/android:versionCode=\s*\"[0-9]{1,}\"/android:versionCode=\"%s\"/g;s/android:versionName=\s*\"[^"]+\"/android:versionName=\"%s\"/g}' %s/AndroidManifest.xml''' % ( args.versioncode, args.versionname, apk_dir) (cost, out, err) = Command.excute(cmd) if len(err) > 0: logging.warn( '[build] Failed to set versionCode & versionName. stderr=%s' % err) status = 'build' (cost, out, err) = Command.excute( 'android update project -p %s -n %s -t %s' % (apk_dir, apk_name, args.target), args.dry_run) cmd_build_apk = 'ant -f %s/build.xml clean release' % apk_dir (cost, out, err) = Command.excute(cmd_build_apk, args.dry_run) if len(err) == 0: logging.info('[%s] Build Project to APK, channel=%s' % (status, channel)) else: # add last 15 lines ant build output in log if len(out.split('\n')) > 15: out = '\n'.join(out.split('\n')[-15:]) logging.error( 'Failed to build APK, channel=%s, cmd=%s, ----err-----%s\n------details-----\n%s' % (channel, cmd_build_apk, err, out)) apk_save_to = apk_name + '-p' + revision + '-release_vc' + args.versioncode + '.apk' status = 'cp' cmd_cp_apk = 'cp %s/bin/%s %s' % (apk_dir, apk_name + '-release.apk', apk_save_to) (cost, out, err) = Command.excute(cmd_cp_apk, args.dry_run) logging.info('[%s] cp apk to running_dir, cmd=%s' % (status, cmd_cp_apk)) if len(err) > 0: logging.error('Failed to copy apk. stderr=%s' % err) status = 'mv' if None != os.environ.get('BUILD_NUMBER'): apk_mv_to = os.path.join(os.environ.get('WORKSPACE'), 'game_apks', os.environ.get('BUILD_NUMBER')) if not os.path.exists(apk_mv_to): os.mkdir(apk_mv_to) cmd_mv_apk = 'mv %s %s' % (apk_save_to, apk_mv_to) (cost, out, err) = Command.excute(cmd_mv_apk, args.dry_run) logging.info('[%s] mv apk to jenkins workspace, cmd=%s' % (status, cmd_mv_apk)) if len(err) > 0: logging.error('Failed to mv apk. stderr=%s' % err) if len(err) == 0: logging.info('[%s]mission done!' % channel) else: logging.error('[%s]mission failed.' % channel) logging.info('======================================')