Ejemplo n.º 1
0
def buildTarget():
    archivePath = getArchivePath()
    profileUUID = Common.getCmdResult(
        "/usr/libexec/PlistBuddy -c 'Print UUID' " + getTmpPlistPath())

    p12Path = getAbspath("p12_path")
    p12Password = m_jsonObj["p12_password"]
    f = open(p12Path, 'rb')
    p12 = load_pkcs12(f.read(), p12Password)
    sign_key = p12.get_friendlyname()
    team_id = p12.get_certificate().get_subject().OU
    f.close()

    buildParams = ' '.join([
        '-project',
        '%s.xcodeproj' % m_newProjName, '-scheme', m_newSchemeName,
        '-configuration', 'Release', '-archivePath', archivePath, 'archive',
        'build',
        'CODE_SIGN_IDENTITY="%s"' % sign_key,
        'PROVISIONING_PROFILE="%s"' % profileUUID,
        'PRODUCT_BUNDLE_IDENTIFIER="%s"' % m_newBundleId,
        'CODE_SIGN_STYLE="Manual"',
        'DEVELOPMENT_TEAM="%s"' % team_id
    ])

    cmd = 'cd %s/..;xcodebuild %s' % (m_projectDir, buildParams)
    Common.runCmd(cmd)
Ejemplo n.º 2
0
def modifyEnginCompilerFlags(file_recorder):
    if m_isNoDingXiang == "1":
        return

    # 修改 xcode 工程
    projPath = getEngineConfigPath()
    Common.assertExit(os.path.isfile(projPath), '文件 %s 不存在' % projPath)

    file_recorder.record_file(projPath)
    sys.path.append(os.path.join(os.path.dirname(__file__), 'obscure'))
    from modify_pbxproj import XcodeProject
    pbx_obj = XcodeProject.Load(projPath)

    build_phase = pbx_obj.get_build_phases('PBXSourcesBuildPhase',
                                           'libcocos2d iOS')
    build_files = pbx_obj.get_build_files_for_phases(build_phase)
    need_skip_files = []
    if ENGINE_SKIP_PERCENT >= 100:
        need_skip_files = build_files
    else:
        skip_count = int(len(build_files) * ENGINE_SKIP_PERCENT / 100)
        import random
        random.seed()
        random.shuffle(build_files)
        for i in range(skip_count):
            need_skip_files.append(build_files[i])

    for f in need_skip_files:
        setting = {'COMPILER_FLAGS': '-skip-steec'}
        pbx_obj.set_build_file_settings(f, setting)

    if pbx_obj.modified:
        pbx_obj.save()
Ejemplo n.º 3
0
def createNewProj(file_recorder, tmp_files):
    srcDir = os.path.join(m_projectDir, "%s.xcodeproj" % m_projectName)
    dstDir = os.path.join(m_projectDir, "%s.xcodeproj" % m_newProjName)
    FileUtils.copyDirctory(srcDir, dstDir)

    tmp_files.append(dstDir)

    # delete the origin project dir
    # file_recorder.record_folder(srcDir)
    # FileUtils.removeDirectory(srcDir)

    # 拷贝配置文件
    srcFile = os.path.join(m_projectDir, "WeiLeProjV3-mobile.entitlements")
    Common.assertExit(os.path.isfile(srcFile), "文件 %s 不存在" % srcFile)
    dstFile = os.path.join(m_projectDir,
                           "%s-mobile.entitlements" % m_newProjName)
    FileUtils.copyFile(srcFile, dstFile)
    tmp_files.append(dstFile)

    # 修改工程名字
    projFilePath = getProjectConfigPath()
    Sed.replaceContent(m_projectName, m_newProjName, projFilePath)

    # 移除临时文件
    for item in os.listdir(dstDir):
        full_path = os.path.join(dstDir, item)
        if full_path == projFilePath:
            continue

        if os.path.isdir(full_path):
            FileUtils.removeDirectory(full_path)
        elif os.path.isfile(full_path):
            FileUtils.removeFile(full_path)
Ejemplo n.º 4
0
def modifyBundleId():
    Common.runCmd(
        '/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier %s" %s' %
        (m_newBundleId, m_infoPlistPath))
    # 修改推送BundleId
    Common.runCmd(
        '/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier %s" %s' %
        (m_newNotifyBundleId, m_notify_info_plist_path))
Ejemplo n.º 5
0
def findPlistInfoForKey(key):
    tmpPlistPath = getTmpPlistPath()
    cmd = "/usr/libexec/PlistBuddy -c 'Print %s' %s" % (key, tmpPlistPath)
    result = Common.getCmdResult(cmd)
    Common.assertExit(
        result.find(key) == -1,
        "查找字段不存在:key=" + key + "(苹果对证书信息做了修改,请查看桌面/Package/tmp.plist数据格式)")
    return result
Ejemplo n.º 6
0
def getAbspath(key):
    Common.assertExit(m_jsonObj[key], "config配置文件缺少参数key=" + key)

    if os.path.isabs(m_jsonObj[key]):
        return m_jsonObj[key]

    configDir = FileUtils.getFileDirectory(m_configPath)
    return FileUtils.getAbsoluteFromPath(configDir, m_jsonObj[key])
Ejemplo n.º 7
0
def createIPA():
    ipaPath = exportPath()
    archivePath = getArchivePath()

    plistPath = getExportOptionsPlist()
    cmd = "cd %s;xcodebuild -exportArchive -archivePath %s -exportPath %s -exportOptionsPlist %s" % (
        m_projectDir, archivePath, ipaPath, plistPath)
    # print "====== " + ipaPath
    Common.runCmd(cmd)
Ejemplo n.º 8
0
def installNotifyProfile():
    tmpPlistPath = getTmpNotifyPlistPath()
    cmd = "security cms -D -i %s > %s" % (m_notifProfilePath, tmpPlistPath)
    Common.runCmd(cmd)

    # 将profile文件拷贝到系统目录
    uuid = findNotifyPlistInfoForKey("UUID")
    targetFile = "/Users/%s/Library/MobileDevice/Provisioning Profiles/%s.mobileprovision" % (
        Common.getUserName(), uuid)
    FileUtils.copyFile(m_notifProfilePath, targetFile)
Ejemplo n.º 9
0
def copyDingXiangFiles():
    if m_isNoDingXiang != "1":
        curDir = os.path.dirname(__file__)
        chainPath = os.path.join(curDir, "dingxiang/DX-VM.lite.xctoolchain")
        keyPath = os.path.join(curDir, "dingxiang/license.key")
        targetDir = os.path.expanduser(
            os.path.join('~/Library/Developer/Toolchains',
                         'DX-VM.lite.xctoolchain'))
        if os.path.isdir(targetDir):
            shutil.rmtree(targetDir)
        targetFile = os.path.expanduser(
            os.path.join('~/Library/Developer/Toolchains', 'license.key'))
        if os.path.isfile(targetFile):
            os.remove(targetFile)
        Common.runCmd("mkdir -p ~/Library/Developer/Toolchains")
        Common.runCmd("cp -R %s %s ~/Library/Developer/Toolchains" %
                      (chainPath, keyPath))
Ejemplo n.º 10
0
def resEncryptByDirName(dirName):
    encryptScript = os.path.normpath(
        os.path.abspath(
            os.path.join(os.path.dirname(__file__),
                         '../../ResEncrypt/ResEncrypt.py')))
    if None == encryptScript:
        return

    targetDir = os.path.join(m_appPath, dirName)
    Common.assertExit(os.path.isdir(targetDir), "配置games文件不存在:" + dirName)

    ASSETS_ENCRYPT_EXCLUDE_CFG = ["mj_common/images/card_packer/*.png"]

    sys.path.append(os.path.dirname(encryptScript))
    from ResEncrypt import ResEncrypt
    encryptor = ResEncrypt(targetDir, targetDir, True,
                           ASSETS_ENCRYPT_EXCLUDE_CFG, False)
    encryptor.do_encrypt()
Ejemplo n.º 11
0
def modifyVersion():
    Common.runCmd(
        '/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString %s" %s' %
        (m_versionName, m_infoPlistPath))
    Common.runCmd('/usr/libexec/PlistBuddy -c "Set :CFBundleVersion %s" %s' %
                  (m_buildName, m_infoPlistPath))
    # 修改推送版本号,与游戏工程一致
    Common.runCmd(
        '/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString %s" %s' %
        (m_versionName, m_notify_info_plist_path))
    Common.runCmd('/usr/libexec/PlistBuddy -c "Set :CFBundleVersion %s" %s' %
                  (m_buildName, m_notify_info_plist_path))
Ejemplo n.º 12
0
def modifyURLTypes():
    # 修改微信id
    urlName = Plist.getForKey(m_infoPlistPath,
                              "CFBundleURLTypes:0:CFBundleURLName")
    Common.assertBoolType(urlName == "wechatshceme",
                          "info.plist的URL TYPES的第一个值必须是wechatshceme")
    weixinUrlScheme = m_jsonObj["weixin_id"]
    idsArray = weixinUrlScheme.split(",")
    Plist.resetArrayForKey(m_infoPlistPath,
                           "CFBundleURLTypes:0:CFBundleURLSchemes", idsArray)

    # 修改第三个值
    urlName = Plist.getForKey(m_infoPlistPath,
                              "CFBundleURLTypes:2:CFBundleURLName")
    Common.assertBoolType(urlName == "com.weile.www",
                          "info.plist的URL TYPES的第三个值必须是com.weile.www")
    appScheme = m_jsonObj["app_scheme"]
    Plist.setForKey(m_infoPlistPath, "CFBundleURLTypes:2:CFBundleURLSchemes:0",
                    appScheme)
Ejemplo n.º 13
0
def installP12():
    p12Path = getAbspath("p12_path")
    Common.assertExit(os.path.isfile(p12Path), "p12证书文件不存在,请检查配置")

    p12Password = m_jsonObj["p12_password"]
    Common.assertExit(p12Password, "未配置参数p12_password")
    p12Cmd = "security import %s -k /Users/%s/Library/Keychains/login.keychain -P %s -T /usr/bin/codesign" % (
        p12Path, Common.getUserName(), p12Password)
    Common.runCmd(p12Cmd)
Ejemplo n.º 14
0
def buildTarget():
    archivePath = getArchivePath()
    profileUUID = Common.getCmdResult(
        "/usr/libexec/PlistBuddy -c 'Print UUID' " + getTmpPlistPath())

    notifyProfileUUID = Common.getCmdResult(
        "/usr/libexec/PlistBuddy -c 'Print UUID' " + getTmpNotifyPlistPath())

    print 'notifyProfile uuid==%s  m_newNotifyBundleId==%s' % (
        notifyProfileUUID, m_newNotifyBundleId)

    p12Path = getAbspath("p12_path")
    p12Password = m_jsonObj["p12_password"]
    f = open(p12Path, 'rb')
    p12 = load_pkcs12(f.read(), p12Password)
    sign_key = p12.get_friendlyname()
    team_id = p12.get_certificate().get_subject().OU
    f.close()

    buildParams = ' '.join([
        '-project',
        '%s.xcodeproj' % m_newProjName, '-scheme', m_newSchemeName,
        '-configuration', 'Release', '-archivePath', archivePath, 'archive',
        'build',
        'CODE_SIGN_IDENTITY="%s"' % sign_key,
        'APP_PROVISIONING_PROFILE="%s"' % profileUUID,
        'APP_BUNDLE_IDENTIFIER="%s"' % m_newBundleId,
        'EXTENSION_PROFILE="%s"' % notifyProfileUUID,
        'EXTENSION_BUNDLE_IDENTIFIER="%s"' % m_newNotifyBundleId,
        'CODE_SIGN_STYLE="Manual"',
        'DEVELOPMENT_TEAM="%s"' % team_id
    ])
    # 添加顶象加固
    if m_isNoDingXiang != "1":
        buildParams += " DX_FLAGS=-steec-extra-opts=-xse=100,-fla=50,-spli=50"
        buildParams += " -toolchain dx-vm.lite"
    else:
        buildParams += ' DX_FLAGS=""'

    cmd = 'cd %s;xcodebuild %s' % (m_projectDir, buildParams)
    Common.runCmd(cmd)
Ejemplo n.º 15
0
def copyConfigFile(file_recorder):
    targetConfigFile = FileUtils.getAbsolutePath("./shell_script/config.json")
    file_recorder.record_file(targetConfigFile)
    FileUtils.copyFile(m_configPath, targetConfigFile)

    configDir = FileUtils.getFileDirectory(m_configPath)
    sourceCfgDir = os.path.join(configDir, "cfg")
    Common.assertExit(os.path.isdir(sourceCfgDir),
                      "cfg配置文件夹不存在" + sourceCfgDir)

    # 检查 cfg_package 中是否定义了 APPLE_ID
    cfg_pkg_file = os.path.join(sourceCfgDir, "cfg_package.lua")
    Common.assertExit(os.path.isfile(cfg_pkg_file),
                      "cfg配置文件夹中不存在 cfg_package 文件")
    f = open(cfg_pkg_file)
    content = f.read()
    f.close()
    if content.find("APPLE_ID") == -1:
        Common.assertExit(False, "cfg_package 中未配置 APPLE_ID ")

    targetCfgDir = FileUtils.getAbsolutePath("./shell_script/cfg")
    file_recorder.record_folder(targetCfgDir)
    FileUtils.replaceCopyDirctory(sourceCfgDir, targetCfgDir)
Ejemplo n.º 16
0
def loadConfig():
    global m_projectDir
    global m_infoPlistPath
    global m_notify_info_plist_path
    global m_projectName
    global m_schemeName
    global m_versionName
    global m_buildName
    global m_newDisplayName
    global m_newBundleId
    global m_newNotifyBundleId
    global m_archiveType
    global m_profilePath
    global m_notifProfilePath
    global m_configPath
    global m_jsonObj
    global m_outputPath
    global m_games
    global m_newProjName
    global m_newSchemeName
    global m_isNoDingXiang  # 是否不使用顶象加固

    Common.assertExit(len(sys.argv[1:]) != 0, "请传入配置文件绝对路径")
    Common.assertExit(os.path.isfile(sys.argv[1]), "传入参数文件不存在")
    m_configPath = sys.argv[1]

    # print "使用测试配置"
    # m_configPath = "/Users/weile/Desktop/SVN/tools/PackIOS/proj_template/config.json"

    m_jsonObj.loadFromFilePath(m_configPath)

    m_isNoDingXiang = m_jsonObj["isNoDingXiang"]

    m_projectDir = getAbspath("project_dir")
    m_infoPlistPath = getAbspath("info_plist_path")

    m_notify_info_plist_path = FileUtils.getAbsoluteFromPath(
        m_projectDir, "notificationService/Info.plist")

    m_archiveType = m_jsonObj["archive_type"]
    Common.assertExit(m_archiveType == 'AdHoc' or m_archiveType == 'AppStore',
                      "archive_type参数只能是AdHoc和AppStore")
    paths = {
        Archive_Type_Key_AdHoc: getAbspath("profile_path_AdHoc"),
        Archive_Type_Key_AppStore: getAbspath("profile_path_AppStore"),
    }
    m_profilePath = paths[m_archiveType]
    Common.assertExit(os.path.isfile(m_profilePath), "配置证书文件不存在,请检查配置")

    notifyPaths = {
        Archive_Type_Key_AdHoc: getAbspath("notifProfile_path_AdHoc"),
        Archive_Type_Key_AppStore: getAbspath("notifProfile_path_AppStore"),
    }
    m_notifProfilePath = notifyPaths[m_archiveType]
    Common.assertExit(os.path.isfile(m_notifProfilePath),
                      "NotificationService证书文件不存在,请检查配置")

    m_projectName = m_jsonObj["project_name"]
    m_schemeName = m_jsonObj["scheme_name"]
    m_versionName = m_jsonObj["version_name"]
    m_buildName = m_jsonObj["build_name"]
    m_newDisplayName = m_jsonObj["game_name"]
    m_newBundleId = m_jsonObj["pkg_name"]
    m_newNotifyBundleId = m_newBundleId + ".notifyService"
    m_games = m_jsonObj["games"]
    m_newProjName = m_jsonObj["proj_name_new"]

    Common.assertExit(m_jsonObj["app_scheme"], "必须配置app_scheme参数")
    Common.assertExit(m_jsonObj["weixin_id"], "必须配置weixin_id参数")
    Common.assertExit(m_newProjName, "必须配置 proj_name_new 参数")
    Common.assertExit(m_projectName != m_newProjName,
                      "proj_name_new 与 project_name 的值不能相同")

    m_newSchemeName = "%s-mobile" % m_newProjName

    if m_jsonObj["track_id"] is None:
        # track_id 必须配置。如果配置为空字符串,效果与不集成热云 SDK 一致
        Common.assertExit(False, "必须配置track_id参数,请联系商务获取热云的 app key")
    if (not m_jsonObj["getui_appId"] or not m_jsonObj["getui_appKey"]
            or not m_jsonObj["getui_appSecret"]
        ) and m_jsonObj["turnOffPush"] != "1":
        # getui 必须配置。如不需要getui需要在config.json文件里添加"turnOffPush": "1"
        Common.assertExit(False, "必须配置getui参数,个推后台获取")

    Common.assertExit(m_jsonObj["region"],
                      '必须配置region参数,值为地区码字符串。如:"region":"23"')
    Common.assertExit(m_jsonObj["build_name"], "必须配置build_name参数")

    if m_jsonObj["output"]:
        m_outputPath = getAbspath("output")
    else:
        m_outputPath = None
Ejemplo n.º 17
0
def modifyDisplayName():
    cmd = '/usr/libexec/PlistBuddy -c "Set :CFBundleDisplayName %s" %s' % (
        m_newDisplayName, m_infoPlistPath)
    Common.runCmd(cmd)
Ejemplo n.º 18
0
def modifyVersion():
    Common.runCmd(
        '/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString %s" %s' %
        (m_versionName, m_infoPlistPath))
    Common.runCmd('/usr/libexec/PlistBuddy -c "Set :CFBundleVersion %s" %s' %
                  (m_buildName, m_infoPlistPath))
Ejemplo n.º 19
0
def cleanTarget():
    Common.runCmd(
        'cd %s/..;xcodebuild clean -project "%s.xcodeproj" -alltargets' %
        (m_projectDir, m_newProjName))
Ejemplo n.º 20
0
def loadConfig():
    global m_appPath
    global m_jsonObj

    Common.assertExit(len(sys.argv[1:]) != 0, "请传入配置文件绝对路径")
    Common.assertExit(os.path.isdir(sys.argv[1]), "传入参数文件夹不存在")
    m_appPath = sys.argv[1]

    configPath = FileUtils.getAbsolutePath("config.json")
    m_jsonObj = JsonObj()
    m_jsonObj.loadFromFilePath(configPath)

    Common.assertExit(Common.isArrayType(m_jsonObj[kGames]), "必须设置参数games")
    Common.assertExit(m_jsonObj[kCfgFiles], "必须设置参数cfg_files")
    Common.assertExit(m_jsonObj[kPkgName], "必须设置参数pkg_name")
    Common.assertExit(m_jsonObj[kRegion], "必须设置参数region")
Ejemplo n.º 21
0
def genResFilesInfo(file_recorder):
    headerPath = os.path.join(m_projectDir, RES_INFO_HEADER_PATH)
    Common.assertExit(os.path.isfile(headerPath), '%s 文件不存在' % headerPath)

    # 扫描需要记录的文件信息
    curDir = os.path.dirname(__file__)
    hallRoot = os.path.dirname(os.path.dirname(curDir))
    srcPath = os.path.join(hallRoot, 'src')
    resPath = os.path.join(hallRoot, 'res')
    gamesDir = os.path.join(os.path.dirname(hallRoot), 'games')
    cfgDir = os.path.join(curDir, 'shell_script/cfg')
    relative_paths = {}
    scanDirs = {srcPath: 'src', resPath: 'res', cfgDir: 'src'}

    for g in m_games:
        key = os.path.join(gamesDir, g)
        scanDirs[key] = ('games/%s' % g)

    # 先把 NativeInfo.lua 加进去
    native_info_path = "src/NativeInfo.lua"
    rel_path = convertFilePath(native_info_path)
    relative_paths[rel_path] = getHashCode(rel_path)
    for dir in scanDirs:
        prefix = scanDirs[dir]
        Common.assertExit(os.path.isdir(dir), "%s 文件夹不存在" % dir)
        for parent, dirs, files in os.walk(dir):
            for f in files:
                if f == '.git' or f == '.DS_Store':
                    continue

                full_path = os.path.join(parent, f)
                rel_path = os.path.relpath(full_path, dir)
                rel_path.lstrip('./')
                if len(prefix) > 0:
                    rel_path = '%s/%s' % (prefix, rel_path)

                rel_path = convertFilePath(rel_path)
                if not relative_paths.has_key(rel_path):
                    relative_paths[rel_path] = getHashCode(rel_path)

    file_recorder.record_file(headerPath)

    # 写文件
    f = open(headerPath)
    lines = f.readlines()
    f.close()

    dumpLines = []
    newLines = []
    for line in lines:
        newLines.append(line)
        if line.find(INSERT_BEGIN_KEYWORDS) > 0:
            # 插入数据
            for key in relative_paths.keys():
                dumpLines.append('"%s" : "%s"' % (key, relative_paths[key]))
                newLines.append(INSERT_LINE_TEMPLATE %
                                (key, relative_paths[key]))

    f = open(headerPath, 'w')
    f.writelines(newLines)
    f.close()

    cur_time_str = datetime.datetime.fromtimestamp(
        time.time()).strftime('%Y%m%d_%H%M%S')
    dumpFileName = 'DumpPathMap_%s.json' % cur_time_str
    dumpContent = '{\n%s\n}\n' % ',\n'.join(dumpLines)
    f = open(os.path.join(getIpaDir(), dumpFileName), 'w')
    f.write(dumpContent)
    f.close()
Ejemplo n.º 22
0
def loadConfig():
    global m_projectDir
    global m_infoPlistPath
    global m_projectName
    global m_schemeName
    global m_versionName
    global m_buildName
    global m_newDisplayName
    global m_newBundleId
    global m_archiveType
    global m_profilePath
    global m_configPath
    global m_jsonObj
    global m_outputPath
    global m_games
    global m_newProjName
    global m_newSchemeName

    Common.assertExit(len(sys.argv[1:]) != 0, "请传入配置文件绝对路径")
    Common.assertExit(os.path.isfile(sys.argv[1]), "传入参数文件不存在")
    m_configPath = sys.argv[1]

    # print "使用测试配置"
    # m_configPath = "/Users/weile/Desktop/SVN/tools/PackIOS/proj_template/config.json"

    # "game_name": "家乡棋牌·微乐",
    # "pkg_name": "com.wljiaxiang.mj",
    # "version_name": "1.1.1",
    # "build_name": "1.1.1.7",

    m_jsonObj.loadFromFilePath(m_configPath)

    m_projectDir = os.path.join(os.path.dirname(__file__),
                                "proj.ios.demo/com.weile.test")
    m_infoPlistPath = os.path.join(m_projectDir, "Info.plist")

    m_archiveType = m_jsonObj["archive_type"]
    Common.assertExit(m_archiveType == 'AdHoc' or m_archiveType == 'AppStore',
                      "archive_type参数只能是AdHoc和AppStore")
    paths = {
        Archive_Type_Key_AdHoc: getAbspath("profile_path_AdHoc"),
        Archive_Type_Key_AppStore: getAbspath("profile_path_AppStore"),
    }
    m_profilePath = paths[m_archiveType]
    Common.assertExit(os.path.isfile(m_profilePath), "配置证书文件不存在,请检查配置")

    m_projectName = "demo"
    m_schemeName = "com.weile.test"
    m_versionName = m_jsonObj["version_name"]
    m_buildName = m_jsonObj["build_name"]
    m_newDisplayName = m_jsonObj["game_name"]
    m_newBundleId = m_jsonObj["pkg_name"]
    m_newProjName = m_jsonObj["proj_name_new"]

    Common.assertExit(m_newProjName, "必须配置 proj_name_new 参数")
    Common.assertExit(m_projectName != m_newProjName,
                      "proj_name_new 与 project_name 的值不能相同")

    m_newSchemeName = m_newProjName

    Common.assertExit(m_jsonObj["build_name"], "必须配置build_name参数")

    if m_jsonObj["output"]:
        m_outputPath = getAbspath("output")
    else:
        m_outputPath = None
Ejemplo n.º 23
0
        for parent, dirs, files in os.walk(srcPath):
            for f in files:
                full_path = os.path.join(parent, f)
                rel_path = os.path.relpath(full_path, m_appPath)
                target_path = os.path.join(m_appPath, getHashPath(rel_path))
                target_dir = os.path.dirname(target_path)
                if not os.path.isdir(target_dir):
                    os.makedirs(target_dir)
                shutil.copy2(full_path, target_path)

        # 移除原始文件
        shutil.rmtree(srcPath)


if __name__ == "__main__":
    Common.assertExit(len(sys.argv[2:]) != 0, "第二个参数不能为空,必须是${CONFIGURATION}")

    # Debug版本不处理
    appPath = sys.argv[1]
    srcPath = os.path.join(appPath, "src")

    # 读取配置表
    loadConfig()

    # 生成 native 环境信息文件
    utils.write_native_info(os.path.join(srcPath, 'NativeInfo.lua'), {
        "no_agora": "true",
        "ios_no_h5": "true"
    })

    if sys.argv[2] == "Debug":