Browse Source

初始化仓库

#Suyghur 3 years ago
parent
commit
79bb3a6bf1
63 changed files with 9908 additions and 9578 deletions
  1. 221 221
      ReplaceJar&Res.py
  2. 134 127
      common_utils.py
  3. 122 119
      config_utils.py
  4. 84 84
      config_utils_record.py
  5. 76 76
      config_utils_shanshen.py
  6. 654 562
      file_utils.py
  7. 58 58
      game_utils.py
  8. 2 2
      package.py
  9. 177 177
      package_channel.py
  10. 92 92
      package_channel_douyou.py
  11. 2 2
      package_record.py
  12. 2 2
      package_shanshen.py
  13. 65 65
      package_test.py
  14. 1631 1473
      package_utils.py
  15. 1246 1246
      package_utils_record.py
  16. 1074 1074
      package_utils_shanshen.py
  17. 1322 1322
      package_utils_yfsdk.py
  18. 361 298
      package_web.py
  19. 313 313
      package_web_record.py
  20. 212 212
      package_web_shanshen.py
  21. 204 204
      package_web_yfsdk.py
  22. 2 2
      package_yfsdk.py
  23. 15 15
      readme.txt
  24. 235 235
      sdk/jm_zy_ysdk/script/sdk_script.py
  25. 47 47
      sdk/shanshen/script/sdk_script.py
  26. 6 6
      sdk_script/jm.py
  27. 27 27
      sdk_script/jm_baidu.py
  28. 26 26
      sdk_script/jm_bamen.py
  29. 25 25
      sdk_script/jm_beiyu.py
  30. 7 0
      sdk_script/jm_beta_sdk.py
  31. 22 22
      sdk_script/jm_erjiuyouaz.py
  32. 27 27
      sdk_script/jm_guopan.py
  33. 28 28
      sdk_script/jm_haixin.py
  34. 24 24
      sdk_script/jm_hongshouzhi.py
  35. 27 27
      sdk_script/jm_huawei.py
  36. 20 20
      sdk_script/jm_jianguo.py
  37. 27 27
      sdk_script/jm_jinli.py
  38. 24 24
      sdk_script/jm_jq.py
  39. 27 27
      sdk_script/jm_kupai.py
  40. 19 19
      sdk_script/jm_landie.py
  41. 26 26
      sdk_script/jm_lianxiang.py
  42. 27 27
      sdk_script/jm_meizu.py
  43. 26 26
      sdk_script/jm_moye.py
  44. 26 26
      sdk_script/jm_oppo.py
  45. 21 21
      sdk_script/jm_quick.py
  46. 27 27
      sdk_script/jm_qytx.py
  47. 30 30
      sdk_script/jm_tianyu.py
  48. 45 45
      sdk_script/jm_tianyuyou.py
  49. 26 26
      sdk_script/jm_tt.py
  50. 28 28
      sdk_script/jm_xiaoqi.py
  51. 28 28
      sdk_script/jm_xingmuyou.py
  52. 38 38
      sdk_script/jm_xq.py
  53. 20 20
      sdk_script/jm_yaodian.py
  54. 20 20
      sdk_script/jm_yijie.py
  55. 30 30
      sdk_script/jm_yiwan.py
  56. 38 38
      sdk_script/jm_ysdk.py
  57. 54 54
      sdk_script/jm_zy_ysdk.py
  58. 62 62
      smali_utils.py
  59. BIN
      tools/linux/lib64/libc++.so
  60. 0 0
      tools/macos/aapt
  61. 0 0
      tools/macos/aapt2
  62. 0 0
      tools/macos/zipalign
  63. 649 649
      xml_utils.py

+ 221 - 221
ReplaceJar&Res.py

@@ -1,221 +1,221 @@
-#! /usr/bin/python
-# -*- coding: UTF-8 -*-
-
-# coding: utf-8
-
-import os,sys
-import random
-import string
-import re
-import time
-import json
-import shutil
-import hashlib
-import time
-import argparse
-import file_utils
-
-import sys
-
-script_path = os.path.split(os.path.realpath(sys.argv[0]))[0]
-currentSdkpath = script_path + '/currentSdk'
-sdkpath = script_path + '/sdk'
-
-
-ignore_path_text = [".a", ".storyboard", ".py",".framework",".DS_Store",".xcuserstate",".jpg",".png"]
-
-ignore_sdk = ['yfsdk']
-
-keyFile = 'zooKeys.json'
-
-
-
-
-def replaceJarNameInFile(full_path, new_text, old_text, tag):
-    with open(full_path, "r") as fileObj:
-        all_text = fileObj.read()
-        fileObj.close()
-    if old_text:
-        oldjar = "%s_%s.jar" % (tag, old_text)
-        newjar = "%s_%s.jar" % (tag, new_text)
-        all_text = all_text.replace(oldjar, newjar)
-        print ("\t替换: %s -> %s" % (oldjar, newjar))
-        with open(full_path, "w") as fileObj:
-            fileObj.write(all_text)
-            fileObj.close()
-    else:
-        print ('cant not find old text')
-
-
-
-def getoldJarDate(full_path):
-    with open(full_path, "r") as fileObj:
-        all_text = fileObj.read()
-        fileObj.close()
-        # 提取jar包日期
-    old_text = (re.findall(r'jm_sdk_([^.jar]+)', all_text)[0])
-    return old_text
-
-def getoldNopayJarDate(full_path):
-    with open(full_path, "r") as fileObj:
-        all_text = fileObj.read()
-        fileObj.close()
-        # 提取jar包日期
-    if all_text.find("jm_sdk_nopay") > -1:
-        old_text = (re.findall(r'jm_sdk_nopay_([^.jar]+)', all_text)[0])
-        return old_text
-    return ""
-
-def replaceNopayJar():
-    global  sdkpath
-    global  currentSdkpath
-    print ('start replace jar ...')
-    print (sdkpath)
-    jarName = ''
-    for parent, folders, files in os.walk(currentSdkpath):
-        for file in files:
-            if file.find(".jar") > -1 and file.find("nopay") > -1:
-                jarName = file
-                print('jarName -->'+ jarName)
-    fullJarPath = os.path.join(currentSdkpath,jarName)
-    newDate = (re.findall(r'jm_sdk_nopay_([^.jar]+)', jarName)[0])
-
-    #修改config字段 及替换Jar包
-    list = os.listdir(sdkpath)
-    for l in list:
-        if l in ignore_sdk:
-            continue
-        full_l_path = os.path.join(sdkpath,l)
-        full_lib_path = os.path.join(full_l_path,'libs')
-        if os.path.isdir(full_l_path):
-            configPath = os.path.join(full_l_path,'libs/config.json')
-            configPath = os.path.normcase(configPath)
-            if os.path.exists(configPath):
-                print(configPath)
-                oldDate = getoldNopayJarDate(configPath)
-                if oldDate == "":
-                    continue
-                # 修改config字段
-                replaceJarNameInFile(configPath,newDate,oldDate,"jm_sdk_nopay")
-                oldJarPath = '%s/jm_sdk_nopay_%s.jar' % (full_lib_path,oldDate)
-                #删除旧文件
-                if os.path.exists(oldJarPath):
-                    print ('delete ---> %s' % oldJarPath)
-                    try:
-                        os.remove(os.path.normcase(oldJarPath))
-                    except Exception as e:
-                        print (e)
-                    else:
-                        print("File is deleted successfully")
-                newJarPath = '%s/jm_sdk_nopay_%s.jar' % (full_lib_path,newDate)
-                print('复制: %s ---> %s' % (fullJarPath,newJarPath))
-                shutil.copyfile(fullJarPath, newJarPath)  # 复制文件
-
-                print('-------------------------')
-
-    print ("\nfinished replace jar")
-
-
-
-######修改config字段 及替换Jar包
-def replaceJar():
-    global  sdkpath
-    global  currentSdkpath
-    print ('start replace jar ...')
-    print (sdkpath)
-    jarName = ''
-    for parent, folders, files in os.walk(currentSdkpath):
-        for file in files:
-            if file.find(".jar") > -1 and file.find("nopay") < 1:
-                jarName = file
-                print('jarName -->'+ jarName)
-    fullJarPath = os.path.join(currentSdkpath,jarName)
-    newDate = (re.findall(r'jm_sdk_([^.jar]+)', jarName)[0])
-
-    #修改config字段 及替换Jar包
-    list = os.listdir(sdkpath)
-    for l in list:
-        if l in ignore_sdk:
-            continue
-        full_l_path = os.path.join(sdkpath,l)
-        full_lib_path = os.path.join(full_l_path,'libs')
-        if os.path.isdir(full_l_path):
-            configPath = os.path.join(full_l_path,'libs/config.json')
-            configPath = os.path.normcase(configPath)
-            if os.path.exists(configPath):
-                print(configPath)
-                oldDate = getoldJarDate(configPath)
-                # 修改config字段
-                replaceJarNameInFile(configPath,newDate,oldDate,"jm_sdk")
-                oldJarPath = '%s/jm_sdk_%s.jar' % (full_lib_path,oldDate)
-                #删除旧文件
-                if os.path.exists(oldJarPath):
-                    print ('delete ---> %s' % oldJarPath)
-                    try:
-                        os.remove(os.path.normcase(oldJarPath))
-                    except Exception as e:
-                        print (e)
-                    else:
-                        print("File is deleted successfully")
-                newJarPath = '%s/jm_sdk_%s.jar' % (full_lib_path,newDate)
-                print('复制: %s ---> %s' % (fullJarPath,newJarPath))
-                shutil.copyfile(fullJarPath, newJarPath)  # 复制文件
-
-                print('-------------------------')
-
-    print ("\nfinished replace jar")
-
-
-######替换Res
-def replaceRes():
-    global  sdkpath
-    global  currentSdkpath
-    print ('start replace jar ...')
-    resPath = os.path.join(currentSdkpath,"res")
-    #print (resPath)
-    list = os.listdir(sdkpath)
-    for l in list:
-        if l.find("jm") > -1:
-            des_res_path = os.path.join(sdkpath,l,"res")
-            print (des_res_path)
-            file_utils.copyDir(resPath,des_res_path)
-
-    #修改config字段 及替换Jar包
-    # for l in list:
-    #     full_l_path = os.path.join(sdkpath,l)
-    #     full_lib_path = os.path.join(full_l_path,'libs')
-    #     if os.path.isdir(full_l_path):
-    #         configPath = os.path.join(full_l_path,'libs/config.json')
-    #         configPath = os.path.normcase(configPath)
-    #         if os.path.exists(configPath):
-    #             print(configPath)
-    #             oldDate = getoldJarDate(configPath)
-    #             # 修改config字段
-    #             replaceJarNameInFile(configPath,newDate,oldDate)
-    #             oldJarPath = '%s/jm_sdk_%s.jar' % (full_lib_path,oldDate)
-    #             #删除旧文件
-    #             if os.path.exists(oldJarPath):
-    #                 print ('delete ---> %s' % oldJarPath)
-    #                 try:
-    #                     os.remove(os.path.normcase(oldJarPath))
-    #                 except Exception as e:
-    #                     print (e)
-    #                 else:
-    #                     print("File is deleted successfully")
-    #             newJarPath = '%s/jm_sdk_%s.jar' % (full_lib_path,newDate)
-    #             print('复制: %s ---> %s' % (fullJarPath,newJarPath))
-    #             shutil.copyfile(fullJarPath, newJarPath)  # 复制文件
-    #
-    #             print('-------------------------')
-
-    print ("\nfinished replace res")
-
-def main():
-    #replaceJar()
-    replaceNopayJar()
-	#####修改了资源文件,要替换#####
-    #replaceRes()
-
-
-if __name__ == "__main__":
-    main()
+#! /usr/bin/python
+# -*- coding: UTF-8 -*-
+
+# coding: utf-8
+
+import os,sys
+import random
+import string
+import re
+import time
+import json
+import shutil
+import hashlib
+import time
+import argparse
+import file_utils
+
+import sys
+
+script_path = os.path.split(os.path.realpath(sys.argv[0]))[0]
+currentSdkpath = script_path + '/currentSdk'
+sdkpath = script_path + '/sdk'
+
+
+ignore_path_text = [".a", ".storyboard", ".py",".framework",".DS_Store",".xcuserstate",".jpg",".png"]
+
+ignore_sdk = ['yfsdk']
+
+keyFile = 'zooKeys.json'
+
+
+
+
+def replaceJarNameInFile(full_path, new_text, old_text, tag):
+    with open(full_path, "r") as fileObj:
+        all_text = fileObj.read()
+        fileObj.close()
+    if old_text:
+        oldjar = "%s_%s.jar" % (tag, old_text)
+        newjar = "%s_%s.jar" % (tag, new_text)
+        all_text = all_text.replace(oldjar, newjar)
+        print ("\t替换: %s -> %s" % (oldjar, newjar))
+        with open(full_path, "w") as fileObj:
+            fileObj.write(all_text)
+            fileObj.close()
+    else:
+        print ('cant not find old text')
+
+
+
+def getoldJarDate(full_path):
+    with open(full_path, "r") as fileObj:
+        all_text = fileObj.read()
+        fileObj.close()
+        # 提取jar包日期
+    old_text = (re.findall(r'jm_sdk_([^.jar]+)', all_text)[0])
+    return old_text
+
+def getoldNopayJarDate(full_path):
+    with open(full_path, "r") as fileObj:
+        all_text = fileObj.read()
+        fileObj.close()
+        # 提取jar包日期
+    if all_text.find("jm_sdk_nopay") > -1:
+        old_text = (re.findall(r'jm_sdk_nopay_([^.jar]+)', all_text)[0])
+        return old_text
+    return ""
+
+def replaceNopayJar():
+    global  sdkpath
+    global  currentSdkpath
+    print ('start replace jar ...')
+    print (sdkpath)
+    jarName = ''
+    for parent, folders, files in os.walk(currentSdkpath):
+        for file in files:
+            if file.find(".jar") > -1 and file.find("nopay") > -1:
+                jarName = file
+                print('jarName -->'+ jarName)
+    fullJarPath = os.path.join(currentSdkpath,jarName)
+    newDate = (re.findall(r'jm_sdk_nopay_([^.jar]+)', jarName)[0])
+
+    #修改config字段 及替换Jar包
+    list = os.listdir(sdkpath)
+    for l in list:
+        if l in ignore_sdk:
+            continue
+        full_l_path = os.path.join(sdkpath,l)
+        full_lib_path = os.path.join(full_l_path,'libs')
+        if os.path.isdir(full_l_path):
+            configPath = os.path.join(full_l_path,'libs/config.json')
+            configPath = os.path.normcase(configPath)
+            if os.path.exists(configPath):
+                print(configPath)
+                oldDate = getoldNopayJarDate(configPath)
+                if oldDate == "":
+                    continue
+                # 修改config字段
+                replaceJarNameInFile(configPath,newDate,oldDate,"jm_sdk_nopay")
+                oldJarPath = '%s/jm_sdk_nopay_%s.jar' % (full_lib_path,oldDate)
+                #删除旧文件
+                if os.path.exists(oldJarPath):
+                    print ('delete ---> %s' % oldJarPath)
+                    try:
+                        os.remove(os.path.normcase(oldJarPath))
+                    except Exception as e:
+                        print (e)
+                    else:
+                        print("File is deleted successfully")
+                newJarPath = '%s/jm_sdk_nopay_%s.jar' % (full_lib_path,newDate)
+                print('复制: %s ---> %s' % (fullJarPath,newJarPath))
+                shutil.copyfile(fullJarPath, newJarPath)  # 复制文件
+
+                print('-------------------------')
+
+    print ("\nfinished replace jar")
+
+
+
+######修改config字段 及替换Jar包
+def replaceJar():
+    global  sdkpath
+    global  currentSdkpath
+    print ('start replace jar ...')
+    print (sdkpath)
+    jarName = ''
+    for parent, folders, files in os.walk(currentSdkpath):
+        for file in files:
+            if file.find(".jar") > -1 and file.find("nopay") < 1:
+                jarName = file
+                print('jarName -->'+ jarName)
+    fullJarPath = os.path.join(currentSdkpath,jarName)
+    newDate = (re.findall(r'jm_sdk_([^.jar]+)', jarName)[0])
+
+    #修改config字段 及替换Jar包
+    list = os.listdir(sdkpath)
+    for l in list:
+        if l in ignore_sdk:
+            continue
+        full_l_path = os.path.join(sdkpath,l)
+        full_lib_path = os.path.join(full_l_path,'libs')
+        if os.path.isdir(full_l_path):
+            configPath = os.path.join(full_l_path,'libs/config.json')
+            configPath = os.path.normcase(configPath)
+            if os.path.exists(configPath):
+                print(configPath)
+                oldDate = getoldJarDate(configPath)
+                # 修改config字段
+                replaceJarNameInFile(configPath,newDate,oldDate,"jm_sdk")
+                oldJarPath = '%s/jm_sdk_%s.jar' % (full_lib_path,oldDate)
+                #删除旧文件
+                if os.path.exists(oldJarPath):
+                    print ('delete ---> %s' % oldJarPath)
+                    try:
+                        os.remove(os.path.normcase(oldJarPath))
+                    except Exception as e:
+                        print (e)
+                    else:
+                        print("File is deleted successfully")
+                newJarPath = '%s/jm_sdk_%s.jar' % (full_lib_path,newDate)
+                print('复制: %s ---> %s' % (fullJarPath,newJarPath))
+                shutil.copyfile(fullJarPath, newJarPath)  # 复制文件
+
+                print('-------------------------')
+
+    print ("\nfinished replace jar")
+
+
+######替换Res
+def replaceRes():
+    global  sdkpath
+    global  currentSdkpath
+    print ('start replace jar ...')
+    resPath = os.path.join(currentSdkpath,"res")
+    #print (resPath)
+    list = os.listdir(sdkpath)
+    for l in list:
+        if l.find("jm") > -1:
+            des_res_path = os.path.join(sdkpath,l,"res")
+            print (des_res_path)
+            file_utils.copyDir(resPath,des_res_path)
+
+    #修改config字段 及替换Jar包
+    # for l in list:
+    #     full_l_path = os.path.join(sdkpath,l)
+    #     full_lib_path = os.path.join(full_l_path,'libs')
+    #     if os.path.isdir(full_l_path):
+    #         configPath = os.path.join(full_l_path,'libs/config.json')
+    #         configPath = os.path.normcase(configPath)
+    #         if os.path.exists(configPath):
+    #             print(configPath)
+    #             oldDate = getoldJarDate(configPath)
+    #             # 修改config字段
+    #             replaceJarNameInFile(configPath,newDate,oldDate)
+    #             oldJarPath = '%s/jm_sdk_%s.jar' % (full_lib_path,oldDate)
+    #             #删除旧文件
+    #             if os.path.exists(oldJarPath):
+    #                 print ('delete ---> %s' % oldJarPath)
+    #                 try:
+    #                     os.remove(os.path.normcase(oldJarPath))
+    #                 except Exception as e:
+    #                     print (e)
+    #                 else:
+    #                     print("File is deleted successfully")
+    #             newJarPath = '%s/jm_sdk_%s.jar' % (full_lib_path,newDate)
+    #             print('复制: %s ---> %s' % (fullJarPath,newJarPath))
+    #             shutil.copyfile(fullJarPath, newJarPath)  # 复制文件
+    #
+    #             print('-------------------------')
+
+    print ("\nfinished replace res")
+
+def main():
+    #replaceJar()
+    replaceNopayJar()
+	#####修改了资源文件,要替换#####
+    #replaceRes()
+
+
+if __name__ == "__main__":
+    main()

+ 134 - 127
common_utils.py

@@ -1,128 +1,135 @@
-import file_utils
-import xml_utils
-import os.path
-
-def changeApplication(game, sdk, subChannel, config, targetApplication):
-    '''
-    修改最顶级的application
-    '''
-
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    application = xml_utils.getApplicationAttr(manifest, 'name')
-
-    if application is None:
-        xml_utils.changeApplicationAttr(manifest, 'name', targetApplication)
-
-        print('change add application %s' % targetApplication)
-    else:
-        smaliPath = os.path.join(decompliePath, 'smali')
-        superApplication = findSuperApplication(smaliPath, application)
-        print('super application is %s' % superApplication)
-
-        if superApplication == targetApplication:
-            return
-        changeSuperApplication(smaliPath, superApplication, targetApplication.replace('.', '/'))
-
-        print('change super application %s to %s' % (superApplication, targetApplication))
-
-
-def changeTopApplication(game, sdk, subChannel, config, targetApplication):
-    '''
-    修改mainfest清单下的application入口。
-    PS:例八门渠道,因游戏app'继承到渠道app'过程中有停住,未进入到渠道app'初始化,故改用渠道app'为入口,继承原游戏app'确保他们的功能正常运行
-    '''
-
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    gameApplication = xml_utils.getApplicationAttr(manifest, 'name')
-    print ("游戏application"+gameApplication)
-    xml_utils.changeApplicationAttr(manifest, 'name', targetApplication)
-    # if application is None:
-    #     xml_utils.changeApplicationAttr(manifest, 'name', targetApplication)
-    #
-    #     print('change add application %s' % targetApplication)
-    # else:
-    smaliPath = os.path.join(decompliePath, 'smali')
-    superApplication = findSuperApplication(smaliPath, targetApplication)
-    print('寻找入口application。super application is %s' % superApplication)
-    changeSuperApplication(smaliPath, superApplication, gameApplication.replace('.', '/'))
-
-    print('change super application %s to %s' % (targetApplication,gameApplication))
-
-def findSuperApplication(basePath, className):
-    '''
-    获取最顶级的application
-    '''
-    tagSuper = '.super Landroid/app/Application;'
-    tag = '.super L'
-    applicationFile = file_utils.getPackagePath(basePath, className) + '.smali'
-
-    topClassName = None
-    superClass = None
-    with openFile(applicationFile, 'r') as f:
-        line = f.readline()
-
-        while line:
-            if tagSuper in line:
-                topClassName = className
-                break
-            elif tag in line:
-                superClass = line[8:-2]
-                superClass = superClass.replace('/', '.')
-                break
-                
-            line = f.readline()
-
-    if topClassName is not None:
-        return topClassName
-    elif superClass is not None:
-        return findSuperApplication(basePath, superClass)
-
-def changeSuperApplication(basePath, className, targetApplication):
-    '''
-    更改application
-    '''
-    applicationFile = file_utils.getPackagePath(basePath, className) + '.smali'
-
-    # 修改application
-    changeSuperApplicationSmali(applicationFile, targetApplication)
-
-def changeSuperApplicationSmali(file, application):
-    '''
-    修改application.smali
-    '''
-    contentSpuer = '.super Landroid/app/Application;'
-    constructor = '.method public constructor <init>()V'
-    direct = 'invoke-direct'
-    invokeSuper = 'invoke-super'
-    applicationTag = 'Landroid/app/Application;->'
-    newContent = ''
-
-    with openFile(file, 'r+') as f:
-        line = f.readline()
-        isConstructor = False
-
-        while line:
-            if contentSpuer in line:
-                newContent += '.super L%s;\n' % application
-            elif invokeSuper in line and applicationTag in line:
-                newContent += line.replace('android/app/Application', application)
-            elif isConstructor and direct in line and applicationTag in line:
-                newContent += line.replace('android/app/Application', application)
-                isConstructor = False
-            else:
-                if constructor in line:
-                    isConstructor = True
-                newContent += line
-
-            line = f.readline()
-
-        f.seek(0, 0)
-        #清空内容
-        f.truncate()
-        f.write(newContent)
-    return 0
-
-def openFile(file, mode):
+import file_utils
+import xml_utils
+import os.path
+import random
+def changeApplication(game, sdk, subChannel, config, targetApplication):
+    '''
+    修改最顶级的application
+    '''
+
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    application = xml_utils.getApplicationAttr(manifest, 'name')
+
+    if application is None:
+        xml_utils.changeApplicationAttr(manifest, 'name', targetApplication)
+
+        print('change add application %s' % targetApplication)
+    else:
+        smaliPath = os.path.join(decompliePath, 'smali')
+        superApplication = findSuperApplication(smaliPath, application)
+        print('super application is %s' % superApplication)
+
+        if superApplication == targetApplication:
+            return
+        changeSuperApplication(smaliPath, superApplication, targetApplication.replace('.', '/'))
+
+        print('change super application %s to %s' % (superApplication, targetApplication))
+
+
+def changeTopApplication(game, sdk, subChannel, config, targetApplication):
+    '''
+    修改mainfest清单下的application入口。
+    PS:例八门渠道,因游戏app'继承到渠道app'过程中有停住,未进入到渠道app'初始化,故改用渠道app'为入口,继承原游戏app'确保他们的功能正常运行
+    '''
+
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    gameApplication = xml_utils.getApplicationAttr(manifest, 'name')
+    print ("游戏application"+gameApplication)
+    xml_utils.changeApplicationAttr(manifest, 'name', targetApplication)
+    # if application is None:
+    #     xml_utils.changeApplicationAttr(manifest, 'name', targetApplication)
+    #
+    #     print('change add application %s' % targetApplication)
+    # else:
+    smaliPath = os.path.join(decompliePath, 'smali')
+    superApplication = findSuperApplication(smaliPath, targetApplication)
+    print('寻找入口application。super application is %s' % superApplication)
+    changeSuperApplication(smaliPath, superApplication, gameApplication.replace('.', '/'))
+
+    print('change super application %s to %s' % (targetApplication,gameApplication))
+
+def findSuperApplication(basePath, className):
+    '''
+    获取最顶级的application
+    '''
+    tagSuper = '.super Landroid/app/Application;'
+    tag = '.super L'
+    applicationFile = file_utils.getPackagePath(basePath, className) + '.smali'
+
+    topClassName = None
+    superClass = None
+    with openFile(applicationFile, 'r') as f:
+        line = f.readline()
+
+        while line:
+            if tagSuper in line:
+                topClassName = className
+                break
+            elif tag in line:
+                superClass = line[8:-2]
+                superClass = superClass.replace('/', '.')
+                break
+                
+            line = f.readline()
+
+    if topClassName is not None:
+        return topClassName
+    elif superClass is not None:
+        return findSuperApplication(basePath, superClass)
+
+def changeSuperApplication(basePath, className, targetApplication):
+    '''
+    更改application
+    '''
+    applicationFile = file_utils.getPackagePath(basePath, className) + '.smali'
+
+    # 修改application
+    changeSuperApplicationSmali(applicationFile, targetApplication)
+
+def changeSuperApplicationSmali(file, application):
+    '''
+    修改application.smali
+    '''
+    contentSpuer = '.super Landroid/app/Application;'
+    constructor = '.method public constructor <init>()V'
+    direct = 'invoke-direct'
+    invokeSuper = 'invoke-super'
+    applicationTag = 'Landroid/app/Application;->'
+    newContent = ''
+
+    with openFile(file, 'r+') as f:
+        line = f.readline()
+        isConstructor = False
+
+        while line:
+            if contentSpuer in line:
+                newContent += '.super L%s;\n' % application
+            elif invokeSuper in line and applicationTag in line:
+                newContent += line.replace('android/app/Application', application)
+            elif isConstructor and direct in line and applicationTag in line:
+                newContent += line.replace('android/app/Application', application)
+                isConstructor = False
+            else:
+                if constructor in line:
+                    isConstructor = True
+                newContent += line
+
+            line = f.readline()
+
+        f.seek(0, 0)
+        #清空内容
+        f.truncate()
+        f.write(newContent)
+    return 0
+def getRandomNumber(size):
+    str = ""
+    for i in range(6):
+        ch = chr(random.randrange(ord('0'), ord('9') + 1))
+        str += ch
+    return str
+
+
+def openFile(file, mode):
     return file_utils.openFile(file, mode)

+ 122 - 119
config_utils.py

@@ -1,119 +1,122 @@
-import time
-
-logSdkMapping = {
-    'jrtt':'com.jmhy.sdk.statistics.JrttStatistics',
-    'gdt':'com.jmhy.sdk.statistics.GdtStatistics'
-}
-
-def checkConfig(config):
-    '''
-    检查配置
-    '''
-    print('check config ...')
-    if type(config) == dict:
-        return checkChannelConfig(config)
-    elif type(config) == list:
-        for itemConfig in config:
-            if not checkChannelConfig(itemConfig):
-                return False
-    return True
-
-def checkChannelConfig(config):
-    if 'name' not in config or 'packageName' not in config:
-        print('name or packageName not exists in config')
-        return False
-
-    if 'subChannel' not in config:
-        print('subChannel not exists in config')
-        return False
-
-    # 默认值
-    if 'changeIcon' not in config:
-        config['changeIcon'] = False
-    if 'switchIcon' not in config:
-        config['switchIcon'] = False
-    if 'addLauncher' not in config:
-        config['addLauncher'] = False
-    if 'splitDex' not in config:
-        config['splitDex'] = True
-    if 'clearCache' not in config:
-        config['clearCache'] = True
-    if 'aapt2disable' not in config:
-        config['aapt2disable'] = False
-    if 'v2disable' not in config:
-        config['v2disable'] = False
-    if 'screenOrientation' not in config:
-        config['screenOrientation'] = 'landscape'
-    if 'outName' not in config:
-        config['outName'] = config['name']
-
-    if 'logSdk' in config:
-        log = config['logSdk']
-        setLog(config, log)
-
-
-
-    return True
-
-def setLog(config, logSdk):
-    clazzList = []
-    for log in logSdk:
-        if log in logSdkMapping:
-            clazzList.append(logSdkMapping[log])
-        
-    configData = None
-    if 'configData' in config:
-        configData = config['configData']
-        configData['jm_log_sdk'] = clazzList
-    else:
-        config['configData'] = {
-            'jm_log_sdk':clazzList
-        }
-
-def replaceArgs(config):
-    '''
-    替换占位符
-    '''
-    if type(config) == dict:
-        replaceItemArgs(config)
-    elif type(config) == list:
-        # 遍历数组
-        for arg in config:
-            replaceItemArgs(arg)
-
-def replaceItemArgs(config):
-    '''
-    替换占位符
-    '''
-    # 遍历字典
-    for arg in config:
-        if type(config[arg]) == dict:
-            replaceArgs(config[arg])
-        elif type(config[arg]) == str:
-            replaceString(config, arg)
-
-def replaceString(config, arg):
-    '''
-    替换占位符
-    '''
-    content = config[arg]
-    if '${DATE}' in content:
-        content = content.replace('${DATE}', getDate())
-
-    config[arg] = content
-
-def getDate():
-    '''
-    获取日期
-    '''
-    return time.strftime("%Y%m%d", time.localtime())
-
-def getTime(seconds):
-    '''
-    获取时间
-    '''
-    time = int(seconds)
-    if time < 60:
-        return str(time) + '秒'
-    else:
-        return str(round(time/60)) + '分' + str(time%60) + '秒'
+import time
+
+logSdkMapping = {
+    'jrtt':'com.jmhy.sdk.statistics.JrttStatistics',
+    'gdt':'com.jmhy.sdk.statistics.GdtStatistics',
+    'ks':'com.jmhy.sdk.statistics.KsStatistics',
+    'uc':'com.jmhy.sdk.statistics.UcStatistics',
+    'bd':'com.jmhy.sdk.statistics.BaiduStatistics'
+}
+
+def checkConfig(config):
+    '''
+    检查配置
+    '''
+    print('check config ...')
+    if type(config) == dict:
+        return checkChannelConfig(config)
+    elif type(config) == list:
+        for itemConfig in config:
+            if not checkChannelConfig(itemConfig):
+                return False
+    return True
+
+def checkChannelConfig(config):
+    if 'name' not in config or 'packageName' not in config:
+        print('name or packageName not exists in config')
+        return False
+
+    if 'subChannel' not in config:
+        print('subChannel not exists in config')
+        return False
+
+    # 默认值
+    if 'changeIcon' not in config:
+        config['changeIcon'] = False
+    if 'switchIcon' not in config:
+        config['switchIcon'] = False
+    if 'addLauncher' not in config:
+        config['addLauncher'] = False
+    if 'splitDex' not in config:
+        config['splitDex'] = True
+    if 'clearCache' not in config:
+        config['clearCache'] = True
+    if 'aapt2disable' not in config:
+        config['aapt2disable'] = False
+    if 'v2disable' not in config:
+        config['v2disable'] = False
+    if 'screenOrientation' not in config:
+        config['screenOrientation'] = 'landscape'
+    if 'outName' not in config:
+        config['outName'] = config['name']
+
+    if 'logSdk' in config:
+        log = config['logSdk']
+        setLog(config, log)
+
+
+
+    return True
+
+def setLog(config, logSdk):
+    clazzList = []
+    for log in logSdk:
+        if log in logSdkMapping:
+            clazzList.append(logSdkMapping[log])
+        
+    configData = None
+    if 'configData' in config:
+        configData = config['configData']
+        configData['jm_log_sdk'] = clazzList
+    else:
+        config['configData'] = {
+            'jm_log_sdk':clazzList
+        }
+
+def replaceArgs(config):
+    '''
+    替换占位符
+    '''
+    if type(config) == dict:
+        replaceItemArgs(config)
+    elif type(config) == list:
+        # 遍历数组
+        for arg in config:
+            replaceItemArgs(arg)
+
+def replaceItemArgs(config):
+    '''
+    替换占位符
+    '''
+    # 遍历字典
+    for arg in config:
+        if type(config[arg]) == dict:
+            replaceArgs(config[arg])
+        elif type(config[arg]) == str:
+            replaceString(config, arg)
+
+def replaceString(config, arg):
+    '''
+    替换占位符
+    '''
+    content = config[arg]
+    if '${DATE}' in content:
+        content = content.replace('${DATE}', getDate())
+
+    config[arg] = content
+
+def getDate():
+    '''
+    获取日期
+    '''
+    return time.strftime("%Y%m%d", time.localtime())
+
+def getTime(seconds):
+    '''
+    获取时间
+    '''
+    time = int(seconds)
+    if time < 60:
+        return str(time) + '秒'
+    else:
+        return str(round(time/60)) + '分' + str(time%60) + '秒'

+ 84 - 84
config_utils_record.py

@@ -1,85 +1,85 @@
-import time
-
-def checkConfig(config):
-    '''
-    检查配置
-    '''
-    print('check config ...')
-    if type(config) == dict:
-        print('check config dict ...')
-        return checkChannelConfig(config)
-    elif type(config) == list:
-        print('check config list ...')
-        for itemConfig in config:
-            if not checkChannelConfig(itemConfig):
-                return False
-    return True
-
-def checkChannelConfig(config):
-    if 'name' not in config or 'packageName' not in config:
-        print('name or packageName not exists in config')
-        return False
-
-    if 'subChannel' not in config:
-        print('subChannel not exists in config')
-        return False
-
-    # 默认值
-    if 'changeIcon' not in config:
-        config['changeIcon'] = False
-    if 'switchIcon' not in config:
-        config['switchIcon'] = False
-    if 'addLauncher' not in config:
-        config['addLauncher'] = False
-    if 'splitDex' not in config:
-        config['splitDex'] = True
-    if 'clearCache' not in config:
-        config['clearCache'] = True
-    if 'aapt2disable' not in config:
-        config['aapt2disable'] = False
-    if 'v2disable' not in config:
-        config['v2disable'] = False
-    if 'screenOrientation' not in config:
-        config['screenOrientation'] = 'landscape'
-    if 'outName' not in config:
-        config['outName'] = config['name']
-        
-    return True
-
-def replaceArgs(config):
-    '''
-    替换占位符
-    '''
-    if type(config) == dict:
-        replaceItemArgs(config)
-    elif type(config) == list:
-        # 遍历数组
-        for arg in config:
-            replaceItemArgs(arg)
-
-def replaceItemArgs(config):
-    '''
-    替换占位符
-    '''
-    # 遍历字典
-    for arg in config:
-        if type(config[arg]) == dict:
-            replaceArgs(config[arg])
-        elif type(config[arg]) == str:
-            replaceString(config, arg)
-
-def replaceString(config, arg):
-    '''
-    替换占位符
-    '''
-    content = config[arg]
-    if '${DATE}' in content:
-        content = content.replace('${DATE}', getDate())
-
-    config[arg] = content
-
-def getDate():
-    '''
-    获取日期
-    '''
+import time
+
+def checkConfig(config):
+    '''
+    检查配置
+    '''
+    print('check config ...')
+    if type(config) == dict:
+        print('check config dict ...')
+        return checkChannelConfig(config)
+    elif type(config) == list:
+        print('check config list ...')
+        for itemConfig in config:
+            if not checkChannelConfig(itemConfig):
+                return False
+    return True
+
+def checkChannelConfig(config):
+    if 'name' not in config or 'packageName' not in config:
+        print('name or packageName not exists in config')
+        return False
+
+    if 'subChannel' not in config:
+        print('subChannel not exists in config')
+        return False
+
+    # 默认值
+    if 'changeIcon' not in config:
+        config['changeIcon'] = False
+    if 'switchIcon' not in config:
+        config['switchIcon'] = False
+    if 'addLauncher' not in config:
+        config['addLauncher'] = False
+    if 'splitDex' not in config:
+        config['splitDex'] = True
+    if 'clearCache' not in config:
+        config['clearCache'] = True
+    if 'aapt2disable' not in config:
+        config['aapt2disable'] = False
+    if 'v2disable' not in config:
+        config['v2disable'] = False
+    if 'screenOrientation' not in config:
+        config['screenOrientation'] = 'landscape'
+    if 'outName' not in config:
+        config['outName'] = config['name']
+        
+    return True
+
+def replaceArgs(config):
+    '''
+    替换占位符
+    '''
+    if type(config) == dict:
+        replaceItemArgs(config)
+    elif type(config) == list:
+        # 遍历数组
+        for arg in config:
+            replaceItemArgs(arg)
+
+def replaceItemArgs(config):
+    '''
+    替换占位符
+    '''
+    # 遍历字典
+    for arg in config:
+        if type(config[arg]) == dict:
+            replaceArgs(config[arg])
+        elif type(config[arg]) == str:
+            replaceString(config, arg)
+
+def replaceString(config, arg):
+    '''
+    替换占位符
+    '''
+    content = config[arg]
+    if '${DATE}' in content:
+        content = content.replace('${DATE}', getDate())
+
+    config[arg] = content
+
+def getDate():
+    '''
+    获取日期
+    '''
     return time.strftime("%Y%m%d", time.localtime()) 

+ 76 - 76
config_utils_shanshen.py

@@ -1,77 +1,77 @@
-import time
-
-def checkConfig(config):
-    '''
-    检查配置
-    '''
-    print('check config ...')
-    if type(config) == dict:
-        return checkChannelConfig(config)
-    elif type(config) == list:
-        for itemConfig in config:
-            if not checkChannelConfig(itemConfig):
-                return False
-    return True
-
-def checkChannelConfig(config):
-    if 'subChannel' not in config:
-        print('subChannel not exists in config')
-        return False
-
-    # 默认值
-    if 'changeIcon' not in config:
-        config['changeIcon'] = False
-    if 'switchIcon' not in config:
-        config['switchIcon'] = False
-    if 'addLauncher' not in config:
-        config['addLauncher'] = False
-    if 'splitDex' not in config:
-        config['splitDex'] = True
-    if 'clearCache' not in config:
-        config['clearCache'] = True
-    if 'aapt2disable' not in config:
-        config['aapt2disable'] = False
-    if 'v2disable' not in config:
-        config['v2disable'] = False
-    if 'outName' not in config:
-        config['outName'] = config['name']
-        
-    return True
-
-def replaceArgs(config):
-    '''
-    替换占位符
-    '''
-    if type(config) == dict:
-        replaceItemArgs(config)
-    elif type(config) == list:
-        # 遍历数组
-        for arg in config:
-            replaceItemArgs(arg)
-
-def replaceItemArgs(config):
-    '''
-    替换占位符
-    '''
-    # 遍历字典
-    for arg in config:
-        if type(config[arg]) == dict:
-            replaceArgs(config[arg])
-        elif type(config[arg]) == str:
-            replaceString(config, arg)
-
-def replaceString(config, arg):
-    '''
-    替换占位符
-    '''
-    content = config[arg]
-    if '${DATE}' in content:
-        content = content.replace('${DATE}', getDate())
-
-    config[arg] = content
-
-def getDate():
-    '''
-    获取日期
-    '''
+import time
+
+def checkConfig(config):
+    '''
+    检查配置
+    '''
+    print('check config ...')
+    if type(config) == dict:
+        return checkChannelConfig(config)
+    elif type(config) == list:
+        for itemConfig in config:
+            if not checkChannelConfig(itemConfig):
+                return False
+    return True
+
+def checkChannelConfig(config):
+    if 'subChannel' not in config:
+        print('subChannel not exists in config')
+        return False
+
+    # 默认值
+    if 'changeIcon' not in config:
+        config['changeIcon'] = False
+    if 'switchIcon' not in config:
+        config['switchIcon'] = False
+    if 'addLauncher' not in config:
+        config['addLauncher'] = False
+    if 'splitDex' not in config:
+        config['splitDex'] = True
+    if 'clearCache' not in config:
+        config['clearCache'] = True
+    if 'aapt2disable' not in config:
+        config['aapt2disable'] = False
+    if 'v2disable' not in config:
+        config['v2disable'] = False
+    if 'outName' not in config:
+        config['outName'] = config['name']
+        
+    return True
+
+def replaceArgs(config):
+    '''
+    替换占位符
+    '''
+    if type(config) == dict:
+        replaceItemArgs(config)
+    elif type(config) == list:
+        # 遍历数组
+        for arg in config:
+            replaceItemArgs(arg)
+
+def replaceItemArgs(config):
+    '''
+    替换占位符
+    '''
+    # 遍历字典
+    for arg in config:
+        if type(config[arg]) == dict:
+            replaceArgs(config[arg])
+        elif type(config[arg]) == str:
+            replaceString(config, arg)
+
+def replaceString(config, arg):
+    '''
+    替换占位符
+    '''
+    content = config[arg]
+    if '${DATE}' in content:
+        content = content.replace('${DATE}', getDate())
+
+    config[arg] = content
+
+def getDate():
+    '''
+    获取日期
+    '''
     return time.strftime("%Y%m%d", time.localtime()) 

+ 654 - 562
file_utils.py

@@ -1,562 +1,654 @@
-import os
-import os.path
-import shutil
-import subprocess
-import platform
-import sys
-import hashlib
-
-def getFullToolPath(name):
-    '''
-    获取工具的目录
-    '''
-    return getFullPath('tools', name)
-
-def getFullGameApk(name):
-    '''
-    获取游戏的原始包
-    '''
-    return getFullPath('game', name, name + '.apk')
-
-def getFullSDKPath(sdk):
-    '''
-    获取sdk的目录
-    '''
-    return getFullPath('sdk', sdk)
-
-def getFullLogSDKPath(sdk):
-    '''
-    获取logsdk的目录
-    '''
-    return getFullPath('log_sdk', sdk)
-
-
-def getFullOaidSDKPath(version):
-    '''
-    获取logsdk的目录
-    '''
-    return getFullPath('oaid_sdk', version)
-
-def getDecompliePath(game, sdk, subChannel, cache):
-    '''
-    获取解包的目录
-    '''
-    return getFullPath('gen', game, sdk, subChannel, cache)
-
-def getSubChannelPath(game, sdk, subChannel):
-    '''
-    获取子渠道的目录
-    '''
-    return getFullPath('game', game, sdk, subChannel)
-
-def getChannelPath(game, sdk):
-    '''
-    获取渠道的目录
-    '''
-    return getFullPath('game', game, sdk)
-
-def getFullGamePath(game):
-    '''
-    获取游戏的目录
-    '''
-    return getFullPath('game', game)
-
-def getFullInternalPath():
-    '''
-    获取内部目录
-    '''
-    return os.path.join(getCurrentPath(), 'internal')
-
-def getFullPath(type, *name):
-    path = os.path.join(getCurrentPath(), type)
-    for n in name:
-        path = os.path.join(path, str(n))
-    return path
-
-def getCurrentPath():
-    '''
-    当前目录
-    '''
-    return sys.path[0]
-
-def execFormatCmd(cmd, cd = None):
-    '''
-    执行cmd命令
-
-    返回值:None —— 子进程尚未结束;
-        ==0 —— 子进程正常退出;
-        > 0—— 子进程异常退出,returncode对应于出错码;
-        < 0—— 子进程被信号杀掉了。
-    '''
-    '''print(cmd)
-    p = os.popen(cmd)
-    print(p.read())'''
-    ret = 0
-    try:
-        s = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, cwd=cd)
-        stdoutput, erroutput = s.communicate()
-
-        if platform.system() == 'Windows':
-            stdoutput = stdoutput.decode('gbk')
-            erroutput = erroutput.decode('gbk')
-            
-        '''
-        None —— 子进程尚未结束;
-        ==0 —— 子进程正常退出;
-        > 0—— 子进程异常退出,returncode对应于出错码;
-        < 0—— 子进程被信号杀掉了。
-        '''
-        ret = s.returncode
-
-        if ret:
-            print('*******ERROR*******')
-            print(stdoutput)
-            print(erroutput)
-            print('*******************')
-
-            cmd = 'error::' + cmd + '  !!!exec Fail!!!  '
-        else:
-            print(stdoutput)
-            print(erroutput)
-
-            cmd = cmd + ' !!!exec success!!! '
-
-        print(cmd)
-
-    except Exception as e:
-        print('Exception ' + e)
-        return 1
-
-    return ret
-
-def execJarCmd(jar, params):
-    '''
-    执行jar
-    '''
-    return execFormatCmd('java -jar "%s" %s' % (jar, params))
-
-def copyFileAllDir(fromDir, toDir, delete = False, support = None):
-    '''
-    拷贝目录下所有文件文件
-    '''
-    #print('copy all file %s --> %s' % (fromDir, toDir))
-    ret = copyDir(fromDir, toDir, delete, support)
-    if ret:
-        return ret
-
-    if delete:
-        deleteFolder(fromDir)
-
-    return 0
-
-def copyDir(fromDir, toDir, delete = False, support = None):
-    '''
-    拷贝目录下所有文件文件
-    '''
-    #print('copy all file %s --> %s' % (fromDir, toDir))
-    if not os.path.exists(fromDir):
-        print('%s not exists!' % fromDir)
-        return 1
-        
-    if not os.path.isdir(fromDir):
-        print('%s not a dir!' % fromDir)
-        return 1
-
-    for fromFile in os.listdir(fromDir):
-        fromFilePath = os.path.join(fromDir, fromFile)
-        toFilePath = os.path.join(toDir, fromFile)
-        if os.path.isdir(fromFilePath):
-            # 不支持的类型
-            if support is not None and fromFile not in support:
-                continue
-
-            ret = copyDir(fromFilePath, toFilePath, delete, support)
-            if ret:
-                return ret
-        else:
-            ret = copyFile(fromFilePath, toFilePath, delete)
-            if ret:
-                return ret
-
-    return 0
-
-def copyFile(formFile, toFile, delete = False):
-    '''
-    拷贝文件
-    '''
-    if not os.path.isfile(formFile):
-        print('----> %s not a file!' % formFile)
-        return 1
-
-    fpath, fname = os.path.split(toFile)  #分离文件名和路径
-    if not os.path.exists(fpath):
-        #print('%s not exists, crate' % fpath)
-        os.makedirs(fpath)              #创建路径
-
-    '''if os.path.exists(toFile) and os.path.getsize(formFile) > 104857600 and equalsFile(formFile, toFile):
-        print('skip copy %s --> %s' % (formFile, toFile))
-        if delete:
-            os.remove(formFile)
-            print('remove %s' % formFile)
-        return 0'''
-
-    if delete:
-        shutil.move(formFile, toFile)      #移动文件
-        #print('move %s --> %s' % (formFile, toFile))
-    else:
-        shutil.copyfile(formFile, toFile)      #复制文件
-        #print('copy %s --> %s' % (formFile, toFile))
-
-    return 0
-
-def replaceContent(file, oldText, newText):
-    '''
-    全局替换
-    '''
-    with openFile(file, 'r+') as f:
-        t = f.read()
-        t = t.replace(oldText, newText)
-        #读写偏移位置移到最开始处
-        f.seek(0, 0)
-        #清空内容
-        f.truncate()
-        f.write(t)
-
-def readFile(file):
-    '''
-    读取文件内容
-    '''
-    content = ''
-    with openFile(file, 'r') as f:
-        content = f.read()
-    return content
-
-def createFile(file, content):
-    '''
-    创建文件
-    '''
-    fpath, fname = os.path.split(file)  #分离文件名和路径
-    if not os.path.exists(fpath):
-        os.makedirs(fpath)
-
-    with openFile(file, 'w') as f:
-        f.write(content)
-        f.close()
-
-def openFile(file, mode):
-    return open(file, mode, encoding='UTF-8')
-
-def deleteFolder(folder):
-    '''
-    删除目录以及目录下的文件
-    '''
-    if not os.path.exists(folder):
-        return
-
-    #print('remove %s ...' % folder)
-    shutil.rmtree(folder)
-    #print('removed %s' % folder)
-
-def getAAPTPath():
-    '''
-    获取aapt
-    '''
-    return getToolWithSystem('aapt')
-
-def getAAPT2Path():
-    '''
-    获取aapt2
-    '''
-    return getToolWithSystem('aapt2')
-
-def getAndroidCompileToolPath():
-    '''
-    获取android.jar
-    '''
-    return getFullToolPath('android.jar')
-
-def getDxPath():
-    '''
-    获取dx.jar
-    '''
-    return getFullToolPath('dx.jar')
-
-def getD8Path():
-    '''
-    获取d8.jar
-    '''
-    return getFullToolPath('d8.jar')
-
-def getAlignPath():
-    '''
-    获取zipalign
-    '''
-    return getToolWithSystem('zipalign')
-
-def getMultiDexPath():
-    '''
-    获取multidex.jar
-    '''
-    return getFullToolPath('android-support-multidex.jar')
-
-def getApkToolPath():
-    '''
-    获取apktool.jar
-    '''
-    return getFullToolPath('apktool_2.4.0.jar')
-
-def getBaksmaliPath():
-    '''
-    获取baksmali.jar
-    '''
-    return getFullToolPath('baksmali-2.3.jar')
-
-def getApksignerPath():
-    '''
-    获取apksigner.jar
-    '''
-    return getFullToolPath('apksigner.jar')
-
-def getWallePath():
-    '''
-    获取walle-cli-all.jar
-    '''
-    return getFullToolPath('walle-cli-all.jar')
-
-def getOutApkPath(game, sdk, subChannel, cache):
-    '''
-    获取输出的apk的目录
-    '''
-    return getFullPath('target', game, sdk, cache, '%s_%s_%s.apk' % (game, sdk, subChannel))
-
-def getAlignApkPath(game, sdk, subChannel, cache):
-    '''
-    获取输出的apk的目录
-    '''
-    return getFullPath('target', game, sdk, cache, '%s_%s_%s_align.apk' % (game, sdk, subChannel))
-
-def getRenameApkPath(game, sdk, cache, name):
-    '''
-    重命名输出的apk名称
-    '''
-    return getFullPath('target', game, sdk, cache, '%s.apk' % name)
-
-def getSignApkPath(game, sdk, subChannel, cache):
-    '''
-    获取输出的apk的目录
-    '''
-    return getFullPath('target', game, sdk, cache, '%s_%s_%s_signed.apk' % (game, sdk, subChannel))
-
-def getPackagePath(basePath, packageName):
-    '''
-    包名对应的目录
-    '''
-    packageNameSplit = packageName.split('.')
-    newPath = basePath
-    for item in packageNameSplit:
-        newPath = os.path.join(newPath, item)
-    return newPath
-
-def getToolWithSystem(tool):
-    '''
-    获取系统相关工具
-    '''
-    system = getSystemPath()
-    suffix = getSystemSuffix()
-    return os.path.join(getFullToolPath(system), tool + suffix)
-
-def getSystemPath():
-    '''
-    获取系统目录
-    '''
-    if platform.system() == 'Windows':
-        return 'win'
-    elif platform.system() == 'Darwin':
-        print ('---------macos----------')
-        return 'macos'
-    else:
-        return 'linux'
-
-def getSystemSuffix():
-    '''
-    系统工具后缀
-    '''
-    if platform.system() == 'Windows':
-        return '.exe'
-    else:
-        return ''
-
-def getApplicationSmaliIndex(file):
-    '''
-    获取application.smali的MultiDex信息
-    '''
-    content = ('invoke-super', '->attachBaseContext(Landroid/content/Context;)V')
-    index = -1
-    with openFile(file, 'r') as f:
-        line = f.readline()
-        while line:
-            if content[0] in line and content[1] in line:
-                index = f.tell()
-                break
-            line = f.readline()
-
-    return index
-
-def insertApplicationSmali(file, index):
-    '''
-    获取application.smali插入MultiDex的信息
-    '''
-    if index == -1:
-        # append
-        content = '''# virtual methods
-.method protected attachBaseContext(Landroid/content/Context;)V
-    .locals 0
-    .param p1, "context"    # Landroid/content/Context;
-
-    invoke-super {p0, p1}, Landroid/app/Application;->attachBaseContext(Landroid/content/Context;)V
-
-    invoke-static {p0}, Landroid/support/multidex/MultiDex;->install(Landroid/content/Context;)V
-
-    return-void
-.end method'''
-        with openFile(file, 'a') as f:
-            f.write(content)
-    else:
-        # insert
-        content = '\n\tinvoke-static {p0}, Landroid/support/multidex/MultiDex;->install(Landroid/content/Context;)V\n'
-        with openFile(file, 'r+') as f:
-            f.seek(index)
-            last = f.read()
-            f.seek(index)
-            f.write(content)
-            f.write(last)
-    return 0
-
-def changeVersion(yml, versionCode = None, versionName = None, targetSdkVersion = None):
-    if versionCode is None and versionName is None and targetSdkVersion is None:
-        return 0
-
-    tag = ['versionCode:', 'versionName:', 'targetSdkVersion:']
-    
-    with openFile(yml, 'r+') as f:
-        content = ''
-        line = f.readline()
-        while line:
-            if versionCode is not None and tag[0] in line:
-                content += '  versionCode: \'%s\'\n' % versionCode
-            elif versionName is not None and tag[1] in line:
-                content += '  versionName: %s\n' % versionName
-            elif targetSdkVersion is not None and tag[2] in line:
-                content += '  targetSdkVersion: \'%s\'\n' % targetSdkVersion
-            else:
-                content += line
-            line = f.readline()
-
-        f.seek(0, 0)
-        f.truncate()
-        f.write(content)
-
-    return 0
-
-def changeMinSdkVersion(yml, minSdkVersion):
-    
-    with openFile(yml, 'r+') as f:
-        content = ''
-        line = f.readline()
-        while line:
-            if 'minSdkVersion' in line:
-                start = line.index("'")
-                version = int(line[start+1:-2])
-                if version < minSdkVersion:
-                    content += '  minSdkVersion: \'%s\'\n' % minSdkVersion
-                else:
-                    return 0
-            else:
-                content += line
-            line = f.readline()
-
-        f.seek(0, 0)
-        f.truncate()
-        f.write(content)
-
-    return 0
-
-def list_files(src, resFiles):
-    '''
-    列出目录下所有的文件
-    '''
-    if os.path.exists(src):
-        if os.path.isfile(src):
-            resFiles.append(src)
-        elif os.path.isdir(src):
-            for f in os.listdir(src):
-                list_files(os.path.join(src, f), resFiles)
-    return resFiles
-
-def getFileMd5(f):
-    '''
-    获取文件的md5
-    '''
-    m = hashlib.md5()
-    while True:
-        data = f.read(1024)  #将文件分块读取
-        if not data:
-            break
-        m.update(data)
-    return m.hexdigest()
-
-def equalsFile(file1, file2):
-    '''
-    比较两个文件是否是同一个文件
-    '''
-    with open(file1, 'rb') as f1, open(file2, 'rb') as f2:
-        file1Md5 = getFileMd5(f1)
-        file2Md5 = getFileMd5(f2)
-        #print('file1Md5:',file1Md5)
-        #print('file2Md5:',file2Md5)
-        return file1Md5 == file2Md5
-
-def getExecPermission(file):
-    '''
-    linux下获取执行权限
-    '''
-    if platform.system() == 'Windows':
-        return 0
-
-    return execFormatCmd('chmod +x "%s"' % file)
-
-
-def copySdkSmaliCode(game, sdk, subChannel, config):
-    '''
-    拷贝代码
-    '''
-    print('copySdkSmaliCode -->  %s' % sdk)
-    sdkPath = getFullSDKPath(sdk)
-
-    xmyFile = os.path.join(sdkPath, 'smali')
-    decompliePath = getDecompliePath(game, sdk, subChannel, config['cache'])
-    smaliPath = os.path.join(decompliePath, 'smali')
-    ret = copyDir(xmyFile, smaliPath)
-
-    return ret
-
-
-def copyGameSmaliCode(game, sdk, subChannel, config):
-    '''
-    拷贝代码
-    '''
-    print('copyGameSmaliCode -->  %s' % sdk)
-
-    if not config['aapt2disable']:
-        print('aapt2disable = false ~~~')
-        return 0
-    path = os.path.join(getCurrentPath(),"game_script",game,"gameSmali")
-
-
-    print('copyDir = gameSmali~~~')
-
-    decompliePath = getDecompliePath(game, sdk, subChannel, config['cache'])
-    smaliPath = os.path.join(decompliePath, 'smali')
-    ret = copyDir(path, smaliPath)
-
-    return ret
+import os
+import os.path
+import shutil
+import subprocess
+import platform
+import sys
+import hashlib
+
+
+def getFullToolPath(name):
+    '''
+    获取工具的目录
+    '''
+    return getFullPath('tools', name)
+
+
+def getFullGameApk(name):
+    '''
+    获取游戏的原始包
+    '''
+    return getFullPath('game', name, name + '.apk')
+
+
+def getCacheGameApk(game, random, sdk):
+    '''
+    获取游戏的原始包
+    '''
+    return getFullPath('game', game, sdk, random, game + '.apk')
+
+
+def getFullSDKPath(sdk):
+    '''
+    获取sdk的目录
+    '''
+    return getFullPath('sdk', sdk)
+
+
+def getFullLogSDKPath(sdk, is_beta=False):
+    '''
+    获取logsdk的目录
+    '''
+    if is_beta:
+        return getFullPath('log_sdk_beta', sdk)
+    else:
+        return getFullPath('log_sdk', sdk)
+
+
+def getFullOaidSDKPath(version):
+    '''
+    获取logsdk的目录
+    '''
+    return getFullPath('oaid_sdk', version)
+
+
+def getDecompliePath(game, sdk, subChannel, cache):
+    '''
+    获取解包的目录
+    '''
+    return getFullPath('gen', game, sdk, subChannel, cache)
+
+
+def getSubChannelPath(game, sdk, subChannel):
+    '''
+    获取子渠道的目录
+    '''
+    return getFullPath('game', game, sdk, subChannel)
+
+
+def getSubChannelPath(game, sdk, tag, subChannel):
+    '''
+    获取子渠道的目录
+    '''
+    return getFullPath('game', game, sdk, tag, subChannel)
+
+
+def getChannelPath(game, sdk):
+    '''
+    获取渠道的目录
+    '''
+    return getFullPath('game', game, sdk)
+
+
+def getChannelPath(game, tag, sdk):
+    '''
+    获取渠道的目录
+    '''
+    return getFullPath('game', game, sdk, tag)
+
+
+def getFullGamePath(game):
+    '''
+    获取游戏的目录
+    '''
+    return getFullPath('game', game)
+
+
+def getFullInternalPath():
+    '''
+    获取内部目录
+    '''
+    return os.path.join(getCurrentPath(), 'internal')
+
+
+def getFullPath(type, *name):
+    path = os.path.join(getCurrentPath(), type)
+    for n in name:
+        path = os.path.join(path, str(n))
+    return path
+
+
+def getCurrentPath():
+    '''
+    当前目录
+    '''
+    return sys.path[0]
+
+
+def execFormatCmd(cmd, cd=None):
+    '''
+    执行cmd命令
+
+    返回值:None —— 子进程尚未结束;
+        ==0 —— 子进程正常退出;
+        > 0—— 子进程异常退出,returncode对应于出错码;
+        < 0—— 子进程被信号杀掉了。
+    '''
+    '''print(cmd)
+    p = os.popen(cmd)
+    print(p.read())'''
+    ret = 0
+    try:
+        s = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+                             stderr=subprocess.PIPE, shell=True, cwd=cd)
+        stdoutput, erroutput = s.communicate()
+
+        if platform.system() == 'Windows':
+            stdoutput = stdoutput.decode('gbk')
+            erroutput = erroutput.decode('gbk')
+
+        '''
+        None —— 子进程尚未结束;
+        ==0 —— 子进程正常退出;
+        > 0—— 子进程异常退出,returncode对应于出错码;
+        < 0—— 子进程被信号杀掉了。
+        '''
+        ret = s.returncode
+
+        if ret:
+            print('*******ERROR*******')
+            print(stdoutput)
+            print(erroutput)
+            print('*******************')
+
+            cmd = 'error::' + cmd + '  !!!exec Fail!!!  '
+        else:
+            print(stdoutput)
+            print(erroutput)
+
+            cmd = cmd + ' !!!exec success!!! '
+
+        print(cmd)
+
+    except Exception as e:
+        print('Exception ' + e)
+        return 1
+
+    return ret
+
+
+def execJarCmd(jar, params):
+    '''
+    执行jar
+    '''
+    return execFormatCmd('java -jar "%s" %s' % (jar, params))
+
+
+def copyFileAllDir(fromDir, toDir, delete=False, support=None):
+    '''
+    拷贝目录下所有文件文件
+    '''
+    # print('copy all file %s --> %s' % (fromDir, toDir))
+    ret = copyDir(fromDir, toDir, delete, support)
+    if ret:
+        return ret
+
+    if delete:
+        deleteFolder(fromDir)
+
+    return 0
+
+
+def copyDir(fromDir, toDir, delete=False, support=None):
+    '''
+    拷贝目录下所有文件文件
+    '''
+    # print('copy all file %s --> %s' % (fromDir, toDir))
+    if not os.path.exists(fromDir):
+        print('%s not exists!' % fromDir)
+        return 1
+
+    if not os.path.isdir(fromDir):
+        print('%s not a dir!' % fromDir)
+        return 1
+
+    for fromFile in os.listdir(fromDir):
+        fromFilePath = os.path.join(fromDir, fromFile)
+        toFilePath = os.path.join(toDir, fromFile)
+        if os.path.isdir(fromFilePath):
+            # 不支持的类型
+            if support is not None and fromFile not in support:
+                continue
+
+            ret = copyDir(fromFilePath, toFilePath, delete, support)
+            if ret:
+                return ret
+        else:
+            ret = copyFile(fromFilePath, toFilePath, delete)
+            if ret:
+                return ret
+
+    return 0
+
+
+def copyFile(formFile, toFile, delete=False):
+    '''
+    拷贝文件
+    '''
+    if not os.path.isfile(formFile):
+        print('----> %s not a file!' % formFile)
+        return 1
+
+    fpath, fname = os.path.split(toFile)  # 分离文件名和路径
+    if not os.path.exists(fpath):
+        # print('%s not exists, crate' % fpath)
+        os.makedirs(fpath)  # 创建路径
+
+    '''if os.path.exists(toFile) and os.path.getsize(formFile) > 104857600 and equalsFile(formFile, toFile):
+        print('skip copy %s --> %s' % (formFile, toFile))
+        if delete:
+            os.remove(formFile)
+            print('remove %s' % formFile)
+        return 0'''
+
+    if delete:
+        shutil.move(formFile, toFile)  # 移动文件
+        # print('move %s --> %s' % (formFile, toFile))
+    else:
+        shutil.copyfile(formFile, toFile)  # 复制文件
+        # print('copy %s --> %s' % (formFile, toFile))
+
+    return 0
+
+
+def replaceContent(file, oldText, newText):
+    '''
+    全局替换
+    '''
+    with openFile(file, 'r+') as f:
+        t = f.read()
+        t = t.replace(oldText, newText)
+        # 读写偏移位置移到最开始处
+        f.seek(0, 0)
+        # 清空内容
+        f.truncate()
+        f.write(t)
+
+
+def readFile(file):
+    '''
+    读取文件内容
+    '''
+    content = ''
+    with openFile(file, 'r') as f:
+        content = f.read()
+    return content
+
+
+def createFile(file, content):
+    '''
+    创建文件
+    '''
+    fpath, fname = os.path.split(file)  # 分离文件名和路径
+    if not os.path.exists(fpath):
+        os.makedirs(fpath)
+
+    with openFile(file, 'w') as f:
+        f.write(content)
+        f.close()
+
+
+def openFile(file, mode):
+    return open(file, mode, encoding='UTF-8')
+
+
+def deleteFolder(folder):
+    '''
+    删除目录以及目录下的文件
+    '''
+    if not os.path.exists(folder):
+        return
+
+    # print('remove %s ...' % folder)
+    shutil.rmtree(folder)
+    # print('removed %s' % folder)
+
+
+def getAAPTPath():
+    '''
+    获取aapt
+    '''
+    return getToolWithSystem('aapt')
+
+
+def getAAPT2Path():
+    '''
+    获取aapt2
+    '''
+    return getToolWithSystem('aapt2')
+
+
+def getAndroidCompileToolPath():
+    '''
+    获取android.jar
+    '''
+    return getFullToolPath('android.jar')
+
+
+def getDxPath():
+    '''
+    获取dx.jar
+    '''
+    return getFullToolPath('dx.jar')
+
+
+def getD8Path():
+    '''
+    获取d8.jar
+    '''
+    return getFullToolPath('d8.jar')
+
+
+def getAlignPath():
+    '''
+    获取zipalign
+    '''
+    return getToolWithSystem('zipalign')
+
+
+def getMultiDexPath():
+    '''
+    获取multidex.jar
+    '''
+    return getFullToolPath('android-support-multidex.jar')
+
+
+def getApkToolPath():
+    '''
+    获取apktool.jar
+    '''
+    return getFullToolPath('apktool_2.4.0.jar')
+
+
+def getBaksmaliPath():
+    '''
+    获取baksmali.jar
+    '''
+    return getFullToolPath('baksmali-2.3.jar')
+
+
+def getApksignerPath():
+    '''
+    获取apksigner.jar
+    '''
+    return getFullToolPath('apksigner.jar')
+
+
+def getWallePath():
+    '''
+    获取walle-cli-all.jar
+    '''
+    return getFullToolPath('walle-cli-all.jar')
+
+
+def getOutApkPath(game, sdk, subChannel, cache):
+    '''
+    获取输出的apk的目录
+    '''
+    return getFullPath('target', game, sdk, cache, '%s_%s_%s.apk' % (game, sdk, subChannel))
+
+
+def getTargetApkPath(game, sdk, cache):
+    '''
+    获取输出的apk的目录
+    '''
+    return getFullPath('target', game, sdk, cache)
+
+
+def getAlignApkPath(game, sdk, subChannel, cache):
+    '''
+    获取输出的apk的目录
+    '''
+    return getFullPath('target', game, sdk, cache, '%s_%s_%s_align.apk' % (game, sdk, subChannel))
+
+
+def getSiginedApkPath(game, sdk, subChannel, cache):
+    '''
+    获取输出的apk的目录
+    '''
+    return getFullPath('target', game, sdk, cache, '%s_%s_%s_signed.apk' % (game, sdk, subChannel))
+
+
+def getWalleApkPath(game, sdk, subChannel, cache):
+    '''
+    获取输出的apk的目录
+    '''
+    return getFullPath('target', game, sdk, cache, '%s_%s_%s_walled.apk' % (game, sdk, subChannel))
+
+
+def getRenameApkPath(game, sdk, cache, name):
+    '''
+    重命名输出的apk名称
+    '''
+    return getFullPath('target', game, sdk, cache, '%s.apk' % name)
+
+
+def getSignApkPath(game, sdk, subChannel, cache):
+    '''
+    获取输出的apk的目录
+    '''
+    return getFullPath('target', game, sdk, cache, '%s_%s_%s_signed.apk' % (game, sdk, subChannel))
+
+
+def getPackagePath(basePath, packageName):
+    '''
+    包名对应的目录
+    '''
+    packageNameSplit = packageName.split('.')
+    newPath = basePath
+    for item in packageNameSplit:
+        newPath = os.path.join(newPath, item)
+    return newPath
+
+
+def getToolWithSystem(tool):
+    '''
+    获取系统相关工具
+    '''
+    system = getSystemPath()
+    suffix = getSystemSuffix()
+    return os.path.join(getFullToolPath(system), tool + suffix)
+
+
+def getSystemPath():
+    '''
+    获取系统目录
+    '''
+    if platform.system() == 'Windows':
+        return 'win'
+    elif platform.system() == 'Darwin':
+        print('---------macos----------')
+        return 'macos'
+    else:
+        return 'linux'
+
+
+def getSystemSuffix():
+    '''
+    系统工具后缀
+    '''
+    if platform.system() == 'Windows':
+        return '.exe'
+    else:
+        return ''
+
+
+def getApplicationSmaliIndex(file):
+    '''
+    获取application.smali的MultiDex信息
+    '''
+    content = ('invoke-super', '->attachBaseContext(Landroid/content/Context;)V')
+    index = -1
+    with openFile(file, 'r') as f:
+        line = f.readline()
+        while line:
+            if content[0] in line and content[1] in line:
+                index = f.tell()
+                break
+            line = f.readline()
+
+    return index
+
+
+def insertApplicationSmali(file, index):
+    '''
+    获取application.smali插入MultiDex的信息
+    '''
+    if index == -1:
+        # append
+        content = '''# virtual methods
+.method protected attachBaseContext(Landroid/content/Context;)V
+    .locals 0
+    .param p1, "context"    # Landroid/content/Context;
+
+    invoke-super {p0, p1}, Landroid/app/Application;->attachBaseContext(Landroid/content/Context;)V
+
+    invoke-static {p0}, Landroid/support/multidex/MultiDex;->install(Landroid/content/Context;)V
+
+    return-void
+.end method'''
+        with openFile(file, 'a') as f:
+            f.write(content)
+    else:
+        # insert
+        content = '\n\tinvoke-static {p0}, Landroid/support/multidex/MultiDex;->install(Landroid/content/Context;)V\n'
+        with openFile(file, 'r+') as f:
+            f.seek(index)
+            last = f.read()
+            f.seek(index)
+            f.write(content)
+            f.write(last)
+    return 0
+
+
+def changeVersion(yml, versionCode=None, versionName=None, targetSdkVersion=None):
+    if versionCode is None and versionName is None and targetSdkVersion is None:
+        return 0
+
+    tag = ['versionCode:', 'versionName:', 'targetSdkVersion:']
+
+    with openFile(yml, 'r+') as f:
+        content = ''
+        line = f.readline()
+        while line:
+            if versionCode is not None and tag[0] in line:
+                content += '  versionCode: \'%s\'\n' % versionCode
+            elif versionName is not None and tag[1] in line:
+                content += '  versionName: %s\n' % versionName
+            elif targetSdkVersion is not None and tag[2] in line:
+                content += '  targetSdkVersion: \'%s\'\n' % targetSdkVersion
+            else:
+                content += line
+            line = f.readline()
+
+        f.seek(0, 0)
+        f.truncate()
+        f.write(content)
+
+    return 0
+
+
+def changeMinSdkVersion(yml, minSdkVersion):
+    with openFile(yml, 'r+') as f:
+        content = ''
+        line = f.readline()
+        while line:
+            if 'minSdkVersion' in line:
+                start = line.index("'")
+                version = int(line[start + 1:-2])
+                if version < minSdkVersion:
+                    content += '  minSdkVersion: \'%s\'\n' % minSdkVersion
+                else:
+                    return 0
+            else:
+                content += line
+            line = f.readline()
+
+        f.seek(0, 0)
+        f.truncate()
+        f.write(content)
+
+    return 0
+
+
+def list_files(src, resFiles):
+    '''
+    列出目录下所有的文件
+    '''
+    if os.path.exists(src):
+        if os.path.isfile(src):
+            resFiles.append(src)
+        elif os.path.isdir(src):
+            for f in os.listdir(src):
+                list_files(os.path.join(src, f), resFiles)
+    return resFiles
+
+
+def getFileMd5(f):
+    '''
+    获取文件的md5
+    '''
+    m = hashlib.md5()
+    while True:
+        data = f.read(1024)  # 将文件分块读取
+        if not data:
+            break
+        m.update(data)
+    return m.hexdigest()
+
+
+def equalsFile(file1, file2):
+    '''
+    比较两个文件是否是同一个文件
+    '''
+    with open(file1, 'rb') as f1, open(file2, 'rb') as f2:
+        file1Md5 = getFileMd5(f1)
+        file2Md5 = getFileMd5(f2)
+        # print('file1Md5:',file1Md5)
+        # print('file2Md5:',file2Md5)
+        return file1Md5 == file2Md5
+
+
+def getExecPermission(file):
+    '''
+    linux下获取执行权限
+    '''
+    if platform.system() == 'Windows':
+        return 0
+
+    return execFormatCmd('chmod +x "%s"' % file)
+
+
+def copySdkSmaliCode(game, sdk, subChannel, config):
+    '''
+    拷贝代码
+    '''
+    print('copySdkSmaliCode -->  %s' % sdk)
+    sdkPath = getFullSDKPath(sdk)
+
+    xmyFile = os.path.join(sdkPath, 'smali')
+    decompliePath = getDecompliePath(game, sdk, subChannel, config['cache'])
+    smaliPath = os.path.join(decompliePath, 'smali')
+    ret = copyDir(xmyFile, smaliPath)
+
+    return ret
+
+
+def copyGameSmaliCode(game, sdk, subChannel, config):
+    '''
+    拷贝代码
+    '''
+    print('copyGameSmaliCode -->  %s' % sdk)
+
+    if not config['aapt2disable']:
+        print('aapt2disable = false ~~~')
+        return 0
+    path = os.path.join(getCurrentPath(), "game_script", game, "gameSmali")
+
+    print('copyDir = gameSmali~~~')
+
+    decompliePath = getDecompliePath(game, sdk, subChannel, config['cache'])
+    smaliPath = os.path.join(decompliePath, 'smali')
+    ret = copyDir(path, smaliPath)
+
+    return ret

+ 58 - 58
game_utils.py

@@ -1,59 +1,59 @@
-import file_utils
-import xml_utils
-import os.path
-import xml.etree.ElementTree as ET
-
-namespaces = {'android' : 'http://schemas.android.com/apk/res/android'}
-encoding = 'UTF-8'
-
-def sdkLebianChange(game, sdk, config):
-    '''
-    乐变的处理,理论上只需要有接入的游戏需要处理
-    考虑到技术人员不可控,所以每个游戏都处理
-    '''
-    print('change Provider Authorities')
-
-    subChannel = config['subChannel']
-
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    changeProviderAuthorities(manifest, config['packageName'])
-    return 0
-
-def changeProviderAuthorities(manifest, packageName):
-    '''
-    标识为com.excelliance
-    更改provider的android:authorities
-    更改activity的android:taskAffinity
-    '''
-    for key in namespaces:
-        ET.register_namespace(key, namespaces[key])
-
-    tree = ET.parse(manifest)
-    root = tree.getroot()
-
-    packageTag = 'com.excelliance'
-    attrAuthorities = xml_utils.getNamespacesFormat('android:authorities', namespaces)
-    for provider in root.findall('application/provider'):
-        
-        if attrAuthorities not in provider.attrib:
-            continue
-
-        authorities = provider.attrib[attrAuthorities]
-        if packageTag not in authorities:
-            continue
-
-        auth = packageName + authorities[authorities.index(':'):]
-        provider.attrib[attrAuthorities] = auth
-    
-    attrName = xml_utils.getNamespacesFormat('android:name', namespaces)
-    attrTaskAffinity = xml_utils.getNamespacesFormat('android:taskAffinity', namespaces)
-
-    for activity in root.findall('application/activity'):
-        if packageTag not in activity.attrib[attrName]:
-            continue
-
-        if attrTaskAffinity in activity.attrib:
-            activity.attrib[attrTaskAffinity] = packageName
-
+import file_utils
+import xml_utils
+import os.path
+import xml.etree.ElementTree as ET
+
+namespaces = {'android' : 'http://schemas.android.com/apk/res/android'}
+encoding = 'UTF-8'
+
+def sdkLebianChange(game, sdk, config):
+    '''
+    乐变的处理,理论上只需要有接入的游戏需要处理
+    考虑到技术人员不可控,所以每个游戏都处理
+    '''
+    print('change Provider Authorities')
+
+    subChannel = config['subChannel']
+
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    changeProviderAuthorities(manifest, config['packageName'])
+    return 0
+
+def changeProviderAuthorities(manifest, packageName):
+    '''
+    标识为com.excelliance
+    更改provider的android:authorities
+    更改activity的android:taskAffinity
+    '''
+    for key in namespaces:
+        ET.register_namespace(key, namespaces[key])
+
+    tree = ET.parse(manifest)
+    root = tree.getroot()
+
+    packageTag = 'com.excelliance'
+    attrAuthorities = xml_utils.getNamespacesFormat('android:authorities', namespaces)
+    for provider in root.findall('application/provider'):
+        
+        if attrAuthorities not in provider.attrib:
+            continue
+
+        authorities = provider.attrib[attrAuthorities]
+        if packageTag not in authorities:
+            continue
+
+        auth = packageName + authorities[authorities.index(':'):]
+        provider.attrib[attrAuthorities] = auth
+    
+    attrName = xml_utils.getNamespacesFormat('android:name', namespaces)
+    attrTaskAffinity = xml_utils.getNamespacesFormat('android:taskAffinity', namespaces)
+
+    for activity in root.findall('application/activity'):
+        if packageTag not in activity.attrib[attrName]:
+            continue
+
+        if attrTaskAffinity in activity.attrib:
+            activity.attrib[attrTaskAffinity] = packageName
+
     tree.write(manifest, encoding)

+ 2 - 2
package.py

@@ -1,3 +1,3 @@
-import package_utils
-
+import package_utils
+
 package_utils.packConsoleInput()

+ 177 - 177
package_channel.py

@@ -1,178 +1,178 @@
-import file_utils
-import config_utils
-import sys
-import os.path
-import json
-
-def packageChannel():
-    if len(sys.argv) < 2:
-        print('argument is missing')
-        return 1
-
-    channelConfig = sys.argv[1]
-
-    jsonText = file_utils.readFile(channelConfig)
-    config = json.loads(jsonText)
-
-    print('*************config*****************')
-    print(jsonText)
-    print('************************************')
-
-    # 检查配置
-    if not checkConfig(config):
-        return 1
-
-    # 检查文件
-    gameApk = config['package']
-    if not os.path.exists(gameApk):
-        print('%s not exists' % gameApk)
-
-    if supportSignV2(gameApk):
-        packageChannelV2(gameApk, config)
-    else:
-        packageChannelV1(gameApk, config)
-
-def supportSignV2(gameApk):
-    '''
-    验证是否APK Signature Scheme v2
-    '''
-    apksigner = file_utils.getApksignerPath()
-    ret = getJavaResult(apksigner, 'verify --verbose "%s"' % gameApk)
-
-    if '(APK Signature Scheme v2): true' in ret:
-        return True
-    return False
-
-def packageChannelV2(gameApk, config):
-    walle = file_utils.getWallePath()
-
-    if not os.path.exists(config['outPath']):
-        os.makedirs(config['outPath'])
-
-    successCount = 0
-    failureCount = 0
-    channels = config['channel']
-    for channel in channels:
-        signedApk = os.path.join(config['outPath'], channel['outName'] + '.apk')
-        print('add channel package %s...' % signedApk)
-        appid = ''
-        appkey = ''
-        version = config_utils.getDate()
-        if 'appid' in channel:
-            appid = channel['appid']
-        if 'appkey' in channel:
-            appkey = channel['appkey']
-        if 'version' in channel:
-            version = channel['version']
-        ret = file_utils.execJarCmd(walle, 'put -e version=%s,agent=%s,appid=%s,appkey=%s "%s" "%s"' % (version, channel['agent'], appid, appkey, gameApk, signedApk))
-        if ret:
-            failureCount += 1
-        else:
-            successCount += 1
-
-    print('success %d, failure %d' % (successCount, failureCount))
-
-def packageChannelV1(gameApk, config):
-    # 解包
-    decompliePath = os.path.join(file_utils.getCurrentPath(), 'gen', 'channel')
-    if os.path.exists(decompliePath):
-        print('delete decomplie folder...')
-        file_utils.deleteFolder(decompliePath)
-
-    print('decomplie apk...')
-    apktoolPath = file_utils.getApkToolPath()
-    ret = file_utils.execJarCmd(apktoolPath, 'd -f "%s" -o "%s"' % (gameApk, decompliePath))
-    if ret:
-        return ret
-
-    if not os.path.exists(config['outPath']):
-        os.makedirs(config['outPath'])
-
-    alignapkTool = file_utils.getAlignPath()
-    apksigner = file_utils.getApksignerPath()
-    path = os.path.join(file_utils.getCurrentPath(), 'keystore', 'key.json')
-    jsonText = file_utils.readFile(path)
-    signConfig = json.loads(jsonText)
-    keystore = signConfig['default']
-    storeFile = os.path.join(file_utils.getCurrentPath(), 'keystore', keystore['storeFile'])
-
-    successCount = 0
-    failureCount = 0
-    channels = config['channel']
-    
-    for channel in channels:
-        changeChannel(decompliePath, channel)
-
-        temp = channel['agent']
-        backApk = os.path.join(decompliePath, temp + '.apk')
-        alignApk = os.path.join(decompliePath, temp + '_align.apk')
-        signedApk = os.path.join(config['outPath'], channel['outName'] + '.apk')
-
-        print('add channel package %s...' % signedApk)
-        print('recomplie apk...')
-        ret = file_utils.execJarCmd(apktoolPath, 'b -f "%s" -o "%s"' % (decompliePath, backApk))
-        if ret:
-            failureCount += 1
-            continue
-
-        print('align apk...')
-        ret = file_utils.execFormatCmd('"%s" -f -p 4 "%s" "%s"' % (alignapkTool, backApk, alignApk))
-        if ret:
-            failureCount += 1
-            continue
-
-        print('sign apk...')
-        ret = file_utils.execJarCmd(apksigner, 'sign --v2-signing-enabled=false --ks "%s" --ks-key-alias %s --ks-pass pass:%s --key-pass pass:%s --out "%s" "%s"' % (storeFile, keystore['keyAlias'], keystore['storePassword'], keystore['keyPassword'], signedApk, alignApk))
-        if ret:
-            failureCount += 1
-        else:
-            successCount += 1
-
-        if os.path.exists(alignApk):
-            os.remove(alignApk)
-        if os.path.exists(backApk):
-            os.remove(backApk)
-
-    print('success %d, failure %d' % (successCount, failureCount))
-
-def changeChannel(decompliePath, channel):
-    '''
-    修改渠道
-    '''
-    properties = os.path.join(decompliePath, 'assets', 'jmhy.properties')
-    appid = ''
-    appkey = ''
-    version = config_utils.getDate()
-    if 'appid' in channel:
-        appid = channel['appid']
-    if 'appkey' in channel:
-        appkey = channel['appkey']
-    if 'version' in channel:
-        version = channel['version']
-    content = 'version=%s\nagent=%s\nappid=%s\nappkey=%s' % (version, channel['agent'], appid, appkey)
-    file_utils.createFile(properties, content)
-
-def checkConfig(config):
-    if 'package' not in config:
-        print('package not exists in config')
-        return False
-
-    if 'outPath' not in config:
-        print('outPath not exists in config')
-        return False
-
-    if 'channel' not in config:
-        print('channel not exists in config')
-        return False
-
-    return True
-
-def getJavaResult(jar, cmd):
-    return getCmdResult('java -jar "%s" %s' % (jar, cmd))
-
-def getCmdResult(cmd):
-    p = os.popen(cmd)
-    content = p.read()
-    return content
-
+import file_utils
+import config_utils
+import sys
+import os.path
+import json
+
+def packageChannel():
+    if len(sys.argv) < 2:
+        print('argument is missing')
+        return 1
+
+    channelConfig = sys.argv[1]
+
+    jsonText = file_utils.readFile(channelConfig)
+    config = json.loads(jsonText)
+
+    print('*************config*****************')
+    print(jsonText)
+    print('************************************')
+
+    # 检查配置
+    if not checkConfig(config):
+        return 1
+
+    # 检查文件
+    gameApk = config['package']
+    if not os.path.exists(gameApk):
+        print('%s not exists' % gameApk)
+
+    if supportSignV2(gameApk):
+        packageChannelV2(gameApk, config)
+    else:
+        packageChannelV1(gameApk, config)
+
+def supportSignV2(gameApk):
+    '''
+    验证是否APK Signature Scheme v2
+    '''
+    apksigner = file_utils.getApksignerPath()
+    ret = getJavaResult(apksigner, 'verify --verbose "%s"' % gameApk)
+
+    if '(APK Signature Scheme v2): true' in ret:
+        return True
+    return False
+
+def packageChannelV2(gameApk, config):
+    walle = file_utils.getWallePath()
+
+    if not os.path.exists(config['outPath']):
+        os.makedirs(config['outPath'])
+
+    successCount = 0
+    failureCount = 0
+    channels = config['channel']
+    for channel in channels:
+        signedApk = os.path.join(config['outPath'], channel['outName'] + '.apk')
+        print('add channel package %s...' % signedApk)
+        appid = ''
+        appkey = ''
+        version = config_utils.getDate()
+        if 'appid' in channel:
+            appid = channel['appid']
+        if 'appkey' in channel:
+            appkey = channel['appkey']
+        if 'version' in channel:
+            version = channel['version']
+        ret = file_utils.execJarCmd(walle, 'put -e version=%s,agent=%s,appid=%s,appkey=%s "%s" "%s"' % (version, channel['agent'], appid, appkey, gameApk, signedApk))
+        if ret:
+            failureCount += 1
+        else:
+            successCount += 1
+
+    print('success %d, failure %d' % (successCount, failureCount))
+
+def packageChannelV1(gameApk, config):
+    # 解包
+    decompliePath = os.path.join(file_utils.getCurrentPath(), 'gen', 'channel')
+    if os.path.exists(decompliePath):
+        print('delete decomplie folder...')
+        file_utils.deleteFolder(decompliePath)
+
+    print('decomplie apk...')
+    apktoolPath = file_utils.getApkToolPath()
+    ret = file_utils.execJarCmd(apktoolPath, 'd -f "%s" -o "%s"' % (gameApk, decompliePath))
+    if ret:
+        return ret
+
+    if not os.path.exists(config['outPath']):
+        os.makedirs(config['outPath'])
+
+    alignapkTool = file_utils.getAlignPath()
+    apksigner = file_utils.getApksignerPath()
+    path = os.path.join(file_utils.getCurrentPath(), 'keystore', 'key.json')
+    jsonText = file_utils.readFile(path)
+    signConfig = json.loads(jsonText)
+    keystore = signConfig['default']
+    storeFile = os.path.join(file_utils.getCurrentPath(), 'keystore', keystore['storeFile'])
+
+    successCount = 0
+    failureCount = 0
+    channels = config['channel']
+    
+    for channel in channels:
+        changeChannel(decompliePath, channel)
+
+        temp = channel['agent']
+        backApk = os.path.join(decompliePath, temp + '.apk')
+        alignApk = os.path.join(decompliePath, temp + '_align.apk')
+        signedApk = os.path.join(config['outPath'], channel['outName'] + '.apk')
+
+        print('add channel package %s...' % signedApk)
+        print('recomplie apk...')
+        ret = file_utils.execJarCmd(apktoolPath, 'b -f "%s" -o "%s"' % (decompliePath, backApk))
+        if ret:
+            failureCount += 1
+            continue
+
+        print('align apk...')
+        ret = file_utils.execFormatCmd('"%s" -f -p 4 "%s" "%s"' % (alignapkTool, backApk, alignApk))
+        if ret:
+            failureCount += 1
+            continue
+
+        print('sign apk...')
+        ret = file_utils.execJarCmd(apksigner, 'sign --v2-signing-enabled=false --ks "%s" --ks-key-alias %s --ks-pass pass:%s --key-pass pass:%s --out "%s" "%s"' % (storeFile, keystore['keyAlias'], keystore['storePassword'], keystore['keyPassword'], signedApk, alignApk))
+        if ret:
+            failureCount += 1
+        else:
+            successCount += 1
+
+        if os.path.exists(alignApk):
+            os.remove(alignApk)
+        if os.path.exists(backApk):
+            os.remove(backApk)
+
+    print('success %d, failure %d' % (successCount, failureCount))
+
+def changeChannel(decompliePath, channel):
+    '''
+    修改渠道
+    '''
+    properties = os.path.join(decompliePath, 'assets', 'jmhy.properties')
+    appid = ''
+    appkey = ''
+    version = config_utils.getDate()
+    if 'appid' in channel:
+        appid = channel['appid']
+    if 'appkey' in channel:
+        appkey = channel['appkey']
+    if 'version' in channel:
+        version = channel['version']
+    content = 'version=%s\nagent=%s\nappid=%s\nappkey=%s' % (version, channel['agent'], appid, appkey)
+    file_utils.createFile(properties, content)
+
+def checkConfig(config):
+    if 'package' not in config:
+        print('package not exists in config')
+        return False
+
+    if 'outPath' not in config:
+        print('outPath not exists in config')
+        return False
+
+    if 'channel' not in config:
+        print('channel not exists in config')
+        return False
+
+    return True
+
+def getJavaResult(jar, cmd):
+    return getCmdResult('java -jar "%s" %s' % (jar, cmd))
+
+def getCmdResult(cmd):
+    p = os.popen(cmd)
+    content = p.read()
+    return content
+
 packageChannel()

+ 92 - 92
package_channel_douyou.py

@@ -1,93 +1,93 @@
-import file_utils
-import config_utils
-import sys
-import os.path
-import json
-
-def packageChannel():
-    if len(sys.argv) < 2:
-        print('argument is missing')
-        return 1
-
-    channelConfig = sys.argv[1]
-
-    jsonText = file_utils.readFile(channelConfig)
-    config = json.loads(jsonText)
-
-    print('*************config*****************')
-    print(jsonText)
-    print('************************************')
-
-    # 检查配置
-    if not checkConfig(config):
-        return 1
-
-    # 检查文件
-    gameApk = config['package']
-    if not os.path.exists(gameApk):
-        print('%s not exists' % gameApk)
-        return 1
-
-    if supportSignV2(gameApk):
-        packageChannelV2(gameApk, config)
-        return 0
-    else:
-        print('apk not support Signature Scheme v2' % gameApk)
-        return 1
-
-def supportSignV2(gameApk):
-    '''
-    验证是否APK Signature Scheme v2
-    '''
-    apksigner = file_utils.getApksignerPath()
-    ret = getJavaResult(apksigner, 'verify --verbose "%s"' % gameApk)
-
-    if '(APK Signature Scheme v2): true' in ret:
-        return True
-    return False
-
-def packageChannelV2(gameApk, config):
-    print('add channel package ...')
-    walle = file_utils.getWallePath()
-
-    if not os.path.exists(config['outPath']):
-        os.makedirs(config['outPath'])
-
-    successCount = 0
-    failureCount = 0
-    channels = config['channel']
-    for channel in channels:
-        print('add channel package %s --> %s...' % (channel['agent'], channel['outName']))
-        signedApk = os.path.join(config['outPath'], channel['outName'] + '.apk')
-        ret = file_utils.execJarCmd(walle, 'put -c %s "%s" "%s"' % (channel['agent'], gameApk, signedApk))
-        if ret:
-            failureCount += 1
-        else:
-            successCount += 1
-
-    print('success %d, failure %d' % (successCount, failureCount))
-
-def checkConfig(config):
-    if 'package' not in config:
-        print('package not exists in config')
-        return False
-
-    if 'outPath' not in config:
-        print('outPath not exists in config')
-        return False
-
-    if 'channel' not in config:
-        print('channel not exists in config')
-        return False
-
-    return True
-
-def getJavaResult(jar, cmd):
-    return getCmdResult('java -jar "%s" %s' % (jar, cmd))
-
-def getCmdResult(cmd):
-    p = os.popen(cmd)
-    content = p.read()
-    return content
-
+import file_utils
+import config_utils
+import sys
+import os.path
+import json
+
+def packageChannel():
+    if len(sys.argv) < 2:
+        print('argument is missing')
+        return 1
+
+    channelConfig = sys.argv[1]
+
+    jsonText = file_utils.readFile(channelConfig)
+    config = json.loads(jsonText)
+
+    print('*************config*****************')
+    print(jsonText)
+    print('************************************')
+
+    # 检查配置
+    if not checkConfig(config):
+        return 1
+
+    # 检查文件
+    gameApk = config['package']
+    if not os.path.exists(gameApk):
+        print('%s not exists' % gameApk)
+        return 1
+
+    if supportSignV2(gameApk):
+        packageChannelV2(gameApk, config)
+        return 0
+    else:
+        print('apk not support Signature Scheme v2' % gameApk)
+        return 1
+
+def supportSignV2(gameApk):
+    '''
+    验证是否APK Signature Scheme v2
+    '''
+    apksigner = file_utils.getApksignerPath()
+    ret = getJavaResult(apksigner, 'verify --verbose "%s"' % gameApk)
+
+    if '(APK Signature Scheme v2): true' in ret:
+        return True
+    return False
+
+def packageChannelV2(gameApk, config):
+    print('add channel package ...')
+    walle = file_utils.getWallePath()
+
+    if not os.path.exists(config['outPath']):
+        os.makedirs(config['outPath'])
+
+    successCount = 0
+    failureCount = 0
+    channels = config['channel']
+    for channel in channels:
+        print('add channel package %s --> %s...' % (channel['agent'], channel['outName']))
+        signedApk = os.path.join(config['outPath'], channel['outName'] + '.apk')
+        ret = file_utils.execJarCmd(walle, 'put -c %s "%s" "%s"' % (channel['agent'], gameApk, signedApk))
+        if ret:
+            failureCount += 1
+        else:
+            successCount += 1
+
+    print('success %d, failure %d' % (successCount, failureCount))
+
+def checkConfig(config):
+    if 'package' not in config:
+        print('package not exists in config')
+        return False
+
+    if 'outPath' not in config:
+        print('outPath not exists in config')
+        return False
+
+    if 'channel' not in config:
+        print('channel not exists in config')
+        return False
+
+    return True
+
+def getJavaResult(jar, cmd):
+    return getCmdResult('java -jar "%s" %s' % (jar, cmd))
+
+def getCmdResult(cmd):
+    p = os.popen(cmd)
+    content = p.read()
+    return content
+
 packageChannel()

+ 2 - 2
package_record.py

@@ -1,3 +1,3 @@
-import package_utils_record
-
+import package_utils_record
+
 package_utils_record.packConsoleInput()

+ 2 - 2
package_shanshen.py

@@ -1,3 +1,3 @@
-import package_utils_shanshen
-
+import package_utils_shanshen
+
 package_utils_shanshen.packConsoleInput()

+ 65 - 65
package_test.py

@@ -1,66 +1,66 @@
-import package_utils
-import file_utils
-import xml_utils
-import config_utils
-import os
-import os.path
-import json
-
-def packTest():
-    '''
-    测试代码
-    '''
-    game = 'sample'
-    sdk = 'float'
-    subChannel = 'test'
-
-    channelPath = file_utils.getChannelPath(game, sdk)
-    configPath = os.path.join(channelPath, 'config.json')
-    jsonText = file_utils.readFile(configPath)
-    config = json.loads(jsonText)
-    config_utils.replaceArgs(config)
-
-    config = getItemConfig(config, subChannel)
-    if config is None:
-        return 1
-
-    package_utils.decomplie(game, sdk, subChannel, config)
-    package_utils.removeNoSupportAttr(game, sdk, subChannel, config)
-    package_utils.mergeDrawableRes(game, sdk, subChannel, config)
-    package_utils.removeSameRes(game, sdk, subChannel, config)
-    package_utils.copyRes(game, sdk, subChannel, config)
-    package_utils.mergeManifestRes(game, sdk, subChannel, config)
-    package_utils.changePlaceholders(game, sdk, subChannel, config)
-    package_utils.addMetaData(game, sdk, subChannel, config)
-    package_utils.copyAppRes(game, sdk, subChannel, config)
-    package_utils.changePackageName(game, sdk, subChannel, config)
-    package_utils.changeAppName(game, sdk, subChannel, config)
-    package_utils.changeAppIcon(game, sdk, subChannel, config)
-    package_utils.addLauncher(game, sdk, subChannel, config)
-    package_utils.packJar(game, sdk, subChannel, config)
-    package_utils.doSDKPostScript(game, sdk, config)
-    package_utils.doGamePostScript(game, sdk, config)
-    package_utils.generateNewRFile(game, sdk, subChannel, config)
-    package_utils.splitDex(game, sdk, subChannel, config)
-    package_utils.recomplie(game, sdk, subChannel, config)
-    package_utils.alignApk(game, sdk, subChannel, config)
-    package_utils.apksignerApk(game, sdk, subChannel, config)
-    package_utils.clearTemp(game, sdk, subChannel, config)
-
-def getCmd(cmd):
-    p = os.popen(cmd)
-    content = p.read()
-    #print(content)
-    return content
-
-def getItemConfig(config, subChannel):
-    if type(config) == dict:
-        if subChannel is None or config['subChannel'] == subChannel:
-            return config
-    elif type(config) == list:
-        for itemConfig in config:
-            if subChannel is None or itemConfig['subChannel'] == subChannel:
-                return subChannel
-    return None
-
+import package_utils
+import file_utils
+import xml_utils
+import config_utils
+import os
+import os.path
+import json
+
+def packTest():
+    '''
+    测试代码
+    '''
+    game = 'sample'
+    sdk = 'float'
+    subChannel = 'test'
+
+    channelPath = file_utils.getChannelPath(game, sdk)
+    configPath = os.path.join(channelPath, 'config.json')
+    jsonText = file_utils.readFile(configPath)
+    config = json.loads(jsonText)
+    config_utils.replaceArgs(config)
+
+    config = getItemConfig(config, subChannel)
+    if config is None:
+        return 1
+
+    package_utils.decomplie(game, sdk, subChannel, config)
+    package_utils.removeNoSupportAttr(game, sdk, subChannel, config)
+    package_utils.mergeDrawableRes(game, sdk, subChannel, config)
+    package_utils.removeSameRes(game, sdk, subChannel, config)
+    package_utils.copyRes(game, sdk, subChannel, config)
+    package_utils.mergeManifestRes(game, sdk, subChannel, config)
+    package_utils.changePlaceholders(game, sdk, subChannel, config)
+    package_utils.addMetaData(game, sdk, subChannel, config)
+    package_utils.copyAppRes(game, sdk, subChannel, config)
+    package_utils.changePackageName(game, sdk, subChannel, config)
+    package_utils.changeAppName(game, sdk, subChannel, config)
+    package_utils.changeAppIcon(game, sdk, subChannel, config)
+    package_utils.addLauncher(game, sdk, subChannel, config)
+    package_utils.packJar(game, sdk, subChannel, config)
+    package_utils.doSDKPostScript(game, sdk, config)
+    package_utils.doGamePostScript(game, sdk, config)
+    package_utils.generateNewRFile(game, sdk, subChannel, config)
+    package_utils.splitDex(game, sdk, subChannel, config)
+    package_utils.recomplie(game, sdk, subChannel, config)
+    package_utils.alignApk(game, sdk, subChannel, config)
+    package_utils.apksignerApk(game, sdk, subChannel, config)
+    package_utils.clearTemp(game, sdk, subChannel, config)
+
+def getCmd(cmd):
+    p = os.popen(cmd)
+    content = p.read()
+    #print(content)
+    return content
+
+def getItemConfig(config, subChannel):
+    if type(config) == dict:
+        if subChannel is None or config['subChannel'] == subChannel:
+            return config
+    elif type(config) == list:
+        for itemConfig in config:
+            if subChannel is None or itemConfig['subChannel'] == subChannel:
+                return subChannel
+    return None
+
 packTest()

+ 1631 - 1473
package_utils.py

@@ -1,1473 +1,1631 @@
-# 安卓游戏打包脚本
-# 1.用apktool解包
-# 2.复制res资源、assets资源、jniLib资源
-# 3.修改包名、app名、渠道文件
-# 4.添加app icon、合并AndroidManifest文件
-# 5.添加app启动图,修改AndroidManifest文件
-# 6.生成新的R文件
-# 7.将新的R文件编译,生成dex,再用baksmali生成smali,替换旧的R文件
-# 8.将jar资源打包成dex,再用baksmali生成smali,拷贝到smali目录下
-# 9.统计方法量,并分割dex(将smali文件拷贝到目录smali_classes2)
-# 10.用apktool回包
-# 11.重新签名
-import file_utils
-import xml_utils
-import smali_utils
-import config_utils
-import game_utils
-import common_utils
-import os
-import os.path
-import json
-import sys
-import importlib
-import uuid
-import zipfile
-import time
-import datetime
-
-
-ignoreLauncher = ['jm_ysdk', 'jm_yijie', 'jm_quick', 'jm_beiyu', 'jm_xq_jrtt','jm_zy_ysdk']
-adaptApp = ['yjzx']
-startTime = ''
-
-def pack(game, sdk, config):
-    config['cache'] = uuid.uuid1()
-    subChannel = config['subChannel']
-    print('game = %s, sdk = %s, subChannel = %s, ...' % (game,sdk,subChannel))
-
-    # 解包
-    ret = decomplie(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 删除旧代码
-    ret = removeOldCode(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 删除一些不支持的属性
-    ret = removeNoSupportAttr(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 删除一些不支持的配置
-    ret = fixUnSupportConfig(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 合并Drawable-v4目录
-    ret = mergeDrawableRes(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 移除相同的资源
-    ret = removeSameRes(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 复制res资源
-    ret = copyRes(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 合并主文件
-    ret = mergeManifestRes(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 替换占位符
-    ret = changePlaceholders(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 添加meta-data
-    ret = addMetaData(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 增加配置文件
-    ret = addConfig(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 复制app res资源
-    ret = copyAppRes(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 更改包名
-    if 'packageName' in config and config['packageName'] != '':
-        ret = changePackageName(game, sdk, subChannel, config)
-        if ret:
-            return ret
-    # 更改app名
-    if 'name' in config and config['name'] != '':
-        ret = changeAppName(game, sdk, subChannel, config)
-        if ret:
-            return ret
-    # 更改app icon
-    if config['changeIcon']:
-        ret = changeAppIcon(game, sdk, subChannel, config)
-        if ret:
-            return ret
-    # 添加启动图操作
-    if config['addLauncher']:
-        ret = addLauncher(game, sdk, subChannel, config)
-        if ret:
-            return ret
-    # 添加多图标
-    #ret = addMoreIcon(game, sdk, subChannel, config)
-    # 复制icon图标到res
-    ret = copyIcon(game, sdk, subChannel, config)
-    #if ret:
-    #    return ret
-    # 打包lib依赖
-
-    ret = packJar(game, sdk, subChannel, config)
-    if ret:
-        return ret
-
-
-    #继承JMApplication
-    common_utils.changeApplication(game, sdk, subChannel, config, 'com.jmhy.sdk.common.JMApplication')
-
-
-    # sdk脚本处理
-    ret = doSDKPostScript(game, sdk, config)
-    if ret:
-        return ret
-    # 乐变sdk的特殊处理
-    ret = game_utils.sdkLebianChange(game, sdk, config)
-    if ret:
-        return ret
-    # 游戏脚本处理
-    ret = doGamePostScript(game, sdk, config)
-    if ret:
-        return ret
-
-    # 游戏独立处理
-    ret = doGameScript(game, sdk, config)
-    if ret:
-        return ret
-
-    #格式化Xml
-    # ret = formatXml(game, sdk, subChannel, config)
-    # if ret:
-    #     return ret
-
-
-    # log sdk
-    if 'logSdk' in config:
-        for log in config['logSdk']:
-            ret = addLogSdk(game, sdk, subChannel, config, log)
-            if ret:
-                return ret
-
-    # oaid sdk
-    ret = addOaidSdk(game, sdk, subChannel, config, "1.0.10")
-    if ret:
-        return ret
-
-    # 生成R文件
-    '''ret = generateNewRFile(game, sdk, subChannel, config)
-    if ret:
-        return ret'''
-    # 添加MultiDex支持
-    if config['splitDex']:
-        ret = splitDex(game, sdk, subChannel, config)
-        if ret:
-            return ret
-    # 更改版本号
-    ret = changeVersion(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 回编译
-    ret = recomplie(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 对齐apk
-    ret = alignApk(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 签名
-    ret = apksignerApk(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 添加渠道信息
-    ret = addChannel(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 清理产生的中间文件
-    if config['clearCache']:
-        clearTemp(game, sdk, subChannel, config)
-
-    endTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
-    d1 = datetime.datetime.strptime(endTime, '%Y-%m-%d %H:%M:%S')
-    d2 = datetime.datetime.strptime(startTime,  '%Y-%m-%d %H:%M:%S')
-    d = d1 - d2
-    print ('开始时间:' + startTime)
-    print ('结束时间:' + endTime)
-    print ('用时:{}'.format(config_utils.getTime(d.seconds)))
-    return 0
-
-def decomplie(game, sdk, subChannel, config):
-    '''
-    解包
-    '''
-    apktoolPath = file_utils.getApkToolPath()
-    gamePath = file_utils.getFullGameApk(game)
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-
-    if os.path.exists(decompliePath):
-        print('delete decomplie folder...')
-        file_utils.deleteFolder(decompliePath)
-
-    print('decomplie apk...')
-
-    return file_utils.execJarCmd(apktoolPath, 'd -f "%s" -o "%s"' % (gamePath, decompliePath))
-
-def removeOldCode(game, sdk, subChannel, config):
-    '''
-    删除旧代码
-    '''
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    codePath = os.path.join(decompliePath, 'smali', 'com', 'jmhy', 'sdk')
-    #file_utils.deleteFolder(codePath)
-    allFiles = []
-    allFiles = file_utils.list_files(codePath, allFiles)
-    for f in allFiles:
-        fpath, fname = os.path.split(f)  #分离文件名和路径
-        if fname == 'R.smali' or fname.startswith('R$'):
-            continue
-        os.remove(f)
-        #print('remove %s' % f)
-    return 0
-
-def copyRes(game, sdk, subChannel, config):
-    '''
-    复制res资源
-    '''
-    # 拷贝sdk资源
-    print('copy res...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    sdkPath = file_utils.getFullSDKPath(sdk)
-    resPath = os.path.join(sdkPath, 'res')
-    decomplieResPath = file_utils.getFullPath(decompliePath, 'res')
-
-    for d in os.listdir(resPath):
-        copyResWithType(resPath, decomplieResPath, d)
-
-    # 拷贝assets
-    print('copy assets...')
-    assetsPath = file_utils.getFullPath(sdkPath, 'assets')
-    decomplieAssetsPath = file_utils.getFullPath(decompliePath, 'assets')
-    if os.path.exists(assetsPath):
-        ret = file_utils.copyFileAllDir(assetsPath, decomplieAssetsPath)
-        if ret:
-            return ret
-
-    # 拷贝jniLib
-    print('copy jniLibs...')
-    jniPath = file_utils.getFullPath(sdkPath, 'jniLibs')
-    decomplieJniPath = file_utils.getFullPath(decompliePath, 'lib')
-    abiFilters = []
-    if os.path.exists(decomplieJniPath):
-        for abi in os.listdir(decomplieJniPath):
-            if abi == 'armeabi-v7a' or abi == 'armeabi':
-                abiFilters.append(abi)
-    else:
-        abiFilters = ['armeabi-v7a']
-
-    if os.path.exists(jniPath):
-        ret = file_utils.copyFileAllDir(jniPath, decomplieJniPath, False, abiFilters)
-        if ret:
-            return ret
-    return 0
-
-def mergeDrawableRes(game, sdk, subChannel, config):
-    '''
-    合并Drawable-v4目录
-    '''
-    print('merge drawable path...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    resPath = os.path.join(decompliePath, 'res')
-
-    for path in os.listdir(resPath):
-        #print('res path %s' % path)
-        if (path.startswith('drawable') or path.startswith('mipmap')) and path.endswith('-v4'):
-            #print('merge path %s' % path)
-            v4DrawablePath = os.path.join(resPath, path)
-            drawablePath = os.path.join(resPath, path[:-3])
-
-            if os.path.exists(drawablePath):
-                ret = file_utils.copyFileAllDir(v4DrawablePath, drawablePath, True)
-                if ret:
-                    return ret
-            else:
-                os.rename(v4DrawablePath, drawablePath)
-    return 0
-
-def removeSameRes(game, sdk, subChannel, config):
-    '''
-    移除相同的资源
-    '''
-    # 读取sdk的资源
-    print('remove same res...')
-    sdkPath = file_utils.getFullSDKPath(sdk)
-    sdkResPath = os.path.join(sdkPath, 'res')
-    resList = []
-    for path in os.listdir(sdkResPath):
-        if not path.startswith('values'):
-            continue
-        absPath = os.path.join(sdkResPath, path)
-        for resFile in os.listdir(absPath):
-            '''if not resFile.startswith('jm_'):
-                continue'''
-            if resFile.endswith('.DS_Store'):
-                continue
-            #print('readAllRes -- > ' + os.path.join(absPath, resFile))
-
-            resList = xml_utils.readAllRes(os.path.join(absPath, resFile), resList)
-
-    if len(resList) == 0:
-        print('no same res found')
-        return 0
-
-    # 移除相同的资源
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    resPath = os.path.join(decompliePath, 'res')
-    for path in os.listdir(resPath):
-        if not path.startswith('values'):
-            continue
-
-        absPath = os.path.join(resPath, path)
-        for resFile in os.listdir(absPath):
-            xml_utils.removeSameRes(os.path.join(absPath, resFile), resList)
-
-    return 0
-
-def mergeManifestRes(game, sdk, subChannel, config):
-    '''
-    合并主文件
-    '''
-    print('merge AndroidManifest...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    sdkPath = file_utils.getFullSDKPath(sdk)
-    libManifest = file_utils.getFullPath(sdkPath, 'manifest.xml')
-    return xml_utils.mergeManifestRes(manifest, libManifest)
-
-def copyAppRes(game, sdk, subChannel, config):
-    '''
-    拷贝app的资源,比如app icon、启动图等
-    '''
-    channelPath = file_utils.getSubChannelPath(game, sdk, subChannel)
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-
-    # assets
-    print('copy assets...')
-    #适配一剑斩仙
-    if game in adaptApp:
-        print('适配一剑斩仙...')
-        decomplieAssetsPath = file_utils.getFullPath(decompliePath, 'assets')
-        skinZipPath = os.path.join(decomplieAssetsPath, 'skin.zip')
-        skinPath = os.path.join(decomplieAssetsPath, 'skin')
-        if os.path.exists(skinZipPath):
-            with zipfile.ZipFile(skinZipPath) as zf:
-                zf.extractall(decomplieAssetsPath)
-                print('create unzip skin' )
-            assetsPath = file_utils.getFullPath(channelPath, 'assets')
-            decomplieAssetsPath = file_utils.getFullPath(decompliePath, 'assets')
-            if os.path.exists(assetsPath):
-                ret = file_utils.copyFileAllDir(assetsPath, decomplieAssetsPath)
-            with zipfile.ZipFile(skinZipPath, 'w') as z:
-                for root, dirs, files in os.walk(skinPath):
-                    for single_file in files:
-                        filepath = os.path.join(root, single_file)
-                        print ('create zip ---> ' + filepath)
-                        temPath = 'skin/' + single_file
-                        z.write(filepath, temPath)
-            z.close()
-        else:
-            print('normal copy assets...')
-            assetsPath = file_utils.getFullPath(channelPath, 'assets')
-            decomplieAssetsPath = file_utils.getFullPath(decompliePath, 'assets')
-            if os.path.exists(assetsPath):
-                ret = file_utils.copyFileAllDir(assetsPath, decomplieAssetsPath)
-                if ret:
-                    return ret
-    else:
-        print('normal copy assets...')
-        assetsPath = file_utils.getFullPath(channelPath, 'assets')
-        decomplieAssetsPath = file_utils.getFullPath(decompliePath, 'assets')
-        if os.path.exists(assetsPath):
-            ret = file_utils.copyFileAllDir(assetsPath, decomplieAssetsPath)
-            if ret:
-                return ret
-
-    # icon
-    print('copy icon...')
-    ret = copyAppResWithType(decompliePath, channelPath, 'icon')
-    if ret:
-        return ret
-    # 启动图
-    print('copy splash...')
-    ret = copyAppResWithType(decompliePath, channelPath, 'splash')
-    if ret:
-        return ret
-    # 其他图片
-    print('copy image...')
-    ret = copyAppResWithType(decompliePath, channelPath, 'image')
-    if ret:
-        return ret
-    return 0
-    
-def copyAppResWithType(decompliePath, channelPath, typeName):
-    decomplieResPath = os.path.join(decompliePath, 'res')
-    iconPath = os.path.join(channelPath, typeName)
-    if not os.path.exists(iconPath):
-        print('dir "%s" not exists' % iconPath)
-        return 0
-    for d in os.listdir(iconPath):
-        ret = copyResWithType(iconPath, decomplieResPath, d)
-        if ret:
-            return ret
-
-    return 0
-
-def copyResWithType(resPath, decomplieResPath, typeName):
-    # appt的打包目录会带-v4后缀
-    resDir = os.path.join(resPath, typeName)
-    target = os.path.join(decomplieResPath, typeName)
-    targetV4 = os.path.join(decomplieResPath, typeName + '-v4')
-    if not os.path.exists(target) and not os.path.exists(targetV4):
-        os.makedirs(target)
-        return file_utils.copyFileAllDir(resDir, target, False)
-    elif not os.path.exists(target):
-        return file_utils.copyFileAllDir(resDir, targetV4, False)
-    else:
-        return file_utils.copyFileAllDir(resDir, target, False)
-
-def removeNoSupportAttr(game, sdk, subChannel, config):
-    '''
-    删除一些不支持的属性
-    '''
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    
-    xml_utils.removeRootAttr(manifest, 'compileSdkVersion')
-    xml_utils.removeRootAttr(manifest, 'compileSdkVersionCodename')
-    
-    return 0
-
-def fixUnSupportConfig(game, sdk, subChannel, config):
-    '''
-    删除一些不支持的配置
-    '''
-    # 检查minSdkVersion
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    yml = os.path.join(decompliePath, 'apktool.yml')
-
-    minSdkVersion = 15
-    file_utils.changeMinSdkVersion(yml, minSdkVersion)
-
-    resPath = os.path.join(decompliePath, 'res')
-
-    tag = '-v'
-    for res in os.listdir(resPath):
-        #print('res = ' + res)
-        if res.startswith('values') and tag in res:
-            start = res.index(tag)
-            version = res[start+len(tag):]
-            if not version.isdigit():
-                continue
-            
-            version = int(version)
-            print('version = %d' % version)
-            if version < minSdkVersion:
-                unSopportPath = os.path.join(resPath, res)
-                print('unSopportPath = ' + unSopportPath)
-                file_utils.deleteFolder(unSopportPath)
-                print('deleteFolder = ' + unSopportPath)
-    
-    return 0
-
-def changePackageName(game, sdk, subChannel, config):
-    '''
-    更改包名
-    '''
-    # 全局替换AndroidManifest里面的包名
-    newPackageName = config['packageName']
-
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    packageName = xml_utils.getPackageName(manifest)
-    
-    xml_utils.changePackageName(manifest, newPackageName)
-    print('change package name %s --> %s' % (packageName, newPackageName))
-    return 0
-
-def changeAppName(game, sdk, subChannel, config):
-    '''
-    更改app名
-    '''
-    # 生成string.xml文件
-    name = config['name']
-
-    resName = 'common_sdk_name'
-    if 'outName' in config:
-        resName = resName + '_' + config['outName']
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    stringFile = os.path.join(decompliePath, 'res', 'values', 'sdk_strings_temp.xml')
-    content = '<?xml version="1.0" encoding="utf-8"?><resources><string name="%s">%s</string></resources>' % (resName, name)
-    file_utils.createFile(stringFile, content)
-
-    # 修改主文件的app名的值
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    xml_utils.changeAppName(manifest, '@string/%s' % resName)
-    print('change app name %s' % name)
-    return 0
-
-def changeAppIcon(game, sdk, subChannel, config):
-    '''
-    更改app icon
-    '''
-    print('change app icon...')
-    resName = 'common_sdk_icon'
-
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    xml_utils.changeAppIcon(manifest, '@mipmap/%s' % resName)
-    return 0
-
-def addMetaData(game, sdk, subChannel, config):
-    '''
-    添加meta-data
-    '''
-    if 'metaData' not in config:
-        return 0
-
-    print('add meta-data...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    xml_utils.addMetaData(manifest, config['metaData'])
-    return 0
-
-def addConfig(game, sdk, subChannel, config):
-    '''
-    添加config.json
-    '''
-    if 'configData' not in config:
-        return 0
-
-    print('add config.json...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    configJson = os.path.join(decompliePath, 'assets', 'jmhy_config.json')
-    jsonText = json.dumps(config['configData'], ensure_ascii=False)
-    file_utils.createFile(configJson, jsonText)
-    return 0
-
-def changePlaceholders(game, sdk, subChannel, config):
-    '''
-    处理掉占位符
-    '''
-    if 'placeholders' not in config:
-        return 0
-
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-
-    placeholders = config['placeholders']
-    for placeholder in placeholders:
-        oldText = '${%s}' % placeholder
-        newText = placeholders[placeholder]
-        print('change placeholder %s -> %s' % (oldText, newText))
-        file_utils.replaceContent(manifest, oldText, newText)
-
-    return 0
-
-def addLauncher(game, sdk, subChannel, config):
-    '''
-    添加启动图
-    '''
-    # ysdk的特殊处理
-    if sdk in ignoreLauncher:
-        return 0
-
-    channelPath = file_utils.getSubChannelPath(game, sdk, subChannel)
-    splashPath = os.path.join(channelPath, 'splash')
-    if len(os.listdir(splashPath)) == 0:
-        print('dir splash is empty')
-        return 0
-
-    print('add launcher...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    activity = xml_utils.getLauncherActivityName(manifest)
-    if activity == 'com.jmhy.sdk.template.LauncherActivity':
-        print('add launcher already exist...')
-        return 1
-    # 添加关联资源
-    internalPath = file_utils.getFullInternalPath()
-    ret = copyAppResWithType(decompliePath, internalPath, 'launcher_res')
-    if ret:
-        return ret
-
-    # 拷贝代码
-    print('copy launcher code...')
-    codePath = os.path.join(internalPath, 'launcher_code', 'smali')
-    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
-    ret = file_utils.copyFileAllDir(codePath, smaliPath)
-    if ret:
-        return ret
-
-    # 修改主文件信息
-    print('change launcher config...')
-    
-    orientation = xml_utils.getScreenOrientation(manifest)
-    activity = xml_utils.removeLauncherActivity(manifest)
-    xml_utils.addLauncherActivity(manifest, orientation, 'com.jmhy.sdk.template.LauncherActivity')
-
-    # 修改跳转的
-    launcherActivity = os.path.join(decompliePath, 'smali', 'com', 'jmhy', 'sdk', 'template', 'LauncherActivity.smali')
-    file_utils.replaceContent(launcherActivity, '{class}', activity)
-
-    print('change launcher %s to %s' % (activity, 'com.jmhy.sdk.template.LauncherActivity'))
-
-    # config['oldLauncher'] = activity
-
-    if 'launcherTime' in config:
-        timeHex = formatHex(config['launcherTime'])
-        file_utils.replaceContent(launcherActivity, '0x0BB8', timeHex)
-
-    return 0
-
-def addMoreIcon(game, sdk, subChannel, config):
-    '''
-    添加多个图标
-    '''
-    print('add more icon support...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    icon = '@mipmap/common_sdk_icon'
-    if not config['changeIcon']:
-        manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-        icon = xml_utils.getApplicationAttr(manifest, 'icon')
-
-    switchIcon = icon
-    if config['switchIcon']:
-        switchIcon = '@mipmap/common_sdk_icon2'
-
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    return xml_utils.addMoreIcon(manifest, icon, switchIcon)
-
-def copyIcon(game, sdk, subChannel, config):
-    '''
-    复制icon到res ,一键登录使用
-    '''
-    if config['changeIcon']:
-        decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-        decomplieResPath = file_utils.getFullPath(decompliePath, 'res')
-        iconPath = os.path.join(decomplieResPath, 'mipmap-xhdpi', 'common_sdk_icon.png')
-        desPath = os.path.join(decomplieResPath, 'drawable-hdpi', 'jm_cmcc_icon.png')
-        file_utils.copyFile(iconPath, desPath)
-    else:
-        decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-        decomplieResPath = file_utils.getFullPath(decompliePath, 'res')
-        desPath = os.path.join(decomplieResPath, 'drawable-hdpi', 'jm_cmcc_icon.png')
-
-        manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-        icon = xml_utils.getApplicationAttr(manifest, 'icon')
-        tag = icon[1:].split("/")
-        if len(tag) < 1:
-            return
-        hdpi = ['-xhdpi', '-xxhdpi', '-xxxhdpi']
-        for h in hdpi:
-            p1 = '%s%s' % (tag[0],h)
-            png = tag[1] + ".png"
-            iconPath = os.path.join(decomplieResPath, p1, png)
-            if os.path.exists(iconPath):
-                print ('iconPath = ' + iconPath)
-                file_utils.copyFile(iconPath, desPath)
-                break
-
-
-def formatHex(millisecond):
-    '''
-    将毫秒转为16进制,4位格式
-    '''
-    timeHex = str(hex(millisecond)).upper()
-    timeHex = timeHex[2:]
-    formatHex = ''
-    if len(timeHex) == 3:
-        formatHex = '0x0' + timeHexaddLauncher
-    elif len(timeHex) == 4:
-        formatHex = '0x' + timeHex
-    else:
-        formatHex = '0x0BB8'
-    return formatHex
-
-def doSDKPostScript(game, sdk, config):
-    '''
-    执行sdk相关特殊处理脚本
-    '''
-    sdkPath = file_utils.getFullSDKPath(sdk)
-    scriptPath = os.path.join(sdkPath, 'script')
-    targetScript = os.path.join(scriptPath, 'sdk_script.py')
-    if not os.path.exists(targetScript):
-        print('sdk_script no exists')
-        return 0
-
-    print('doSDKPostScript...')
-    sys.path.append(scriptPath)
-
-    module = importlib.import_module('sdk_script')
-    ret = module.execute(game, sdk, config)
-
-    sys.path.remove(scriptPath)
-
-    return ret
-
-def doGamePostScript(game, sdk, config):
-    '''
-    执行游戏相关特殊处理脚本
-    '''
-    channelPath = file_utils.getFullGamePath(game)
-    scriptPath = os.path.join(channelPath, 'script')
-    targetScript = os.path.join(scriptPath, 'game_script.py')
-    if not os.path.exists(targetScript):
-        print('game_script no exists')
-        return 0
-
-    print('doGamePostScript...')
-    sys.path.append(scriptPath)
-
-    module = importlib.import_module('game_script')
-    ret = module.execute(game, sdk, config)
-
-    sys.path.remove(scriptPath)
-
-    return ret
-
-
-def doGameScript(game, sdk, config):
-    '''
-    执行游戏相关特殊处理脚本
-    '''
-    channelPath = file_utils.getFullPath('game_script', game)
-    targetScript = os.path.join(channelPath, 'game_script.py')
-    print(targetScript + "--------")
-    if not os.path.exists(targetScript):
-        print('game_script no exists')
-        return 0
-
-    print('doGameScript...')
-    sys.path.append(channelPath)
-
-    module = importlib.import_module('game_script')
-    ret = module.execute(game, sdk, config)
-
-    sys.path.remove(channelPath)
-
-    return ret
-
-def addLogSdk(game, sdk, subChannel, config, logSdk):
-    # 拷贝jniLibs
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    sdkPath = file_utils.getFullLogSDKPath(logSdk)
-
-    print('copy log jniLibs...')
-    jniPath = file_utils.getFullPath(sdkPath, 'jniLibs')
-    decomplieJniPath = file_utils.getFullPath(decompliePath, 'lib')
-    abiFilters = []
-    if os.path.exists(decomplieJniPath):
-        for abi in os.listdir(decomplieJniPath):
-            if abi == 'armeabi-v7a' or abi == 'armeabi':
-                abiFilters.append(abi)
-    else:
-        abiFilters = ['armeabi-v7a']
-
-    if os.path.exists(jniPath):
-        ret = file_utils.copyFileAllDir(jniPath, decomplieJniPath, False, abiFilters)
-        if ret:
-            return ret
-    
-    print('merge log AndroidManifest...')
-    libManifest = file_utils.getFullPath(sdkPath, 'manifest.xml')
-    if os.path.exists(libManifest):
-        manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-        ret = xml_utils.mergeManifestRes(manifest, libManifest)
-        if ret:
-            return ret
-
-    return packLogJar(game, sdk, subChannel, config, logSdk)
-
-
-def addOaidSdk(game, sdk, subChannel, config, oaidVersion):
-
-    sdkPath = file_utils.getFullOaidSDKPath(oaidVersion)
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-
-    # 拷贝assets
-    print('copy oaid assets...')
-    assetsPath = file_utils.getFullPath(sdkPath, 'assets')
-    decomplieAssetsPath = file_utils.getFullPath(decompliePath, 'assets')
-    if os.path.exists(assetsPath):
-        ret = file_utils.copyFileAllDir(assetsPath, decomplieAssetsPath)
-        if ret:
-            return ret
-
-
-    # 拷贝jniLibs
-
-    print('copy oaid jniLibs...')
-    jniPath = file_utils.getFullPath(sdkPath, 'jniLibs')
-    decomplieJniPath = file_utils.getFullPath(decompliePath, 'lib')
-    abiFilters = []
-    if os.path.exists(decomplieJniPath):
-        for abi in os.listdir(decomplieJniPath):
-            if abi == 'armeabi-v7a' or abi == 'armeabi':
-                abiFilters.append(abi)
-    else:
-        abiFilters = ['armeabi-v7a']
-
-    if os.path.exists(jniPath):
-        ret = file_utils.copyFileAllDir(jniPath, decomplieJniPath, False, abiFilters)
-        if ret:
-            return ret
-
-    print('merge oaid AndroidManifest...')
-    libManifest = file_utils.getFullPath(sdkPath, 'manifest.xml')
-    if os.path.exists(libManifest):
-        manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-        ret = xml_utils.mergeManifestRes(manifest, libManifest)
-        if ret:
-            return ret
-
-    return packOaidJar(game, sdk, subChannel, config, oaidVersion)
-
-
-
-def generateNewRFile(game, sdk, subChannel, config):
-    '''
-    生成新的R文件
-    '''
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    androidPlatforms = file_utils.getAndroidCompileToolPath()
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    decomplieResPath = file_utils.getFullPath(decompliePath, 'res')
-    compliePath = file_utils.getFullPath(decompliePath, 'gen')
-
-    if not os.path.exists(compliePath):
-        os.makedirs(compliePath)
-
-    # 生成R文件
-    print('生成R文件 ...')
-    if config['aapt2disable']:
-        aapt = file_utils.getAAPTPath()
-        ret = file_utils.getExecPermission(aapt)
-        if ret:
-            return ret
-        createRCmd = '"%s" p -f -m -J "%s" -S "%s" -I "%s" -M "%s"' % (aapt, compliePath, decomplieResPath, androidPlatforms, manifest)
-        ret = file_utils.execFormatCmd(createRCmd)
-        if ret:
-            return ret
-    else:
-        # compile
-        aapt = file_utils.getAAPT2Path()
-        ret = file_utils.getExecPermission(aapt)
-        if ret:
-            return ret
-
-        print('compiled res ...')
-        complieResPath = os.path.join(compliePath, 'compiled')
-        complieResCmd = '"%s" compile --dir "%s" -o "%s"' % (aapt, decomplieResPath, complieResPath)
-        file_utils.execFormatCmd(complieResCmd)
-
-        # unzip
-        print('unzip compiled res ...')
-        unzipResPath = os.path.join(compliePath, 'aapt2_res')
-        with zipfile.ZipFile(complieResPath) as zf:
-            zf.extractall(unzipResPath)
-            print('create unzip %s' % unzipResPath)
-
-        # link
-        print('link res ...')
-        outApk = os.path.join(compliePath, 'res.apk')
-        linkResCmd = '"%s" link -o "%s" -I "%s" --manifest "%s" --java "%s" --auto-add-overlay' % (aapt, outApk, androidPlatforms, manifest, compliePath)
-        for filename in os.listdir(unzipResPath):
-            linkResCmd += ' %s' % filename
-        print('link cmd len is %s' % len(linkResCmd))
-        ret = file_utils.execFormatCmd(linkResCmd, unzipResPath)
-        if ret:
-            return ret
-
-    # 编译R文件
-    print('complie R.java ...')
-    packageName = xml_utils.getPackageName(manifest)
-    packagePath = file_utils.getPackagePath(compliePath, packageName)
-    RSourceFile = os.path.join(packagePath, 'R.java')
-    complieRCmd = 'javac -source 1.8 -target 1.8 -encoding UTF-8 "%s"' % RSourceFile
-    ret = file_utils.execFormatCmd(complieRCmd)
-    if ret:
-        return ret
-
-    # 生成dex
-    print('dex R.class ...')
-    outDex = os.path.join(compliePath, 'classes.dex')
-    if config['aapt2disable']:
-        dx = file_utils.getDxPath()
-        dexCmd = '--dex --no-warning --output="%s" "%s"' % (outDex, compliePath)
-    else:
-        dx = file_utils.getD8Path()
-        clazz = os.path.join(packagePath, '*.class')
-        dexCmd = '--lib "%s" --output "%s" %s' % (androidPlatforms, compliePath, clazz)
-    ret = file_utils.execJarCmd(dx, dexCmd)
-    if ret:
-        return ret
-
-    # 反向dex生成smali
-    # 存放在out目录
-    print('baksmali classes.dex ...')
-    baksmaliPath = file_utils.getBaksmaliPath()
-    outPath = file_utils.getFullPath(decompliePath, 'out')
-
-    ret = file_utils.execJarCmd(baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
-    if ret:
-        return ret
-
-    # 将生成的文件拷贝到目标目录
-    print('copy R.smali ...')
-    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
-    file_utils.copyFileAllDir(outPath, smaliPath)
-    return 0
-
-def packJar(game, sdk, subChannel, config):
-    '''
-    打包所有的jar
-    '''
-    splitDex = config['splitDex']
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    outPath = file_utils.getFullPath(decompliePath, 'gen')
-
-    if not os.path.exists(outPath):
-        os.makedirs(outPath)
-    if config['aapt2disable']:
-        dx = file_utils.getDxPath()
-        dexCmd = '--dex  --no-warning --output="%s"' % outPath
-    else:
-        dx = file_utils.getD8Path()
-        androidPlatforms = file_utils.getAndroidCompileToolPath()
-        dexCmd = '--lib "%s" --output "%s"' % (androidPlatforms, outPath)
-
-    # 找到所有lib依赖
-    sdkPath = file_utils.getFullSDKPath(sdk)
-    libs = os.path.join(sdkPath, 'libs')
-    libConfig = os.path.join(libs, 'config.json')
-
-    #
-
-    # 存在配置文件
-    if os.path.exists(libConfig):
-        jsonText = file_utils.readFile(libConfig)
-        libConf = json.loads(jsonText)
-        if 'libConfig' in config and config['libConfig'] in libConf:
-            conf = config['libConfig']
-            libList = libConf[conf]
-            for jar in libList:
-                dexCmd += ' ' + os.path.join(libs, jar)
-        elif 'default' in libConf:
-            libList = libConf['default']
-            for jar in libList:
-                dexCmd += ' ' + os.path.join(libs, jar)
-        else:
-            for jar in os.listdir(libs):
-                if not jar.endswith('.jar'):
-                    continue
-                dexCmd += ' ' + os.path.join(libs, jar)
-    else:
-        for jar in os.listdir(libs):
-            if not jar.endswith('.jar'):
-                continue
-            dexCmd += ' ' + os.path.join(libs, jar)
-
-    # multidex.jar
-    if splitDex:
-        print('getMultiDexPath ...')
-        dexCmd += ' ' + file_utils.getMultiDexPath()
-
-    # sdk实现类
-    print('packageing all jar ...')
-    dexCmd += ' ' + os.path.join(sdkPath, '%s.jar' % sdk)
-    ret = file_utils.execJarCmd(dx, dexCmd)
-    if ret:
-        return ret
-
-
-    # 反向dex生成smali
-    # 存放在out目录
-    print('baksmali classes.dex ...')
-    outDex = os.path.join(outPath, 'classes.dex')
-    baksmaliPath = file_utils.getBaksmaliPath()
-    outPath = file_utils.getFullPath(decompliePath, 'out')
-    
-    ret = file_utils.execJarCmd(baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
-    if ret:
-        return ret
-
-    # 将生成的文件拷贝到目标目录
-    print('copy all smali ...')
-    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
-    ret = file_utils.copyFileAllDir(outPath, smaliPath, True)
-    if ret:
-        return ret
-
-    return 0
-
-def packLogJar(game, sdk, subChannel, config, logSdk):
-    '''
-    打包Log jar
-    '''
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    outPath = file_utils.getFullPath(decompliePath, 'gen')
-
-    if not os.path.exists(outPath):
-        os.makedirs(outPath)
-
-    if config['aapt2disable']:
-        dx = file_utils.getDxPath()
-        dexCmd = '--dex --multi-dex --no-warning --output="%s"' % outPath
-    else:
-        dx = file_utils.getD8Path()
-        androidPlatforms = file_utils.getAndroidCompileToolPath()
-        dexCmd = '--lib "%s" --output "%s"' % (androidPlatforms, outPath)
-
-    # 找到所有lib依赖
-    sdkPath = file_utils.getFullLogSDKPath(logSdk)
-    libs = os.path.join(sdkPath, 'libs')
-    libConfig = os.path.join(libs, 'config.json')
-
-    # 存在配置文件
-    if os.path.exists(libConfig):
-        jsonText = file_utils.readFile(libConfig)
-        libList = json.loads(jsonText)
-        for jar in libList:
-            if not jar.endswith('.jar'):
-                continue
-            dexCmd += ' ' + os.path.join(libs, jar)
-    else:
-        for jar in os.listdir(libs):
-            if not jar.endswith('.jar'):
-                continue
-            dexCmd += ' ' + os.path.join(libs, jar)
-
-    # sdk实现类
-    print('packageing all log jar ...')
-    dexCmd += ' ' + os.path.join(sdkPath, '%s.jar' % logSdk)
-    ret = file_utils.execJarCmd(dx, dexCmd)
-    if ret:
-        return ret
-
-    # 反向dex生成smali
-    # 存放在out目录
-    print('baksmali classes.dex ...')
-    outDex = os.path.join(outPath, 'classes.dex')
-    baksmaliPath = file_utils.getBaksmaliPath()
-    outPath = file_utils.getFullPath(decompliePath, 'out')
-    
-    ret = file_utils.execJarCmd(baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
-    if ret:
-        return ret
-
-    # 将生成的文件拷贝到目标目录
-    print('copy all log smali ...')
-    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
-    ret = file_utils.copyFileAllDir(outPath, smaliPath, True)
-    if ret:
-        return ret
-
-    return 0
-
-
-def packOaidJar(game, sdk, subChannel, config, oaidVerion):
-    '''
-    打包oaid jar
-    '''
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    outPath = file_utils.getFullPath(decompliePath, 'gen')
-
-    if not os.path.exists(outPath):
-        os.makedirs(outPath)
-
-    if config['aapt2disable']:
-        dx = file_utils.getDxPath()
-        dexCmd = '--dex --multi-dex --no-warning --output="%s"' % outPath
-    else:
-        dx = file_utils.getD8Path()
-        androidPlatforms = file_utils.getAndroidCompileToolPath()
-        dexCmd = '--lib "%s" --output "%s"' % (androidPlatforms, outPath)
-
-    # 找到所有lib依赖
-    sdkPath = file_utils.getFullOaidSDKPath(oaidVerion)
-    libs = os.path.join(sdkPath, 'libs')
-    libConfig = os.path.join(libs, 'config.json')
-
-    # 存在配置文件
-    # if os.path.exists(libConfig):
-    #     jsonText = file_utils.readFile(libConfig)
-    #     libList = json.loads(jsonText)
-    #     for jar in libList:
-    #         if not jar.endswith('.jar'):
-    #             continue
-    #         dexCmd += ' ' + os.path.join(libs, jar)
-    # else:
-    #     for jar in os.listdir(libs):
-    #         if not jar.endswith('.jar'):
-    #             continue
-    #         dexCmd += ' ' + os.path.join(libs, jar)
-
-    # sdk实现类
-    print('packageing oaid jar ...')
-    dexCmd += ' ' + os.path.join(libs, 'miit_mdid_%s.jar' % oaidVerion)
-    ret = file_utils.execJarCmd(dx, dexCmd)
-    if ret:
-        return ret
-
-    # 反向dex生成smali
-    # 存放在out目录
-    print('baksmali classes.dex ...')
-    outDex = os.path.join(outPath, 'classes.dex')
-    baksmaliPath = file_utils.getBaksmaliPath()
-    outPath = file_utils.getFullPath(decompliePath, 'out')
-
-    ret = file_utils.execJarCmd(baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
-    if ret:
-        return ret
-
-    # 将生成的文件拷贝到目标目录
-    print('copy all log smali ...')
-    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
-    ret = file_utils.copyFileAllDir(outPath, smaliPath, True)
-    if ret:
-        return ret
-
-    return 0
-
-
-def splitDex(game, sdk, subChannel, config):
-    '''
-    分割dex
-    '''
-    # 判断是否已经存在application
-    # 存在,则往原application添加内容
-    # 不存在,则拷贝一个默认的android.support.multidex.MultiDexApplication
-    print('add MultiDex support...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    application = xml_utils.getApplicationAttr(manifest, 'name')
-    if application is None:
-        ret = xml_utils.changeApplicationAttr(manifest, 'name', 'android.support.multidex.MultiDexApplication')
-        if ret:
-            return ret
-    else:
-        smaliPath = os.path.join(decompliePath, 'smali')
-        applicationFile = file_utils.getPackagePath(smaliPath, application)
-        applicationFile += '.smali'
-        ret = changeApplicationDex(applicationFile)
-        if ret:
-            return ret
-
-    return splitSmali(game, sdk, subChannel, config, application)
-
-def changeApplicationDex(file):
-    '''
-    修改application的smali文件,增加MultiDex操作
-    '''
-    index = file_utils.getApplicationSmaliIndex(file)
-    file_utils.insertApplicationSmali(file, index)
-    return 0
-
-def splitSmali(game, sdk, subChannel, config, application):
-    '''
-    如果函数上限超过限制,自动拆分smali,以便生成多个dex文件
-    '''
-    print('splitSmali...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    smaliPath = os.path.join(decompliePath, 'smali')
-
-    appPackage = None
-    if application:
-        appPackage = application[:application.rfind('.')]
-        appPackage = appPackage.replace('.', '/')
-
-    allFiles = []
-    allFiles = file_utils.list_files(smaliPath, allFiles)
-    
-    #print('file count is %d' % len(allFiles))
-
-    #maxFuncNum = 65535
-    # 留一点空间,防止计算误差
-    maxFuncNum = 64000
-    currFucNum = 0
-    totalFucNum = 0
-
-    currDexIndex = 1
-
-    allRefs = []
-
-    #保证Application等类在第一个classex.dex文件中
-    for f in allFiles:
-        f = f.replace('\\', '/')
-        if (appPackage and appPackage in f) or '/android/support/multidex' in f:
-            currFucNum += smali_utils.get_smali_method_count(f, allRefs)
-
-    totalFucNum = currFucNum
-    for f in allFiles:
-        f = f.replace('\\', '/')
-        if not f.endswith('.smali'):
-            continue
-
-        if (appPackage and appPackage in f) or '/android/support/multidex' in f:
-            continue
-
-        thisFucNum = smali_utils.get_smali_method_count(f, allRefs)
-        totalFucNum += thisFucNum
-
-        #print('%d # %d ==> %s' % (thisFucNum, currDexIndex, f))
-        #print('totalFucNum is %d' % totalFucNum)
-        if currFucNum + thisFucNum >= maxFuncNum:
-            currFucNum = thisFucNum
-            currDexIndex += 1
-            newDexPath = os.path.join(decompliePath, 'smali_classes%d' % currDexIndex)
-            os.makedirs(newDexPath)
-        else:
-            currFucNum += thisFucNum
-
-        if currDexIndex > 1:
-            newDexPath = os.path.join(decompliePath, 'smali_classes%d' % currDexIndex)
-            targetFile = newDexPath + f[len(smaliPath):]
-            file_utils.copyFile(f, targetFile, True)
-    return 0
-
-def changeVersion(game, sdk, subChannel, config):
-    '''
-    更改版本号
-    '''
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    yml = os.path.join(decompliePath, 'apktool.yml')
-
-    versionCode = None
-    versionName = None
-    targetSdkVersion = None
-    if 'versionCode' in config:
-        versionCode = config['versionCode']
-    if 'versionName' in config:
-        versionName = config['versionName']
-    if 'targetSdkVersion' in config:
-        targetSdkVersion = config['targetSdkVersion']
-    else:
-        targetSdkVersion = 26
-    print('changeVersion versionCode=%s,versionName=%s,targetSdkVersion=%s' % (versionCode, versionName, targetSdkVersion))
-
-    return file_utils.changeVersion(yml, versionCode, versionName, targetSdkVersion)
-
-def recomplie(game, sdk, subChannel, config):
-    '''
-    回编译
-    '''
-    print('recomplie apk...')
-    apktoolPath = file_utils.getApkToolPath()
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    outApk = file_utils.getOutApkPath(game, sdk, subChannel, config['cache'])
-
-    useAppt2 = ' --use-aapt2'
-    if config['aapt2disable']:
-        useAppt2 = ''
-
-    return file_utils.execJarCmd(apktoolPath, 'b -f "%s" -o "%s"%s' % (decompliePath, outApk, useAppt2))
-
-def alignApk(game, sdk, subChannel, config):
-    '''
-    对齐apk
-    '''
-    print('align apk...')
-    outApk = file_utils.getOutApkPath(game, sdk, subChannel, config['cache'])
-    alignApk = file_utils.getAlignApkPath(game, sdk, subChannel, config['cache'])
-    alignapkTool = file_utils.getAlignPath()
-    if os.path.exists(alignApk):
-        os.remove(alignApk)
-
-    ret = file_utils.getExecPermission(alignapkTool)
-    if ret:
-        return ret
-
-    # zipalign.exe -v -p 4 input.apk output.apk
-    return file_utils.execFormatCmd('"%s" -f -p 4 "%s" "%s"' % (alignapkTool, outApk, alignApk))
-
-def apksignerApk(game, sdk, subChannel, config):
-    '''
-    签名apk
-    '''
-    print('sign apk...')
-    print('game = %s, sdk = %s, subChannel = %s, ...' % (game,sdk,subChannel))
-    path = os.path.join(file_utils.getCurrentPath(), 'keystore', 'key.json')
-    jsonText = file_utils.readFile(path)
-    signConfig = json.loads(jsonText)
-    keystore = {}
-    for key in signConfig.keys():
-        print(key)
-        if game.find(key) > -1 or game == key:
-            if sdk in signConfig[key]:
-                keystore = signConfig[key][sdk]
-                break
-            else:
-                keystore = signConfig['default']
-        else:
-            keystore = signConfig['default']
-
-    # if game in signConfig:
-    #     if sdk in signConfig[game]:
-    #         keystore = signConfig[game][sdk]
-    #     else:
-    #         keystore = signConfig['default']
-    # else:
-    #     keystore = signConfig['default']
-
-    print('storeFile is "%s"' % keystore['storeFile'])
-    
-    apksigner = file_utils.getApksignerPath()
-    alignApk = file_utils.getAlignApkPath(game, sdk, subChannel, config['cache'])
-    signedApk = file_utils.getSignApkPath(game, sdk, subChannel, config['cache'])
-    storeFile = os.path.join(file_utils.getCurrentPath(), 'keystore', keystore['storeFile'])
-
-    if 'outName' in config and 'outPath' in config:
-        if not os.path.exists(config['outPath']):
-            os.makedirs(config['outPath'])
-
-        signedApk = os.path.join(config['outPath'], config['outName'] + '.apk')
-    elif 'outName' in config:
-        signedApk = file_utils.getRenameApkPath(game, sdk, config['cache'], config['outName'])
-    
-    # java -jar apksigner.jar sign --ks key.jks --ks-key-alias releasekey --ks-pass pass:pp123456 --key-pass pass:pp123456 --out output.apk input.apk
-    v2disable = ''
-    if 'v2disable' in config and config['v2disable']:
-        v2disable = ' --v2-signing-enabled=false'
-        
-    return file_utils.execJarCmd(apksigner, 'sign%s --ks "%s" --ks-key-alias %s --ks-pass pass:%s --key-pass pass:%s --out "%s" "%s"' % (v2disable, storeFile, keystore['keyAlias'], keystore['storePassword'], keystore['keyPassword'], signedApk, alignApk))
-
-def addChannel(game, sdk, subChannel, config):
-    '''
-    添加渠道信息
-    '''
-    if 'v2disable' in config and config['v2disable']:
-        return 0
-    
-    walle = file_utils.getWallePath()
-    signedApk = file_utils.getSignApkPath(game, sdk, subChannel, config['cache'])
-    if 'outName' in config and 'outPath' in config:
-        signedApk = os.path.join(config['outPath'], config['outName'] + '.apk')
-    elif 'outName' in config:
-        signedApk = file_utils.getRenameApkPath(game, sdk, config['cache'], config['outName'])
-
-    properties = config['properties']
-
-    appid = ''
-    appkey = ''
-    host = ''
-    if 'appid' in properties:
-        appid = properties['appid']
-    if 'appkey' in properties:
-        appkey = properties['appkey']
-    if 'host' in properties:
-        host = properties['host']
-
-    return file_utils.execJarCmd(walle, 'put -e version=%s,agent=%s,appid=%s,appkey=%s,host=%s "%s" "%s"' % (config_utils.getDate(), properties['agent'], appid, appkey, host, signedApk, signedApk))
-
-def clearTemp(game, sdk, subChannel, config):
-    '''
-    清空中间产生的文件
-    '''
-    print('clear temp...')
-    alignApk = file_utils.getAlignApkPath(game, sdk, subChannel, config['cache'])
-    outApk = file_utils.getOutApkPath(game, sdk, subChannel, config['cache'])
-    if os.path.exists(alignApk):
-        os.remove(alignApk)
-    if os.path.exists(outApk):
-        os.remove(outApk)
-
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    file_utils.deleteFolder(decompliePath)
-
-    print('clear temp end')
-
-def packConsoleInput():
-    '''
-    控制台打包
-    '''
-    if len(sys.argv) < 3:
-        print('argument is missing')
-        return 1
-
-    # 校验参数
-    game = sys.argv[1]
-    sdk = sys.argv[2]
-    # 可选参数,没有则默认打全部渠道
-    subChannel = None
-    if len(sys.argv) > 3:
-        subChannel = sys.argv[3]
-        
-    return packConsole(game, sdk, subChannel)
-
-def packConsole(game, sdk, subChannel):
-    '''
-    控制台打包
-    '''
-    if not os.path.exists(file_utils.getFullGameApk(game)):
-        print('game "%s" not exists' % game)
-        return 1
-    if not os.path.exists(file_utils.getFullSDKPath(sdk)):
-        print('sdk "%s" not exists' % sdk)
-        return 1
-    global  startTime
-    startTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
-
-    # 读取配置
-    channelPath = file_utils.getChannelPath(game, sdk)
-    configPath = os.path.join(channelPath, 'config.json')
-    if not os.path.exists(configPath):
-        print('%s not exists' % configPath)
-        return 1
-    
-    jsonText = file_utils.readFile(configPath)
-    config = json.loads(jsonText)
-
-    # 检查参数
-    if not config_utils.checkConfig(config):
-        return 1
-
-    # 处理参数
-    config_utils.replaceArgs(config)
-
-    successCount = 0
-    failureCount = 0
-    if type(config) == dict:
-        if subChannel is None or config['subChannel'] == subChannel:
-            ret = pack(game, sdk, config)
-            if ret:
-                failureCount += 1
-            else:
-                successCount += 1
-        else:
-            print('subChannel "%s" no found' % subChannel)
-            return 1
-    elif type(config) == list:
-        found = False
-        for itemConfig in config:
-            if subChannel is None or itemConfig['subChannel'] == subChannel:
-                found = True
-                ret = pack(game, sdk, itemConfig)
-                if ret:
-                    failureCount += 1
-                else:
-                    successCount += 1
-
-        if not found:
-            print('subChannel "%s" no found' % subChannel)
-            return 1
-
-    print('success %d, failure %d' % (successCount, failureCount))
-        
-    return 0
-
-def formatXml(game, sdk, subChannel, config):
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    return xml_utils.formatXml(manifest)
+# 安卓游戏打包脚本
+# 1.用apktool解包
+# 2.复制res资源、assets资源、jniLib资源
+# 3.修改包名、app名、渠道文件
+# 4.添加app icon、合并AndroidManifest文件
+# 5.添加app启动图,修改AndroidManifest文件
+# 6.生成新的R文件
+# 7.将新的R文件编译,生成dex,再用baksmali生成smali,替换旧的R文件
+# 8.将jar资源打包成dex,再用baksmali生成smali,拷贝到smali目录下
+# 9.统计方法量,并分割dex(将smali文件拷贝到目录smali_classes2)
+# 10.用apktool回包
+# 11.重新签名
+import re
+
+import file_utils
+import xml_utils
+import smali_utils
+import config_utils
+import game_utils
+import common_utils
+import os
+import os.path
+import json
+import sys
+import importlib
+import uuid
+import zipfile
+import time
+import datetime
+
+ignoreLauncher = ['jm_ysdk', 'jm_yijie', 'jm_quick',
+                  'jm_beiyu', 'jm_xq_jrtt', 'jm_zy_ysdk']
+adaptApp = ['yjzx']
+startTime = ''
+
+
+def pack(game, sdk, config):
+    config['cache'] = uuid.uuid1()
+    subChannel = config['subChannel']
+    print('game = %s, sdk = %s, subChannel = %s, ...' %
+          (game, sdk, subChannel))
+
+    # 解包
+    ret = decomplie(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 删除旧代码
+    ret = removeOldCode(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 删除一些不支持的属性
+    ret = removeNoSupportAttr(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 删除一些不支持的配置
+    ret = fixUnSupportConfig(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 合并Drawable-v4目录
+    ret = mergeDrawableRes(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 移除相同的资源
+    ret = removeSameRes(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 复制res资源
+    ret = copyRes(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 合并主文件
+    ret = mergeManifestRes(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 替换占位符
+    ret = changePlaceholders(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 添加meta-data
+    ret = addMetaData(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 增加配置文件
+    ret = addConfig(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 复制app res资源
+    ret = copyAppRes(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 更改包名
+    if 'packageName' in config and config['packageName'] != '':
+        ret = changePackageName(game, sdk, subChannel, config)
+        if ret:
+            return ret
+    # 更改app名
+    if 'name' in config and config['name'] != '':
+        ret = changeAppName(game, sdk, subChannel, config)
+        if ret:
+            return ret
+    # 更改app icon
+    if config['changeIcon']:
+        ret = changeAppIcon(game, sdk, subChannel, config)
+        if ret:
+            return ret
+    # 添加启动图操作
+    if config['addLauncher']:
+        ret = addLauncher(game, sdk, subChannel, config)
+        if ret:
+            return ret
+    # 添加多图标
+    # ret = addMoreIcon(game, sdk, subChannel, config)
+    # 复制icon图标到res
+    ret = copyIcon(game, sdk, subChannel, config)
+    # if ret:
+    #    return ret
+    # 打包lib依赖
+
+    ret = packJar(game, sdk, subChannel, config)
+    if ret:
+        return ret
+
+    # 继承JMApplication
+    common_utils.changeApplication(
+        game, sdk, subChannel, config, 'com.jmhy.sdk.common.JMApplication')
+
+    # sdk脚本处理
+    ret = doSDKPostScript(game, sdk, config)
+    if ret:
+        return ret
+    # 乐变sdk的特殊处理
+    ret = game_utils.sdkLebianChange(game, sdk, config)
+    if ret:
+        return ret
+    # 游戏脚本处理
+    ret = doGamePostScript(game, sdk, config)
+    if ret:
+        return ret
+
+    # 游戏独立处理
+    ret = doGameScript(game, sdk, config)
+    if ret:
+        return ret
+
+    # 格式化Xml
+    # ret = formatXml(game, sdk, subChannel, config)
+    # if ret:
+    #     return ret
+
+    # log sdk
+    if 'logSdk' in config:
+        for log in config['logSdk']:
+            ret = addLogSdk(game, sdk, subChannel, config, log)
+            if ret:
+                return ret
+
+    # oaid sdk
+    ret = addOaidSdk(game, sdk, subChannel, config, "1.0.10")
+    if ret:
+        return ret
+
+    # 生成R文件
+    '''ret = generateNewRFile(game, sdk, subChannel, config)
+    if ret:
+        return ret'''
+    # 添加MultiDex支持
+    if config['splitDex']:
+        ret = splitDex(game, sdk, subChannel, config)
+        if ret:
+            return ret
+    # 更改版本号
+    ret = changeVersion(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 更改HardwareAccelerated属性
+    ret = replaceAmHardwareAccelerated(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 回编译
+    ret = recomplie(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 对齐apk
+    ret = alignApk(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 签名
+    ret = apksignerApk(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 添加渠道信息
+    ret = addChannel(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    ret = copyApk2OutDir(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 清理产生的中间文件
+    if config['clearCache']:
+        clearTemp(game, sdk, subChannel, config)
+
+    endTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+    d1 = datetime.datetime.strptime(endTime, '%Y-%m-%d %H:%M:%S')
+    d2 = datetime.datetime.strptime(startTime, '%Y-%m-%d %H:%M:%S')
+    d = d1 - d2
+    print('开始时间:' + startTime)
+    print('结束时间:' + endTime)
+    print('用时:{}'.format(config_utils.getTime(d.seconds)))
+    return 0
+
+
+def decomplie(game, sdk, subChannel, config):
+    '''
+    解包
+    '''
+    apktoolPath = file_utils.getApkToolPath()
+    #    gamePath = file_utils.getFullGameApk(game)
+    cacheGameApk = file_utils.getCacheGameApk(game, config['random'], sdk)
+    decompliePath = file_utils.getDecompliePath(
+        game, sdk, subChannel, config['cache'])
+
+    if os.path.exists(decompliePath):
+        print('delete decomplie folder...')
+        file_utils.deleteFolder(decompliePath)
+
+    print('decomplie apk...')
+
+    return file_utils.execJarCmd(apktoolPath, 'd -f "%s" -o "%s"' % (cacheGameApk, decompliePath))
+
+
+def removeOldCode(game, sdk, subChannel, config):
+    '''
+    删除旧代码
+    '''
+    decompliePath = file_utils.getDecompliePath(
+        game, sdk, subChannel, config['cache'])
+    codePath = os.path.join(decompliePath, 'smali', 'com', 'jmhy', 'sdk')
+    # file_utils.deleteFolder(codePath)
+    allFiles = []
+    allFiles = file_utils.list_files(codePath, allFiles)
+    for f in allFiles:
+        fpath, fname = os.path.split(f)  # 分离文件名和路径
+        if fname == 'R.smali' or fname.startswith('R$'):
+            continue
+        os.remove(f)
+        # print('remove %s' % f)
+    return 0
+
+
+def copyRes(game, sdk, subChannel, config):
+    '''
+    复制res资源
+    '''
+    # 拷贝sdk资源
+    print('copy res...')
+    decompliePath = file_utils.getDecompliePath(
+        game, sdk, subChannel, config['cache'])
+    sdkPath = file_utils.getFullSDKPath(sdk)
+    resPath = os.path.join(sdkPath, 'res')
+    decomplieResPath = file_utils.getFullPath(decompliePath, 'res')
+
+    for d in os.listdir(resPath):
+        copyResWithType(resPath, decomplieResPath, d)
+
+    # 拷贝assets
+    print('copy assets...')
+    assetsPath = file_utils.getFullPath(sdkPath, 'assets')
+    decomplieAssetsPath = file_utils.getFullPath(decompliePath, 'assets')
+    if os.path.exists(assetsPath):
+        ret = file_utils.copyFileAllDir(assetsPath, decomplieAssetsPath)
+        if ret:
+            return ret
+
+    # 拷贝jniLib
+    print('copy jniLibs...')
+    jniPath = file_utils.getFullPath(sdkPath, 'jniLibs')
+    decomplieJniPath = file_utils.getFullPath(decompliePath, 'lib')
+    abiFilters = []
+    if os.path.exists(decomplieJniPath):
+        for abi in os.listdir(decomplieJniPath):
+            # if abi == 'armeabi-v7a' or abi == 'armeabi' or abi == 'arm64-v8a':
+            print('append : ' + abi)
+            abiFilters.append(abi)
+    else:
+        abiFilters = ['armeabi-v7a']
+
+    if os.path.exists(jniPath):
+        ret = file_utils.copyFileAllDir(
+            jniPath, decomplieJniPath, False, abiFilters)
+        if ret:
+            return ret
+    return 0
+
+
+def mergeDrawableRes(game, sdk, subChannel, config):
+    '''
+    合并Drawable-v4目录
+    '''
+    print('merge drawable path...')
+    decompliePath = file_utils.getDecompliePath(
+        game, sdk, subChannel, config['cache'])
+    resPath = os.path.join(decompliePath, 'res')
+
+    for path in os.listdir(resPath):
+        # print('res path %s' % path)
+        if (path.startswith('drawable') or path.startswith('mipmap')) and path.endswith('-v4'):
+            # print('merge path %s' % path)
+            v4DrawablePath = os.path.join(resPath, path)
+            drawablePath = os.path.join(resPath, path[:-3])
+
+            if os.path.exists(drawablePath):
+                ret = file_utils.copyFileAllDir(
+                    v4DrawablePath, drawablePath, True)
+                if ret:
+                    return ret
+            else:
+                os.rename(v4DrawablePath, drawablePath)
+    return 0
+
+
+def removeSameRes(game, sdk, subChannel, config):
+    '''
+    移除相同的资源
+    '''
+    # 读取sdk的资源
+    print('remove same res...')
+    sdkPath = file_utils.getFullSDKPath(sdk)
+    sdkResPath = os.path.join(sdkPath, 'res')
+    resList = []
+    for path in os.listdir(sdkResPath):
+        if not path.startswith('values'):
+            continue
+        absPath = os.path.join(sdkResPath, path)
+        for resFile in os.listdir(absPath):
+            '''if not resFile.startswith('jm_'):
+                continue'''
+            if resFile.endswith('.DS_Store'):
+                continue
+            # print('readAllRes -- > ' + os.path.join(absPath, resFile))
+
+            resList = xml_utils.readAllRes(
+                os.path.join(absPath, resFile), resList)
+
+    if len(resList) == 0:
+        print('no same res found')
+        return 0
+
+    # 移除相同的资源
+    decompliePath = file_utils.getDecompliePath(
+        game, sdk, subChannel, config['cache'])
+    resPath = os.path.join(decompliePath, 'res')
+    for path in os.listdir(resPath):
+        if not path.startswith('values'):
+            continue
+
+        absPath = os.path.join(resPath, path)
+        for resFile in os.listdir(absPath):
+            xml_utils.removeSameRes(os.path.join(absPath, resFile), resList)
+
+    return 0
+
+
+def mergeManifestRes(game, sdk, subChannel, config):
+    '''
+    合并主文件
+    '''
+    print('merge AndroidManifest...')
+    decompliePath = file_utils.getDecompliePath(
+        game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    sdkPath = file_utils.getFullSDKPath(sdk)
+    libManifest = file_utils.getFullPath(sdkPath, 'manifest.xml')
+    return xml_utils.mergeManifestRes(manifest, libManifest)
+
+
+def copyAppRes(game, sdk, subChannel, config):
+    '''
+    拷贝app的资源,比如app icon、启动图等
+    '''
+    random = config['random']
+    channelPath = file_utils.getSubChannelPath(game, sdk, random, subChannel)
+    decompliePath = file_utils.getDecompliePath(
+        game, sdk, subChannel, config['cache'])
+
+    # assets
+    print('copy assets...')
+    # 适配一剑斩仙
+    if game in adaptApp:
+        print('适配一剑斩仙...')
+        decomplieAssetsPath = file_utils.getFullPath(decompliePath, 'assets')
+        skinZipPath = os.path.join(decomplieAssetsPath, 'skin.zip')
+        skinPath = os.path.join(decomplieAssetsPath, 'skin')
+        if os.path.exists(skinZipPath):
+            with zipfile.ZipFile(skinZipPath) as zf:
+                zf.extractall(decomplieAssetsPath)
+                print('create unzip skin')
+            assetsPath = file_utils.getFullPath(channelPath, 'assets')
+            decomplieAssetsPath = file_utils.getFullPath(
+                decompliePath, 'assets')
+            if os.path.exists(assetsPath):
+                ret = file_utils.copyFileAllDir(
+                    assetsPath, decomplieAssetsPath)
+            with zipfile.ZipFile(skinZipPath, 'w') as z:
+                for root, dirs, files in os.walk(skinPath):
+                    for single_file in files:
+                        filepath = os.path.join(root, single_file)
+                        print('create zip ---> ' + filepath)
+                        temPath = 'skin/' + single_file
+                        z.write(filepath, temPath)
+            z.close()
+        else:
+            print('normal copy assets...')
+            assetsPath = file_utils.getFullPath(channelPath, 'assets')
+            decomplieAssetsPath = file_utils.getFullPath(
+                decompliePath, 'assets')
+            if os.path.exists(assetsPath):
+                ret = file_utils.copyFileAllDir(
+                    assetsPath, decomplieAssetsPath)
+                if ret:
+                    return ret
+    else:
+        print('normal copy assets...')
+        assetsPath = file_utils.getFullPath(channelPath, 'assets')
+        decomplieAssetsPath = file_utils.getFullPath(decompliePath, 'assets')
+        if os.path.exists(assetsPath):
+            ret = file_utils.copyFileAllDir(assetsPath, decomplieAssetsPath)
+            if ret:
+                return ret
+
+    # icon
+    print('copy icon...')
+    ret = copyAppResWithType(decompliePath, channelPath, 'icon')
+    if ret:
+        return ret
+    # 启动图
+    print('copy splash...')
+    ret = copyAppResWithType(decompliePath, channelPath, 'splash')
+    if ret:
+        return ret
+    # 其他图片
+    print('copy image...')
+    ret = copyAppResWithType(decompliePath, channelPath, 'image')
+    if ret:
+        return ret
+    return 0
+
+
+def copyAppResWithType(decompliePath, channelPath, typeName):
+    decomplieResPath = os.path.join(decompliePath, 'res')
+    iconPath = os.path.join(channelPath, typeName)
+    if not os.path.exists(iconPath):
+        print('dir "%s" not exists' % iconPath)
+        return 0
+    for d in os.listdir(iconPath):
+        ret = copyResWithType(iconPath, decomplieResPath, d)
+        if ret:
+            return ret
+
+    return 0
+
+
+def copyResWithType(resPath, decomplieResPath, typeName):
+    # appt的打包目录会带-v4后缀
+    resDir = os.path.join(resPath, typeName)
+    target = os.path.join(decomplieResPath, typeName)
+    targetV4 = os.path.join(decomplieResPath, typeName + '-v4')
+    if not os.path.exists(target) and not os.path.exists(targetV4):
+        os.makedirs(target)
+        return file_utils.copyFileAllDir(resDir, target, False)
+    elif not os.path.exists(target):
+        return file_utils.copyFileAllDir(resDir, targetV4, False)
+    else:
+        return file_utils.copyFileAllDir(resDir, target, False)
+
+
+def removeNoSupportAttr(game, sdk, subChannel, config):
+    '''
+    删除一些不支持的属性
+    '''
+    decompliePath = file_utils.getDecompliePath(
+        game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+
+    xml_utils.removeRootAttr(manifest, 'compileSdkVersion')
+    xml_utils.removeRootAttr(manifest, 'compileSdkVersionCodename')
+
+    return 0
+
+
+def fixUnSupportConfig(game, sdk, subChannel, config):
+    '''
+    删除一些不支持的配置
+    '''
+    # 检查minSdkVersion
+    decompliePath = file_utils.getDecompliePath(
+        game, sdk, subChannel, config['cache'])
+    yml = os.path.join(decompliePath, 'apktool.yml')
+
+    minSdkVersion = 15
+    file_utils.changeMinSdkVersion(yml, minSdkVersion)
+
+    resPath = os.path.join(decompliePath, 'res')
+
+    tag = '-v'
+    for res in os.listdir(resPath):
+        # print('res = ' + res)
+        if res.startswith('values') and tag in res:
+            start = res.index(tag)
+            version = res[start + len(tag):]
+            if not version.isdigit():
+                continue
+
+            version = int(version)
+            print('version = %d' % version)
+            if version < minSdkVersion:
+                unSopportPath = os.path.join(resPath, res)
+                print('unSopportPath = ' + unSopportPath)
+                file_utils.deleteFolder(unSopportPath)
+                print('deleteFolder = ' + unSopportPath)
+
+    return 0
+
+
+def changePackageName(game, sdk, subChannel, config):
+    '''
+    更改包名
+    '''
+    # 全局替换AndroidManifest里面的包名
+    newPackageName = config['packageName']
+
+    decompliePath = file_utils.getDecompliePath(
+        game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    packageName = xml_utils.getPackageName(manifest)
+
+    xml_utils.changePackageName(manifest, newPackageName)
+    print('change package name %s --> %s' % (packageName, newPackageName))
+    return 0
+
+
+def changeAppName(game, sdk, subChannel, config):
+    '''
+    更改app名
+    '''
+    # 生成string.xml文件
+    name = config['name']
+
+    resName = 'common_sdk_name'
+    if 'outName' in config:
+        resName = resName + '_' + config['outName']
+    decompliePath = file_utils.getDecompliePath(
+        game, sdk, subChannel, config['cache'])
+    stringFile = os.path.join(decompliePath, 'res',
+                              'values', 'sdk_strings_temp.xml')
+    content = '<?xml version="1.0" encoding="utf-8"?><resources><string name="%s">%s</string></resources>' % (
+        resName, name)
+    file_utils.createFile(stringFile, content)
+
+    # 修改主文件的app名的值
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    xml_utils.changeAppName(manifest, '@string/%s' % resName)
+    print('change app name %s' % name)
+    return 0
+
+
+def changeAppIcon(game, sdk, subChannel, config):
+    '''
+    更改app icon
+    '''
+    print('change app icon...')
+    resName = 'common_sdk_icon'
+
+    decompliePath = file_utils.getDecompliePath(
+        game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    xml_utils.changeAppIcon(manifest, '@mipmap/%s' % resName)
+    return 0
+
+
+def addMetaData(game, sdk, subChannel, config):
+    '''
+    添加meta-data
+    '''
+    if 'metaData' not in config:
+        return 0
+
+    print('add meta-data...')
+    decompliePath = file_utils.getDecompliePath(
+        game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    xml_utils.addMetaData(manifest, config['metaData'])
+    return 0
+
+
+def addConfig(game, sdk, subChannel, config):
+    '''
+    添加config.json
+    '''
+    if 'configData' not in config:
+        return 0
+
+    print('add config.json...')
+    decompliePath = file_utils.getDecompliePath(
+        game, sdk, subChannel, config['cache'])
+    configJson = os.path.join(decompliePath, 'assets', 'jmhy_config.json')
+    jsonText = json.dumps(config['configData'], ensure_ascii=False)
+    file_utils.createFile(configJson, jsonText)
+    return 0
+
+
+def changePlaceholders(game, sdk, subChannel, config):
+    '''
+    处理掉占位符
+    '''
+    if 'placeholders' not in config:
+        return 0
+
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+
+    placeholders = config['placeholders']
+    for placeholder in placeholders:
+        oldText = '${%s}' % placeholder
+        newText = placeholders[placeholder]
+        print('change placeholder %s -> %s' % (oldText, newText))
+        file_utils.replaceContent(manifest, oldText, newText)
+
+    return 0
+
+
+def addLauncher(game, sdk, subChannel, config):
+    '''
+    添加启动图
+    '''
+    # ysdk的特殊处理
+    if sdk in ignoreLauncher:
+        return 0
+    random = config['random']
+    channelPath = file_utils.getSubChannelPath(game, sdk, random, subChannel)
+    splashPath = os.path.join(channelPath, 'splash')
+    if len(os.listdir(splashPath)) == 0:
+        print('dir splash is empty')
+        return 0
+
+    print('add launcher...')
+    decompliePath = file_utils.getDecompliePath(
+        game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    activity = xml_utils.getLauncherActivityName(manifest)
+    if activity == 'com.jmhy.sdk.template.LauncherActivity':
+        print('add launcher already exist...')
+        return 1
+    # 添加关联资源
+    internalPath = file_utils.getFullInternalPath()
+    ret = copyAppResWithType(decompliePath, internalPath, 'launcher_res')
+    if ret:
+        return ret
+
+    # 拷贝代码
+    print('copy launcher code...')
+    codePath = os.path.join(internalPath, 'launcher_code', 'smali')
+    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
+    ret = file_utils.copyFileAllDir(codePath, smaliPath)
+    if ret:
+        return ret
+
+    # 修改主文件信息
+    print('change launcher config...')
+
+    orientation = xml_utils.getScreenOrientation(manifest)
+    activity = xml_utils.removeLauncherActivity(manifest)
+    xml_utils.addLauncherActivity(
+        manifest, orientation, 'com.jmhy.sdk.template.LauncherActivity')
+
+    # 修改跳转的
+    launcherActivity = os.path.join(
+        decompliePath, 'smali', 'com', 'jmhy', 'sdk', 'template', 'LauncherActivity.smali')
+    file_utils.replaceContent(launcherActivity, '{class}', activity)
+
+    print('change launcher %s to %s' %
+          (activity, 'com.jmhy.sdk.template.LauncherActivity'))
+
+    # config['oldLauncher'] = activity
+
+    if 'launcherTime' in config:
+        timeHex = formatHex(config['launcherTime'])
+        file_utils.replaceContent(launcherActivity, '0x0BB8', timeHex)
+
+    return 0
+
+
+def addMoreIcon(game, sdk, subChannel, config):
+    '''
+    添加多个图标
+    '''
+    print('add more icon support...')
+    decompliePath = file_utils.getDecompliePath(
+        game, sdk, subChannel, config['cache'])
+    icon = '@mipmap/common_sdk_icon'
+    if not config['changeIcon']:
+        manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+        icon = xml_utils.getApplicationAttr(manifest, 'icon')
+
+    switchIcon = icon
+    if config['switchIcon']:
+        switchIcon = '@mipmap/common_sdk_icon2'
+
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    return xml_utils.addMoreIcon(manifest, icon, switchIcon)
+
+
+def copyIcon(game, sdk, subChannel, config):
+    '''
+    复制icon到res ,一键登录使用
+    '''
+    if config['changeIcon']:
+        decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+        decomplieResPath = file_utils.getFullPath(decompliePath, 'res')
+        iconPath = os.path.join(decomplieResPath, 'mipmap-xhdpi', 'common_sdk_icon.png')
+        desPath = os.path.join(
+            decomplieResPath, 'drawable-hdpi', 'jm_cmcc_icon.png')
+        file_utils.copyFile(iconPath, desPath)
+    else:
+        decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+        decomplieResPath = file_utils.getFullPath(decompliePath, 'res')
+        desPath = os.path.join(decomplieResPath, 'drawable-hdpi', 'jm_cmcc_icon.png')
+
+        manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+        icon = xml_utils.getApplicationAttr(manifest, 'icon')
+        tag = icon[1:].split("/")
+        if len(tag) < 1:
+            return
+        hdpi = ['-xhdpi', '-xxhdpi', '-xxxhdpi']
+        for h in hdpi:
+            p1 = '%s%s' % (tag[0], h)
+            png = tag[1] + ".png"
+            iconPath = os.path.join(decomplieResPath, p1, png)
+            if os.path.exists(iconPath):
+                print('iconPath = ' + iconPath)
+                file_utils.copyFile(iconPath, desPath)
+                break
+
+
+def formatHex(millisecond):
+    '''
+    将毫秒转为16进制,4位格式
+    '''
+    timeHex = str(hex(millisecond)).upper()
+    timeHex = timeHex[2:]
+    formatHex = ''
+    if len(timeHex) == 3:
+        formatHex = '0x0' + timeHexaddLauncher
+    elif len(timeHex) == 4:
+        formatHex = '0x' + timeHex
+    else:
+        formatHex = '0x0BB8'
+    return formatHex
+
+
+def doSDKPostScript(game, sdk, config):
+    '''
+    执行sdk相关特殊处理脚本
+    '''
+    sdkPath = file_utils.getFullSDKPath(sdk)
+    scriptPath = os.path.join(sdkPath, 'script')
+    targetScript = os.path.join(scriptPath, 'sdk_script.py')
+    if not os.path.exists(targetScript):
+        print('sdk_script no exists')
+        return 0
+
+    print('doSDKPostScript...')
+    sys.path.append(scriptPath)
+
+    module = importlib.import_module('sdk_script')
+    ret = module.execute(game, sdk, config)
+
+    sys.path.remove(scriptPath)
+
+    return ret
+
+
+def doGamePostScript(game, sdk, config):
+    '''
+    执行游戏相关特殊处理脚本
+    '''
+    channelPath = file_utils.getFullGamePath(game)
+    scriptPath = os.path.join(channelPath, 'script')
+    targetScript = os.path.join(scriptPath, 'game_script.py')
+    if not os.path.exists(targetScript):
+        print('game_script no exists')
+        return 0
+
+    print('doGamePostScript...')
+    sys.path.append(scriptPath)
+
+    module = importlib.import_module('game_script')
+    ret = module.execute(game, sdk, config)
+
+    sys.path.remove(scriptPath)
+
+    return ret
+
+
+def doGameScript(game, sdk, config):
+    '''
+    执行游戏相关特殊处理脚本
+    '''
+    channelPath = file_utils.getFullPath('game_script', game)
+    targetScript = os.path.join(channelPath, 'game_script.py')
+    print(targetScript + "--------")
+    if not os.path.exists(targetScript):
+        print('game_script no exists')
+        return 0
+
+    print('doGameScript...')
+    sys.path.append(channelPath)
+
+    module = importlib.import_module('game_script')
+    ret = module.execute(game, sdk, config)
+
+    sys.path.remove(channelPath)
+
+    return ret
+
+
+def addLogSdk(game, sdk, subChannel, config, logSdk):
+    # 拷贝jniLibs
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    sdkPath = ''
+    print('add log sdk, sdk:' + sdk)
+    if sdk == 'jm_beta_sdk' or sdk == 'beta_sdk':
+        sdkPath = file_utils.getFullLogSDKPath(logSdk, True)
+    else:
+        sdkPath = file_utils.getFullLogSDKPath(logSdk)
+
+    print('copy log jniLibs...')
+    jniPath = file_utils.getFullPath(sdkPath, 'jniLibs')
+    decomplieJniPath = file_utils.getFullPath(decompliePath, 'lib')
+    abiFilters = []
+    if os.path.exists(decomplieJniPath):
+        for abi in os.listdir(decomplieJniPath):
+            if abi == 'armeabi-v7a' or abi == 'armeabi' or abi == 'arm64-v8a':
+                abiFilters.append(abi)
+    else:
+        abiFilters = ['armeabi-v7a']
+
+    if os.path.exists(jniPath):
+        ret = file_utils.copyFileAllDir(
+            jniPath, decomplieJniPath, False, abiFilters)
+        if ret:
+            return ret
+
+    print('merge log AndroidManifest...')
+    libManifest = file_utils.getFullPath(sdkPath, 'manifest.xml')
+    if os.path.exists(libManifest):
+        manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+        ret = xml_utils.mergeManifestRes(manifest, libManifest)
+        if ret:
+            return ret
+
+    changePlaceholders(game, sdk, subChannel, config)
+
+    return packLogJar(game, sdk, subChannel, config, logSdk)
+
+
+def addOaidSdk(game, sdk, subChannel, config, oaidVersion):
+    sdkPath = file_utils.getFullOaidSDKPath(oaidVersion)
+    decompliePath = file_utils.getDecompliePath(
+        game, sdk, subChannel, config['cache'])
+
+    # 拷贝assets
+    print('copy oaid assets...')
+    assetsPath = file_utils.getFullPath(sdkPath, 'assets')
+    decomplieAssetsPath = file_utils.getFullPath(decompliePath, 'assets')
+    if os.path.exists(assetsPath):
+        ret = file_utils.copyFileAllDir(assetsPath, decomplieAssetsPath)
+        if ret:
+            return ret
+
+    # 拷贝jniLibs
+
+    print('copy oaid jniLibs...')
+    jniPath = file_utils.getFullPath(sdkPath, 'jniLibs')
+    decomplieJniPath = file_utils.getFullPath(decompliePath, 'lib')
+    abiFilters = []
+    if os.path.exists(decomplieJniPath):
+        for abi in os.listdir(decomplieJniPath):
+            if abi == 'armeabi-v7a' or abi == 'armeabi':
+                abiFilters.append(abi)
+    else:
+        abiFilters = ['armeabi-v7a']
+
+    if os.path.exists(jniPath):
+        ret = file_utils.copyFileAllDir(
+            jniPath, decomplieJniPath, False, abiFilters)
+        if ret:
+            return ret
+
+    print('merge oaid AndroidManifest...')
+    libManifest = file_utils.getFullPath(sdkPath, 'manifest.xml')
+    if os.path.exists(libManifest):
+        manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+        ret = xml_utils.mergeManifestRes(manifest, libManifest)
+        if ret:
+            return ret
+
+    return packOaidJar(game, sdk, subChannel, config, oaidVersion)
+
+
+def generateNewRFile(game, sdk, subChannel, config):
+    '''
+    生成新的R文件
+    '''
+    decompliePath = file_utils.getDecompliePath(
+        game, sdk, subChannel, config['cache'])
+    androidPlatforms = file_utils.getAndroidCompileToolPath()
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    decomplieResPath = file_utils.getFullPath(decompliePath, 'res')
+    compliePath = file_utils.getFullPath(decompliePath, 'gen')
+
+    if not os.path.exists(compliePath):
+        os.makedirs(compliePath)
+
+    # 生成R文件
+    print('生成R文件 ...')
+    if config['aapt2disable']:
+        aapt = file_utils.getAAPTPath()
+        ret = file_utils.getExecPermission(aapt)
+        if ret:
+            return ret
+        createRCmd = '"%s" p -f -m -J "%s" -S "%s" -I "%s" -M "%s"' % (
+            aapt, compliePath, decomplieResPath, androidPlatforms, manifest)
+        ret = file_utils.execFormatCmd(createRCmd)
+        if ret:
+            return ret
+    else:
+        # compile
+        aapt = file_utils.getAAPT2Path()
+        ret = file_utils.getExecPermission(aapt)
+        if ret:
+            return ret
+
+        print('compiled res ...')
+        complieResPath = os.path.join(compliePath, 'compiled')
+        complieResCmd = '"%s" compile --dir "%s" -o "%s"' % (
+            aapt, decomplieResPath, complieResPath)
+        file_utils.execFormatCmd(complieResCmd)
+
+        # unzip
+        print('unzip compiled res ...')
+        unzipResPath = os.path.join(compliePath, 'aapt2_res')
+        with zipfile.ZipFile(complieResPath) as zf:
+            zf.extractall(unzipResPath)
+            print('create unzip %s' % unzipResPath)
+
+        # link
+        print('link res ...')
+        outApk = os.path.join(compliePath, 'res.apk')
+        linkResCmd = '"%s" link -o "%s" -I "%s" --manifest "%s" --java "%s" --auto-add-overlay' % (
+            aapt, outApk, androidPlatforms, manifest, compliePath)
+        for filename in os.listdir(unzipResPath):
+            linkResCmd += ' %s' % filename
+        print('link cmd len is %s' % len(linkResCmd))
+        ret = file_utils.execFormatCmd(linkResCmd, unzipResPath)
+        if ret:
+            return ret
+
+    # 编译R文件
+    print('complie R.java ...')
+    packageName = xml_utils.getPackageName(manifest)
+    packagePath = file_utils.getPackagePath(compliePath, packageName)
+    RSourceFile = os.path.join(packagePath, 'R.java')
+    complieRCmd = 'javac -source 1.8 -target 1.8 -encoding UTF-8 "%s"' % RSourceFile
+    ret = file_utils.execFormatCmd(complieRCmd)
+    if ret:
+        return ret
+
+    # 生成dex
+    print('dex R.class ...')
+    outDex = os.path.join(compliePath, 'classes.dex')
+    if config['aapt2disable']:
+        dx = file_utils.getDxPath()
+        dexCmd = '--dex --no-warning --output="%s" "%s"' % (
+            outDex, compliePath)
+    else:
+        dx = file_utils.getD8Path()
+        clazz = os.path.join(packagePath, '*.class')
+        dexCmd = '--lib "%s" --output "%s" %s' % (
+            androidPlatforms, compliePath, clazz)
+    ret = file_utils.execJarCmd(dx, dexCmd)
+    if ret:
+        return ret
+
+    # 反向dex生成smali
+    # 存放在out目录
+    print('baksmali classes.dex ...')
+    baksmaliPath = file_utils.getBaksmaliPath()
+    outPath = file_utils.getFullPath(decompliePath, 'out')
+
+    ret = file_utils.execJarCmd(
+        baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
+    if ret:
+        return ret
+
+    # 将生成的文件拷贝到目标目录
+    print('copy R.smali ...')
+    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
+    file_utils.copyFileAllDir(outPath, smaliPath)
+    return 0
+
+
+def packJar(game, sdk, subChannel, config):
+    '''
+    打包所有的jar
+    '''
+    splitDex = config['splitDex']
+    decompliePath = file_utils.getDecompliePath(
+        game, sdk, subChannel, config['cache'])
+    outPath = file_utils.getFullPath(decompliePath, 'gen')
+
+    if not os.path.exists(outPath):
+        os.makedirs(outPath)
+    if config['aapt2disable']:
+        dx = file_utils.getDxPath()
+        dexCmd = '--dex  --no-warning --output="%s"' % outPath
+    else:
+        dx = file_utils.getD8Path()
+        androidPlatforms = file_utils.getAndroidCompileToolPath()
+        dexCmd = '--lib "%s" --output "%s"' % (androidPlatforms, outPath)
+
+    # 找到所有lib依赖
+    sdkPath = file_utils.getFullSDKPath(sdk)
+    libs = os.path.join(sdkPath, 'libs')
+    libConfig = os.path.join(libs, 'config.json')
+
+    #
+
+    # 存在配置文件
+    if os.path.exists(libConfig):
+        jsonText = file_utils.readFile(libConfig)
+        libConf = json.loads(jsonText)
+        if 'libConfig' in config and config['libConfig'] in libConf:
+            conf = config['libConfig']
+            libList = libConf[conf]
+            for jar in libList:
+                dexCmd += ' ' + os.path.join(libs, jar)
+        elif 'default' in libConf:
+            libList = libConf['default']
+            for jar in libList:
+                dexCmd += ' ' + os.path.join(libs, jar)
+        else:
+            for jar in os.listdir(libs):
+                if not jar.endswith('.jar'):
+                    continue
+                dexCmd += ' ' + os.path.join(libs, jar)
+    else:
+        for jar in os.listdir(libs):
+            if not jar.endswith('.jar'):
+                continue
+            dexCmd += ' ' + os.path.join(libs, jar)
+
+    # multidex.jar
+    if splitDex:
+        print('getMultiDexPath ...')
+        dexCmd += ' ' + file_utils.getMultiDexPath()
+
+    # sdk实现类
+    print('packageing all jar ...')
+    dexCmd += ' ' + os.path.join(sdkPath, '%s.jar' % sdk)
+    ret = file_utils.execJarCmd(dx, dexCmd)
+    if ret:
+        return ret
+
+    # 反向dex生成smali
+    # 存放在out目录
+    print('baksmali classes.dex ...')
+    outDex = os.path.join(outPath, 'classes.dex')
+    baksmaliPath = file_utils.getBaksmaliPath()
+    outPath = file_utils.getFullPath(decompliePath, 'out')
+
+    ret = file_utils.execJarCmd(
+        baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
+    if ret:
+        return ret
+
+    # 将生成的文件拷贝到目标目录
+    print('copy all smali ...')
+    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
+    ret = file_utils.copyFileAllDir(outPath, smaliPath, True)
+    if ret:
+        return ret
+
+    return 0
+
+
+def packLogJar(game, sdk, subChannel, config, logSdk):
+    '''
+    打包Log jar
+    '''
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    outPath = file_utils.getFullPath(decompliePath, 'gen')
+
+    if not os.path.exists(outPath):
+        os.makedirs(outPath)
+
+    if config['aapt2disable']:
+        dx = file_utils.getDxPath()
+        dexCmd = '--dex --multi-dex --no-warning --output="%s"' % outPath
+    else:
+        dx = file_utils.getD8Path()
+        androidPlatforms = file_utils.getAndroidCompileToolPath()
+        dexCmd = '--lib "%s" --output "%s"' % (androidPlatforms, outPath)
+
+    # 找到所有lib依赖
+    if sdk == 'jm_beta_sdk' or sdk == 'beta_sdk':
+        sdkPath = file_utils.getFullLogSDKPath(logSdk, True)
+    else:
+        sdkPath = file_utils.getFullLogSDKPath(logSdk)
+    libs = os.path.join(sdkPath, 'libs')
+    libConfig = os.path.join(libs, 'config.json')
+
+    # 存在配置文件
+    if os.path.exists(libConfig):
+        jsonText = file_utils.readFile(libConfig)
+        libList = json.loads(jsonText)
+        for jar in libList:
+            if not jar.endswith('.jar'):
+                continue
+            dexCmd += ' ' + os.path.join(libs, jar)
+    else:
+        for jar in os.listdir(libs):
+            if not jar.endswith('.jar'):
+                continue
+            dexCmd += ' ' + os.path.join(libs, jar)
+
+    # sdk实现类
+    print('packageing all log jar ...')
+    dexCmd += ' ' + os.path.join(sdkPath, '%s.jar' % logSdk)
+    ret = file_utils.execJarCmd(dx, dexCmd)
+    if ret:
+        return ret
+
+    # 反向dex生成smali
+    # 存放在out目录
+    print('baksmali classes.dex ...')
+    outDex = os.path.join(outPath, 'classes.dex')
+    baksmaliPath = file_utils.getBaksmaliPath()
+    outPath = file_utils.getFullPath(decompliePath, 'out')
+
+    ret = file_utils.execJarCmd(
+        baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
+    if ret:
+        return ret
+
+    # 将生成的文件拷贝到目标目录
+    print('copy all log smali ...')
+    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
+    ret = file_utils.copyFileAllDir(outPath, smaliPath, True)
+    if ret:
+        return ret
+
+    return 0
+
+
+def packOaidJar(game, sdk, subChannel, config, oaidVerion):
+    '''
+    打包oaid jar
+    '''
+    decompliePath = file_utils.getDecompliePath(
+        game, sdk, subChannel, config['cache'])
+    outPath = file_utils.getFullPath(decompliePath, 'gen')
+
+    if not os.path.exists(outPath):
+        os.makedirs(outPath)
+
+    if config['aapt2disable']:
+        dx = file_utils.getDxPath()
+        dexCmd = '--dex --multi-dex --no-warning --output="%s"' % outPath
+    else:
+        dx = file_utils.getD8Path()
+        androidPlatforms = file_utils.getAndroidCompileToolPath()
+        dexCmd = '--lib "%s" --output "%s"' % (androidPlatforms, outPath)
+
+    # 找到所有lib依赖
+    sdkPath = file_utils.getFullOaidSDKPath(oaidVerion)
+    libs = os.path.join(sdkPath, 'libs')
+    libConfig = os.path.join(libs, 'config.json')
+
+    # 存在配置文件
+    # if os.path.exists(libConfig):
+    #     jsonText = file_utils.readFile(libConfig)
+    #     libList = json.loads(jsonText)
+    #     for jar in libList:
+    #         if not jar.endswith('.jar'):
+    #             continue
+    #         dexCmd += ' ' + os.path.join(libs, jar)
+    # else:
+    #     for jar in os.listdir(libs):
+    #         if not jar.endswith('.jar'):
+    #             continue
+    #         dexCmd += ' ' + os.path.join(libs, jar)
+
+    # sdk实现类
+    print('packageing oaid jar ...')
+    dexCmd += ' ' + os.path.join(libs, 'miit_mdid_%s.jar' % oaidVerion)
+    ret = file_utils.execJarCmd(dx, dexCmd)
+    if ret:
+        return ret
+
+    # 反向dex生成smali
+    # 存放在out目录
+    print('baksmali classes.dex ...')
+    outDex = os.path.join(outPath, 'classes.dex')
+    baksmaliPath = file_utils.getBaksmaliPath()
+    outPath = file_utils.getFullPath(decompliePath, 'out')
+
+    ret = file_utils.execJarCmd(
+        baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
+    if ret:
+        return ret
+
+    # 将生成的文件拷贝到目标目录
+    print('copy all log smali ...')
+    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
+    ret = file_utils.copyFileAllDir(outPath, smaliPath, True)
+    if ret:
+        return ret
+
+    return 0
+
+
+def splitDex(game, sdk, subChannel, config):
+    '''
+    分割dex
+    '''
+    # 判断是否已经存在application
+    # 存在,则往原application添加内容
+    # 不存在,则拷贝一个默认的android.support.multidex.MultiDexApplication
+    print('add MultiDex support...')
+    decompliePath = file_utils.getDecompliePath(
+        game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    application = xml_utils.getApplicationAttr(manifest, 'name')
+    if application is None:
+        ret = xml_utils.changeApplicationAttr(
+            manifest, 'name', 'android.support.multidex.MultiDexApplication')
+        if ret:
+            return ret
+    else:
+        smaliPath = os.path.join(decompliePath, 'smali')
+        applicationFile = file_utils.getPackagePath(smaliPath, application)
+        applicationFile += '.smali'
+        ret = changeApplicationDex(applicationFile)
+        if ret:
+            return ret
+
+    return splitSmali(game, sdk, subChannel, config, application)
+
+
+def changeApplicationDex(file):
+    '''
+    修改application的smali文件,增加MultiDex操作
+    '''
+    index = file_utils.getApplicationSmaliIndex(file)
+    file_utils.insertApplicationSmali(file, index)
+    return 0
+
+
+def splitSmali(game, sdk, subChannel, config, application):
+    '''
+    如果函数上限超过限制,自动拆分smali,以便生成多个dex文件
+    '''
+    print('splitSmali...')
+    decompliePath = file_utils.getDecompliePath(
+        game, sdk, subChannel, config['cache'])
+    smaliPath = os.path.join(decompliePath, 'smali')
+
+    appPackage = None
+    if application:
+        appPackage = application[:application.rfind('.')]
+        appPackage = appPackage.replace('.', '/')
+
+    allFiles = []
+    allFiles = file_utils.list_files(smaliPath, allFiles)
+
+    # print('file count is %d' % len(allFiles))
+
+    # maxFuncNum = 65535
+    # 留一点空间,防止计算误差
+    maxFuncNum = 64000
+    currFucNum = 0
+    totalFucNum = 0
+
+    currDexIndex = 1
+
+    allRefs = []
+
+    # 保证Application等类在第一个classex.dex文件中
+    for f in allFiles:
+        f = f.replace('\\', '/')
+        if (appPackage and appPackage in f) or '/android/support/multidex' in f:
+            currFucNum += smali_utils.get_smali_method_count(f, allRefs)
+
+    totalFucNum = currFucNum
+    for f in allFiles:
+        f = f.replace('\\', '/')
+        if not f.endswith('.smali'):
+            continue
+
+        if (appPackage and appPackage in f) or '/android/support/multidex' in f:
+            continue
+
+        thisFucNum = smali_utils.get_smali_method_count(f, allRefs)
+        totalFucNum += thisFucNum
+
+        # print('%d # %d ==> %s' % (thisFucNum, currDexIndex, f))
+        # print('totalFucNum is %d' % totalFucNum)
+        if currFucNum + thisFucNum >= maxFuncNum:
+            currFucNum = thisFucNum
+            currDexIndex += 1
+            newDexPath = os.path.join(
+                decompliePath, 'smali_classes%d' % currDexIndex)
+            os.makedirs(newDexPath)
+        else:
+            currFucNum += thisFucNum
+
+        if currDexIndex > 1:
+            newDexPath = os.path.join(
+                decompliePath, 'smali_classes%d' % currDexIndex)
+            targetFile = newDexPath + f[len(smaliPath):]
+            file_utils.copyFile(f, targetFile, True)
+    return 0
+
+
+def changeVersion(game, sdk, subChannel, config):
+    '''
+    更改版本号
+    '''
+    decompliePath = file_utils.getDecompliePath(
+        game, sdk, subChannel, config['cache'])
+    yml = os.path.join(decompliePath, 'apktool.yml')
+
+    versionCode = None
+    versionName = None
+    targetSdkVersion = None
+    if 'versionCode' in config:
+        versionCode = config['versionCode']
+    if 'versionName' in config:
+        versionName = config['versionName']
+    if 'targetSdkVersion' in config:
+        targetSdkVersion = config['targetSdkVersion']
+    else:
+        targetSdkVersion = 26
+    print('changeVersion versionCode=%s,versionName=%s,targetSdkVersion=%s' %
+          (versionCode, versionName, targetSdkVersion))
+
+    return file_utils.changeVersion(yml, versionCode, versionName, targetSdkVersion)
+
+
+def recomplie(game, sdk, subChannel, config):
+    '''
+    回编译
+    '''
+    print('recomplie apk...')
+    apktoolPath = file_utils.getApkToolPath()
+    decompliePath = file_utils.getDecompliePath(
+        game, sdk, subChannel, config['cache'])
+    outApk = file_utils.getOutApkPath(game, sdk, subChannel, config['cache'])
+
+    useAppt2 = ' --use-aapt2'
+    if config['aapt2disable']:
+        useAppt2 = ''
+
+    return file_utils.execJarCmd(apktoolPath, 'b -f "%s" -o "%s"%s' % (decompliePath, outApk, useAppt2))
+
+
+def alignApk(game, sdk, subChannel, config):
+    '''
+    对齐apk
+    '''
+    print('align apk...')
+    outApk = file_utils.getOutApkPath(game, sdk, subChannel, config['cache'])
+    alignApk = file_utils.getAlignApkPath(
+        game, sdk, subChannel, config['cache'])
+    alignapkTool = file_utils.getAlignPath()
+    if os.path.exists(alignApk):
+        os.remove(alignApk)
+
+    ret = file_utils.getExecPermission(alignapkTool)
+    if ret:
+        return ret
+
+    # zipalign.exe -v -p 4 input.apk output.apk
+    return file_utils.execFormatCmd('"%s" -f -p 4 "%s" "%s"' % (alignapkTool, outApk, alignApk))
+
+
+def apksignerApk(game, sdk, subChannel, config):
+    '''
+    签名apk
+    '''
+    print('sign apk...')
+    print('game = %s, sdk = %s, subChannel = %s, ...' %
+          (game, sdk, subChannel))
+    path = os.path.join(file_utils.getCurrentPath(), 'keystore', 'key.json')
+    jsonText = file_utils.readFile(path)
+    signConfig = json.loads(jsonText)
+    keystore = {}
+    for key in signConfig.keys():
+        print(key)
+        if game.find(key) > -1 or game == key:
+            if sdk in signConfig[key]:
+                keystore = signConfig[key][sdk]
+                break
+            else:
+                keystore = signConfig['default']
+        else:
+            keystore = signConfig['default']
+
+    # if game in signConfig:
+    #     if sdk in signConfig[game]:
+    #         keystore = signConfig[game][sdk]
+    #     else:
+    #         keystore = signConfig['default']
+    # else:
+    #     keystore = signConfig['default']
+
+    print('storeFile is "%s"' % keystore['storeFile'])
+
+    apksigner = file_utils.getApksignerPath()
+    alignApk = file_utils.getAlignApkPath(
+        game, sdk, subChannel, config['cache'])
+    signedApk = file_utils.getSiginedApkPath(
+        game, sdk, subChannel, config['cache'])
+    storeFile = os.path.join(file_utils.getCurrentPath(),
+                             'keystore', keystore['storeFile'])
+
+    # java -jar apksigner.jar sign --ks key.jks --ks-key-alias releasekey --ks-pass pass:pp123456 --key-pass pass:pp123456 --out output.apk input.apk
+    v2disable = ''
+    if 'v2disable' in config and config['v2disable']:
+        v2disable = ' --v2-signing-enabled=false'
+
+    return file_utils.execJarCmd(apksigner,
+                                 'sign%s --ks "%s" --ks-key-alias %s --ks-pass pass:%s --key-pass pass:%s --out "%s" "%s"' % (
+                                     v2disable, storeFile, keystore['keyAlias'], keystore['storePassword'],
+                                     keystore['keyPassword'], signedApk, alignApk))
+
+
+def addChannel(game, sdk, subChannel, config):
+    '''
+    添加渠道信息
+    '''
+    if 'v2disable' in config and config['v2disable']:
+        return 0
+
+    walle = file_utils.getWallePath()
+    signedApk = file_utils.getSiginedApkPath(
+        game, sdk, subChannel, config['cache'])
+    walleApk = file_utils.getWalleApkPath(
+        game, sdk, subChannel, config['cache'])
+
+    properties = config['properties']
+
+    appid = ''
+    appkey = ''
+    host = ''
+    if 'appid' in properties:
+        appid = properties['appid']
+    if 'appkey' in properties:
+        appkey = properties['appkey']
+    if 'host' in properties:
+        host = properties['host']
+
+    return file_utils.execJarCmd(walle, 'put -e version=%s,agent=%s,appid=%s,appkey=%s,host=%s "%s" "%s"' % (
+        config_utils.getDate(), properties['agent'], appid, appkey, host, signedApk, walleApk))
+
+
+def clearTemp(game, sdk, subChannel, config):
+    '''
+    清空中间产生的文件
+    '''
+    print('clear temp...')
+
+    targetApkPath = file_utils.getTargetApkPath(game, sdk, config['cache'])
+
+    if os.path.exists(targetApkPath):
+        file_utils.deleteFolder(targetApkPath)
+
+    decompliePath = file_utils.getDecompliePath(
+        game, sdk, subChannel, config['cache'])
+    if os.path.exists(decompliePath):
+        file_utils.deleteFolder(decompliePath)
+
+    random = config['random']
+    channelPath = file_utils.getChannelPath(game, random, sdk)
+    if os.path.exists(channelPath):
+        file_utils.deleteFolder(channelPath)
+    print('clear temp end')
+
+
+def packConsoleInput():
+    '''
+    控制台打包
+    '''
+    if len(sys.argv) < 3:
+        print('argument is missing')
+        return 1
+
+    # 校验参数
+    game = sys.argv[1]
+    sdk = sys.argv[2]
+    # 可选参数,没有则默认打全部渠道
+    subChannel = None
+    if len(sys.argv) > 3:
+        subChannel = sys.argv[3]
+
+    return packConsole(game, sdk, subChannel)
+
+
+def packConsole(game, sdk, config, subChannel):
+    '''
+    控制台打包
+    '''
+    cache_game_apk_path = file_utils.getCacheGameApk(game, config['random'], sdk)
+    print('cache game apk path %s' % cache_game_apk_path)
+    if not os.path.exists(cache_game_apk_path):
+        print('game "%s" not exists' % game)
+        return 1
+    if not os.path.exists(file_utils.getFullSDKPath(sdk)):
+        print('sdk "%s" not exists' % sdk)
+        return 1
+    global startTime
+    startTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+
+    # 读取配置
+    random = config['random']
+    channelPath = file_utils.getChannelPath(game, random, sdk)
+    configPath = os.path.join(channelPath, 'config.json')
+    if not os.path.exists(configPath):
+        print('%s not exists' % configPath)
+        return 1
+
+    jsonText = file_utils.readFile(configPath)
+    config = json.loads(jsonText)
+
+    # 检查参数
+    if not config_utils.checkConfig(config):
+        return 1
+
+    # 处理参数
+    config_utils.replaceArgs(config)
+
+    successCount = 0
+    failureCount = 0
+    if type(config) == dict:
+        if subChannel is None or config['subChannel'] == subChannel:
+            ret = pack(game, sdk, config)
+            if ret:
+                failureCount += 1
+            else:
+                successCount += 1
+        else:
+            print('subChannel "%s" no found' % subChannel)
+            return 1
+    elif type(config) == list:
+        found = False
+        for itemConfig in config:
+            if subChannel is None or itemConfig['subChannel'] == subChannel:
+                found = True
+                ret = pack(game, sdk, itemConfig)
+                if ret:
+                    failureCount += 1
+                else:
+                    successCount += 1
+
+        if not found:
+            print('subChannel "%s" no found' % subChannel)
+            return 1
+
+    print('success %d, failure %d' % (successCount, failureCount))
+
+    subChannelPath = os.path.join(channelPath, subChannel)
+    print('------subChannelPath 目录清空:%s  -------' % subChannelPath)
+    file_utils.deleteFolder(subChannelPath)
+    return 0
+
+
+def formatXml(game, sdk, subChannel, config):
+    decompliePath = file_utils.getDecompliePath(
+        game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    return xml_utils.formatXml(manifest)
+
+
+def copyApk2OutDir(game, sdk, subChannel, config):
+    walleApk = file_utils.getWalleApkPath(
+        game, sdk, subChannel, config['cache'])
+    releaseApkPath = ""
+    if 'outName' in config and 'outPath' in config:
+        if not os.path.exists(config['outPath']):
+            os.makedirs(config['outPath'])
+
+        releaseApkPath = os.path.join(
+            config['outPath'], config['outName'] + '.apk')
+    elif 'outName' in config:
+        releaseApkPath = file_utils.getRenameApkPath(
+            game, sdk, config['cache'], config['outName'])
+    print('------生成正式包路径 %s  -------' % releaseApkPath)
+    file_utils.copyFile(walleApk, releaseApkPath)
+
+
+def replaceAmHardwareAccelerated(game, sdk, subChannel, config):
+    decompliePath = file_utils.getDecompliePath(
+        game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+
+    lines = open(manifest).readlines()
+    fp = open(manifest, "w")
+
+    isReplaced = False
+    for l in lines:
+        if isReplaced == False and l.find("android:hardwareAccelerated=") >= 0:
+            isReplace = True
+            l = re.sub("android:hardwareAccelerated=\"false\"",
+                       "android:hardwareAccelerated=\"true\"", l)
+        fp.write(l)
+    fp.close()
+    pass
+
+
+def openFile(file, mode):
+    return open(file, mode, encoding='UTF-8')

+ 1246 - 1246
package_utils_record.py

@@ -1,1246 +1,1246 @@
-# 安卓游戏打包脚本
-# 1.用apktool解包
-# 2.复制res资源、assets资源、jniLib资源
-# 3.修改包名、app名、渠道文件
-# 4.添加app icon、合并AndroidManifest文件
-# 5.添加app启动图,修改AndroidManifest文件
-# 6.生成新的R文件
-# 7.将新的R文件编译,生成dex,再用baksmali生成smali,替换旧的R文件
-# 8.将jar资源打包成dex,再用baksmali生成smali,拷贝到smali目录下
-# 9.统计方法量,并分割dex(将smali文件拷贝到目录smali_classes2)
-# 10.用apktool回包
-# 11.重新签名
-import file_utils
-import xml_utils
-import smali_utils
-import config_utils_record
-import game_utils
-import os
-import os.path
-import json
-import sys
-import importlib
-import uuid
-import zipfile
-
-from xml.etree import ElementTree as ET
-from xml.etree.ElementTree import SubElement
-
-def pack(game, sdk, config):
-    config['cache'] = uuid.uuid1()
-    subChannel = config['subChannel']
-    # 解包
-    ret = decomplie(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 删除旧代码
-    ret = removeOldCode(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    if 'deleteList' in config:
-        # 删除旧资源
-        ret = removeOldRes(game, sdk, subChannel, config)
-        if ret:
-            return ret
-    # 删除一些不支持的属性
-    ret = removeNoSupportAttr(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 删除一些不支持的配置
-    ret = fixUnSupportConfig(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 合并Drawable-v4目录
-    ret = mergeDrawableRes(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 移除相同的资源
-    ret = removeSameRes(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 复制res资源
-    ret = copyRes(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 合并主文件
-    ret = mergeManifestRes(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 替换占位符
-    ret = changePlaceholders(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 添加meta-data
-    ret = addMetaData(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 复制app res资源
-    ret = copyAppRes(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 合并语言文件
-    ret = mergeLanguage(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 增加配置文件
-    ret = addConfig(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    #保存旧包名
-    config['oldPackageName'] = getPackageName(game, sdk, subChannel, config)
-    # 更改包名
-    if 'packageName' in config and config['packageName'] != '':
-        ret = changePackageName(game, sdk, subChannel, config)
-        if ret:
-            return ret
-    else:
-        config['packageName'] = getPackageName(game, sdk, subChannel, config)
-    # 更改app名
-    if 'name' in config and config['name'] != '':
-        ret = changeAppName(game, sdk, subChannel, config)
-        if ret:
-            return ret
-    # 更改app icon
-    if config['changeIcon']:
-        ret = changeAppIcon(game, sdk, subChannel, config)
-        if ret:
-            return ret
-    # 添加启动图操作
-    if config['addLauncher']:
-        ret = addLauncher(game, sdk, subChannel, config)
-        if ret:
-            return ret
-    # 打包lib依赖
-    ret = packJar(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # sdk脚本处理
-    ret = doSDKPostScript(game, sdk, config)
-    if ret:
-        return ret
-    # 乐变sdk的特殊处理
-    ret = game_utils.sdkLebianChange(game, sdk, config)
-    if ret:
-        return ret
-    # 复制EntryActivity文件
-    ret = copyEntryActivityCode(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 游戏脚本处理
-    ret = doGamePostScript(game, sdk, config)
-    if ret:
-        return ret
-    # 生成R文件
-    '''ret = generateNewRFile(game, sdk, subChannel, config)
-    if ret:
-        return ret'''
-    # 添加MultiDex支持
-    if config['splitDex']:
-        ret = splitDex(game, sdk, subChannel, config)
-        if ret:
-            return ret
-    # 更改版本号
-    ret = changeVersion(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 回编译
-    ret = recomplie(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 对齐apk
-    ret = alignApk(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 签名
-    ret = apksignerApk(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 清理产生的中间文件
-    if config['clearCache']:
-        clearTemp(game, sdk, subChannel, config)
-
-    return 0
-
-def decomplie(game, sdk, subChannel, config):
-    '''
-    解包
-    '''
-    apktoolPath = file_utils.getApkToolPath()
-    gamePath = file_utils.getFullGameApk(game)
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-
-    if os.path.exists(decompliePath):
-        print('delete decomplie folder...')
-        file_utils.deleteFolder(decompliePath)
-
-    print('decomplie apk...')
-
-    return file_utils.execJarCmd(apktoolPath, 'd -f "%s" -o "%s"' % (gamePath, decompliePath))
-
-def removeOldRes(game, sdk, subChannel, config):
-    '''
-    删除旧资源
-    '''
-    print('delete res ...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    for subPath in config['deleteList']:
-        resPath = os.path.join(decompliePath, subPath)
-        if os.path.exists(resPath):
-            os.remove(resPath)
-            print('delete ' + resPath)
-    return 0
-
-def removeOldCode(game, sdk, subChannel, config):
-    '''
-    删除旧代码
-    '''
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    codePath = os.path.join(decompliePath, 'smali', 'com', 'jmhy', 'lib', 'record')
-    #file_utils.deleteFolder(codePath)
-    allFiles = []
-    allFiles = file_utils.list_files(codePath, allFiles)
-    for f in allFiles:
-        fpath, fname = os.path.split(f)  #分离文件名和路径
-        if fname == 'R.smali' or fname.startswith('R$'):
-            continue
-        os.remove(f)
-        print('remove %s' % f)
-    return 0
-
-def copyRes(game, sdk, subChannel, config):
-    '''
-    复制res资源
-    '''
-    # 拷贝sdk资源
-    print('copy res...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    sdkPath = file_utils.getFullSDKPath(sdk)
-    resPath = os.path.join(sdkPath, 'res')
-    decomplieResPath = file_utils.getFullPath(decompliePath, 'res')
-
-    for d in os.listdir(resPath):
-        copyResWithType(resPath, decomplieResPath, d)
-
-    # 拷贝assets
-    print('copy assets...')
-    assetsPath = file_utils.getFullPath(sdkPath, 'assets')
-    decomplieAssetsPath = file_utils.getFullPath(decompliePath, 'assets')
-    if os.path.exists(assetsPath):
-        ret = file_utils.copyFileAllDir(assetsPath, decomplieAssetsPath)
-        if ret:
-            return ret
-
-    # 拷贝jniLib
-    print('copy jniLibs...')
-    jniPath = file_utils.getFullPath(sdkPath, 'jniLibs')
-    decomplieJniPath = file_utils.getFullPath(decompliePath, 'lib')
-    abiFilters = []
-    if os.path.exists(decomplieJniPath):
-        for abi in os.listdir(decomplieJniPath):
-            if abi == 'armeabi-v7a' or abi == 'armeabi':
-                abiFilters.append(abi)
-    else:
-        abiFilters = ['armeabi-v7a']
-
-    if os.path.exists(jniPath):
-        ret = file_utils.copyFileAllDir(jniPath, decomplieJniPath, False, abiFilters)
-        if ret:
-            return ret
-
-    return 0
-
-def mergeDrawableRes(game, sdk, subChannel, config):
-    '''
-    合并Drawable-v4目录
-    '''
-    print('merge drawable path...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    resPath = os.path.join(decompliePath, 'res')
-
-    for path in os.listdir(resPath):
-        print('res path %s' % path)
-        if (path.startswith('drawable') or path.startswith('mipmap')) and path.endswith('-v4'):
-            print('merge path %s' % path)
-            v4DrawablePath = os.path.join(resPath, path)
-            drawablePath = os.path.join(resPath, path[:-3])
-
-            if os.path.exists(drawablePath):
-                ret = file_utils.copyFileAllDir(v4DrawablePath, drawablePath, True)
-                if ret:
-                    return ret
-            else:
-                os.rename(v4DrawablePath, drawablePath)
-    return 0
-
-def removeSameRes(game, sdk, subChannel, config):
-    '''
-    移除相同的资源
-    '''
-    # 读取sdk的资源
-    print('remove same res...')
-    sdkPath = file_utils.getFullSDKPath(sdk)
-    sdkResPath = os.path.join(sdkPath, 'res')
-    resList = []
-    for path in os.listdir(sdkResPath):
-        if not path.startswith('values'):
-            continue
-
-        absPath = os.path.join(sdkResPath, path)
-        for resFile in os.listdir(absPath):
-            '''if not resFile.startswith('jm_'):
-                continue'''
-
-            resList = xml_utils.readAllRes(os.path.join(absPath, resFile), resList)
-
-    if len(resList) == 0:
-        print('no same res found')
-        return 0
-
-    removeList = []
-    # 移除相同的资源
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    resPath = os.path.join(decompliePath, 'res')
-    for path in os.listdir(resPath):
-        if not path.startswith('values'):
-            continue
-
-        absPath = os.path.join(resPath, path)
-        for resFile in os.listdir(absPath):
-            print('resFile ==> ' + os.path.join(absPath, resFile))
-            #xml_utils.removeSameRes(os.path.join(absPath, resFile), resList)
-            removeList = xml_utils.removeSameRes2(os.path.join(absPath, resFile), resList, removeList)
-
-    print('--------------')
-    print(removeList)
-    if len(removeList) == 0:
-        print('no same res remove')
-        return 0
-    publicResPath = os.path.join(decompliePath, 'res/values/public.xml')
-    print('publicResPath ---->' + publicResPath)
-    xml_utils.removeIdFromPublic(publicResPath,removeList)
-
-
-    return 0
-
-def mergeManifestRes(game, sdk, subChannel, config):
-    '''
-    合并主文件
-    '''
-    print('merge AndroidManifest...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    sdkPath = file_utils.getFullSDKPath(sdk)
-    libManifest = file_utils.getFullPath(sdkPath, 'manifest.xml')
-    return xml_utils.mergeManifestRes(manifest, libManifest)
-
-def copyAppRes(game, sdk, subChannel, config):
-    '''
-    拷贝app的资源,比如app icon、启动图等
-    '''
-    channelPath = file_utils.getSubChannelPath(game, sdk, subChannel)
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-
-    # assets
-    print('copy assets...')
-    assetsPath = file_utils.getFullPath(channelPath, 'assets')
-    decomplieAssetsPath = file_utils.getFullPath(decompliePath, 'assets')
-    if os.path.exists(assetsPath):
-        ret = file_utils.copyFileAllDir(assetsPath, decomplieAssetsPath)
-        if ret:
-            return ret
-
-    # icon
-    print('copy icon...')
-    ret = copyAppResWithType(decompliePath, channelPath, 'icon')
-    if ret:
-        return ret
-    # 启动图
-    print('copy splash...')
-    ret = copyAppResWithType(decompliePath, channelPath, 'splash')
-    if ret:
-        return ret
-    # 其他图片
-    print('copy image...')
-    ret = copyAppResWithType(decompliePath, channelPath, 'image')
-    if ret:
-        return ret
-    return 0
-
-def mergeLanguage(game, sdk, subChannel, config):
-    '''
-    合并语言文件
-    '''
-    print('merge language...')
-    channelPath = file_utils.getSubChannelPath(game, sdk, subChannel)
-    mergePath = file_utils.getFullPath(channelPath, 'merge')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-
-    if not os.path.exists(mergePath):
-        print('%s not exists!' % mergePath)
-        return 0
-
-    if not os.path.isdir(mergePath):
-        print('%s not a dir!' % mergePath)
-        return 0
-
-    for fileName in os.listdir(mergePath):
-        mergeJson(mergePath, decompliePath, fileName)
-    return 0
-
-def mergeJson(srcDir, changeDir, fileName):
-    srcFile = os.path.join(srcDir, fileName)
-    if os.path.isdir(srcFile):
-        for fileName2 in os.listdir(srcFile):
-            changeDir2 = os.path.join(changeDir, fileName)
-            mergeJson(srcFile, changeDir2, fileName2)
-    else:
-        changeFile = os.path.join(changeDir, fileName)
-        if not os.path.exists(changeFile):
-            print('%s not exists!' % changeFile)
-            return 0
-        jsonText1 = file_utils.readFile(srcFile)
-        jsonText2 = file_utils.readFile(changeFile)
-        print('*************src config*************')
-        print(jsonText1)
-        print('************************************')
-        print('*************target config*************')
-        print(jsonText2)
-        print('************************************')
-
-        json1 = json.loads(jsonText1)
-        json2 = json.loads(jsonText2)
-
-        for item in json1:
-            if item in json2:
-                json2[item] = json1[item]
-
-        jsonStr = json.dumps(json2, ensure_ascii=False)
-        print('*************merge config*************')
-        print(jsonStr)
-        print('************************************')
-        print('>> %s' % changeFile)
-        file_utils.createFile(changeFile, jsonStr)
-    return 0
-    
-def copyAppResWithType(decompliePath, channelPath, typeName):
-    decomplieResPath = os.path.join(decompliePath, 'res')
-    iconPath = os.path.join(channelPath, typeName)
-    if not os.path.exists(iconPath):
-        print('dir "%s" not exists' % iconPath)
-        return 0
-    for d in os.listdir(iconPath):
-        ret = copyResWithType(iconPath, decomplieResPath, d)
-        if ret:
-            return ret
-
-    return 0
-
-def copyResWithType(resPath, decomplieResPath, typeName):
-    # appt的打包目录会带-v4后缀
-    resDir = os.path.join(resPath, typeName)
-    target = os.path.join(decomplieResPath, typeName)
-    targetV4 = os.path.join(decomplieResPath, typeName + '-v4')
-    if not os.path.exists(target) and not os.path.exists(targetV4):
-        os.makedirs(target)
-        return file_utils.copyFileAllDir(resDir, target, False)
-    elif not os.path.exists(target):
-        return file_utils.copyFileAllDir(resDir, targetV4, False)
-    else:
-        return file_utils.copyFileAllDir(resDir, target, False)
-
-def removeNoSupportAttr(game, sdk, subChannel, config):
-    '''
-    删除一些不支持的属性
-    '''
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    
-    xml_utils.removeRootAttr(manifest, 'compileSdkVersion')
-    xml_utils.removeRootAttr(manifest, 'compileSdkVersionCodename')
-    
-    return 0
-
-def fixUnSupportConfig(game, sdk, subChannel, config):
-    '''
-    删除一些不支持的配置
-    '''
-    # 检查minSdkVersion
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    yml = os.path.join(decompliePath, 'apktool.yml')
-
-    minSdkVersion = 15
-    file_utils.changeMinSdkVersion(yml, minSdkVersion)
-
-    resPath = os.path.join(decompliePath, 'res')
-
-    tag = '-v'
-    for res in os.listdir(resPath):
-        print('res = ' + res)
-        if res.startswith('values') and tag in res:
-            start = res.index(tag)
-            version = res[start+len(tag):]
-            if not version.isdigit():
-                continue
-            
-            version = int(version)
-            print('version = %d' % version)
-            if version < minSdkVersion:
-                unSopportPath = os.path.join(resPath, res)
-                print('unSopportPath = ' + unSopportPath)
-                file_utils.deleteFolder(unSopportPath)
-                print('deleteFolder = ' + unSopportPath)
-    
-    return 0
-
-def changePackageName(game, sdk, subChannel, config):
-    '''
-    更改包名
-    '''
-    # 全局替换AndroidManifest里面的包名
-    newPackageName = config['packageName']
-
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    packageName = xml_utils.getPackageName(manifest)
-    
-    xml_utils.changePackageName(manifest, newPackageName)
-    print('change package name %s --> %s' % (packageName, newPackageName))
-    return 0
-
-def getPackageName(game, sdk, subChannel, config):
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    packageName = xml_utils.getPackageName(manifest)
-    return packageName
-
-def changeAppName(game, sdk, subChannel, config):
-    '''
-    更改app名
-    '''
-    # 生成string.xml文件
-    name = config['name']
-
-    resName = 'shanshen_sdk_name'
-    if 'outName' in config:
-        resName = resName + '_' + config['outName']
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    stringFile = os.path.join(decompliePath, 'res', 'values', 'sdk_strings_temp.xml')
-    content = '<?xml version="1.0" encoding="utf-8"?><resources><string name="%s">%s</string></resources>' % (resName, name)
-    file_utils.createFile(stringFile, content)
-
-    # 修改主文件的app名的值
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    xml_utils.changeAppName(manifest, '@string/%s' % resName)
-    print('change app name %s' % name)
-    return 0
-
-def changeAppIcon(game, sdk, subChannel, config):
-    '''
-    更改app icon
-    '''
-    print('change app icon...')
-    resName = 'record_sdk_icon'
-
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    xml_utils.changeAppIcon(manifest, '@mipmap/%s' % resName)
-    return 0
-
-def addMetaData(game, sdk, subChannel, config):
-    '''
-    添加meta-data
-    '''
-    if 'metaData' not in config:
-        return 0
-
-    print('add meta-data...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    xml_utils.addMetaData(manifest, config['metaData'])
-    return 0
-
-def addConfig(game, sdk, subChannel, config):
-    '''
-    添加config.json
-    '''
-    if 'configData' not in config:
-        print('configData is null')
-        return 0
-
-    print('add config.json...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    configJson = os.path.join(decompliePath, 'assets', 'tool_config.json')
-    jsonText = json.dumps(config['configData'], ensure_ascii=False)
-    file_utils.createFile(configJson, jsonText)
-    return 0
-
-def changePlaceholders(game, sdk, subChannel, config):
-    '''
-    处理掉占位符
-    '''
-    if 'placeholders' not in config:
-        return 0
-
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-
-    placeholders = config['placeholders']
-    for placeholder in placeholders:
-        oldText = '${%s}' % placeholder
-        newText = placeholders[placeholder]
-        print('change placeholder %s -> %s' % (oldText, newText))
-        file_utils.replaceContent(manifest, oldText, newText)
-
-    return 0
-
-def addLauncher(game, sdk, subChannel, config):
-    '''
-    添加启动图
-    '''
-    channelPath = file_utils.getSubChannelPath(game, sdk, subChannel)
-    splashPath = os.path.join(channelPath, 'splash')
-    if len(os.listdir(splashPath)) == 0:
-        print('dir splash is empty')
-        return 0
-
-    print('add launcher...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    activity = xml_utils.getLauncherActivityName(manifest)
-    if activity == 'com.shanshen.sdk.template.LauncherActivity':
-        print('add launcher already exist...')
-        return 1
-
-    # 添加关联资源
-    internalPath = os.path.join(file_utils.getCurrentPath(), 'internal_shanshen')
-    ret = copyAppResWithType(decompliePath, internalPath, 'launcher_res')
-    if ret:
-        return ret
-
-    # 拷贝代码
-    print('copy launcher code...')
-    codePath = os.path.join(internalPath, 'launcher_code', 'smali')
-    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
-    ret = file_utils.copyFileAllDir(codePath, smaliPath)
-    if ret:
-        return ret
-
-    # 修改主文件信息
-    print('change launcher config...')
-    orientation = xml_utils.getScreenOrientation(manifest)
-    activity = xml_utils.removeLauncherActivity(manifest)
-    xml_utils.addLauncherActivity(manifest, orientation, 'com.shanshen.sdk.template.LauncherActivity')
-
-    # 修改跳转的
-    launcherActivity = os.path.join(decompliePath, 'smali', 'com', 'shanshen', 'sdk', 'template', 'LauncherActivity.smali')
-    file_utils.replaceContent(launcherActivity, '{class}', activity)
-
-    print('change launcher %s to %s' % (activity, 'com.shanshen.sdk.template.LauncherActivity'))
-
-    # config['oldLauncher'] = activity
-
-    if 'launcherTime' in config:
-        timeHex = formatHex(config['launcherTime'])
-        file_utils.replaceContent(launcherActivity, '0x0BB8', timeHex)
-
-    return 0
-
-def addMoreIcon(game, sdk, subChannel, config):
-    '''
-    添加多个图标
-    '''
-    print('add more icon support...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    icon = '@mipmap/common_sdk_icon'
-    if not config['changeIcon']:
-        manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-        icon = xml_utils.getApplicationAttr(manifest, 'icon')
-
-    switchIcon = icon
-    if config['switchIcon']:
-        switchIcon = '@mipmap/common_sdk_icon2'
-
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    return xml_utils.addMoreIcon(manifest, icon, switchIcon)
-
-def formatHex(millisecond):
-    '''
-    将毫秒转为16进制,4位格式
-    '''
-    timeHex = str(hex(millisecond)).upper()
-    timeHex = timeHex[2:]
-    formatHex = ''
-    if len(timeHex) == 3:
-        formatHex = '0x0' + timeHex
-    elif len(timeHex) == 4:
-        formatHex = '0x' + timeHex
-    else:
-        formatHex = '0x0BB8'
-    return formatHex
-
-def doSDKPostScript(game, sdk, config):
-    '''
-    执行sdk相关特殊处理脚本
-    '''
-    sdkPath = file_utils.getFullSDKPath(sdk)
-    scriptPath = os.path.join(sdkPath, 'script')
-    targetScript = os.path.join(scriptPath, 'sdk_script.py')
-    if not os.path.exists(targetScript):
-        print('sdk_script no exists')
-        return 0
-
-    print('doSDKPostScript...')
-    sys.path.append(scriptPath)
-
-    module = importlib.import_module('sdk_script')
-    ret = module.execute(game, sdk, config)
-
-    sys.path.remove(scriptPath)
-
-    return ret
-
-def doGamePostScript(game, sdk, config):
-    '''
-    执行游戏相关特殊处理脚本
-    '''
-    channelPath = file_utils.getFullGamePath(game)
-    scriptPath = os.path.join(channelPath, 'script')
-    targetScript = os.path.join(scriptPath, 'game_script.py')
-    if not os.path.exists(targetScript):
-        print('game_script no exists')
-        return 0
-
-    print('doGamePostScript...')
-    sys.path.append(scriptPath)
-
-    module = importlib.import_module('game_script')
-    ret = module.execute(game, sdk, config)
-
-    sys.path.remove(scriptPath)
-
-    return ret
-
-def generateNewRFile(game, sdk, subChannel, config):
-    '''
-    生成新的R文件
-    '''
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    androidPlatforms = file_utils.getAndroidCompileToolPath()
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    decomplieResPath = file_utils.getFullPath(decompliePath, 'res')
-    compliePath = file_utils.getFullPath(decompliePath, 'gen')
-
-    if not os.path.exists(compliePath):
-        os.makedirs(compliePath)
-
-    # 生成R文件
-    print('create R.java ...')
-    if config['aapt2disable']:
-        aapt = file_utils.getAAPTPath()
-        ret = file_utils.getExecPermission(aapt)
-        if ret:
-            return ret
-        createRCmd = '"%s" p -f -m -J "%s" -S "%s" -I "%s" -M "%s"' % (aapt, compliePath, decomplieResPath, androidPlatforms, manifest)
-        ret = file_utils.execFormatCmd(createRCmd)
-        if ret:
-            return ret
-    else:
-        # compile
-        aapt = file_utils.getAAPT2Path()
-        ret = file_utils.getExecPermission(aapt)
-        if ret:
-            return ret
-
-        print('compiled res ...')
-        complieResPath = os.path.join(compliePath, 'compiled')
-        complieResCmd = '"%s" compile --dir "%s" -o "%s"' % (aapt, decomplieResPath, complieResPath)
-        file_utils.execFormatCmd(complieResCmd)
-
-        # unzip
-        print('unzip compiled res ...')
-        unzipResPath = os.path.join(compliePath, 'aapt2_res')
-        with zipfile.ZipFile(complieResPath) as zf:
-            zf.extractall(unzipResPath)
-            print('create unzip %s' % unzipResPath)
-
-        # link
-        print('link res ...')
-        outApk = os.path.join(compliePath, 'res.apk')
-        linkResCmd = '"%s" link -o "%s" -I "%s" --manifest "%s" --java "%s" --auto-add-overlay' % (aapt, outApk, androidPlatforms, manifest, compliePath)
-        for filename in os.listdir(unzipResPath):
-            linkResCmd += ' %s' % filename
-        print('link cmd len is %s' % len(linkResCmd))
-        ret = file_utils.execFormatCmd(linkResCmd, unzipResPath)
-        if ret:
-            return ret
-
-    # 编译R文件
-    print('complie R.java ...')
-    packageName = xml_utils.getPackageName(manifest)
-    packagePath = file_utils.getPackagePath(compliePath, packageName)
-    RSourceFile = os.path.join(packagePath, 'R.java')
-    complieRCmd = 'javac -source 1.8 -target 1.8 -encoding UTF-8 "%s"' % RSourceFile
-    ret = file_utils.execFormatCmd(complieRCmd)
-    if ret:
-        return ret
-
-    # 生成dex
-    print('dex R.class ...')
-    dx = file_utils.getDxPath()
-    outDex = os.path.join(compliePath, 'classes.dex')
-    ret = file_utils.execJarCmd(dx, '--dex --output="%s" "%s"' % (outDex, compliePath))
-    if ret:
-        return ret
-
-    # 反向dex生成smali
-    # 存放在out目录
-    print('baksmali classes.dex ...')
-    baksmaliPath = file_utils.getBaksmaliPath()
-    outPath = file_utils.getFullPath(decompliePath, 'out')
-    ret = file_utils.execJarCmd(baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
-    if ret:
-        return ret
-
-    # 将生成的文件拷贝到目标目录
-    print('copy R.smali ...')
-    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
-    file_utils.copyFileAllDir(outPath, smaliPath)
-    return 0
-
-def packJar(game, sdk, subChannel, config):
-    '''
-    打包所有的jar
-    '''
-    splitDex = config['splitDex']
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    outPath = file_utils.getFullPath(decompliePath, 'gen')
-
-    if not os.path.exists(outPath):
-        os.makedirs(outPath)
-
-    if config['aapt2disable']:
-        dx = file_utils.getDxPath()
-        dexCmd = '--dex --multi-dex --no-warning --output="%s"' % outPath
-    else:
-        dx = file_utils.getD8Path()
-        androidPlatforms = file_utils.getAndroidCompileToolPath()
-        dexCmd = '--lib "%s" --output "%s"' % (androidPlatforms, outPath)
-
-    # 找到所有lib依赖
-    sdkPath = file_utils.getFullSDKPath(sdk)
-    libs = os.path.join(sdkPath, 'libs')
-    libConfig = os.path.join(libs, 'config.json')
-
-    # 存在配置文件
-    if os.path.exists(libConfig):
-        jsonText = file_utils.readFile(libConfig)
-        libConf = json.loads(jsonText)
-        if 'libConfig' in config and config['libConfig'] in libConf:
-            conf = config['libConfig']
-            libList = libConf[conf]
-            for jar in libList:
-                dexCmd += ' ' + os.path.join(libs, jar)
-        elif 'default' in libConf:
-            libList = libConf['default']
-            for jar in libList:
-                dexCmd += ' ' + os.path.join(libs, jar)
-        else:
-            for jar in os.listdir(libs):
-                if not jar.endswith('.jar'):
-                    continue
-                dexCmd += ' ' + os.path.join(libs, jar)
-    else:
-        for jar in os.listdir(libs):
-            if not jar.endswith('.jar'):
-                continue
-            dexCmd += ' ' + os.path.join(libs, jar)
-
-    # multidex.jar
-    if splitDex:
-        dexCmd += ' ' + file_utils.getMultiDexPath()
-
-    # sdk实现类
-    print('packageing all jar ...')
-    ret = file_utils.execJarCmd(dx, dexCmd)
-    if ret:
-        return ret
-
-    # 反向dex生成smali
-    # 存放在out目录
-    print('baksmali classes.dex ...')
-    outDex = os.path.join(outPath, 'classes.dex')
-    baksmaliPath = file_utils.getBaksmaliPath()
-    outPath = file_utils.getFullPath(decompliePath, 'out')
-    
-    ret = file_utils.execJarCmd(baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
-    if ret:
-        return ret
-
-    # 将生成的文件拷贝到目标目录
-    print('copy all smali ...')
-    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
-    ret = file_utils.copyFileAllDir(outPath, smaliPath, True)
-    if ret:
-        return ret
-
-    return 0
-
-def splitDex(game, sdk, subChannel, config):
-    '''
-    分割dex
-    '''
-    # 判断是否已经存在application
-    # 存在,则往原application添加内容
-    # 不存在,则拷贝一个默认的android.support.multidex.MultiDexApplication
-    print('add MultiDex support...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    application = xml_utils.getApplicationAttr(manifest, 'name')
-    if application is None:
-        ret = xml_utils.changeApplicationAttr(manifest, 'name', 'android.support.multidex.MultiDexApplication')
-        if ret:
-            return ret
-    else:
-        smaliPath = os.path.join(decompliePath, 'smali')
-        applicationFile = file_utils.getPackagePath(smaliPath, application)
-        applicationFile += '.smali'
-        ret = changeApplicationDex(applicationFile)
-        if ret:
-            return ret
-
-    return splitSmali(game, sdk, subChannel, config, application)
-
-def changeApplicationDex(file):
-    '''
-    修改application的smali文件,增加MultiDex操作
-    '''
-    index = file_utils.getApplicationSmaliIndex(file)
-    file_utils.insertApplicationSmali(file, index)
-    return 0
-
-def splitSmali(game, sdk, subChannel, config, application):
-    '''
-    如果函数上限超过限制,自动拆分smali,以便生成多个dex文件
-    '''
-    print('splitSmali...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    smaliPath = os.path.join(decompliePath, 'smali')
-
-    appPackage = None
-    if application:
-        appPackage = application[:application.rfind('.')]
-        appPackage = appPackage.replace('.', '/')
-
-    allFiles = []
-    allFiles = file_utils.list_files(smaliPath, allFiles)
-    
-    #print('file count is %d' % len(allFiles))
-
-    #maxFuncNum = 65535
-    # 留一点空间,防止计算误差
-    maxFuncNum = 64000
-    currFucNum = 0
-    totalFucNum = 0
-
-    currDexIndex = 1
-
-    allRefs = []
-
-    #保证Application等类在第一个classex.dex文件中
-    for f in allFiles:
-        f = f.replace('\\', '/')
-        if (appPackage and appPackage in f) or '/android/support/multidex' in f:
-            currFucNum += smali_utils.get_smali_method_count(f, allRefs)
-
-    totalFucNum = currFucNum
-    for f in allFiles:
-        f = f.replace('\\', '/')
-        if not f.endswith('.smali'):
-            continue
-
-        if (appPackage and appPackage in f) or '/android/support/multidex' in f:
-            continue
-
-        thisFucNum = smali_utils.get_smali_method_count(f, allRefs)
-        totalFucNum += thisFucNum
-
-        #print('%d # %d ==> %s' % (thisFucNum, currDexIndex, f))
-        #print('totalFucNum is %d' % totalFucNum)
-        if currFucNum + thisFucNum >= maxFuncNum:
-            currFucNum = thisFucNum
-            currDexIndex += 1
-            newDexPath = os.path.join(decompliePath, 'smali_classes%d' % currDexIndex)
-            os.makedirs(newDexPath)
-        else:
-            currFucNum += thisFucNum
-
-        if currDexIndex > 1:
-            newDexPath = os.path.join(decompliePath, 'smali_classes%d' % currDexIndex)
-            targetFile = newDexPath + f[len(smaliPath):]
-            file_utils.copyFile(f, targetFile, True)
-    return 0
-
-def changeVersion(game, sdk, subChannel, config):
-    '''
-    更改版本号
-    '''
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    yml = os.path.join(decompliePath, 'apktool.yml')
-
-    versionCode = None
-    versionName = None
-    targetSdkVersion = None
-    if 'versionCode' in config:
-        versionCode = config['versionCode']
-    if 'versionName' in config:
-        versionName = config['versionName']
-    if 'targetSdkVersion' in config:
-        targetSdkVersion = config['targetSdkVersion']
-
-    return file_utils.changeVersion(yml, versionCode, versionName, targetSdkVersion)
-
-def recomplie(game, sdk, subChannel, config):
-    '''
-    回编译
-    '''
-    print('recomplie apk...')
-    apktoolPath = file_utils.getApkToolPath()
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    outApk = file_utils.getOutApkPath(game, sdk, subChannel, config['cache'])
-
-    useAppt2 = ' --use-aapt2'
-    if config['aapt2disable']:
-        useAppt2 = ''
-
-    return file_utils.execJarCmd(apktoolPath, 'b -f "%s" -o "%s"%s' % (decompliePath, outApk, useAppt2))
-
-def alignApk(game, sdk, subChannel, config):
-    '''
-    对齐apk
-    '''
-    print('align apk...')
-    outApk = file_utils.getOutApkPath(game, sdk, subChannel, config['cache'])
-    alignApk = file_utils.getAlignApkPath(game, sdk, subChannel, config['cache'])
-    alignapkTool = file_utils.getAlignPath()
-    if os.path.exists(alignApk):
-        os.remove(alignApk)
-
-    ret = file_utils.getExecPermission(alignapkTool)
-    if ret:
-        return ret
-
-    # zipalign.exe -v -p 4 input.apk output.apk
-    return file_utils.execFormatCmd('"%s" -f -p 4 "%s" "%s"' % (alignapkTool, outApk, alignApk))
-
-def apksignerApk(game, sdk, subChannel, config):
-    '''
-    签名apk
-    '''
-    print('sign apk...')
-    path = os.path.join(file_utils.getCurrentPath(), 'keystore', 'key.json')
-    jsonText = file_utils.readFile(path)
-    signConfig = json.loads(jsonText)
-    keystore = {}
-    if game in signConfig:
-        if sdk in signConfig[game] and subChannel in signConfig[game][sdk]:
-            keystore = signConfig[game][sdk][subChannel]
-        else:
-            keystore = signConfig['default']
-    else:
-        keystore = signConfig['default']
-
-    print('storeFile is "%s"' % keystore['storeFile'])
-    
-    apksigner = file_utils.getApksignerPath()
-    alignApk = file_utils.getAlignApkPath(game, sdk, subChannel, config['cache'])
-    signedApk = file_utils.getSignApkPath(game, sdk, subChannel, config['cache'])
-    storeFile = os.path.join(file_utils.getCurrentPath(), 'keystore', keystore['storeFile'])
-
-    if 'outName' in config and 'outPath' in config:
-        if not os.path.exists(config['outPath']):
-            os.makedirs(config['outPath'])
-
-        signedApk = os.path.join(config['outPath'], config['outName'] + '.apk')
-        print('signedApk = ' + signedApk)
-    elif 'outName' in config:
-        signedApk = file_utils.getRenameApkPath(game, sdk, config['cache'], config['outName'])
-        print('signedApk = ' + signedApk)
-
-    # java -jar apksigner.jar sign --ks key.jks --ks-key-alias releasekey --ks-pass pass:pp123456 --key-pass pass:pp123456 --out output.apk input.apk
-    v2disable = ''
-    if 'v2disable' in config and config['v2disable']:
-        v2disable = ' --v2-signing-enabled=false'
-        
-    return file_utils.execJarCmd(apksigner, 'sign%s --ks "%s" --ks-key-alias %s --ks-pass pass:%s --key-pass pass:%s --out "%s" "%s"' % (v2disable, storeFile, keystore['keyAlias'], keystore['storePassword'], keystore['keyPassword'], signedApk, alignApk))
-
-def addChannel(game, sdk, subChannel, config):
-    '''
-    添加渠道信息
-    '''
-    if 'v2disable' in config and config['v2disable']:
-        return 0
-    
-    walle = file_utils.getWallePath()
-    signedApk = file_utils.getSignApkPath(game, sdk, subChannel, config['cache'])
-    if 'outName' in config and 'outPath' in config:
-        signedApk = os.path.join(config['outPath'], config['outName'] + '.apk')
-    elif 'outName' in config:
-        signedApk = file_utils.getRenameApkPath(game, sdk, config['cache'], config['outName'])
-
-    properties = config['properties']
-
-    appid = ''
-    appkey = ''
-    if 'appid' in properties:
-        appid = properties['appid']
-    if 'appkey' in properties:
-        appkey = properties['appkey']
-
-    return file_utils.execJarCmd(walle, 'put -e version=%s,agent=%s,appid=%s,appkey=%s "%s" "%s"' % (config_utils_record.getDate(), properties['agent'], appid, appkey, signedApk, signedApk))
-
-def clearTemp(game, sdk, subChannel, config):
-    '''
-    清空中间产生的文件
-    '''
-    print('clear temp...')
-    alignApk = file_utils.getAlignApkPath(game, sdk, subChannel, config['cache'])
-    outApk = file_utils.getOutApkPath(game, sdk, subChannel, config['cache'])
-    if os.path.exists(alignApk):
-        os.remove(alignApk)
-    if os.path.exists(outApk):
-        os.remove(outApk)
-
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    file_utils.deleteFolder(decompliePath)
-
-    print('clear temp end')
-
-def packConsoleInput():
-    '''
-    控制台打包
-    '''
-    if len(sys.argv) < 3:
-        print('argument is missing')
-        return 1
-
-    # 校验参数
-    game = sys.argv[1]
-    sdk = sys.argv[2]
-    # 可选参数,没有则默认打全部渠道
-    subChannel = None
-    if len(sys.argv) > 3:
-        subChannel = sys.argv[3]
-        
-    return packConsole(game, sdk, subChannel)
-
-def packConsole(game, sdk, subChannel):
-    '''
-    控制台打包
-    '''
-    if not os.path.exists(file_utils.getFullGameApk(game)):
-        print('game "%s" not exists' % game)
-        return 1
-    if not os.path.exists(file_utils.getFullSDKPath(sdk)):
-        print('sdk "%s" not exists' % sdk)
-        return 1
-
-    # 读取配置
-    channelPath = file_utils.getChannelPath(game, sdk)
-    configPath = os.path.join(channelPath, 'config.json')
-    if not os.path.exists(configPath):
-        print('%s not exists' % configPath)
-        return 1
-    
-    jsonText = file_utils.readFile(configPath)
-    config = json.loads(jsonText)
-
-    # 检查参数
-    if not config_utils_record.checkConfig(config):
-        return 1
-
-    # 处理参数
-    config_utils_record.replaceArgs(config)
-
-    successCount = 0
-    failureCount = 0
-    if type(config) == dict:
-        if subChannel is None or config['subChannel'] == subChannel:
-            ret = pack(game, sdk, config)
-            if ret:
-                failureCount += 1
-            else:
-                successCount += 1
-        else:
-            print('subChannel "%s" no found' % subChannel)
-            return 1
-    elif type(config) == list:
-        found = False
-        for itemConfig in config:
-            if subChannel is None or itemConfig['subChannel'] == subChannel:
-                found = True
-                ret = pack(game, sdk, itemConfig)
-                if ret:
-                    failureCount += 1
-                else:
-                    successCount += 1
-
-        if not found:
-            print('subChannel "%s" no found' % subChannel)
-            return 1
-
-    print('success %d, failure %d' % (successCount, failureCount))
-        
-    return 0
-
-def copyEntryActivityCode(game, sdk, subChannel, config):
-    '''
-    拷贝代码
-    '''
-    print('copy EntryActivity.smali')
-    sdkPath = file_utils.getFullSDKPath(sdk)
-    EntryActivity = 'EntryActivity.smali'
-    entryFile = os.path.join(sdkPath, 'smali', EntryActivity)
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    smaliPath = os.path.join(decompliePath, 'smali')
-    targetPath = file_utils.getPackagePath(smaliPath, config['packageName'])
-    targetFile = os.path.join(targetPath, EntryActivity)
-    ret = file_utils.copyFile(entryFile, targetFile)
-    if ret:
-        return ret
-    writeActivityToManifest(os.path.join(decompliePath, 'AndroidManifest.xml'),config)
-    oldText = 'com/jmhy/floatsdk/sample/EntryActivity'
-    newText = config['packageName'].replace('.', '/') + "/EntryActivity"
-    print("EntryActivity.smali change '{}' to '{}' ...".format(oldText,newText))
-    file_utils.replaceContent(targetFile, oldText, newText)
-    return 0
-
-def writeActivityToManifest(targetManifest, config):
-    androidNS = 'http://schemas.android.com/apk/res/android'
-    ET.register_namespace('android', androidNS)
-    targetTree = ET.parse(targetManifest)
-    targetRoot = targetTree.getroot()
-    appNode = targetRoot.find('application')
-    activitys = appNode.findall('activity')
-    keyName = "{0}{1}{2}name".format("{",androidNS,"}")
-    theme = "{0}{1}{2}theme".format("{",androidNS,"}")
-    for activity in activitys:
-        activityName = activity.get(keyName)
-        if activityName.find('.EntryActivity')>=0:
-            oldName = activityName;
-            newName = config['packageName'] + ".EntryActivity"
-            activity.set(keyName,newName)
-            print("EntryActivity change '{}' to '{}' ...".format(oldName, newName))
-        if activityName.find('com.tool.floatsdk.ui.WebActivity')>=0:
-            if activity.get(theme) is not None or activity.get(theme) != "":
-                del activity.attrib[theme]
-
-    perNode = targetRoot.find('permissions')
-    #permissions = perNode.findall('uses-permission')
-    print(perNode)
-    print("------------")
-
-    targetTree.write(targetManifest, 'UTF-8')
-
-
-
-
+# 安卓游戏打包脚本
+# 1.用apktool解包
+# 2.复制res资源、assets资源、jniLib资源
+# 3.修改包名、app名、渠道文件
+# 4.添加app icon、合并AndroidManifest文件
+# 5.添加app启动图,修改AndroidManifest文件
+# 6.生成新的R文件
+# 7.将新的R文件编译,生成dex,再用baksmali生成smali,替换旧的R文件
+# 8.将jar资源打包成dex,再用baksmali生成smali,拷贝到smali目录下
+# 9.统计方法量,并分割dex(将smali文件拷贝到目录smali_classes2)
+# 10.用apktool回包
+# 11.重新签名
+import file_utils
+import xml_utils
+import smali_utils
+import config_utils_record
+import game_utils
+import os
+import os.path
+import json
+import sys
+import importlib
+import uuid
+import zipfile
+
+from xml.etree import ElementTree as ET
+from xml.etree.ElementTree import SubElement
+
+def pack(game, sdk, config):
+    config['cache'] = uuid.uuid1()
+    subChannel = config['subChannel']
+    # 解包
+    ret = decomplie(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 删除旧代码
+    ret = removeOldCode(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    if 'deleteList' in config:
+        # 删除旧资源
+        ret = removeOldRes(game, sdk, subChannel, config)
+        if ret:
+            return ret
+    # 删除一些不支持的属性
+    ret = removeNoSupportAttr(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 删除一些不支持的配置
+    ret = fixUnSupportConfig(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 合并Drawable-v4目录
+    ret = mergeDrawableRes(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 移除相同的资源
+    ret = removeSameRes(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 复制res资源
+    ret = copyRes(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 合并主文件
+    ret = mergeManifestRes(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 替换占位符
+    ret = changePlaceholders(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 添加meta-data
+    ret = addMetaData(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 复制app res资源
+    ret = copyAppRes(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 合并语言文件
+    ret = mergeLanguage(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 增加配置文件
+    ret = addConfig(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    #保存旧包名
+    config['oldPackageName'] = getPackageName(game, sdk, subChannel, config)
+    # 更改包名
+    if 'packageName' in config and config['packageName'] != '':
+        ret = changePackageName(game, sdk, subChannel, config)
+        if ret:
+            return ret
+    else:
+        config['packageName'] = getPackageName(game, sdk, subChannel, config)
+    # 更改app名
+    if 'name' in config and config['name'] != '':
+        ret = changeAppName(game, sdk, subChannel, config)
+        if ret:
+            return ret
+    # 更改app icon
+    if config['changeIcon']:
+        ret = changeAppIcon(game, sdk, subChannel, config)
+        if ret:
+            return ret
+    # 添加启动图操作
+    if config['addLauncher']:
+        ret = addLauncher(game, sdk, subChannel, config)
+        if ret:
+            return ret
+    # 打包lib依赖
+    ret = packJar(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # sdk脚本处理
+    ret = doSDKPostScript(game, sdk, config)
+    if ret:
+        return ret
+    # 乐变sdk的特殊处理
+    ret = game_utils.sdkLebianChange(game, sdk, config)
+    if ret:
+        return ret
+    # 复制EntryActivity文件
+    ret = copyEntryActivityCode(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 游戏脚本处理
+    ret = doGamePostScript(game, sdk, config)
+    if ret:
+        return ret
+    # 生成R文件
+    '''ret = generateNewRFile(game, sdk, subChannel, config)
+    if ret:
+        return ret'''
+    # 添加MultiDex支持
+    if config['splitDex']:
+        ret = splitDex(game, sdk, subChannel, config)
+        if ret:
+            return ret
+    # 更改版本号
+    ret = changeVersion(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 回编译
+    ret = recomplie(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 对齐apk
+    ret = alignApk(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 签名
+    ret = apksignerApk(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 清理产生的中间文件
+    if config['clearCache']:
+        clearTemp(game, sdk, subChannel, config)
+
+    return 0
+
+def decomplie(game, sdk, subChannel, config):
+    '''
+    解包
+    '''
+    apktoolPath = file_utils.getApkToolPath()
+    gamePath = file_utils.getFullGameApk(config,game)
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+
+    if os.path.exists(decompliePath):
+        print('delete decomplie folder...')
+        file_utils.deleteFolder(decompliePath)
+
+    print('decomplie apk...')
+
+    return file_utils.execJarCmd(apktoolPath, 'd -f "%s" -o "%s"' % (gamePath, decompliePath))
+
+def removeOldRes(game, sdk, subChannel, config):
+    '''
+    删除旧资源
+    '''
+    print('delete res ...')
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    for subPath in config['deleteList']:
+        resPath = os.path.join(decompliePath, subPath)
+        if os.path.exists(resPath):
+            os.remove(resPath)
+            print('delete ' + resPath)
+    return 0
+
+def removeOldCode(game, sdk, subChannel, config):
+    '''
+    删除旧代码
+    '''
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    codePath = os.path.join(decompliePath, 'smali', 'com', 'jmhy', 'lib', 'record')
+    #file_utils.deleteFolder(codePath)
+    allFiles = []
+    allFiles = file_utils.list_files(codePath, allFiles)
+    for f in allFiles:
+        fpath, fname = os.path.split(f)  #分离文件名和路径
+        if fname == 'R.smali' or fname.startswith('R$'):
+            continue
+        os.remove(f)
+        print('remove %s' % f)
+    return 0
+
+def copyRes(game, sdk, subChannel, config):
+    '''
+    复制res资源
+    '''
+    # 拷贝sdk资源
+    print('copy res...')
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    sdkPath = file_utils.getFullSDKPath(sdk)
+    resPath = os.path.join(sdkPath, 'res')
+    decomplieResPath = file_utils.getFullPath(decompliePath, 'res')
+
+    for d in os.listdir(resPath):
+        copyResWithType(resPath, decomplieResPath, d)
+
+    # 拷贝assets
+    print('copy assets...')
+    assetsPath = file_utils.getFullPath(sdkPath, 'assets')
+    decomplieAssetsPath = file_utils.getFullPath(decompliePath, 'assets')
+    if os.path.exists(assetsPath):
+        ret = file_utils.copyFileAllDir(assetsPath, decomplieAssetsPath)
+        if ret:
+            return ret
+
+    # 拷贝jniLib
+    print('copy jniLibs...')
+    jniPath = file_utils.getFullPath(sdkPath, 'jniLibs')
+    decomplieJniPath = file_utils.getFullPath(decompliePath, 'lib')
+    abiFilters = []
+    if os.path.exists(decomplieJniPath):
+        for abi in os.listdir(decomplieJniPath):
+            if abi == 'armeabi-v7a' or abi == 'armeabi':
+                abiFilters.append(abi)
+    else:
+        abiFilters = ['armeabi-v7a']
+
+    if os.path.exists(jniPath):
+        ret = file_utils.copyFileAllDir(jniPath, decomplieJniPath, False, abiFilters)
+        if ret:
+            return ret
+
+    return 0
+
+def mergeDrawableRes(game, sdk, subChannel, config):
+    '''
+    合并Drawable-v4目录
+    '''
+    print('merge drawable path...')
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    resPath = os.path.join(decompliePath, 'res')
+
+    for path in os.listdir(resPath):
+        print('res path %s' % path)
+        if (path.startswith('drawable') or path.startswith('mipmap')) and path.endswith('-v4'):
+            print('merge path %s' % path)
+            v4DrawablePath = os.path.join(resPath, path)
+            drawablePath = os.path.join(resPath, path[:-3])
+
+            if os.path.exists(drawablePath):
+                ret = file_utils.copyFileAllDir(v4DrawablePath, drawablePath, True)
+                if ret:
+                    return ret
+            else:
+                os.rename(v4DrawablePath, drawablePath)
+    return 0
+
+def removeSameRes(game, sdk, subChannel, config):
+    '''
+    移除相同的资源
+    '''
+    # 读取sdk的资源
+    print('remove same res...')
+    sdkPath = file_utils.getFullSDKPath(sdk)
+    sdkResPath = os.path.join(sdkPath, 'res')
+    resList = []
+    for path in os.listdir(sdkResPath):
+        if not path.startswith('values'):
+            continue
+
+        absPath = os.path.join(sdkResPath, path)
+        for resFile in os.listdir(absPath):
+            '''if not resFile.startswith('jm_'):
+                continue'''
+
+            resList = xml_utils.readAllRes(os.path.join(absPath, resFile), resList)
+
+    if len(resList) == 0:
+        print('no same res found')
+        return 0
+
+    removeList = []
+    # 移除相同的资源
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    resPath = os.path.join(decompliePath, 'res')
+    for path in os.listdir(resPath):
+        if not path.startswith('values'):
+            continue
+
+        absPath = os.path.join(resPath, path)
+        for resFile in os.listdir(absPath):
+            print('resFile ==> ' + os.path.join(absPath, resFile))
+            #xml_utils.removeSameRes(os.path.join(absPath, resFile), resList)
+            removeList = xml_utils.removeSameRes2(os.path.join(absPath, resFile), resList, removeList)
+
+    print('--------------')
+    print(removeList)
+    if len(removeList) == 0:
+        print('no same res remove')
+        return 0
+    publicResPath = os.path.join(decompliePath, 'res/values/public.xml')
+    print('publicResPath ---->' + publicResPath)
+    xml_utils.removeIdFromPublic(publicResPath,removeList)
+
+
+    return 0
+
+def mergeManifestRes(game, sdk, subChannel, config):
+    '''
+    合并主文件
+    '''
+    print('merge AndroidManifest...')
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    sdkPath = file_utils.getFullSDKPath(sdk)
+    libManifest = file_utils.getFullPath(sdkPath, 'manifest.xml')
+    return xml_utils.mergeManifestRes(manifest, libManifest)
+
+def copyAppRes(game, sdk, subChannel, config):
+    '''
+    拷贝app的资源,比如app icon、启动图等
+    '''
+    channelPath = file_utils.getSubChannelPath(game, sdk, subChannel)
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+
+    # assets
+    print('copy assets...')
+    assetsPath = file_utils.getFullPath(channelPath, 'assets')
+    decomplieAssetsPath = file_utils.getFullPath(decompliePath, 'assets')
+    if os.path.exists(assetsPath):
+        ret = file_utils.copyFileAllDir(assetsPath, decomplieAssetsPath)
+        if ret:
+            return ret
+
+    # icon
+    print('copy icon...')
+    ret = copyAppResWithType(decompliePath, channelPath, 'icon')
+    if ret:
+        return ret
+    # 启动图
+    print('copy splash...')
+    ret = copyAppResWithType(decompliePath, channelPath, 'splash')
+    if ret:
+        return ret
+    # 其他图片
+    print('copy image...')
+    ret = copyAppResWithType(decompliePath, channelPath, 'image')
+    if ret:
+        return ret
+    return 0
+
+def mergeLanguage(game, sdk, subChannel, config):
+    '''
+    合并语言文件
+    '''
+    print('merge language...')
+    channelPath = file_utils.getSubChannelPath(game, sdk, subChannel)
+    mergePath = file_utils.getFullPath(channelPath, 'merge')
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+
+    if not os.path.exists(mergePath):
+        print('%s not exists!' % mergePath)
+        return 0
+
+    if not os.path.isdir(mergePath):
+        print('%s not a dir!' % mergePath)
+        return 0
+
+    for fileName in os.listdir(mergePath):
+        mergeJson(mergePath, decompliePath, fileName)
+    return 0
+
+def mergeJson(srcDir, changeDir, fileName):
+    srcFile = os.path.join(srcDir, fileName)
+    if os.path.isdir(srcFile):
+        for fileName2 in os.listdir(srcFile):
+            changeDir2 = os.path.join(changeDir, fileName)
+            mergeJson(srcFile, changeDir2, fileName2)
+    else:
+        changeFile = os.path.join(changeDir, fileName)
+        if not os.path.exists(changeFile):
+            print('%s not exists!' % changeFile)
+            return 0
+        jsonText1 = file_utils.readFile(srcFile)
+        jsonText2 = file_utils.readFile(changeFile)
+        print('*************src config*************')
+        print(jsonText1)
+        print('************************************')
+        print('*************target config*************')
+        print(jsonText2)
+        print('************************************')
+
+        json1 = json.loads(jsonText1)
+        json2 = json.loads(jsonText2)
+
+        for item in json1:
+            if item in json2:
+                json2[item] = json1[item]
+
+        jsonStr = json.dumps(json2, ensure_ascii=False)
+        print('*************merge config*************')
+        print(jsonStr)
+        print('************************************')
+        print('>> %s' % changeFile)
+        file_utils.createFile(changeFile, jsonStr)
+    return 0
+    
+def copyAppResWithType(decompliePath, channelPath, typeName):
+    decomplieResPath = os.path.join(decompliePath, 'res')
+    iconPath = os.path.join(channelPath, typeName)
+    if not os.path.exists(iconPath):
+        print('dir "%s" not exists' % iconPath)
+        return 0
+    for d in os.listdir(iconPath):
+        ret = copyResWithType(iconPath, decomplieResPath, d)
+        if ret:
+            return ret
+
+    return 0
+
+def copyResWithType(resPath, decomplieResPath, typeName):
+    # appt的打包目录会带-v4后缀
+    resDir = os.path.join(resPath, typeName)
+    target = os.path.join(decomplieResPath, typeName)
+    targetV4 = os.path.join(decomplieResPath, typeName + '-v4')
+    if not os.path.exists(target) and not os.path.exists(targetV4):
+        os.makedirs(target)
+        return file_utils.copyFileAllDir(resDir, target, False)
+    elif not os.path.exists(target):
+        return file_utils.copyFileAllDir(resDir, targetV4, False)
+    else:
+        return file_utils.copyFileAllDir(resDir, target, False)
+
+def removeNoSupportAttr(game, sdk, subChannel, config):
+    '''
+    删除一些不支持的属性
+    '''
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    
+    xml_utils.removeRootAttr(manifest, 'compileSdkVersion')
+    xml_utils.removeRootAttr(manifest, 'compileSdkVersionCodename')
+    
+    return 0
+
+def fixUnSupportConfig(game, sdk, subChannel, config):
+    '''
+    删除一些不支持的配置
+    '''
+    # 检查minSdkVersion
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    yml = os.path.join(decompliePath, 'apktool.yml')
+
+    minSdkVersion = 15
+    file_utils.changeMinSdkVersion(yml, minSdkVersion)
+
+    resPath = os.path.join(decompliePath, 'res')
+
+    tag = '-v'
+    for res in os.listdir(resPath):
+        print('res = ' + res)
+        if res.startswith('values') and tag in res:
+            start = res.index(tag)
+            version = res[start+len(tag):]
+            if not version.isdigit():
+                continue
+            
+            version = int(version)
+            print('version = %d' % version)
+            if version < minSdkVersion:
+                unSopportPath = os.path.join(resPath, res)
+                print('unSopportPath = ' + unSopportPath)
+                file_utils.deleteFolder(unSopportPath)
+                print('deleteFolder = ' + unSopportPath)
+    
+    return 0
+
+def changePackageName(game, sdk, subChannel, config):
+    '''
+    更改包名
+    '''
+    # 全局替换AndroidManifest里面的包名
+    newPackageName = config['packageName']
+
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    packageName = xml_utils.getPackageName(manifest)
+    
+    xml_utils.changePackageName(manifest, newPackageName)
+    print('change package name %s --> %s' % (packageName, newPackageName))
+    return 0
+
+def getPackageName(game, sdk, subChannel, config):
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    packageName = xml_utils.getPackageName(manifest)
+    return packageName
+
+def changeAppName(game, sdk, subChannel, config):
+    '''
+    更改app名
+    '''
+    # 生成string.xml文件
+    name = config['name']
+
+    resName = 'shanshen_sdk_name'
+    if 'outName' in config:
+        resName = resName + '_' + config['outName']
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    stringFile = os.path.join(decompliePath, 'res', 'values', 'sdk_strings_temp.xml')
+    content = '<?xml version="1.0" encoding="utf-8"?><resources><string name="%s">%s</string></resources>' % (resName, name)
+    file_utils.createFile(stringFile, content)
+
+    # 修改主文件的app名的值
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    xml_utils.changeAppName(manifest, '@string/%s' % resName)
+    print('change app name %s' % name)
+    return 0
+
+def changeAppIcon(game, sdk, subChannel, config):
+    '''
+    更改app icon
+    '''
+    print('change app icon...')
+    resName = 'record_sdk_icon'
+
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    xml_utils.changeAppIcon(manifest, '@mipmap/%s' % resName)
+    return 0
+
+def addMetaData(game, sdk, subChannel, config):
+    '''
+    添加meta-data
+    '''
+    if 'metaData' not in config:
+        return 0
+
+    print('add meta-data...')
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    xml_utils.addMetaData(manifest, config['metaData'])
+    return 0
+
+def addConfig(game, sdk, subChannel, config):
+    '''
+    添加config.json
+    '''
+    if 'configData' not in config:
+        print('configData is null')
+        return 0
+
+    print('add config.json...')
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    configJson = os.path.join(decompliePath, 'assets', 'tool_config.json')
+    jsonText = json.dumps(config['configData'], ensure_ascii=False)
+    file_utils.createFile(configJson, jsonText)
+    return 0
+
+def changePlaceholders(game, sdk, subChannel, config):
+    '''
+    处理掉占位符
+    '''
+    if 'placeholders' not in config:
+        return 0
+
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+
+    placeholders = config['placeholders']
+    for placeholder in placeholders:
+        oldText = '${%s}' % placeholder
+        newText = placeholders[placeholder]
+        print('change placeholder %s -> %s' % (oldText, newText))
+        file_utils.replaceContent(manifest, oldText, newText)
+
+    return 0
+
+def addLauncher(game, sdk, subChannel, config):
+    '''
+    添加启动图
+    '''
+    channelPath = file_utils.getSubChannelPath(game, sdk, subChannel)
+    splashPath = os.path.join(channelPath, 'splash')
+    if len(os.listdir(splashPath)) == 0:
+        print('dir splash is empty')
+        return 0
+
+    print('add launcher...')
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    activity = xml_utils.getLauncherActivityName(manifest)
+    if activity == 'com.shanshen.sdk.template.LauncherActivity':
+        print('add launcher already exist...')
+        return 1
+
+    # 添加关联资源
+    internalPath = os.path.join(file_utils.getCurrentPath(), 'internal_shanshen')
+    ret = copyAppResWithType(decompliePath, internalPath, 'launcher_res')
+    if ret:
+        return ret
+
+    # 拷贝代码
+    print('copy launcher code...')
+    codePath = os.path.join(internalPath, 'launcher_code', 'smali')
+    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
+    ret = file_utils.copyFileAllDir(codePath, smaliPath)
+    if ret:
+        return ret
+
+    # 修改主文件信息
+    print('change launcher config...')
+    orientation = xml_utils.getScreenOrientation(manifest)
+    activity = xml_utils.removeLauncherActivity(manifest)
+    xml_utils.addLauncherActivity(manifest, orientation, 'com.shanshen.sdk.template.LauncherActivity')
+
+    # 修改跳转的
+    launcherActivity = os.path.join(decompliePath, 'smali', 'com', 'shanshen', 'sdk', 'template', 'LauncherActivity.smali')
+    file_utils.replaceContent(launcherActivity, '{class}', activity)
+
+    print('change launcher %s to %s' % (activity, 'com.shanshen.sdk.template.LauncherActivity'))
+
+    # config['oldLauncher'] = activity
+
+    if 'launcherTime' in config:
+        timeHex = formatHex(config['launcherTime'])
+        file_utils.replaceContent(launcherActivity, '0x0BB8', timeHex)
+
+    return 0
+
+def addMoreIcon(game, sdk, subChannel, config):
+    '''
+    添加多个图标
+    '''
+    print('add more icon support...')
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    icon = '@mipmap/common_sdk_icon'
+    if not config['changeIcon']:
+        manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+        icon = xml_utils.getApplicationAttr(manifest, 'icon')
+
+    switchIcon = icon
+    if config['switchIcon']:
+        switchIcon = '@mipmap/common_sdk_icon2'
+
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    return xml_utils.addMoreIcon(manifest, icon, switchIcon)
+
+def formatHex(millisecond):
+    '''
+    将毫秒转为16进制,4位格式
+    '''
+    timeHex = str(hex(millisecond)).upper()
+    timeHex = timeHex[2:]
+    formatHex = ''
+    if len(timeHex) == 3:
+        formatHex = '0x0' + timeHex
+    elif len(timeHex) == 4:
+        formatHex = '0x' + timeHex
+    else:
+        formatHex = '0x0BB8'
+    return formatHex
+
+def doSDKPostScript(game, sdk, config):
+    '''
+    执行sdk相关特殊处理脚本
+    '''
+    sdkPath = file_utils.getFullSDKPath(sdk)
+    scriptPath = os.path.join(sdkPath, 'script')
+    targetScript = os.path.join(scriptPath, 'sdk_script.py')
+    if not os.path.exists(targetScript):
+        print('sdk_script no exists')
+        return 0
+
+    print('doSDKPostScript...')
+    sys.path.append(scriptPath)
+
+    module = importlib.import_module('sdk_script')
+    ret = module.execute(game, sdk, config)
+
+    sys.path.remove(scriptPath)
+
+    return ret
+
+def doGamePostScript(game, sdk, config):
+    '''
+    执行游戏相关特殊处理脚本
+    '''
+    channelPath = file_utils.getFullGamePath(game)
+    scriptPath = os.path.join(channelPath, 'script')
+    targetScript = os.path.join(scriptPath, 'game_script.py')
+    if not os.path.exists(targetScript):
+        print('game_script no exists')
+        return 0
+
+    print('doGamePostScript...')
+    sys.path.append(scriptPath)
+
+    module = importlib.import_module('game_script')
+    ret = module.execute(game, sdk, config)
+
+    sys.path.remove(scriptPath)
+
+    return ret
+
+def generateNewRFile(game, sdk, subChannel, config):
+    '''
+    生成新的R文件
+    '''
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    androidPlatforms = file_utils.getAndroidCompileToolPath()
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    decomplieResPath = file_utils.getFullPath(decompliePath, 'res')
+    compliePath = file_utils.getFullPath(decompliePath, 'gen')
+
+    if not os.path.exists(compliePath):
+        os.makedirs(compliePath)
+
+    # 生成R文件
+    print('create R.java ...')
+    if config['aapt2disable']:
+        aapt = file_utils.getAAPTPath()
+        ret = file_utils.getExecPermission(aapt)
+        if ret:
+            return ret
+        createRCmd = '"%s" p -f -m -J "%s" -S "%s" -I "%s" -M "%s"' % (aapt, compliePath, decomplieResPath, androidPlatforms, manifest)
+        ret = file_utils.execFormatCmd(createRCmd)
+        if ret:
+            return ret
+    else:
+        # compile
+        aapt = file_utils.getAAPT2Path()
+        ret = file_utils.getExecPermission(aapt)
+        if ret:
+            return ret
+
+        print('compiled res ...')
+        complieResPath = os.path.join(compliePath, 'compiled')
+        complieResCmd = '"%s" compile --dir "%s" -o "%s"' % (aapt, decomplieResPath, complieResPath)
+        file_utils.execFormatCmd(complieResCmd)
+
+        # unzip
+        print('unzip compiled res ...')
+        unzipResPath = os.path.join(compliePath, 'aapt2_res')
+        with zipfile.ZipFile(complieResPath) as zf:
+            zf.extractall(unzipResPath)
+            print('create unzip %s' % unzipResPath)
+
+        # link
+        print('link res ...')
+        outApk = os.path.join(compliePath, 'res.apk')
+        linkResCmd = '"%s" link -o "%s" -I "%s" --manifest "%s" --java "%s" --auto-add-overlay' % (aapt, outApk, androidPlatforms, manifest, compliePath)
+        for filename in os.listdir(unzipResPath):
+            linkResCmd += ' %s' % filename
+        print('link cmd len is %s' % len(linkResCmd))
+        ret = file_utils.execFormatCmd(linkResCmd, unzipResPath)
+        if ret:
+            return ret
+
+    # 编译R文件
+    print('complie R.java ...')
+    packageName = xml_utils.getPackageName(manifest)
+    packagePath = file_utils.getPackagePath(compliePath, packageName)
+    RSourceFile = os.path.join(packagePath, 'R.java')
+    complieRCmd = 'javac -source 1.8 -target 1.8 -encoding UTF-8 "%s"' % RSourceFile
+    ret = file_utils.execFormatCmd(complieRCmd)
+    if ret:
+        return ret
+
+    # 生成dex
+    print('dex R.class ...')
+    dx = file_utils.getDxPath()
+    outDex = os.path.join(compliePath, 'classes.dex')
+    ret = file_utils.execJarCmd(dx, '--dex --output="%s" "%s"' % (outDex, compliePath))
+    if ret:
+        return ret
+
+    # 反向dex生成smali
+    # 存放在out目录
+    print('baksmali classes.dex ...')
+    baksmaliPath = file_utils.getBaksmaliPath()
+    outPath = file_utils.getFullPath(decompliePath, 'out')
+    ret = file_utils.execJarCmd(baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
+    if ret:
+        return ret
+
+    # 将生成的文件拷贝到目标目录
+    print('copy R.smali ...')
+    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
+    file_utils.copyFileAllDir(outPath, smaliPath)
+    return 0
+
+def packJar(game, sdk, subChannel, config):
+    '''
+    打包所有的jar
+    '''
+    splitDex = config['splitDex']
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    outPath = file_utils.getFullPath(decompliePath, 'gen')
+
+    if not os.path.exists(outPath):
+        os.makedirs(outPath)
+
+    if config['aapt2disable']:
+        dx = file_utils.getDxPath()
+        dexCmd = '--dex --multi-dex --no-warning --output="%s"' % outPath
+    else:
+        dx = file_utils.getD8Path()
+        androidPlatforms = file_utils.getAndroidCompileToolPath()
+        dexCmd = '--lib "%s" --output "%s"' % (androidPlatforms, outPath)
+
+    # 找到所有lib依赖
+    sdkPath = file_utils.getFullSDKPath(sdk)
+    libs = os.path.join(sdkPath, 'libs')
+    libConfig = os.path.join(libs, 'config.json')
+
+    # 存在配置文件
+    if os.path.exists(libConfig):
+        jsonText = file_utils.readFile(libConfig)
+        libConf = json.loads(jsonText)
+        if 'libConfig' in config and config['libConfig'] in libConf:
+            conf = config['libConfig']
+            libList = libConf[conf]
+            for jar in libList:
+                dexCmd += ' ' + os.path.join(libs, jar)
+        elif 'default' in libConf:
+            libList = libConf['default']
+            for jar in libList:
+                dexCmd += ' ' + os.path.join(libs, jar)
+        else:
+            for jar in os.listdir(libs):
+                if not jar.endswith('.jar'):
+                    continue
+                dexCmd += ' ' + os.path.join(libs, jar)
+    else:
+        for jar in os.listdir(libs):
+            if not jar.endswith('.jar'):
+                continue
+            dexCmd += ' ' + os.path.join(libs, jar)
+
+    # multidex.jar
+    if splitDex:
+        dexCmd += ' ' + file_utils.getMultiDexPath()
+
+    # sdk实现类
+    print('packageing all jar ...')
+    ret = file_utils.execJarCmd(dx, dexCmd)
+    if ret:
+        return ret
+
+    # 反向dex生成smali
+    # 存放在out目录
+    print('baksmali classes.dex ...')
+    outDex = os.path.join(outPath, 'classes.dex')
+    baksmaliPath = file_utils.getBaksmaliPath()
+    outPath = file_utils.getFullPath(decompliePath, 'out')
+    
+    ret = file_utils.execJarCmd(baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
+    if ret:
+        return ret
+
+    # 将生成的文件拷贝到目标目录
+    print('copy all smali ...')
+    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
+    ret = file_utils.copyFileAllDir(outPath, smaliPath, True)
+    if ret:
+        return ret
+
+    return 0
+
+def splitDex(game, sdk, subChannel, config):
+    '''
+    分割dex
+    '''
+    # 判断是否已经存在application
+    # 存在,则往原application添加内容
+    # 不存在,则拷贝一个默认的android.support.multidex.MultiDexApplication
+    print('add MultiDex support...')
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    application = xml_utils.getApplicationAttr(manifest, 'name')
+    if application is None:
+        ret = xml_utils.changeApplicationAttr(manifest, 'name', 'android.support.multidex.MultiDexApplication')
+        if ret:
+            return ret
+    else:
+        smaliPath = os.path.join(decompliePath, 'smali')
+        applicationFile = file_utils.getPackagePath(smaliPath, application)
+        applicationFile += '.smali'
+        ret = changeApplicationDex(applicationFile)
+        if ret:
+            return ret
+
+    return splitSmali(game, sdk, subChannel, config, application)
+
+def changeApplicationDex(file):
+    '''
+    修改application的smali文件,增加MultiDex操作
+    '''
+    index = file_utils.getApplicationSmaliIndex(file)
+    file_utils.insertApplicationSmali(file, index)
+    return 0
+
+def splitSmali(game, sdk, subChannel, config, application):
+    '''
+    如果函数上限超过限制,自动拆分smali,以便生成多个dex文件
+    '''
+    print('splitSmali...')
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    smaliPath = os.path.join(decompliePath, 'smali')
+
+    appPackage = None
+    if application:
+        appPackage = application[:application.rfind('.')]
+        appPackage = appPackage.replace('.', '/')
+
+    allFiles = []
+    allFiles = file_utils.list_files(smaliPath, allFiles)
+    
+    #print('file count is %d' % len(allFiles))
+
+    #maxFuncNum = 65535
+    # 留一点空间,防止计算误差
+    maxFuncNum = 64000
+    currFucNum = 0
+    totalFucNum = 0
+
+    currDexIndex = 1
+
+    allRefs = []
+
+    #保证Application等类在第一个classex.dex文件中
+    for f in allFiles:
+        f = f.replace('\\', '/')
+        if (appPackage and appPackage in f) or '/android/support/multidex' in f:
+            currFucNum += smali_utils.get_smali_method_count(f, allRefs)
+
+    totalFucNum = currFucNum
+    for f in allFiles:
+        f = f.replace('\\', '/')
+        if not f.endswith('.smali'):
+            continue
+
+        if (appPackage and appPackage in f) or '/android/support/multidex' in f:
+            continue
+
+        thisFucNum = smali_utils.get_smali_method_count(f, allRefs)
+        totalFucNum += thisFucNum
+
+        #print('%d # %d ==> %s' % (thisFucNum, currDexIndex, f))
+        #print('totalFucNum is %d' % totalFucNum)
+        if currFucNum + thisFucNum >= maxFuncNum:
+            currFucNum = thisFucNum
+            currDexIndex += 1
+            newDexPath = os.path.join(decompliePath, 'smali_classes%d' % currDexIndex)
+            os.makedirs(newDexPath)
+        else:
+            currFucNum += thisFucNum
+
+        if currDexIndex > 1:
+            newDexPath = os.path.join(decompliePath, 'smali_classes%d' % currDexIndex)
+            targetFile = newDexPath + f[len(smaliPath):]
+            file_utils.copyFile(f, targetFile, True)
+    return 0
+
+def changeVersion(game, sdk, subChannel, config):
+    '''
+    更改版本号
+    '''
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    yml = os.path.join(decompliePath, 'apktool.yml')
+
+    versionCode = None
+    versionName = None
+    targetSdkVersion = None
+    if 'versionCode' in config:
+        versionCode = config['versionCode']
+    if 'versionName' in config:
+        versionName = config['versionName']
+    if 'targetSdkVersion' in config:
+        targetSdkVersion = config['targetSdkVersion']
+
+    return file_utils.changeVersion(yml, versionCode, versionName, targetSdkVersion)
+
+def recomplie(game, sdk, subChannel, config):
+    '''
+    回编译
+    '''
+    print('recomplie apk...')
+    apktoolPath = file_utils.getApkToolPath()
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    outApk = file_utils.getOutApkPath(game, sdk, subChannel, config['cache'])
+
+    useAppt2 = ' --use-aapt2'
+    if config['aapt2disable']:
+        useAppt2 = ''
+
+    return file_utils.execJarCmd(apktoolPath, 'b -f "%s" -o "%s"%s' % (decompliePath, outApk, useAppt2))
+
+def alignApk(game, sdk, subChannel, config):
+    '''
+    对齐apk
+    '''
+    print('align apk...')
+    outApk = file_utils.getOutApkPath(game, sdk, subChannel, config['cache'])
+    alignApk = file_utils.getAlignApkPath(game, sdk, subChannel, config['cache'])
+    alignapkTool = file_utils.getAlignPath()
+    if os.path.exists(alignApk):
+        os.remove(alignApk)
+
+    ret = file_utils.getExecPermission(alignapkTool)
+    if ret:
+        return ret
+
+    # zipalign.exe -v -p 4 input.apk output.apk
+    return file_utils.execFormatCmd('"%s" -f -p 4 "%s" "%s"' % (alignapkTool, outApk, alignApk))
+
+def apksignerApk(game, sdk, subChannel, config):
+    '''
+    签名apk
+    '''
+    print('sign apk...')
+    path = os.path.join(file_utils.getCurrentPath(), 'keystore', 'key.json')
+    jsonText = file_utils.readFile(path)
+    signConfig = json.loads(jsonText)
+    keystore = {}
+    if game in signConfig:
+        if sdk in signConfig[game] and subChannel in signConfig[game][sdk]:
+            keystore = signConfig[game][sdk][subChannel]
+        else:
+            keystore = signConfig['default']
+    else:
+        keystore = signConfig['default']
+
+    print('storeFile is "%s"' % keystore['storeFile'])
+    
+    apksigner = file_utils.getApksignerPath()
+    alignApk = file_utils.getAlignApkPath(game, sdk, subChannel, config['cache'])
+    signedApk = file_utils.getSignApkPath(game, sdk, subChannel, config['cache'])
+    storeFile = os.path.join(file_utils.getCurrentPath(), 'keystore', keystore['storeFile'])
+
+    if 'outName' in config and 'outPath' in config:
+        if not os.path.exists(config['outPath']):
+            os.makedirs(config['outPath'])
+
+        signedApk = os.path.join(config['outPath'], config['outName'] + '.apk')
+        print('signedApk = ' + signedApk)
+    elif 'outName' in config:
+        signedApk = file_utils.getRenameApkPath(game, sdk, config['cache'], config['outName'])
+        print('signedApk = ' + signedApk)
+
+    # java -jar apksigner.jar sign --ks key.jks --ks-key-alias releasekey --ks-pass pass:pp123456 --key-pass pass:pp123456 --out output.apk input.apk
+    v2disable = ''
+    if 'v2disable' in config and config['v2disable']:
+        v2disable = ' --v2-signing-enabled=false'
+        
+    return file_utils.execJarCmd(apksigner, 'sign%s --ks "%s" --ks-key-alias %s --ks-pass pass:%s --key-pass pass:%s --out "%s" "%s"' % (v2disable, storeFile, keystore['keyAlias'], keystore['storePassword'], keystore['keyPassword'], signedApk, alignApk))
+
+def addChannel(game, sdk, subChannel, config):
+    '''
+    添加渠道信息
+    '''
+    if 'v2disable' in config and config['v2disable']:
+        return 0
+    
+    walle = file_utils.getWallePath()
+    signedApk = file_utils.getSignApkPath(game, sdk, subChannel, config['cache'])
+    if 'outName' in config and 'outPath' in config:
+        signedApk = os.path.join(config['outPath'], config['outName'] + '.apk')
+    elif 'outName' in config:
+        signedApk = file_utils.getRenameApkPath(game, sdk, config['cache'], config['outName'])
+
+    properties = config['properties']
+
+    appid = ''
+    appkey = ''
+    if 'appid' in properties:
+        appid = properties['appid']
+    if 'appkey' in properties:
+        appkey = properties['appkey']
+
+    return file_utils.execJarCmd(walle, 'put -e version=%s,agent=%s,appid=%s,appkey=%s "%s" "%s"' % (config_utils_record.getDate(), properties['agent'], appid, appkey, signedApk, signedApk))
+
+def clearTemp(game, sdk, subChannel, config):
+    '''
+    清空中间产生的文件
+    '''
+    print('clear temp...')
+    alignApk = file_utils.getAlignApkPath(game, sdk, subChannel, config['cache'])
+    outApk = file_utils.getOutApkPath(game, sdk, subChannel, config['cache'])
+    if os.path.exists(alignApk):
+        os.remove(alignApk)
+    if os.path.exists(outApk):
+        os.remove(outApk)
+
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    file_utils.deleteFolder(decompliePath)
+
+    print('clear temp end')
+
+def packConsoleInput():
+    '''
+    控制台打包
+    '''
+    if len(sys.argv) < 3:
+        print('argument is missing')
+        return 1
+
+    # 校验参数
+    game = sys.argv[1]
+    sdk = sys.argv[2]
+    # 可选参数,没有则默认打全部渠道
+    subChannel = None
+    if len(sys.argv) > 3:
+        subChannel = sys.argv[3]
+        
+    return packConsole(game, sdk, subChannel)
+
+def packConsole(game, sdk, subChannel):
+    '''
+    控制台打包
+    '''
+    if not os.path.exists(file_utils.getFullGameApk(game)):
+        print('game "%s" not exists' % game)
+        return 1
+    if not os.path.exists(file_utils.getFullSDKPath(sdk)):
+        print('sdk "%s" not exists' % sdk)
+        return 1
+
+    # 读取配置
+    channelPath = file_utils.getChannelPath(game, sdk)
+    configPath = os.path.join(channelPath, 'config.json')
+    if not os.path.exists(configPath):
+        print('%s not exists' % configPath)
+        return 1
+    
+    jsonText = file_utils.readFile(configPath)
+    config = json.loads(jsonText)
+
+    # 检查参数
+    if not config_utils_record.checkConfig(config):
+        return 1
+
+    # 处理参数
+    config_utils_record.replaceArgs(config)
+
+    successCount = 0
+    failureCount = 0
+    if type(config) == dict:
+        if subChannel is None or config['subChannel'] == subChannel:
+            ret = pack(game, sdk, config)
+            if ret:
+                failureCount += 1
+            else:
+                successCount += 1
+        else:
+            print('subChannel "%s" no found' % subChannel)
+            return 1
+    elif type(config) == list:
+        found = False
+        for itemConfig in config:
+            if subChannel is None or itemConfig['subChannel'] == subChannel:
+                found = True
+                ret = pack(game, sdk, itemConfig)
+                if ret:
+                    failureCount += 1
+                else:
+                    successCount += 1
+
+        if not found:
+            print('subChannel "%s" no found' % subChannel)
+            return 1
+
+    print('success %d, failure %d' % (successCount, failureCount))
+        
+    return 0
+
+def copyEntryActivityCode(game, sdk, subChannel, config):
+    '''
+    拷贝代码
+    '''
+    print('copy EntryActivity.smali')
+    sdkPath = file_utils.getFullSDKPath(sdk)
+    EntryActivity = 'EntryActivity.smali'
+    entryFile = os.path.join(sdkPath, 'smali', EntryActivity)
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    smaliPath = os.path.join(decompliePath, 'smali')
+    targetPath = file_utils.getPackagePath(smaliPath, config['packageName'])
+    targetFile = os.path.join(targetPath, EntryActivity)
+    ret = file_utils.copyFile(entryFile, targetFile)
+    if ret:
+        return ret
+    writeActivityToManifest(os.path.join(decompliePath, 'AndroidManifest.xml'),config)
+    oldText = 'com/jmhy/floatsdk/sample/EntryActivity'
+    newText = config['packageName'].replace('.', '/') + "/EntryActivity"
+    print("EntryActivity.smali change '{}' to '{}' ...".format(oldText,newText))
+    file_utils.replaceContent(targetFile, oldText, newText)
+    return 0
+
+def writeActivityToManifest(targetManifest, config):
+    androidNS = 'http://schemas.android.com/apk/res/android'
+    ET.register_namespace('android', androidNS)
+    targetTree = ET.parse(targetManifest)
+    targetRoot = targetTree.getroot()
+    appNode = targetRoot.find('application')
+    activitys = appNode.findall('activity')
+    keyName = "{0}{1}{2}name".format("{",androidNS,"}")
+    theme = "{0}{1}{2}theme".format("{",androidNS,"}")
+    for activity in activitys:
+        activityName = activity.get(keyName)
+        if activityName.find('.EntryActivity')>=0:
+            oldName = activityName;
+            newName = config['packageName'] + ".EntryActivity"
+            activity.set(keyName,newName)
+            print("EntryActivity change '{}' to '{}' ...".format(oldName, newName))
+        if activityName.find('com.tool.floatsdk.ui.WebActivity')>=0:
+            if activity.get(theme) is not None or activity.get(theme) != "":
+                del activity.attrib[theme]
+
+    perNode = targetRoot.find('permissions')
+    #permissions = perNode.findall('uses-permission')
+    print(perNode)
+    print("------------")
+
+    targetTree.write(targetManifest, 'UTF-8')
+
+
+
+

+ 1074 - 1074
package_utils_shanshen.py

@@ -1,1075 +1,1075 @@
-# 安卓游戏打包脚本
-# 1.用apktool解包
-# 2.复制res资源、assets资源、jniLib资源
-# 3.修改包名、app名、渠道文件
-# 4.添加app icon、合并AndroidManifest文件
-# 5.添加app启动图,修改AndroidManifest文件
-# 6.生成新的R文件
-# 7.将新的R文件编译,生成dex,再用baksmali生成smali,替换旧的R文件
-# 8.将jar资源打包成dex,再用baksmali生成smali,拷贝到smali目录下
-# 9.统计方法量,并分割dex(将smali文件拷贝到目录smali_classes2)
-# 10.用apktool回包
-# 11.重新签名
-import file_utils
-import xml_utils
-import smali_utils
-import config_utils_shanshen
-import game_utils
-import os
-import os.path
-import json
-import sys
-import importlib
-import uuid
-import zipfile
-
-def pack(game, sdk, config):
-    config['cache'] = uuid.uuid1()
-    subChannel = config['subChannel']
-    # 解包
-    ret = decomplie(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 删除旧代码
-    ret = removeOldCode(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 删除一些不支持的属性
-    ret = removeNoSupportAttr(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 删除一些不支持的配置
-    ret = fixUnSupportConfig(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 合并Drawable-v4目录
-    ret = mergeDrawableRes(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 移除相同的资源
-    ret = removeSameRes(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 复制res资源
-    ret = copyRes(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 合并主文件
-    ret = mergeManifestRes(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 替换占位符
-    ret = changePlaceholders(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 添加meta-data
-    ret = addMetaData(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 复制app res资源
-    ret = copyAppRes(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 更改包名
-    if 'packageName' in config and config['packageName'] != '':
-        ret = changePackageName(game, sdk, subChannel, config)
-        if ret:
-            return ret
-    else:
-        config['packageName'] = getPackageName(game, sdk, subChannel, config)
-    # 更改app名
-    if 'name' in config and config['name'] != '':
-        ret = changeAppName(game, sdk, subChannel, config)
-        if ret:
-            return ret
-    # 更改app icon
-    if config['changeIcon']:
-        ret = changeAppIcon(game, sdk, subChannel, config)
-        if ret:
-            return ret
-    # 添加启动图操作
-    if config['addLauncher']:
-        ret = addLauncher(game, sdk, subChannel, config)
-        if ret:
-            return ret
-    # 打包lib依赖
-    ret = packJar(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # sdk脚本处理
-    ret = doSDKPostScript(game, sdk, config)
-    if ret:
-        return ret
-    # 乐变sdk的特殊处理
-    ret = game_utils.sdkLebianChange(game, sdk, config)
-    if ret:
-        return ret
-    # 游戏脚本处理
-    ret = doGamePostScript(game, sdk, config)
-    if ret:
-        return ret
-    # 生成R文件
-    '''ret = generateNewRFile(game, sdk, subChannel, config)
-    if ret:
-        return ret'''
-    # 添加MultiDex支持
-    if config['splitDex']:
-        ret = splitDex(game, sdk, subChannel, config)
-        if ret:
-            return ret
-    # 更改版本号
-    ret = changeVersion(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 回编译
-    ret = recomplie(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 对齐apk
-    ret = alignApk(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 签名
-    ret = apksignerApk(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 添加渠道信息
-    ret = addChannel(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 清理产生的中间文件
-    if config['clearCache']:
-        clearTemp(game, sdk, subChannel, config)
-
-    return 0
-
-def decomplie(game, sdk, subChannel, config):
-    '''
-    解包
-    '''
-    apktoolPath = file_utils.getApkToolPath()
-    gamePath = file_utils.getFullGameApk(game)
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-
-    if os.path.exists(decompliePath):
-        print('delete decomplie folder...')
-        file_utils.deleteFolder(decompliePath)
-
-    print('decomplie apk...')
-
-    return file_utils.execJarCmd(apktoolPath, 'd -f "%s" -o "%s"' % (gamePath, decompliePath))
-
-def removeOldCode(game, sdk, subChannel, config):
-    '''
-    删除旧代码
-    '''
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    codePath = os.path.join(decompliePath, 'smali', 'com', 'shanshen', 'sdk')
-    #file_utils.deleteFolder(codePath)
-    allFiles = []
-    allFiles = file_utils.list_files(codePath, allFiles)
-    for f in allFiles:
-        fpath, fname = os.path.split(f)  #分离文件名和路径
-        if fname == 'R.smali' or fname.startswith('R$'):
-            continue
-        os.remove(f)
-        print('remove %s' % f)
-    return 0
-
-def copyRes(game, sdk, subChannel, config):
-    '''
-    复制res资源
-    '''
-    # 拷贝sdk资源
-    print('copy res...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    sdkPath = file_utils.getFullSDKPath(sdk)
-    resPath = os.path.join(sdkPath, 'res')
-    decomplieResPath = file_utils.getFullPath(decompliePath, 'res')
-
-    for d in os.listdir(resPath):
-        copyResWithType(resPath, decomplieResPath, d)
-
-    # 拷贝assets
-    print('copy assets...')
-    assetsPath = file_utils.getFullPath(sdkPath, 'assets')
-    decomplieAssetsPath = file_utils.getFullPath(decompliePath, 'assets')
-    if os.path.exists(assetsPath):
-        ret = file_utils.copyFileAllDir(assetsPath, decomplieAssetsPath)
-        if ret:
-            return ret
-
-    # 拷贝jniLib
-    print('copy jniLibs...')
-    jniPath = file_utils.getFullPath(sdkPath, 'jniLibs')
-    decomplieJniPath = file_utils.getFullPath(decompliePath, 'lib')
-    abiFilters = []
-    if os.path.exists(decomplieJniPath):
-        for abi in os.listdir(decomplieJniPath):
-            if abi == 'armeabi-v7a' or abi == 'armeabi':
-                abiFilters.append(abi)
-    else:
-        abiFilters = ['armeabi-v7a']
-
-    if os.path.exists(jniPath):
-        ret = file_utils.copyFileAllDir(jniPath, decomplieJniPath, False, abiFilters)
-        if ret:
-            return ret
-    return 0
-
-def mergeDrawableRes(game, sdk, subChannel, config):
-    '''
-    合并Drawable-v4目录
-    '''
-    print('merge drawable path...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    resPath = os.path.join(decompliePath, 'res')
-
-    for path in os.listdir(resPath):
-        print('res path %s' % path)
-        if (path.startswith('drawable') or path.startswith('mipmap')) and path.endswith('-v4'):
-            print('merge path %s' % path)
-            v4DrawablePath = os.path.join(resPath, path)
-            drawablePath = os.path.join(resPath, path[:-3])
-
-            if os.path.exists(drawablePath):
-                ret = file_utils.copyFileAllDir(v4DrawablePath, drawablePath, True)
-                if ret:
-                    return ret
-            else:
-                os.rename(v4DrawablePath, drawablePath)
-    return 0
-
-def removeSameRes(game, sdk, subChannel, config):
-    '''
-    移除相同的资源
-    '''
-    # 读取sdk的资源
-    print('remove same res...')
-    sdkPath = file_utils.getFullSDKPath(sdk)
-    sdkResPath = os.path.join(sdkPath, 'res')
-    resList = []
-    for path in os.listdir(sdkResPath):
-        if not path.startswith('values'):
-            continue
-
-        absPath = os.path.join(sdkResPath, path)
-        for resFile in os.listdir(absPath):
-            '''if not resFile.startswith('jm_'):
-                continue'''
-
-            resList = xml_utils.readAllRes(os.path.join(absPath, resFile), resList)
-
-    if len(resList) == 0:
-        print('no same res found')
-        return 0
-
-    # 移除相同的资源
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    resPath = os.path.join(decompliePath, 'res')
-    for path in os.listdir(resPath):
-        if not path.startswith('values'):
-            continue
-
-        absPath = os.path.join(resPath, path)
-        for resFile in os.listdir(absPath):
-            xml_utils.removeSameRes(os.path.join(absPath, resFile), resList)
-
-    return 0
-
-def mergeManifestRes(game, sdk, subChannel, config):
-    '''
-    合并主文件
-    '''
-    print('merge AndroidManifest...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    sdkPath = file_utils.getFullSDKPath(sdk)
-    libManifest = file_utils.getFullPath(sdkPath, 'manifest.xml')
-    return xml_utils.mergeManifestRes(manifest, libManifest)
-
-def copyAppRes(game, sdk, subChannel, config):
-    '''
-    拷贝app的资源,比如app icon、启动图等
-    '''
-    channelPath = file_utils.getSubChannelPath(game, sdk, subChannel)
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-
-    # assets
-    print('copy assets...')
-    assetsPath = file_utils.getFullPath(channelPath, 'assets')
-    decomplieAssetsPath = file_utils.getFullPath(decompliePath, 'assets')
-    if os.path.exists(assetsPath):
-        ret = file_utils.copyFileAllDir(assetsPath, decomplieAssetsPath)
-        if ret:
-            return ret
-
-    # icon
-    print('copy icon...')
-    ret = copyAppResWithType(decompliePath, channelPath, 'icon')
-    if ret:
-        return ret
-    # 启动图
-    print('copy splash...')
-    ret = copyAppResWithType(decompliePath, channelPath, 'splash')
-    if ret:
-        return ret
-    # 其他图片
-    print('copy image...')
-    ret = copyAppResWithType(decompliePath, channelPath, 'image')
-    if ret:
-        return ret
-    return 0
-    
-def copyAppResWithType(decompliePath, channelPath, typeName):
-    decomplieResPath = os.path.join(decompliePath, 'res')
-    iconPath = os.path.join(channelPath, typeName)
-    if not os.path.exists(iconPath):
-        print('dir "%s" not exists' % iconPath)
-        return 0
-    for d in os.listdir(iconPath):
-        ret = copyResWithType(iconPath, decomplieResPath, d)
-        if ret:
-            return ret
-
-    return 0
-
-def copyResWithType(resPath, decomplieResPath, typeName):
-    # appt的打包目录会带-v4后缀
-    resDir = os.path.join(resPath, typeName)
-    target = os.path.join(decomplieResPath, typeName)
-    targetV4 = os.path.join(decomplieResPath, typeName + '-v4')
-    if not os.path.exists(target) and not os.path.exists(targetV4):
-        os.makedirs(target)
-        return file_utils.copyFileAllDir(resDir, target, False)
-    elif not os.path.exists(target):
-        return file_utils.copyFileAllDir(resDir, targetV4, False)
-    else:
-        return file_utils.copyFileAllDir(resDir, target, False)
-
-def removeNoSupportAttr(game, sdk, subChannel, config):
-    '''
-    删除一些不支持的属性
-    '''
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    
-    xml_utils.removeRootAttr(manifest, 'compileSdkVersion')
-    xml_utils.removeRootAttr(manifest, 'compileSdkVersionCodename')
-    
-    return 0
-
-def fixUnSupportConfig(game, sdk, subChannel, config):
-    '''
-    删除一些不支持的配置
-    '''
-    # 检查minSdkVersion
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    yml = os.path.join(decompliePath, 'apktool.yml')
-
-    minSdkVersion = 15
-    file_utils.changeMinSdkVersion(yml, minSdkVersion)
-
-    resPath = os.path.join(decompliePath, 'res')
-
-    tag = '-v'
-    for res in os.listdir(resPath):
-        print('res = ' + res)
-        if res.startswith('values') and tag in res:
-            start = res.index(tag)
-            version = res[start+len(tag):]
-            if not version.isdigit():
-                continue
-            
-            version = int(version)
-            print('version = %d' % version)
-            if version < minSdkVersion:
-                unSopportPath = os.path.join(resPath, res)
-                print('unSopportPath = ' + unSopportPath)
-                file_utils.deleteFolder(unSopportPath)
-                print('deleteFolder = ' + unSopportPath)
-    
-    return 0
-
-def changePackageName(game, sdk, subChannel, config):
-    '''
-    更改包名
-    '''
-    # 全局替换AndroidManifest里面的包名
-    newPackageName = config['packageName']
-
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    packageName = xml_utils.getPackageName(manifest)
-    
-    xml_utils.changePackageName(manifest, newPackageName)
-    print('change package name %s --> %s' % (packageName, newPackageName))
-    return 0
-
-def getPackageName(game, sdk, subChannel, config):
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    packageName = xml_utils.getPackageName(manifest)
-    return packageName
-
-def changeAppName(game, sdk, subChannel, config):
-    '''
-    更改app名
-    '''
-    # 生成string.xml文件
-    name = config['name']
-
-    resName = 'shanshen_sdk_name'
-    if 'outName' in config:
-        resName = resName + '_' + config['outName']
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    stringFile = os.path.join(decompliePath, 'res', 'values', 'sdk_strings_temp.xml')
-    content = '<?xml version="1.0" encoding="utf-8"?><resources><string name="%s">%s</string></resources>' % (resName, name)
-    file_utils.createFile(stringFile, content)
-
-    # 修改主文件的app名的值
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    xml_utils.changeAppName(manifest, '@string/%s' % resName)
-    print('change app name %s' % name)
-    return 0
-
-def changeAppIcon(game, sdk, subChannel, config):
-    '''
-    更改app icon
-    '''
-    print('change app icon...')
-    resName = 'shanshen_sdk_icon'
-
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    xml_utils.changeAppIcon(manifest, '@mipmap/%s' % resName)
-    return 0
-
-def addMetaData(game, sdk, subChannel, config):
-    '''
-    添加meta-data
-    '''
-    if 'metaData' not in config:
-        return 0
-
-    print('add meta-data...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    xml_utils.addMetaData(manifest, config['metaData'])
-    return 0
-
-def changePlaceholders(game, sdk, subChannel, config):
-    '''
-    处理掉占位符
-    '''
-    if 'placeholders' not in config:
-        return 0
-
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-
-    placeholders = config['placeholders']
-    for placeholder in placeholders:
-        oldText = '${%s}' % placeholder
-        newText = placeholders[placeholder]
-        print('change placeholder %s -> %s' % (oldText, newText))
-        file_utils.replaceContent(manifest, oldText, newText)
-
-    return 0
-
-def addLauncher(game, sdk, subChannel, config):
-    '''
-    添加启动图
-    '''
-    channelPath = file_utils.getSubChannelPath(game, sdk, subChannel)
-    splashPath = os.path.join(channelPath, 'splash')
-    if len(os.listdir(splashPath)) == 0:
-        print('dir splash is empty')
-        return 0
-
-    print('add launcher...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    activity = xml_utils.getLauncherActivityName(manifest)
-    if activity == 'com.shanshen.sdk.template.LauncherActivity':
-        print('add launcher already exist...')
-        return 1
-    
-    # 添加关联资源
-    internalPath = os.path.join(file_utils.getCurrentPath(), 'internal_shanshen')
-    ret = copyAppResWithType(decompliePath, internalPath, 'launcher_res')
-    if ret:
-        return ret
-
-    # 拷贝代码
-    print('copy launcher code...')
-    codePath = os.path.join(internalPath, 'launcher_code', 'smali')
-    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
-    ret = file_utils.copyFileAllDir(codePath, smaliPath)
-    if ret:
-        return ret
-
-    # 修改主文件信息
-    print('change launcher config...')
-    orientation = xml_utils.getScreenOrientation(manifest)
-    activity = xml_utils.removeLauncherActivity(manifest)
-    xml_utils.addLauncherActivity(manifest, orientation, 'com.shanshen.sdk.template.LauncherActivity')
-
-    # 修改跳转的
-    launcherActivity = os.path.join(decompliePath, 'smali', 'com', 'shanshen', 'sdk', 'template', 'LauncherActivity.smali')
-    file_utils.replaceContent(launcherActivity, '{class}', activity)
-
-    print('change launcher %s to %s' % (activity, 'com.shanshen.sdk.template.LauncherActivity'))
-
-    # config['oldLauncher'] = activity
-
-    if 'launcherTime' in config:
-        timeHex = formatHex(config['launcherTime'])
-        file_utils.replaceContent(launcherActivity, '0x0BB8', timeHex)
-
-    return 0
-
-def addMoreIcon(game, sdk, subChannel, config):
-    '''
-    添加多个图标
-    '''
-    print('add more icon support...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    icon = '@mipmap/common_sdk_icon'
-    if not config['changeIcon']:
-        manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-        icon = xml_utils.getApplicationAttr(manifest, 'icon')
-
-    switchIcon = icon
-    if config['switchIcon']:
-        switchIcon = '@mipmap/common_sdk_icon2'
-
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    return xml_utils.addMoreIcon(manifest, icon, switchIcon)
-
-def formatHex(millisecond):
-    '''
-    将毫秒转为16进制,4位格式
-    '''
-    timeHex = str(hex(millisecond)).upper()
-    timeHex = timeHex[2:]
-    formatHex = ''
-    if len(timeHex) == 3:
-        formatHex = '0x0' + timeHex
-    elif len(timeHex) == 4:
-        formatHex = '0x' + timeHex
-    else:
-        formatHex = '0x0BB8'
-    return formatHex
-
-def doSDKPostScript(game, sdk, config):
-    '''
-    执行sdk相关特殊处理脚本
-    '''
-    sdkPath = file_utils.getFullSDKPath(sdk)
-    scriptPath = os.path.join(sdkPath, 'script')
-    targetScript = os.path.join(scriptPath, 'sdk_script.py')
-    if not os.path.exists(targetScript):
-        print('sdk_script no exists')
-        return 0
-
-    print('doSDKPostScript...')
-    sys.path.append(scriptPath)
-
-    module = importlib.import_module('sdk_script')
-    ret = module.execute(game, sdk, config)
-
-    sys.path.remove(scriptPath)
-
-    return ret
-
-def doGamePostScript(game, sdk, config):
-    '''
-    执行游戏相关特殊处理脚本
-    '''
-    channelPath = file_utils.getFullGamePath(game)
-    scriptPath = os.path.join(channelPath, 'script')
-    targetScript = os.path.join(scriptPath, 'game_script.py')
-    if not os.path.exists(targetScript):
-        print('game_script no exists')
-        return 0
-
-    print('doGamePostScript...')
-    sys.path.append(scriptPath)
-
-    module = importlib.import_module('game_script')
-    ret = module.execute(game, sdk, config)
-
-    sys.path.remove(scriptPath)
-
-    return ret
-
-def generateNewRFile(game, sdk, subChannel, config):
-    '''
-    生成新的R文件
-    '''
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    androidPlatforms = file_utils.getAndroidCompileToolPath()
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    decomplieResPath = file_utils.getFullPath(decompliePath, 'res')
-    compliePath = file_utils.getFullPath(decompliePath, 'gen')
-
-    if not os.path.exists(compliePath):
-        os.makedirs(compliePath)
-
-    # 生成R文件
-    print('create R.java ...')
-    if config['aapt2disable']:
-        aapt = file_utils.getAAPTPath()
-        ret = file_utils.getExecPermission(aapt)
-        if ret:
-            return ret
-        createRCmd = '"%s" p -f -m -J "%s" -S "%s" -I "%s" -M "%s"' % (aapt, compliePath, decomplieResPath, androidPlatforms, manifest)
-        ret = file_utils.execFormatCmd(createRCmd)
-        if ret:
-            return ret
-    else:
-        # compile
-        aapt = file_utils.getAAPT2Path()
-        ret = file_utils.getExecPermission(aapt)
-        if ret:
-            return ret
-
-        print('compiled res ...')
-        complieResPath = os.path.join(compliePath, 'compiled')
-        complieResCmd = '"%s" compile --dir "%s" -o "%s"' % (aapt, decomplieResPath, complieResPath)
-        file_utils.execFormatCmd(complieResCmd)
-
-        # unzip
-        print('unzip compiled res ...')
-        unzipResPath = os.path.join(compliePath, 'aapt2_res')
-        with zipfile.ZipFile(complieResPath) as zf:
-            zf.extractall(unzipResPath)
-            print('create unzip %s' % unzipResPath)
-
-        # link
-        print('link res ...')
-        outApk = os.path.join(compliePath, 'res.apk')
-        linkResCmd = '"%s" link -o "%s" -I "%s" --manifest "%s" --java "%s" --auto-add-overlay' % (aapt, outApk, androidPlatforms, manifest, compliePath)
-        for filename in os.listdir(unzipResPath):
-            linkResCmd += ' %s' % filename
-        print('link cmd len is %s' % len(linkResCmd))
-        ret = file_utils.execFormatCmd(linkResCmd, unzipResPath)
-        if ret:
-            return ret
-
-    # 编译R文件
-    print('complie R.java ...')
-    packageName = xml_utils.getPackageName(manifest)
-    packagePath = file_utils.getPackagePath(compliePath, packageName)
-    RSourceFile = os.path.join(packagePath, 'R.java')
-    complieRCmd = 'javac -source 1.8 -target 1.8 -encoding UTF-8 "%s"' % RSourceFile
-    ret = file_utils.execFormatCmd(complieRCmd)
-    if ret:
-        return ret
-
-    # 生成dex
-    print('dex R.class ...')
-    dx = file_utils.getDxPath()
-    outDex = os.path.join(compliePath, 'classes.dex')
-    ret = file_utils.execJarCmd(dx, '--dex --output="%s" "%s"' % (outDex, compliePath))
-    if ret:
-        return ret
-
-    # 反向dex生成smali
-    # 存放在out目录
-    print('baksmali classes.dex ...')
-    baksmaliPath = file_utils.getBaksmaliPath()
-    outPath = file_utils.getFullPath(decompliePath, 'out')
-    ret = file_utils.execJarCmd(baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
-    if ret:
-        return ret
-
-    # 将生成的文件拷贝到目标目录
-    print('copy R.smali ...')
-    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
-    file_utils.copyFileAllDir(outPath, smaliPath)
-    return 0
-
-def packJar(game, sdk, subChannel, config):
-    '''
-    打包所有的jar
-    '''
-    splitDex = config['splitDex']
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    outPath = file_utils.getFullPath(decompliePath, 'gen')
-
-    if not os.path.exists(outPath):
-        os.makedirs(outPath)
-
-    if config['aapt2disable']:
-        dx = file_utils.getDxPath()
-        dexCmd = '--dex --multi-dex --no-warning --output="%s"' % outPath
-    else:
-        dx = file_utils.getD8Path()
-        androidPlatforms = file_utils.getAndroidCompileToolPath()
-        dexCmd = '--lib "%s" --output "%s"' % (androidPlatforms, outPath)
-
-    # 找到所有lib依赖
-    sdkPath = file_utils.getFullSDKPath(sdk)
-    libs = os.path.join(sdkPath, 'libs')
-    libConfig = os.path.join(libs, 'config.json')
-
-    # 存在配置文件
-    if os.path.exists(libConfig):
-        jsonText = file_utils.readFile(libConfig)
-        libConf = json.loads(jsonText)
-        if 'libConfig' in config and config['libConfig'] in libConf:
-            conf = config['libConfig']
-            libList = libConf[conf]
-            for jar in libList:
-                dexCmd += ' ' + os.path.join(libs, jar)
-        elif 'default' in libConf:
-            libList = libConf['default']
-            for jar in libList:
-                dexCmd += ' ' + os.path.join(libs, jar)
-        else:
-            for jar in os.listdir(libs):
-                if not jar.endswith('.jar'):
-                    continue
-                dexCmd += ' ' + os.path.join(libs, jar)
-    else:
-        for jar in os.listdir(libs):
-            if not jar.endswith('.jar'):
-                continue
-            dexCmd += ' ' + os.path.join(libs, jar)
-
-    # multidex.jar
-    if splitDex:
-        dexCmd += ' ' + file_utils.getMultiDexPath()
-
-    # sdk实现类
-    print('packageing all jar ...')
-    ret = file_utils.execJarCmd(dx, dexCmd)
-    if ret:
-        return ret
-
-    # 反向dex生成smali
-    # 存放在out目录
-    print('baksmali classes.dex ...')
-    outDex = os.path.join(outPath, 'classes.dex')
-    baksmaliPath = file_utils.getBaksmaliPath()
-    outPath = file_utils.getFullPath(decompliePath, 'out')
-    
-    ret = file_utils.execJarCmd(baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
-    if ret:
-        return ret
-
-    # 将生成的文件拷贝到目标目录
-    print('copy all smali ...')
-    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
-    ret = file_utils.copyFileAllDir(outPath, smaliPath, True)
-    if ret:
-        return ret
-
-    return 0
-
-def splitDex(game, sdk, subChannel, config):
-    '''
-    分割dex
-    '''
-    # 判断是否已经存在application
-    # 存在,则往原application添加内容
-    # 不存在,则拷贝一个默认的android.support.multidex.MultiDexApplication
-    print('add MultiDex support...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    application = xml_utils.getApplicationAttr(manifest, 'name')
-    if application is None:
-        ret = xml_utils.changeApplicationAttr(manifest, 'name', 'android.support.multidex.MultiDexApplication')
-        if ret:
-            return ret
-    else:
-        smaliPath = os.path.join(decompliePath, 'smali')
-        applicationFile = file_utils.getPackagePath(smaliPath, application)
-        applicationFile += '.smali'
-        ret = changeApplicationDex(applicationFile)
-        if ret:
-            return ret
-
-    return splitSmali(game, sdk, subChannel, config, application)
-
-def changeApplicationDex(file):
-    '''
-    修改application的smali文件,增加MultiDex操作
-    '''
-    index = file_utils.getApplicationSmaliIndex(file)
-    file_utils.insertApplicationSmali(file, index)
-    return 0
-
-def splitSmali(game, sdk, subChannel, config, application):
-    '''
-    如果函数上限超过限制,自动拆分smali,以便生成多个dex文件
-    '''
-    print('splitSmali...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    smaliPath = os.path.join(decompliePath, 'smali')
-
-    appPackage = None
-    if application:
-        appPackage = application[:application.rfind('.')]
-        appPackage = appPackage.replace('.', '/')
-
-    allFiles = []
-    allFiles = file_utils.list_files(smaliPath, allFiles)
-    
-    #print('file count is %d' % len(allFiles))
-
-    #maxFuncNum = 65535
-    # 留一点空间,防止计算误差
-    maxFuncNum = 64000
-    currFucNum = 0
-    totalFucNum = 0
-
-    currDexIndex = 1
-
-    allRefs = []
-
-    #保证Application等类在第一个classex.dex文件中
-    for f in allFiles:
-        f = f.replace('\\', '/')
-        if (appPackage and appPackage in f) or '/android/support/multidex' in f:
-            currFucNum += smali_utils.get_smali_method_count(f, allRefs)
-
-    totalFucNum = currFucNum
-    for f in allFiles:
-        f = f.replace('\\', '/')
-        if not f.endswith('.smali'):
-            continue
-
-        if (appPackage and appPackage in f) or '/android/support/multidex' in f:
-            continue
-
-        thisFucNum = smali_utils.get_smali_method_count(f, allRefs)
-        totalFucNum += thisFucNum
-
-        #print('%d # %d ==> %s' % (thisFucNum, currDexIndex, f))
-        #print('totalFucNum is %d' % totalFucNum)
-        if currFucNum + thisFucNum >= maxFuncNum:
-            currFucNum = thisFucNum
-            currDexIndex += 1
-            newDexPath = os.path.join(decompliePath, 'smali_classes%d' % currDexIndex)
-            os.makedirs(newDexPath)
-        else:
-            currFucNum += thisFucNum
-
-        if currDexIndex > 1:
-            newDexPath = os.path.join(decompliePath, 'smali_classes%d' % currDexIndex)
-            targetFile = newDexPath + f[len(smaliPath):]
-            file_utils.copyFile(f, targetFile, True)
-    return 0
-
-def changeVersion(game, sdk, subChannel, config):
-    '''
-    更改版本号
-    '''
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    yml = os.path.join(decompliePath, 'apktool.yml')
-
-    versionCode = None
-    versionName = None
-    targetSdkVersion = None
-    if 'versionCode' in config:
-        versionCode = config['versionCode']
-    if 'versionName' in config:
-        versionName = config['versionName']
-    if 'targetSdkVersion' in config:
-        targetSdkVersion = config['targetSdkVersion']
-
-    return file_utils.changeVersion(yml, versionCode, versionName, targetSdkVersion)
-
-def recomplie(game, sdk, subChannel, config):
-    '''
-    回编译
-    '''
-    print('recomplie apk...')
-    apktoolPath = file_utils.getApkToolPath()
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    outApk = file_utils.getOutApkPath(game, sdk, subChannel, config['cache'])
-
-    useAppt2 = ' --use-aapt2'
-    if config['aapt2disable']:
-        useAppt2 = ''
-
-    return file_utils.execJarCmd(apktoolPath, 'b -f "%s" -o "%s"%s' % (decompliePath, outApk, useAppt2))
-
-def alignApk(game, sdk, subChannel, config):
-    '''
-    对齐apk
-    '''
-    print('align apk...')
-    outApk = file_utils.getOutApkPath(game, sdk, subChannel, config['cache'])
-    alignApk = file_utils.getAlignApkPath(game, sdk, subChannel, config['cache'])
-    alignapkTool = file_utils.getAlignPath()
-    if os.path.exists(alignApk):
-        os.remove(alignApk)
-
-    ret = file_utils.getExecPermission(alignapkTool)
-    if ret:
-        return ret
-
-    # zipalign.exe -v -p 4 input.apk output.apk
-    return file_utils.execFormatCmd('"%s" -f -p 4 "%s" "%s"' % (alignapkTool, outApk, alignApk))
-
-def apksignerApk(game, sdk, subChannel, config):
-    '''
-    签名apk
-    '''
-    print('sign apk...')
-    path = os.path.join(file_utils.getCurrentPath(), 'keystore', 'key.json')
-    jsonText = file_utils.readFile(path)
-    signConfig = json.loads(jsonText)
-    keystore = {}
-    if game in signConfig:
-        if sdk in signConfig[game] and subChannel in signConfig[game][sdk]:
-            keystore = signConfig[game][sdk][subChannel]
-        else:
-            keystore = signConfig['default']
-    else:
-        keystore = signConfig['default']
-
-    print('storeFile is "%s"' % keystore['storeFile'])
-    
-    apksigner = file_utils.getApksignerPath()
-    alignApk = file_utils.getAlignApkPath(game, sdk, subChannel, config['cache'])
-    signedApk = file_utils.getSignApkPath(game, sdk, subChannel, config['cache'])
-    storeFile = os.path.join(file_utils.getCurrentPath(), 'keystore', keystore['storeFile'])
-
-    if 'outName' in config and 'outPath' in config:
-        if not os.path.exists(config['outPath']):
-            os.makedirs(config['outPath'])
-
-        signedApk = os.path.join(config['outPath'], config['outName'] + '.apk')
-    elif 'outName' in config:
-        signedApk = file_utils.getRenameApkPath(game, sdk, config['cache'], config['outName'])
-    
-    # java -jar apksigner.jar sign --ks key.jks --ks-key-alias releasekey --ks-pass pass:pp123456 --key-pass pass:pp123456 --out output.apk input.apk
-    v2disable = ''
-    if 'v2disable' in config and config['v2disable']:
-        v2disable = ' --v2-signing-enabled=false'
-        
-    return file_utils.execJarCmd(apksigner, 'sign%s --ks "%s" --ks-key-alias %s --ks-pass pass:%s --key-pass pass:%s --out "%s" "%s"' % (v2disable, storeFile, keystore['keyAlias'], keystore['storePassword'], keystore['keyPassword'], signedApk, alignApk))
-
-def addChannel(game, sdk, subChannel, config):
-    '''
-    添加渠道信息
-    '''
-    if 'v2disable' in config and config['v2disable']:
-        return 0
-    
-    walle = file_utils.getWallePath()
-    signedApk = file_utils.getSignApkPath(game, sdk, subChannel, config['cache'])
-    if 'outName' in config and 'outPath' in config:
-        signedApk = os.path.join(config['outPath'], config['outName'] + '.apk')
-    elif 'outName' in config:
-        signedApk = file_utils.getRenameApkPath(game, sdk, config['cache'], config['outName'])
-
-    properties = config['properties']
-
-    appid = ''
-    appkey = ''
-    if 'appid' in properties:
-        appid = properties['appid']
-    if 'appkey' in properties:
-        appkey = properties['appkey']
-
-    return file_utils.execJarCmd(walle, 'put -e version=%s,agent=%s,appid=%s,appkey=%s "%s" "%s"' % (config_utils_shanshen.getDate(), properties['agent'], appid, appkey, signedApk, signedApk))
-
-def clearTemp(game, sdk, subChannel, config):
-    '''
-    清空中间产生的文件
-    '''
-    print('clear temp...')
-    alignApk = file_utils.getAlignApkPath(game, sdk, subChannel, config['cache'])
-    outApk = file_utils.getOutApkPath(game, sdk, subChannel, config['cache'])
-    if os.path.exists(alignApk):
-        os.remove(alignApk)
-    if os.path.exists(outApk):
-        os.remove(outApk)
-
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    file_utils.deleteFolder(decompliePath)
-
-    print('clear temp end')
-
-def packConsoleInput():
-    '''
-    控制台打包
-    '''
-    if len(sys.argv) < 3:
-        print('argument is missing')
-        return 1
-
-    # 校验参数
-    game = sys.argv[1]
-    sdk = sys.argv[2]
-    # 可选参数,没有则默认打全部渠道
-    subChannel = None
-    if len(sys.argv) > 3:
-        subChannel = sys.argv[3]
-        
-    return packConsole(game, sdk, subChannel)
-
-def packConsole(game, sdk, subChannel):
-    '''
-    控制台打包
-    '''
-    if not os.path.exists(file_utils.getFullGameApk(game)):
-        print('game "%s" not exists' % game)
-        return 1
-    if not os.path.exists(file_utils.getFullSDKPath(sdk)):
-        print('sdk "%s" not exists' % sdk)
-        return 1
-
-    # 读取配置
-    channelPath = file_utils.getChannelPath(game, sdk)
-    configPath = os.path.join(channelPath, 'config.json')
-    if not os.path.exists(configPath):
-        print('%s not exists' % configPath)
-        return 1
-    
-    jsonText = file_utils.readFile(configPath)
-    config = json.loads(jsonText)
-
-    # 检查参数
-    if not config_utils_shanshen.checkConfig(config):
-        return 1
-
-    # 处理参数
-    config_utils_shanshen.replaceArgs(config)
-
-    successCount = 0
-    failureCount = 0
-    if type(config) == dict:
-        if subChannel is None or config['subChannel'] == subChannel:
-            ret = pack(game, sdk, config)
-            if ret:
-                failureCount += 1
-            else:
-                successCount += 1
-        else:
-            print('subChannel "%s" no found' % subChannel)
-            return 1
-    elif type(config) == list:
-        found = False
-        for itemConfig in config:
-            if subChannel is None or itemConfig['subChannel'] == subChannel:
-                found = True
-                ret = pack(game, sdk, itemConfig)
-                if ret:
-                    failureCount += 1
-                else:
-                    successCount += 1
-
-        if not found:
-            print('subChannel "%s" no found' % subChannel)
-            return 1
-
-    print('success %d, failure %d' % (successCount, failureCount))
-        
+# 安卓游戏打包脚本
+# 1.用apktool解包
+# 2.复制res资源、assets资源、jniLib资源
+# 3.修改包名、app名、渠道文件
+# 4.添加app icon、合并AndroidManifest文件
+# 5.添加app启动图,修改AndroidManifest文件
+# 6.生成新的R文件
+# 7.将新的R文件编译,生成dex,再用baksmali生成smali,替换旧的R文件
+# 8.将jar资源打包成dex,再用baksmali生成smali,拷贝到smali目录下
+# 9.统计方法量,并分割dex(将smali文件拷贝到目录smali_classes2)
+# 10.用apktool回包
+# 11.重新签名
+import file_utils
+import xml_utils
+import smali_utils
+import config_utils_shanshen
+import game_utils
+import os
+import os.path
+import json
+import sys
+import importlib
+import uuid
+import zipfile
+
+def pack(game, sdk, config):
+    config['cache'] = uuid.uuid1()
+    subChannel = config['subChannel']
+    # 解包
+    ret = decomplie(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 删除旧代码
+    ret = removeOldCode(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 删除一些不支持的属性
+    ret = removeNoSupportAttr(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 删除一些不支持的配置
+    ret = fixUnSupportConfig(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 合并Drawable-v4目录
+    ret = mergeDrawableRes(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 移除相同的资源
+    ret = removeSameRes(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 复制res资源
+    ret = copyRes(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 合并主文件
+    ret = mergeManifestRes(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 替换占位符
+    ret = changePlaceholders(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 添加meta-data
+    ret = addMetaData(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 复制app res资源
+    ret = copyAppRes(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 更改包名
+    if 'packageName' in config and config['packageName'] != '':
+        ret = changePackageName(game, sdk, subChannel, config)
+        if ret:
+            return ret
+    else:
+        config['packageName'] = getPackageName(game, sdk, subChannel, config)
+    # 更改app名
+    if 'name' in config and config['name'] != '':
+        ret = changeAppName(game, sdk, subChannel, config)
+        if ret:
+            return ret
+    # 更改app icon
+    if config['changeIcon']:
+        ret = changeAppIcon(game, sdk, subChannel, config)
+        if ret:
+            return ret
+    # 添加启动图操作
+    if config['addLauncher']:
+        ret = addLauncher(game, sdk, subChannel, config)
+        if ret:
+            return ret
+    # 打包lib依赖
+    ret = packJar(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # sdk脚本处理
+    ret = doSDKPostScript(game, sdk, config)
+    if ret:
+        return ret
+    # 乐变sdk的特殊处理
+    ret = game_utils.sdkLebianChange(game, sdk, config)
+    if ret:
+        return ret
+    # 游戏脚本处理
+    ret = doGamePostScript(game, sdk, config)
+    if ret:
+        return ret
+    # 生成R文件
+    '''ret = generateNewRFile(game, sdk, subChannel, config)
+    if ret:
+        return ret'''
+    # 添加MultiDex支持
+    if config['splitDex']:
+        ret = splitDex(game, sdk, subChannel, config)
+        if ret:
+            return ret
+    # 更改版本号
+    ret = changeVersion(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 回编译
+    ret = recomplie(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 对齐apk
+    ret = alignApk(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 签名
+    ret = apksignerApk(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 添加渠道信息
+    ret = addChannel(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 清理产生的中间文件
+    if config['clearCache']:
+        clearTemp(game, sdk, subChannel, config)
+
+    return 0
+
+def decomplie(game, sdk, subChannel, config):
+    '''
+    解包
+    '''
+    apktoolPath = file_utils.getApkToolPath()
+    gamePath = file_utils.getFullGameApk(game)
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+
+    if os.path.exists(decompliePath):
+        print('delete decomplie folder...')
+        file_utils.deleteFolder(decompliePath)
+
+    print('decomplie apk...')
+
+    return file_utils.execJarCmd(apktoolPath, 'd -f "%s" -o "%s"' % (gamePath, decompliePath))
+
+def removeOldCode(game, sdk, subChannel, config):
+    '''
+    删除旧代码
+    '''
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    codePath = os.path.join(decompliePath, 'smali', 'com', 'shanshen', 'sdk')
+    #file_utils.deleteFolder(codePath)
+    allFiles = []
+    allFiles = file_utils.list_files(codePath, allFiles)
+    for f in allFiles:
+        fpath, fname = os.path.split(f)  #分离文件名和路径
+        if fname == 'R.smali' or fname.startswith('R$'):
+            continue
+        os.remove(f)
+        print('remove %s' % f)
+    return 0
+
+def copyRes(game, sdk, subChannel, config):
+    '''
+    复制res资源
+    '''
+    # 拷贝sdk资源
+    print('copy res...')
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    sdkPath = file_utils.getFullSDKPath(sdk)
+    resPath = os.path.join(sdkPath, 'res')
+    decomplieResPath = file_utils.getFullPath(decompliePath, 'res')
+
+    for d in os.listdir(resPath):
+        copyResWithType(resPath, decomplieResPath, d)
+
+    # 拷贝assets
+    print('copy assets...')
+    assetsPath = file_utils.getFullPath(sdkPath, 'assets')
+    decomplieAssetsPath = file_utils.getFullPath(decompliePath, 'assets')
+    if os.path.exists(assetsPath):
+        ret = file_utils.copyFileAllDir(assetsPath, decomplieAssetsPath)
+        if ret:
+            return ret
+
+    # 拷贝jniLib
+    print('copy jniLibs...')
+    jniPath = file_utils.getFullPath(sdkPath, 'jniLibs')
+    decomplieJniPath = file_utils.getFullPath(decompliePath, 'lib')
+    abiFilters = []
+    if os.path.exists(decomplieJniPath):
+        for abi in os.listdir(decomplieJniPath):
+            if abi == 'armeabi-v7a' or abi == 'armeabi':
+                abiFilters.append(abi)
+    else:
+        abiFilters = ['armeabi-v7a']
+
+    if os.path.exists(jniPath):
+        ret = file_utils.copyFileAllDir(jniPath, decomplieJniPath, False, abiFilters)
+        if ret:
+            return ret
+    return 0
+
+def mergeDrawableRes(game, sdk, subChannel, config):
+    '''
+    合并Drawable-v4目录
+    '''
+    print('merge drawable path...')
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    resPath = os.path.join(decompliePath, 'res')
+
+    for path in os.listdir(resPath):
+        print('res path %s' % path)
+        if (path.startswith('drawable') or path.startswith('mipmap')) and path.endswith('-v4'):
+            print('merge path %s' % path)
+            v4DrawablePath = os.path.join(resPath, path)
+            drawablePath = os.path.join(resPath, path[:-3])
+
+            if os.path.exists(drawablePath):
+                ret = file_utils.copyFileAllDir(v4DrawablePath, drawablePath, True)
+                if ret:
+                    return ret
+            else:
+                os.rename(v4DrawablePath, drawablePath)
+    return 0
+
+def removeSameRes(game, sdk, subChannel, config):
+    '''
+    移除相同的资源
+    '''
+    # 读取sdk的资源
+    print('remove same res...')
+    sdkPath = file_utils.getFullSDKPath(sdk)
+    sdkResPath = os.path.join(sdkPath, 'res')
+    resList = []
+    for path in os.listdir(sdkResPath):
+        if not path.startswith('values'):
+            continue
+
+        absPath = os.path.join(sdkResPath, path)
+        for resFile in os.listdir(absPath):
+            '''if not resFile.startswith('jm_'):
+                continue'''
+
+            resList = xml_utils.readAllRes(os.path.join(absPath, resFile), resList)
+
+    if len(resList) == 0:
+        print('no same res found')
+        return 0
+
+    # 移除相同的资源
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    resPath = os.path.join(decompliePath, 'res')
+    for path in os.listdir(resPath):
+        if not path.startswith('values'):
+            continue
+
+        absPath = os.path.join(resPath, path)
+        for resFile in os.listdir(absPath):
+            xml_utils.removeSameRes(os.path.join(absPath, resFile), resList)
+
+    return 0
+
+def mergeManifestRes(game, sdk, subChannel, config):
+    '''
+    合并主文件
+    '''
+    print('merge AndroidManifest...')
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    sdkPath = file_utils.getFullSDKPath(sdk)
+    libManifest = file_utils.getFullPath(sdkPath, 'manifest.xml')
+    return xml_utils.mergeManifestRes(manifest, libManifest)
+
+def copyAppRes(game, sdk, subChannel, config):
+    '''
+    拷贝app的资源,比如app icon、启动图等
+    '''
+    channelPath = file_utils.getSubChannelPath(game, sdk, subChannel)
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+
+    # assets
+    print('copy assets...')
+    assetsPath = file_utils.getFullPath(channelPath, 'assets')
+    decomplieAssetsPath = file_utils.getFullPath(decompliePath, 'assets')
+    if os.path.exists(assetsPath):
+        ret = file_utils.copyFileAllDir(assetsPath, decomplieAssetsPath)
+        if ret:
+            return ret
+
+    # icon
+    print('copy icon...')
+    ret = copyAppResWithType(decompliePath, channelPath, 'icon')
+    if ret:
+        return ret
+    # 启动图
+    print('copy splash...')
+    ret = copyAppResWithType(decompliePath, channelPath, 'splash')
+    if ret:
+        return ret
+    # 其他图片
+    print('copy image...')
+    ret = copyAppResWithType(decompliePath, channelPath, 'image')
+    if ret:
+        return ret
+    return 0
+    
+def copyAppResWithType(decompliePath, channelPath, typeName):
+    decomplieResPath = os.path.join(decompliePath, 'res')
+    iconPath = os.path.join(channelPath, typeName)
+    if not os.path.exists(iconPath):
+        print('dir "%s" not exists' % iconPath)
+        return 0
+    for d in os.listdir(iconPath):
+        ret = copyResWithType(iconPath, decomplieResPath, d)
+        if ret:
+            return ret
+
+    return 0
+
+def copyResWithType(resPath, decomplieResPath, typeName):
+    # appt的打包目录会带-v4后缀
+    resDir = os.path.join(resPath, typeName)
+    target = os.path.join(decomplieResPath, typeName)
+    targetV4 = os.path.join(decomplieResPath, typeName + '-v4')
+    if not os.path.exists(target) and not os.path.exists(targetV4):
+        os.makedirs(target)
+        return file_utils.copyFileAllDir(resDir, target, False)
+    elif not os.path.exists(target):
+        return file_utils.copyFileAllDir(resDir, targetV4, False)
+    else:
+        return file_utils.copyFileAllDir(resDir, target, False)
+
+def removeNoSupportAttr(game, sdk, subChannel, config):
+    '''
+    删除一些不支持的属性
+    '''
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    
+    xml_utils.removeRootAttr(manifest, 'compileSdkVersion')
+    xml_utils.removeRootAttr(manifest, 'compileSdkVersionCodename')
+    
+    return 0
+
+def fixUnSupportConfig(game, sdk, subChannel, config):
+    '''
+    删除一些不支持的配置
+    '''
+    # 检查minSdkVersion
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    yml = os.path.join(decompliePath, 'apktool.yml')
+
+    minSdkVersion = 15
+    file_utils.changeMinSdkVersion(yml, minSdkVersion)
+
+    resPath = os.path.join(decompliePath, 'res')
+
+    tag = '-v'
+    for res in os.listdir(resPath):
+        print('res = ' + res)
+        if res.startswith('values') and tag in res:
+            start = res.index(tag)
+            version = res[start+len(tag):]
+            if not version.isdigit():
+                continue
+            
+            version = int(version)
+            print('version = %d' % version)
+            if version < minSdkVersion:
+                unSopportPath = os.path.join(resPath, res)
+                print('unSopportPath = ' + unSopportPath)
+                file_utils.deleteFolder(unSopportPath)
+                print('deleteFolder = ' + unSopportPath)
+    
+    return 0
+
+def changePackageName(game, sdk, subChannel, config):
+    '''
+    更改包名
+    '''
+    # 全局替换AndroidManifest里面的包名
+    newPackageName = config['packageName']
+
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    packageName = xml_utils.getPackageName(manifest)
+    
+    xml_utils.changePackageName(manifest, newPackageName)
+    print('change package name %s --> %s' % (packageName, newPackageName))
+    return 0
+
+def getPackageName(game, sdk, subChannel, config):
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    packageName = xml_utils.getPackageName(manifest)
+    return packageName
+
+def changeAppName(game, sdk, subChannel, config):
+    '''
+    更改app名
+    '''
+    # 生成string.xml文件
+    name = config['name']
+
+    resName = 'shanshen_sdk_name'
+    if 'outName' in config:
+        resName = resName + '_' + config['outName']
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    stringFile = os.path.join(decompliePath, 'res', 'values', 'sdk_strings_temp.xml')
+    content = '<?xml version="1.0" encoding="utf-8"?><resources><string name="%s">%s</string></resources>' % (resName, name)
+    file_utils.createFile(stringFile, content)
+
+    # 修改主文件的app名的值
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    xml_utils.changeAppName(manifest, '@string/%s' % resName)
+    print('change app name %s' % name)
+    return 0
+
+def changeAppIcon(game, sdk, subChannel, config):
+    '''
+    更改app icon
+    '''
+    print('change app icon...')
+    resName = 'shanshen_sdk_icon'
+
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    xml_utils.changeAppIcon(manifest, '@mipmap/%s' % resName)
+    return 0
+
+def addMetaData(game, sdk, subChannel, config):
+    '''
+    添加meta-data
+    '''
+    if 'metaData' not in config:
+        return 0
+
+    print('add meta-data...')
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    xml_utils.addMetaData(manifest, config['metaData'])
+    return 0
+
+def changePlaceholders(game, sdk, subChannel, config):
+    '''
+    处理掉占位符
+    '''
+    if 'placeholders' not in config:
+        return 0
+
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+
+    placeholders = config['placeholders']
+    for placeholder in placeholders:
+        oldText = '${%s}' % placeholder
+        newText = placeholders[placeholder]
+        print('change placeholder %s -> %s' % (oldText, newText))
+        file_utils.replaceContent(manifest, oldText, newText)
+
+    return 0
+
+def addLauncher(game, sdk, subChannel, config):
+    '''
+    添加启动图
+    '''
+    channelPath = file_utils.getSubChannelPath(game, sdk, subChannel)
+    splashPath = os.path.join(channelPath, 'splash')
+    if len(os.listdir(splashPath)) == 0:
+        print('dir splash is empty')
+        return 0
+
+    print('add launcher...')
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    activity = xml_utils.getLauncherActivityName(manifest)
+    if activity == 'com.shanshen.sdk.template.LauncherActivity':
+        print('add launcher already exist...')
+        return 1
+    
+    # 添加关联资源
+    internalPath = os.path.join(file_utils.getCurrentPath(), 'internal_shanshen')
+    ret = copyAppResWithType(decompliePath, internalPath, 'launcher_res')
+    if ret:
+        return ret
+
+    # 拷贝代码
+    print('copy launcher code...')
+    codePath = os.path.join(internalPath, 'launcher_code', 'smali')
+    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
+    ret = file_utils.copyFileAllDir(codePath, smaliPath)
+    if ret:
+        return ret
+
+    # 修改主文件信息
+    print('change launcher config...')
+    orientation = xml_utils.getScreenOrientation(manifest)
+    activity = xml_utils.removeLauncherActivity(manifest)
+    xml_utils.addLauncherActivity(manifest, orientation, 'com.shanshen.sdk.template.LauncherActivity')
+
+    # 修改跳转的
+    launcherActivity = os.path.join(decompliePath, 'smali', 'com', 'shanshen', 'sdk', 'template', 'LauncherActivity.smali')
+    file_utils.replaceContent(launcherActivity, '{class}', activity)
+
+    print('change launcher %s to %s' % (activity, 'com.shanshen.sdk.template.LauncherActivity'))
+
+    # config['oldLauncher'] = activity
+
+    if 'launcherTime' in config:
+        timeHex = formatHex(config['launcherTime'])
+        file_utils.replaceContent(launcherActivity, '0x0BB8', timeHex)
+
+    return 0
+
+def addMoreIcon(game, sdk, subChannel, config):
+    '''
+    添加多个图标
+    '''
+    print('add more icon support...')
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    icon = '@mipmap/common_sdk_icon'
+    if not config['changeIcon']:
+        manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+        icon = xml_utils.getApplicationAttr(manifest, 'icon')
+
+    switchIcon = icon
+    if config['switchIcon']:
+        switchIcon = '@mipmap/common_sdk_icon2'
+
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    return xml_utils.addMoreIcon(manifest, icon, switchIcon)
+
+def formatHex(millisecond):
+    '''
+    将毫秒转为16进制,4位格式
+    '''
+    timeHex = str(hex(millisecond)).upper()
+    timeHex = timeHex[2:]
+    formatHex = ''
+    if len(timeHex) == 3:
+        formatHex = '0x0' + timeHex
+    elif len(timeHex) == 4:
+        formatHex = '0x' + timeHex
+    else:
+        formatHex = '0x0BB8'
+    return formatHex
+
+def doSDKPostScript(game, sdk, config):
+    '''
+    执行sdk相关特殊处理脚本
+    '''
+    sdkPath = file_utils.getFullSDKPath(sdk)
+    scriptPath = os.path.join(sdkPath, 'script')
+    targetScript = os.path.join(scriptPath, 'sdk_script.py')
+    if not os.path.exists(targetScript):
+        print('sdk_script no exists')
+        return 0
+
+    print('doSDKPostScript...')
+    sys.path.append(scriptPath)
+
+    module = importlib.import_module('sdk_script')
+    ret = module.execute(game, sdk, config)
+
+    sys.path.remove(scriptPath)
+
+    return ret
+
+def doGamePostScript(game, sdk, config):
+    '''
+    执行游戏相关特殊处理脚本
+    '''
+    channelPath = file_utils.getFullGamePath(game)
+    scriptPath = os.path.join(channelPath, 'script')
+    targetScript = os.path.join(scriptPath, 'game_script.py')
+    if not os.path.exists(targetScript):
+        print('game_script no exists')
+        return 0
+
+    print('doGamePostScript...')
+    sys.path.append(scriptPath)
+
+    module = importlib.import_module('game_script')
+    ret = module.execute(game, sdk, config)
+
+    sys.path.remove(scriptPath)
+
+    return ret
+
+def generateNewRFile(game, sdk, subChannel, config):
+    '''
+    生成新的R文件
+    '''
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    androidPlatforms = file_utils.getAndroidCompileToolPath()
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    decomplieResPath = file_utils.getFullPath(decompliePath, 'res')
+    compliePath = file_utils.getFullPath(decompliePath, 'gen')
+
+    if not os.path.exists(compliePath):
+        os.makedirs(compliePath)
+
+    # 生成R文件
+    print('create R.java ...')
+    if config['aapt2disable']:
+        aapt = file_utils.getAAPTPath()
+        ret = file_utils.getExecPermission(aapt)
+        if ret:
+            return ret
+        createRCmd = '"%s" p -f -m -J "%s" -S "%s" -I "%s" -M "%s"' % (aapt, compliePath, decomplieResPath, androidPlatforms, manifest)
+        ret = file_utils.execFormatCmd(createRCmd)
+        if ret:
+            return ret
+    else:
+        # compile
+        aapt = file_utils.getAAPT2Path()
+        ret = file_utils.getExecPermission(aapt)
+        if ret:
+            return ret
+
+        print('compiled res ...')
+        complieResPath = os.path.join(compliePath, 'compiled')
+        complieResCmd = '"%s" compile --dir "%s" -o "%s"' % (aapt, decomplieResPath, complieResPath)
+        file_utils.execFormatCmd(complieResCmd)
+
+        # unzip
+        print('unzip compiled res ...')
+        unzipResPath = os.path.join(compliePath, 'aapt2_res')
+        with zipfile.ZipFile(complieResPath) as zf:
+            zf.extractall(unzipResPath)
+            print('create unzip %s' % unzipResPath)
+
+        # link
+        print('link res ...')
+        outApk = os.path.join(compliePath, 'res.apk')
+        linkResCmd = '"%s" link -o "%s" -I "%s" --manifest "%s" --java "%s" --auto-add-overlay' % (aapt, outApk, androidPlatforms, manifest, compliePath)
+        for filename in os.listdir(unzipResPath):
+            linkResCmd += ' %s' % filename
+        print('link cmd len is %s' % len(linkResCmd))
+        ret = file_utils.execFormatCmd(linkResCmd, unzipResPath)
+        if ret:
+            return ret
+
+    # 编译R文件
+    print('complie R.java ...')
+    packageName = xml_utils.getPackageName(manifest)
+    packagePath = file_utils.getPackagePath(compliePath, packageName)
+    RSourceFile = os.path.join(packagePath, 'R.java')
+    complieRCmd = 'javac -source 1.8 -target 1.8 -encoding UTF-8 "%s"' % RSourceFile
+    ret = file_utils.execFormatCmd(complieRCmd)
+    if ret:
+        return ret
+
+    # 生成dex
+    print('dex R.class ...')
+    dx = file_utils.getDxPath()
+    outDex = os.path.join(compliePath, 'classes.dex')
+    ret = file_utils.execJarCmd(dx, '--dex --output="%s" "%s"' % (outDex, compliePath))
+    if ret:
+        return ret
+
+    # 反向dex生成smali
+    # 存放在out目录
+    print('baksmali classes.dex ...')
+    baksmaliPath = file_utils.getBaksmaliPath()
+    outPath = file_utils.getFullPath(decompliePath, 'out')
+    ret = file_utils.execJarCmd(baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
+    if ret:
+        return ret
+
+    # 将生成的文件拷贝到目标目录
+    print('copy R.smali ...')
+    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
+    file_utils.copyFileAllDir(outPath, smaliPath)
+    return 0
+
+def packJar(game, sdk, subChannel, config):
+    '''
+    打包所有的jar
+    '''
+    splitDex = config['splitDex']
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    outPath = file_utils.getFullPath(decompliePath, 'gen')
+
+    if not os.path.exists(outPath):
+        os.makedirs(outPath)
+
+    if config['aapt2disable']:
+        dx = file_utils.getDxPath()
+        dexCmd = '--dex --multi-dex --no-warning --output="%s"' % outPath
+    else:
+        dx = file_utils.getD8Path()
+        androidPlatforms = file_utils.getAndroidCompileToolPath()
+        dexCmd = '--lib "%s" --output "%s"' % (androidPlatforms, outPath)
+
+    # 找到所有lib依赖
+    sdkPath = file_utils.getFullSDKPath(sdk)
+    libs = os.path.join(sdkPath, 'libs')
+    libConfig = os.path.join(libs, 'config.json')
+
+    # 存在配置文件
+    if os.path.exists(libConfig):
+        jsonText = file_utils.readFile(libConfig)
+        libConf = json.loads(jsonText)
+        if 'libConfig' in config and config['libConfig'] in libConf:
+            conf = config['libConfig']
+            libList = libConf[conf]
+            for jar in libList:
+                dexCmd += ' ' + os.path.join(libs, jar)
+        elif 'default' in libConf:
+            libList = libConf['default']
+            for jar in libList:
+                dexCmd += ' ' + os.path.join(libs, jar)
+        else:
+            for jar in os.listdir(libs):
+                if not jar.endswith('.jar'):
+                    continue
+                dexCmd += ' ' + os.path.join(libs, jar)
+    else:
+        for jar in os.listdir(libs):
+            if not jar.endswith('.jar'):
+                continue
+            dexCmd += ' ' + os.path.join(libs, jar)
+
+    # multidex.jar
+    if splitDex:
+        dexCmd += ' ' + file_utils.getMultiDexPath()
+
+    # sdk实现类
+    print('packageing all jar ...')
+    ret = file_utils.execJarCmd(dx, dexCmd)
+    if ret:
+        return ret
+
+    # 反向dex生成smali
+    # 存放在out目录
+    print('baksmali classes.dex ...')
+    outDex = os.path.join(outPath, 'classes.dex')
+    baksmaliPath = file_utils.getBaksmaliPath()
+    outPath = file_utils.getFullPath(decompliePath, 'out')
+    
+    ret = file_utils.execJarCmd(baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
+    if ret:
+        return ret
+
+    # 将生成的文件拷贝到目标目录
+    print('copy all smali ...')
+    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
+    ret = file_utils.copyFileAllDir(outPath, smaliPath, True)
+    if ret:
+        return ret
+
+    return 0
+
+def splitDex(game, sdk, subChannel, config):
+    '''
+    分割dex
+    '''
+    # 判断是否已经存在application
+    # 存在,则往原application添加内容
+    # 不存在,则拷贝一个默认的android.support.multidex.MultiDexApplication
+    print('add MultiDex support...')
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    application = xml_utils.getApplicationAttr(manifest, 'name')
+    if application is None:
+        ret = xml_utils.changeApplicationAttr(manifest, 'name', 'android.support.multidex.MultiDexApplication')
+        if ret:
+            return ret
+    else:
+        smaliPath = os.path.join(decompliePath, 'smali')
+        applicationFile = file_utils.getPackagePath(smaliPath, application)
+        applicationFile += '.smali'
+        ret = changeApplicationDex(applicationFile)
+        if ret:
+            return ret
+
+    return splitSmali(game, sdk, subChannel, config, application)
+
+def changeApplicationDex(file):
+    '''
+    修改application的smali文件,增加MultiDex操作
+    '''
+    index = file_utils.getApplicationSmaliIndex(file)
+    file_utils.insertApplicationSmali(file, index)
+    return 0
+
+def splitSmali(game, sdk, subChannel, config, application):
+    '''
+    如果函数上限超过限制,自动拆分smali,以便生成多个dex文件
+    '''
+    print('splitSmali...')
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    smaliPath = os.path.join(decompliePath, 'smali')
+
+    appPackage = None
+    if application:
+        appPackage = application[:application.rfind('.')]
+        appPackage = appPackage.replace('.', '/')
+
+    allFiles = []
+    allFiles = file_utils.list_files(smaliPath, allFiles)
+    
+    #print('file count is %d' % len(allFiles))
+
+    #maxFuncNum = 65535
+    # 留一点空间,防止计算误差
+    maxFuncNum = 64000
+    currFucNum = 0
+    totalFucNum = 0
+
+    currDexIndex = 1
+
+    allRefs = []
+
+    #保证Application等类在第一个classex.dex文件中
+    for f in allFiles:
+        f = f.replace('\\', '/')
+        if (appPackage and appPackage in f) or '/android/support/multidex' in f:
+            currFucNum += smali_utils.get_smali_method_count(f, allRefs)
+
+    totalFucNum = currFucNum
+    for f in allFiles:
+        f = f.replace('\\', '/')
+        if not f.endswith('.smali'):
+            continue
+
+        if (appPackage and appPackage in f) or '/android/support/multidex' in f:
+            continue
+
+        thisFucNum = smali_utils.get_smali_method_count(f, allRefs)
+        totalFucNum += thisFucNum
+
+        #print('%d # %d ==> %s' % (thisFucNum, currDexIndex, f))
+        #print('totalFucNum is %d' % totalFucNum)
+        if currFucNum + thisFucNum >= maxFuncNum:
+            currFucNum = thisFucNum
+            currDexIndex += 1
+            newDexPath = os.path.join(decompliePath, 'smali_classes%d' % currDexIndex)
+            os.makedirs(newDexPath)
+        else:
+            currFucNum += thisFucNum
+
+        if currDexIndex > 1:
+            newDexPath = os.path.join(decompliePath, 'smali_classes%d' % currDexIndex)
+            targetFile = newDexPath + f[len(smaliPath):]
+            file_utils.copyFile(f, targetFile, True)
+    return 0
+
+def changeVersion(game, sdk, subChannel, config):
+    '''
+    更改版本号
+    '''
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    yml = os.path.join(decompliePath, 'apktool.yml')
+
+    versionCode = None
+    versionName = None
+    targetSdkVersion = None
+    if 'versionCode' in config:
+        versionCode = config['versionCode']
+    if 'versionName' in config:
+        versionName = config['versionName']
+    if 'targetSdkVersion' in config:
+        targetSdkVersion = config['targetSdkVersion']
+
+    return file_utils.changeVersion(yml, versionCode, versionName, targetSdkVersion)
+
+def recomplie(game, sdk, subChannel, config):
+    '''
+    回编译
+    '''
+    print('recomplie apk...')
+    apktoolPath = file_utils.getApkToolPath()
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    outApk = file_utils.getOutApkPath(game, sdk, subChannel, config['cache'])
+
+    useAppt2 = ' --use-aapt2'
+    if config['aapt2disable']:
+        useAppt2 = ''
+
+    return file_utils.execJarCmd(apktoolPath, 'b -f "%s" -o "%s"%s' % (decompliePath, outApk, useAppt2))
+
+def alignApk(game, sdk, subChannel, config):
+    '''
+    对齐apk
+    '''
+    print('align apk...')
+    outApk = file_utils.getOutApkPath(game, sdk, subChannel, config['cache'])
+    alignApk = file_utils.getAlignApkPath(game, sdk, subChannel, config['cache'])
+    alignapkTool = file_utils.getAlignPath()
+    if os.path.exists(alignApk):
+        os.remove(alignApk)
+
+    ret = file_utils.getExecPermission(alignapkTool)
+    if ret:
+        return ret
+
+    # zipalign.exe -v -p 4 input.apk output.apk
+    return file_utils.execFormatCmd('"%s" -f -p 4 "%s" "%s"' % (alignapkTool, outApk, alignApk))
+
+def apksignerApk(game, sdk, subChannel, config):
+    '''
+    签名apk
+    '''
+    print('sign apk...')
+    path = os.path.join(file_utils.getCurrentPath(), 'keystore', 'key.json')
+    jsonText = file_utils.readFile(path)
+    signConfig = json.loads(jsonText)
+    keystore = {}
+    if game in signConfig:
+        if sdk in signConfig[game] and subChannel in signConfig[game][sdk]:
+            keystore = signConfig[game][sdk][subChannel]
+        else:
+            keystore = signConfig['default']
+    else:
+        keystore = signConfig['default']
+
+    print('storeFile is "%s"' % keystore['storeFile'])
+    
+    apksigner = file_utils.getApksignerPath()
+    alignApk = file_utils.getAlignApkPath(game, sdk, subChannel, config['cache'])
+    signedApk = file_utils.getSignApkPath(game, sdk, subChannel, config['cache'])
+    storeFile = os.path.join(file_utils.getCurrentPath(), 'keystore', keystore['storeFile'])
+
+    if 'outName' in config and 'outPath' in config:
+        if not os.path.exists(config['outPath']):
+            os.makedirs(config['outPath'])
+
+        signedApk = os.path.join(config['outPath'], config['outName'] + '.apk')
+    elif 'outName' in config:
+        signedApk = file_utils.getRenameApkPath(game, sdk, config['cache'], config['outName'])
+    
+    # java -jar apksigner.jar sign --ks key.jks --ks-key-alias releasekey --ks-pass pass:pp123456 --key-pass pass:pp123456 --out output.apk input.apk
+    v2disable = ''
+    if 'v2disable' in config and config['v2disable']:
+        v2disable = ' --v2-signing-enabled=false'
+        
+    return file_utils.execJarCmd(apksigner, 'sign%s --ks "%s" --ks-key-alias %s --ks-pass pass:%s --key-pass pass:%s --out "%s" "%s"' % (v2disable, storeFile, keystore['keyAlias'], keystore['storePassword'], keystore['keyPassword'], signedApk, alignApk))
+
+def addChannel(game, sdk, subChannel, config):
+    '''
+    添加渠道信息
+    '''
+    if 'v2disable' in config and config['v2disable']:
+        return 0
+    
+    walle = file_utils.getWallePath()
+    signedApk = file_utils.getSignApkPath(game, sdk, subChannel, config['cache'])
+    if 'outName' in config and 'outPath' in config:
+        signedApk = os.path.join(config['outPath'], config['outName'] + '.apk')
+    elif 'outName' in config:
+        signedApk = file_utils.getRenameApkPath(game, sdk, config['cache'], config['outName'])
+
+    properties = config['properties']
+
+    appid = ''
+    appkey = ''
+    if 'appid' in properties:
+        appid = properties['appid']
+    if 'appkey' in properties:
+        appkey = properties['appkey']
+
+    return file_utils.execJarCmd(walle, 'put -e version=%s,agent=%s,appid=%s,appkey=%s "%s" "%s"' % (config_utils_shanshen.getDate(), properties['agent'], appid, appkey, signedApk, signedApk))
+
+def clearTemp(game, sdk, subChannel, config):
+    '''
+    清空中间产生的文件
+    '''
+    print('clear temp...')
+    alignApk = file_utils.getAlignApkPath(game, sdk, subChannel, config['cache'])
+    outApk = file_utils.getOutApkPath(game, sdk, subChannel, config['cache'])
+    if os.path.exists(alignApk):
+        os.remove(alignApk)
+    if os.path.exists(outApk):
+        os.remove(outApk)
+
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    file_utils.deleteFolder(decompliePath)
+
+    print('clear temp end')
+
+def packConsoleInput():
+    '''
+    控制台打包
+    '''
+    if len(sys.argv) < 3:
+        print('argument is missing')
+        return 1
+
+    # 校验参数
+    game = sys.argv[1]
+    sdk = sys.argv[2]
+    # 可选参数,没有则默认打全部渠道
+    subChannel = None
+    if len(sys.argv) > 3:
+        subChannel = sys.argv[3]
+        
+    return packConsole(game, sdk, subChannel)
+
+def packConsole(game, sdk, subChannel):
+    '''
+    控制台打包
+    '''
+    if not os.path.exists(file_utils.getFullGameApk(game)):
+        print('game "%s" not exists' % game)
+        return 1
+    if not os.path.exists(file_utils.getFullSDKPath(sdk)):
+        print('sdk "%s" not exists' % sdk)
+        return 1
+
+    # 读取配置
+    channelPath = file_utils.getChannelPath(game, sdk)
+    configPath = os.path.join(channelPath, 'config.json')
+    if not os.path.exists(configPath):
+        print('%s not exists' % configPath)
+        return 1
+    
+    jsonText = file_utils.readFile(configPath)
+    config = json.loads(jsonText)
+
+    # 检查参数
+    if not config_utils_shanshen.checkConfig(config):
+        return 1
+
+    # 处理参数
+    config_utils_shanshen.replaceArgs(config)
+
+    successCount = 0
+    failureCount = 0
+    if type(config) == dict:
+        if subChannel is None or config['subChannel'] == subChannel:
+            ret = pack(game, sdk, config)
+            if ret:
+                failureCount += 1
+            else:
+                successCount += 1
+        else:
+            print('subChannel "%s" no found' % subChannel)
+            return 1
+    elif type(config) == list:
+        found = False
+        for itemConfig in config:
+            if subChannel is None or itemConfig['subChannel'] == subChannel:
+                found = True
+                ret = pack(game, sdk, itemConfig)
+                if ret:
+                    failureCount += 1
+                else:
+                    successCount += 1
+
+        if not found:
+            print('subChannel "%s" no found' % subChannel)
+            return 1
+
+    print('success %d, failure %d' % (successCount, failureCount))
+        
     return 0

+ 1322 - 1322
package_utils_yfsdk.py

@@ -1,1323 +1,1323 @@
-# 安卓游戏打包脚本
-# 1.用apktool解包
-# 2.复制res资源、assets资源、jniLib资源
-# 3.修改包名、app名、渠道文件
-# 4.添加app icon、合并AndroidManifest文件
-# 5.添加app启动图,修改AndroidManifest文件
-# 6.生成新的R文件
-# 7.将新的R文件编译,生成dex,再用baksmali生成smali,替换旧的R文件
-# 8.将jar资源打包成dex,再用baksmali生成smali,拷贝到smali目录下
-# 9.统计方法量,并分割dex(将smali文件拷贝到目录smali_classes2)
-# 10.用apktool回包
-# 11.重新签名
-import file_utils
-import xml_utils
-import smali_utils
-import config_utils
-import game_utils
-import os
-import os.path
-import json
-import sys
-import importlib
-import uuid
-import zipfile
-import time
-import datetime
-
-
-ignoreLauncher = ['jm_ysdk', 'jm_yijie', 'jm_quick', 'jm_beiyu', 'jm_xq_jrtt','jm_zy_ysdk']
-adaptApp = ['yjzx']
-startTime = ''
-
-def pack(game, sdk, config):
-    config['cache'] = uuid.uuid1()
-    subChannel = config['subChannel']
-    print('game = %s, sdk = %s, subChannel = %s, ...' % (game,sdk,subChannel))
-
-    # 解包
-    ret = decomplie(game, sdk, subChannel, config)
-    if ret:
-        return ret
-        # 删除旧代码
-    ret = removeOldCode(game, sdk, subChannel, config)
-    if ret:
-        return ret
-
-    # 复制app res资源
-    ret = copyAppRes(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 更改包名
-    if 'packageName' in config and config['packageName'] != '':
-        ret = changePackageName(game, sdk, subChannel, config)
-        if ret:
-            return ret
-    # 更改app名
-    if 'name' in config and config['name'] != '':
-        ret = changeAppName(game, sdk, subChannel, config)
-        if ret:
-            return ret
-    # 更改app icon
-    if config['changeIcon']:
-        ret = changeAppIcon(game, sdk, subChannel, config)
-        if ret:
-            return ret
-    # 添加启动图操作
-    if config['addLauncher']:
-        ret = addLauncher(game, sdk, subChannel, config)
-        if ret:
-            return ret
-
-    ret = copyIcon(game, sdk, subChannel, config)
-
-    ret = packJar(game, sdk, subChannel, config)
-    if ret:
-        return ret
-
-    # 增加配置文件
-    ret = createJmhyProperties(game, sdk, subChannel, config)
-    if ret:
-        return ret
-
-    # 更改版本号
-    ret = changeVersion(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 回编译
-    ret = recomplie(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 对齐apk
-    ret = alignApk(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 签名
-    ret = apksignerApk(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    # 清理产生的中间文件
-    if config['clearCache']:
-        clearTemp(game, sdk, subChannel, config)
-
-    endTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
-    d1 = datetime.datetime.strptime(endTime, '%Y-%m-%d %H:%M:%S')
-    d2 = datetime.datetime.strptime(startTime,  '%Y-%m-%d %H:%M:%S')
-    d = d1 - d2
-    print ('开始时间:' + startTime)
-    print ('结束时间:' + endTime)
-    print ('用时:{}'.format(config_utils.getTime(d.seconds)))
-    return 0
-
-def decomplie(game, sdk, subChannel, config):
-    '''
-    解包
-    '''
-    apktoolPath = file_utils.getApkToolPath()
-    gamePath = file_utils.getFullGameApk(game)
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-
-    if os.path.exists(decompliePath):
-        print('delete decomplie folder...')
-        file_utils.deleteFolder(decompliePath)
-
-    print('decomplie apk...')
-
-    return file_utils.execJarCmd(apktoolPath, 'd -f "%s" -o "%s"' % (gamePath, decompliePath))
-
-def removeOldCode(game, sdk, subChannel, config):
-    '''
-    删除旧代码
-    '''
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    codePath = os.path.join(decompliePath, 'smali', 'com', 'Jcat', 'Adsdk')
-    #file_utils.deleteFolder(codePath)
-    allFiles = []
-    allFiles = file_utils.list_files(codePath, allFiles)
-    for f in allFiles:
-        fpath, fname = os.path.split(f)  #分离文件名和路径
-        if fname == 'R.smali' or fname.startswith('R$'):
-            continue
-        os.remove(f)
-        #print('remove %s' % f)
-    return 0
-
-def copyRes(game, sdk, subChannel, config):
-    '''
-    复制res资源
-    '''
-    # 拷贝sdk资源
-    print('copy res...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    sdkPath = file_utils.getFullSDKPath(sdk)
-    resPath = os.path.join(sdkPath, 'res')
-    decomplieResPath = file_utils.getFullPath(decompliePath, 'res')
-
-    for d in os.listdir(resPath):
-        copyResWithType(resPath, decomplieResPath, d)
-
-    # 拷贝assets
-    print('copy assets...')
-    assetsPath = file_utils.getFullPath(sdkPath, 'assets')
-    decomplieAssetsPath = file_utils.getFullPath(decompliePath, 'assets')
-    if os.path.exists(assetsPath):
-        ret = file_utils.copyFileAllDir(assetsPath, decomplieAssetsPath)
-        if ret:
-            return ret
-
-    # 拷贝jniLib
-    print('copy jniLibs...')
-    jniPath = file_utils.getFullPath(sdkPath, 'jniLibs')
-    decomplieJniPath = file_utils.getFullPath(decompliePath, 'lib')
-    abiFilters = []
-    if os.path.exists(decomplieJniPath):
-        for abi in os.listdir(decomplieJniPath):
-            if abi == 'armeabi-v7a' or abi == 'armeabi':
-                abiFilters.append(abi)
-    else:
-        abiFilters = ['armeabi-v7a']
-
-    if os.path.exists(jniPath):
-        ret = file_utils.copyFileAllDir(jniPath, decomplieJniPath, False, abiFilters)
-        if ret:
-            return ret
-    return 0
-
-def mergeDrawableRes(game, sdk, subChannel, config):
-    '''
-    合并Drawable-v4目录
-    '''
-    print('merge drawable path...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    resPath = os.path.join(decompliePath, 'res')
-
-    for path in os.listdir(resPath):
-        print('res path %s' % path)
-        if (path.startswith('drawable') or path.startswith('mipmap')) and path.endswith('-v4'):
-            print('merge path %s' % path)
-            v4DrawablePath = os.path.join(resPath, path)
-            drawablePath = os.path.join(resPath, path[:-3])
-
-            if os.path.exists(drawablePath):
-                ret = file_utils.copyFileAllDir(v4DrawablePath, drawablePath, True)
-                if ret:
-                    return ret
-            else:
-                os.rename(v4DrawablePath, drawablePath)
-    return 0
-
-def removeSameRes(game, sdk, subChannel, config):
-    '''
-    移除相同的资源
-    '''
-    # 读取sdk的资源
-    print('remove same res...')
-    sdkPath = file_utils.getFullSDKPath(sdk)
-    sdkResPath = os.path.join(sdkPath, 'res')
-    resList = []
-    for path in os.listdir(sdkResPath):
-        if not path.startswith('values'):
-            continue
-        absPath = os.path.join(sdkResPath, path)
-        for resFile in os.listdir(absPath):
-            '''if not resFile.startswith('jm_'):
-                continue'''
-            if resFile.endswith('.DS_Store'):
-                continue
-            #print('readAllRes -- > ' + os.path.join(absPath, resFile))
-
-            resList = xml_utils.readAllRes(os.path.join(absPath, resFile), resList)
-
-    if len(resList) == 0:
-        print('no same res found')
-        return 0
-
-    # 移除相同的资源
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    resPath = os.path.join(decompliePath, 'res')
-    for path in os.listdir(resPath):
-        if not path.startswith('values'):
-            continue
-
-        absPath = os.path.join(resPath, path)
-        for resFile in os.listdir(absPath):
-            xml_utils.removeSameRes(os.path.join(absPath, resFile), resList)
-
-    return 0
-
-def mergeManifestRes(game, sdk, subChannel, config):
-    '''
-    合并主文件
-    '''
-    print('merge AndroidManifest...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    sdkPath = file_utils.getFullSDKPath(sdk)
-    libManifest = file_utils.getFullPath(sdkPath, 'manifest.xml')
-    return xml_utils.mergeManifestRes(manifest, libManifest)
-
-def copyAppRes(game, sdk, subChannel, config):
-    '''
-    拷贝app的资源,比如app icon、启动图等
-    '''
-    channelPath = file_utils.getSubChannelPath(game, sdk, subChannel)
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-
-    # assets
-    print('copy assets...')
-    #适配一剑斩仙
-    if game in adaptApp:
-        print('适配一剑斩仙...')
-        decomplieAssetsPath = file_utils.getFullPath(decompliePath, 'assets')
-        skinZipPath = os.path.join(decomplieAssetsPath, 'skin.zip')
-        skinPath = os.path.join(decomplieAssetsPath, 'skin')
-        if os.path.exists(skinZipPath):
-            with zipfile.ZipFile(skinZipPath) as zf:
-                zf.extractall(decomplieAssetsPath)
-                print('create unzip skin' )
-            assetsPath = file_utils.getFullPath(channelPath, 'assets')
-            decomplieAssetsPath = file_utils.getFullPath(decompliePath, 'assets')
-            if os.path.exists(assetsPath):
-                ret = file_utils.copyFileAllDir(assetsPath, decomplieAssetsPath)
-            with zipfile.ZipFile(skinZipPath, 'w') as z:
-                for root, dirs, files in os.walk(skinPath):
-                    for single_file in files:
-                        filepath = os.path.join(root, single_file)
-                        print ('create zip ---> ' + filepath)
-                        temPath = 'skin/' + single_file
-                        z.write(filepath, temPath)
-            z.close()
-        else:
-            print('normal copy assets...')
-            assetsPath = file_utils.getFullPath(channelPath, 'assets')
-            decomplieAssetsPath = file_utils.getFullPath(decompliePath, 'assets')
-            if os.path.exists(assetsPath):
-                ret = file_utils.copyFileAllDir(assetsPath, decomplieAssetsPath)
-                if ret:
-                    return ret
-    else:
-        print('normal copy assets...')
-        assetsPath = file_utils.getFullPath(channelPath, 'assets')
-        decomplieAssetsPath = file_utils.getFullPath(decompliePath, 'assets')
-        if os.path.exists(assetsPath):
-            ret = file_utils.copyFileAllDir(assetsPath, decomplieAssetsPath)
-            if ret:
-                return ret
-
-    # icon
-    print('copy icon...')
-    ret = copyAppResWithType(decompliePath, channelPath, 'icon')
-    if ret:
-        return ret
-    # 启动图
-    print('copy splash...')
-    ret = copyAppResWithType(decompliePath, channelPath, 'splash')
-    if ret:
-        return ret
-    # 其他图片
-    print('copy image...')
-    ret = copyAppResWithType(decompliePath, channelPath, 'image')
-    if ret:
-        return ret
-    return 0
-    
-def copyAppResWithType(decompliePath, channelPath, typeName):
-    decomplieResPath = os.path.join(decompliePath, 'res')
-    iconPath = os.path.join(channelPath, typeName)
-    if not os.path.exists(iconPath):
-        print('dir "%s" not exists' % iconPath)
-        return 0
-    for d in os.listdir(iconPath):
-        ret = copyResWithType(iconPath, decomplieResPath, d)
-        if ret:
-            return ret
-
-    return 0
-
-def copyResWithType(resPath, decomplieResPath, typeName):
-    # appt的打包目录会带-v4后缀
-    resDir = os.path.join(resPath, typeName)
-    target = os.path.join(decomplieResPath, typeName)
-    targetV4 = os.path.join(decomplieResPath, typeName + '-v4')
-    if not os.path.exists(target) and not os.path.exists(targetV4):
-        os.makedirs(target)
-        return file_utils.copyFileAllDir(resDir, target, False)
-    elif not os.path.exists(target):
-        return file_utils.copyFileAllDir(resDir, targetV4, False)
-    else:
-        return file_utils.copyFileAllDir(resDir, target, False)
-
-def removeNoSupportAttr(game, sdk, subChannel, config):
-    '''
-    删除一些不支持的属性
-    '''
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    
-    xml_utils.removeRootAttr(manifest, 'compileSdkVersion')
-    xml_utils.removeRootAttr(manifest, 'compileSdkVersionCodename')
-    
-    return 0
-
-def fixUnSupportConfig(game, sdk, subChannel, config):
-    '''
-    删除一些不支持的配置
-    '''
-    # 检查minSdkVersion
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    yml = os.path.join(decompliePath, 'apktool.yml')
-
-    minSdkVersion = 15
-    file_utils.changeMinSdkVersion(yml, minSdkVersion)
-
-    resPath = os.path.join(decompliePath, 'res')
-
-    tag = '-v'
-    for res in os.listdir(resPath):
-        #print('res = ' + res)
-        if res.startswith('values') and tag in res:
-            start = res.index(tag)
-            version = res[start+len(tag):]
-            if not version.isdigit():
-                continue
-            
-            version = int(version)
-            print('version = %d' % version)
-            if version < minSdkVersion:
-                unSopportPath = os.path.join(resPath, res)
-                print('unSopportPath = ' + unSopportPath)
-                file_utils.deleteFolder(unSopportPath)
-                print('deleteFolder = ' + unSopportPath)
-    
-    return 0
-
-def changePackageName(game, sdk, subChannel, config):
-    '''
-    更改包名
-    '''
-    # 全局替换AndroidManifest里面的包名
-    newPackageName = config['packageName']
-
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    packageName = xml_utils.getPackageName(manifest)
-    
-    xml_utils.changePackageName(manifest, newPackageName)
-    print('change package name %s --> %s' % (packageName, newPackageName))
-    return 0
-
-def changeAppName(game, sdk, subChannel, config):
-    '''
-    更改app名
-    '''
-    # 生成string.xml文件
-    name = config['name']
-
-    resName = 'common_sdk_name'
-    if 'outName' in config:
-        resName = resName + '_' + config['outName']
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    stringFile = os.path.join(decompliePath, 'res', 'values', 'sdk_strings_temp.xml')
-    content = '<?xml version="1.0" encoding="utf-8"?><resources><string name="%s">%s</string></resources>' % (resName, name)
-    file_utils.createFile(stringFile, content)
-
-    # 修改主文件的app名的值
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    xml_utils.changeAppName(manifest, '@string/%s' % resName)
-    print('change app name %s' % name)
-    return 0
-
-def changeAppIcon(game, sdk, subChannel, config):
-    '''
-    更改app icon
-    '''
-    print('change app icon...')
-    resName = 'common_sdk_icon'
-
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    xml_utils.changeAppIcon(manifest, '@mipmap/%s' % resName)
-    return 0
-
-def addMetaData(game, sdk, subChannel, config):
-    '''
-    添加meta-data
-    '''
-    if 'metaData' not in config:
-        return 0
-
-    print('add meta-data...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    xml_utils.addMetaData(manifest, config['metaData'])
-    return 0
-
-def addConfig(game, sdk, subChannel, config):
-    '''
-    添加config.json
-    '''
-    if 'configData' not in config:
-        return 0
-
-    print('add jmad.properties...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    configJson = os.path.join(decompliePath, 'assets', 'jmad.properties')
-    jsonText = json.dumps(config['configData'], ensure_ascii=False)
-    file_utils.createFile(configJson, jsonText)
-    return 0
-
-def createJmhyProperties(game, sdk, subChannel, config):
-    '''
-    创建jmhy.properties
-    '''
-    print('create jmad.properties...')
-    propValue = config['properties']
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    properties = os.path.join(decompliePath, 'assets', 'jmad.properties')
-    content = ''
-    for key in propValue:
-        content = '%s%s=%s\n' % (content, key, propValue[key])
-    file_utils.createFile(properties, content)
-    return 0
-
-def changePlaceholders(game, sdk, subChannel, config):
-    '''
-    处理掉占位符
-    '''
-    if 'placeholders' not in config:
-        return 0
-
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-
-    placeholders = config['placeholders']
-    for placeholder in placeholders:
-        oldText = '${%s}' % placeholder
-        newText = placeholders[placeholder]
-        print('change placeholder %s -> %s' % (oldText, newText))
-        file_utils.replaceContent(manifest, oldText, newText)
-
-    return 0
-
-def addLauncher(game, sdk, subChannel, config):
-    '''
-    添加启动图
-    '''
-    # ysdk的特殊处理
-    if sdk in ignoreLauncher:
-        return 0
-
-    channelPath = file_utils.getSubChannelPath(game, sdk, subChannel)
-    splashPath = os.path.join(channelPath, 'splash')
-    if len(os.listdir(splashPath)) == 0:
-        print('dir splash is empty')
-        return 0
-
-    print('add launcher...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    activity = xml_utils.getLauncherActivityName(manifest)
-    if activity == 'com.jmhy.sdk.template.LauncherActivity':
-        print('add launcher already exist...')
-        return 1
-    # 添加关联资源
-    internalPath = file_utils.getFullInternalPath()
-    ret = copyAppResWithType(decompliePath, internalPath, 'launcher_res')
-    if ret:
-        return ret
-
-    # 拷贝代码
-    print('copy launcher code...')
-    codePath = os.path.join(internalPath, 'launcher_code', 'smali')
-    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
-    ret = file_utils.copyFileAllDir(codePath, smaliPath)
-    if ret:
-        return ret
-
-    # 修改主文件信息
-    print('change launcher config...')
-    
-    orientation = xml_utils.getScreenOrientation(manifest)
-    activity = xml_utils.removeLauncherActivity(manifest)
-    xml_utils.addLauncherActivity(manifest, orientation, 'com.jmhy.sdk.template.LauncherActivity')
-
-    # 修改跳转的
-    launcherActivity = os.path.join(decompliePath, 'smali', 'com', 'jmhy', 'sdk', 'template', 'LauncherActivity.smali')
-    file_utils.replaceContent(launcherActivity, '{class}', activity)
-
-    print('change launcher %s to %s' % (activity, 'com.jmhy.sdk.template.LauncherActivity'))
-
-    # config['oldLauncher'] = activity
-
-    if 'launcherTime' in config:
-        timeHex = formatHex(config['launcherTime'])
-        file_utils.replaceContent(launcherActivity, '0x0BB8', timeHex)
-
-    return 0
-
-def addMoreIcon(game, sdk, subChannel, config):
-    '''
-    添加多个图标
-    '''
-    print('add more icon support...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    icon = '@mipmap/common_sdk_icon'
-    if not config['changeIcon']:
-        manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-        icon = xml_utils.getApplicationAttr(manifest, 'icon')
-
-    switchIcon = icon
-    if config['switchIcon']:
-        switchIcon = '@mipmap/common_sdk_icon2'
-
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    return xml_utils.addMoreIcon(manifest, icon, switchIcon)
-
-def copyIcon(game, sdk, subChannel, config):
-    '''
-    复制icon到res ,一键登录使用
-    '''
-    if config['changeIcon']:
-        decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-        decomplieResPath = file_utils.getFullPath(decompliePath, 'res')
-        iconPath = os.path.join(decomplieResPath, 'mipmap-xhdpi', 'common_sdk_icon.png')
-        desPath = os.path.join(decomplieResPath, 'drawable-hdpi', 'jm_cmcc_icon.png')
-        file_utils.copyFile(iconPath, desPath)
-    else:
-        decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-        decomplieResPath = file_utils.getFullPath(decompliePath, 'res')
-        desPath = os.path.join(decomplieResPath, 'drawable-hdpi', 'jm_cmcc_icon.png')
-
-        manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-        icon = xml_utils.getApplicationAttr(manifest, 'icon')
-        tag = icon[1:].split("/")
-        if len(tag) < 1:
-            return
-        hdpi = ['-xhdpi', '-xxhdpi', '-xxxhdpi']
-        for h in hdpi:
-            p1 = '%s%s' % (tag[0],h)
-            png = tag[1] + ".png"
-            iconPath = os.path.join(decomplieResPath, p1, png)
-            if os.path.exists(iconPath):
-                print ('iconPath = ' + iconPath)
-                file_utils.copyFile(iconPath, desPath)
-                break
-
-
-def formatHex(millisecond):
-    '''
-    将毫秒转为16进制,4位格式
-    '''
-    timeHex = str(hex(millisecond)).upper()
-    timeHex = timeHex[2:]
-    formatHex = ''
-    if len(timeHex) == 3:
-        formatHex = '0x0' + timeHexaddLauncher
-    elif len(timeHex) == 4:
-        formatHex = '0x' + timeHex
-    else:
-        formatHex = '0x0BB8'
-    return formatHex
-
-def doSDKPostScript(game, sdk, config):
-    '''
-    执行sdk相关特殊处理脚本
-    '''
-    sdkPath = file_utils.getFullSDKPath(sdk)
-    scriptPath = os.path.join(sdkPath, 'script')
-    targetScript = os.path.join(scriptPath, 'sdk_script.py')
-    if not os.path.exists(targetScript):
-        print('sdk_script no exists')
-        return 0
-
-    print('doSDKPostScript...')
-    sys.path.append(scriptPath)
-
-    module = importlib.import_module('sdk_script')
-    ret = module.execute(game, sdk, config)
-
-    sys.path.remove(scriptPath)
-
-    return ret
-
-def doGamePostScript(game, sdk, config):
-    '''
-    执行游戏相关特殊处理脚本
-    '''
-    channelPath = file_utils.getFullGamePath(game)
-    scriptPath = os.path.join(channelPath, 'script')
-    targetScript = os.path.join(scriptPath, 'game_script.py')
-    if not os.path.exists(targetScript):
-        print('game_script no exists')
-        return 0
-
-    print('doGamePostScript...')
-    sys.path.append(scriptPath)
-
-    module = importlib.import_module('game_script')
-    ret = module.execute(game, sdk, config)
-
-    sys.path.remove(scriptPath)
-
-    return ret
-
-def addLogSdk(game, sdk, subChannel, config, logSdk):
-    # 拷贝jniLibs
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    sdkPath = file_utils.getFullLogSDKPath(logSdk)
-
-    print('copy log jniLibs...')
-    jniPath = file_utils.getFullPath(sdkPath, 'jniLibs')
-    decomplieJniPath = file_utils.getFullPath(decompliePath, 'lib')
-    abiFilters = []
-    if os.path.exists(decomplieJniPath):
-        for abi in os.listdir(decomplieJniPath):
-            if abi == 'armeabi-v7a' or abi == 'armeabi':
-                abiFilters.append(abi)
-    else:
-        abiFilters = ['armeabi-v7a']
-
-    if os.path.exists(jniPath):
-        ret = file_utils.copyFileAllDir(jniPath, decomplieJniPath, False, abiFilters)
-        if ret:
-            return ret
-    
-    print('merge log AndroidManifest...')
-    libManifest = file_utils.getFullPath(sdkPath, 'manifest.xml')
-    if os.path.exists(libManifest):
-        manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-        ret = xml_utils.mergeManifestRes(manifest, libManifest)
-        if ret:
-            return ret
-
-    return packLogJar(game, sdk, subChannel, config, logSdk)
-
-def generateNewRFile(game, sdk, subChannel, config):
-    '''
-    生成新的R文件
-    '''
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    androidPlatforms = file_utils.getAndroidCompileToolPath()
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    decomplieResPath = file_utils.getFullPath(decompliePath, 'res')
-    compliePath = file_utils.getFullPath(decompliePath, 'gen')
-
-    if not os.path.exists(compliePath):
-        os.makedirs(compliePath)
-
-    # 生成R文件
-    print('生成R文件 ...')
-    if config['aapt2disable']:
-        aapt = file_utils.getAAPTPath()
-        ret = file_utils.getExecPermission(aapt)
-        if ret:
-            return ret
-        createRCmd = '"%s" p -f -m -J "%s" -S "%s" -I "%s" -M "%s"' % (aapt, compliePath, decomplieResPath, androidPlatforms, manifest)
-        ret = file_utils.execFormatCmd(createRCmd)
-        if ret:
-            return ret
-    else:
-        # compile
-        aapt = file_utils.getAAPT2Path()
-        ret = file_utils.getExecPermission(aapt)
-        if ret:
-            return ret
-
-        print('compiled res ...')
-        complieResPath = os.path.join(compliePath, 'compiled')
-        complieResCmd = '"%s" compile --dir "%s" -o "%s"' % (aapt, decomplieResPath, complieResPath)
-        file_utils.execFormatCmd(complieResCmd)
-
-        # unzip
-        print('unzip compiled res ...')
-        unzipResPath = os.path.join(compliePath, 'aapt2_res')
-        with zipfile.ZipFile(complieResPath) as zf:
-            zf.extractall(unzipResPath)
-            print('create unzip %s' % unzipResPath)
-
-        # link
-        print('link res ...')
-        outApk = os.path.join(compliePath, 'res.apk')
-        linkResCmd = '"%s" link -o "%s" -I "%s" --manifest "%s" --java "%s" --auto-add-overlay' % (aapt, outApk, androidPlatforms, manifest, compliePath)
-        for filename in os.listdir(unzipResPath):
-            linkResCmd += ' %s' % filename
-        print('link cmd len is %s' % len(linkResCmd))
-        ret = file_utils.execFormatCmd(linkResCmd, unzipResPath)
-        if ret:
-            return ret
-
-    # 编译R文件
-    print('complie R.java ...')
-    packageName = xml_utils.getPackageName(manifest)
-    packagePath = file_utils.getPackagePath(compliePath, packageName)
-    RSourceFile = os.path.join(packagePath, 'R.java')
-    complieRCmd = 'javac -source 1.8 -target 1.8 -encoding UTF-8 "%s"' % RSourceFile
-    ret = file_utils.execFormatCmd(complieRCmd)
-    if ret:
-        return ret
-
-    # 生成dex
-    print('dex R.class ...')
-    outDex = os.path.join(compliePath, 'classes.dex')
-    if config['aapt2disable']:
-        dx = file_utils.getDxPath()
-        dexCmd = '--dex --no-warning --output="%s" "%s"' % (outDex, compliePath)
-    else:
-        dx = file_utils.getD8Path()
-        clazz = os.path.join(packagePath, '*.class')
-        dexCmd = '--lib "%s" --output "%s" %s' % (androidPlatforms, compliePath, clazz)
-    ret = file_utils.execJarCmd(dx, dexCmd)
-    if ret:
-        return ret
-
-    # 反向dex生成smali
-    # 存放在out目录
-    print('baksmali classes.dex ...')
-    baksmaliPath = file_utils.getBaksmaliPath()
-    outPath = file_utils.getFullPath(decompliePath, 'out')
-
-    ret = file_utils.execJarCmd(baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
-    if ret:
-        return ret
-
-    # 将生成的文件拷贝到目标目录
-    print('copy R.smali ...')
-    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
-    file_utils.copyFileAllDir(outPath, smaliPath)
-    return 0
-
-def packJar(game, sdk, subChannel, config):
-    '''
-    打包所有的jar
-    '''
-    splitDex = config['splitDex']
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    outPath = file_utils.getFullPath(decompliePath, 'gen')
-
-    if not os.path.exists(outPath):
-        os.makedirs(outPath)
-    if config['aapt2disable']:
-        dx = file_utils.getDxPath()
-        dexCmd = '--dex --multi-dex --no-warning --output="%s"' % outPath
-    else:
-        dx = file_utils.getD8Path()
-        androidPlatforms = file_utils.getAndroidCompileToolPath()
-        dexCmd = '--lib "%s" --output "%s"' % (androidPlatforms, outPath)
-
-    # 找到所有lib依赖
-    sdkPath = file_utils.getFullSDKPath(sdk)
-    print('sdkpath --> ' + sdkPath)
-    libs = os.path.join(sdkPath, 'libs')
-    libConfig = os.path.join(libs, 'config.json')
-
-    # 存在配置文件
-    if os.path.exists(libConfig):
-        jsonText = file_utils.readFile(libConfig)
-        libConf = json.loads(jsonText)
-        if 'libConfig' in config and config['libConfig'] in libConf:
-            conf = config['libConfig']
-            libList = libConf[conf]
-            for jar in libList:
-                dexCmd += ' ' + os.path.join(libs, jar)
-        elif 'default' in libConf:
-            libList = libConf['default']
-            for jar in libList:
-                dexCmd += ' ' + os.path.join(libs, jar)
-        else:
-            for jar in os.listdir(libs):
-                if not jar.endswith('.jar'):
-                    continue
-                dexCmd += ' ' + os.path.join(libs, jar)
-    else:
-        for jar in os.listdir(libs):
-            if not jar.endswith('.jar'):
-                continue
-            dexCmd += ' ' + os.path.join(libs, jar)
-
-    # multidex.jar
-    if splitDex:
-        dexCmd += ' ' + file_utils.getMultiDexPath()
-
-    # sdk实现类
-    print('packageing all jar ...')
-    #dexCmd += ' ' + os.path.join(sdkPath, '%s.jar' % sdk)
-    ret = file_utils.execJarCmd(dx, dexCmd)
-    if ret:
-        return ret
-
-    # 反向dex生成smali
-    # 存放在out目录
-    print('baksmali classes.dex ...')
-    outDex = os.path.join(outPath, 'classes.dex')
-    baksmaliPath = file_utils.getBaksmaliPath()
-    outPath = file_utils.getFullPath(decompliePath, 'out')
-    
-    ret = file_utils.execJarCmd(baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
-    if ret:
-        return ret
-
-    # 将生成的文件拷贝到目标目录
-    print('copy all smali ...')
-    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
-    ret = file_utils.copyFileAllDir(outPath, smaliPath, True)
-    if ret:
-        return ret
-
-    return 0
-
-def packLogJar(game, sdk, subChannel, config, logSdk):
-    '''
-    打包Log jar
-    '''
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    outPath = file_utils.getFullPath(decompliePath, 'gen')
-
-    if not os.path.exists(outPath):
-        os.makedirs(outPath)
-
-    if config['aapt2disable']:
-        dx = file_utils.getDxPath()
-        dexCmd = '--dex --multi-dex --no-warning --output="%s"' % outPath
-    else:
-        dx = file_utils.getD8Path()
-        androidPlatforms = file_utils.getAndroidCompileToolPath()
-        dexCmd = '--lib "%s" --output "%s"' % (androidPlatforms, outPath)
-
-    # 找到所有lib依赖
-    sdkPath = file_utils.getFullLogSDKPath(logSdk)
-    libs = os.path.join(sdkPath, 'libs')
-    libConfig = os.path.join(libs, 'config.json')
-
-    # 存在配置文件
-    if os.path.exists(libConfig):
-        jsonText = file_utils.readFile(libConfig)
-        libList = json.loads(jsonText)
-        for jar in libList:
-            if not jar.endswith('.jar'):
-                continue
-            dexCmd += ' ' + os.path.join(libs, jar)
-    else:
-        for jar in os.listdir(libs):
-            if not jar.endswith('.jar'):
-                continue
-            dexCmd += ' ' + os.path.join(libs, jar)
-
-    # sdk实现类
-    print('packageing all log jar ...')
-    dexCmd += ' ' + os.path.join(sdkPath, '%s.jar' % logSdk)
-    ret = file_utils.execJarCmd(dx, dexCmd)
-    if ret:
-        return ret
-
-    # 反向dex生成smali
-    # 存放在out目录
-    print('baksmali classes.dex ...')
-    outDex = os.path.join(outPath, 'classes.dex')
-    baksmaliPath = file_utils.getBaksmaliPath()
-    outPath = file_utils.getFullPath(decompliePath, 'out')
-    
-    ret = file_utils.execJarCmd(baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
-    if ret:
-        return ret
-
-    # 将生成的文件拷贝到目标目录
-    print('copy all log smali ...')
-    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
-    ret = file_utils.copyFileAllDir(outPath, smaliPath, True)
-    if ret:
-        return ret
-
-    return 0
-
-
-
-
-def packReativeJar(game, sdk, subChannel, config, logSdk):
-    '''
-    打包Reative jar
-    '''
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    outPath = file_utils.getFullPath(decompliePath, 'gen')
-
-    if not os.path.exists(outPath):
-        os.makedirs(outPath)
-
-    if config['aapt2disable']:
-        dx = file_utils.getDxPath()
-        dexCmd = '--dex --multi-dex --no-warning --output="%s"' % outPath
-    else:
-        dx = file_utils.getD8Path()
-        androidPlatforms = file_utils.getAndroidCompileToolPath()
-        dexCmd = '--lib "%s" --output "%s"' % (androidPlatforms, outPath)
-
-    # 找到所有lib依赖
-    sdkPath = file_utils.getFullLogSDKPath(logSdk)
-    libs = os.path.join(sdkPath, 'libs')
-    libConfig = os.path.join(libs, 'config.json')
-
-    # 存在配置文件
-    if os.path.exists(libConfig):
-        jsonText = file_utils.readFile(libConfig)
-        libList = json.loads(jsonText)
-        for jar in libList:
-            if not jar.endswith('.jar'):
-                continue
-            dexCmd += ' ' + os.path.join(libs, jar)
-    else:
-        for jar in os.listdir(libs):
-            if not jar.endswith('.jar'):
-                continue
-            dexCmd += ' ' + os.path.join(libs, jar)
-
-    # sdk实现类
-    print('packageing all log jar ...')
-    dexCmd += ' ' + os.path.join(sdkPath, '%s.jar' % logSdk)
-    ret = file_utils.execJarCmd(dx, dexCmd)
-    if ret:
-        return ret
-
-    # 反向dex生成smali
-    # 存放在out目录
-    print('baksmali classes.dex ...')
-    outDex = os.path.join(outPath, 'classes.dex')
-    baksmaliPath = file_utils.getBaksmaliPath()
-    outPath = file_utils.getFullPath(decompliePath, 'out')
-
-    ret = file_utils.execJarCmd(baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
-    if ret:
-        return ret
-
-    # 将生成的文件拷贝到目标目录
-    print('copy all log smali ...')
-    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
-    ret = file_utils.copyFileAllDir(outPath, smaliPath, True)
-    if ret:
-        return ret
-
-    return 0
-
-def splitDex(game, sdk, subChannel, config):
-    '''
-    分割dex
-    '''
-    # 判断是否已经存在application
-    # 存在,则往原application添加内容
-    # 不存在,则拷贝一个默认的android.support.multidex.MultiDexApplication
-    print('add MultiDex support...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    application = xml_utils.getApplicationAttr(manifest, 'name')
-    if application is None:
-        ret = xml_utils.changeApplicationAttr(manifest, 'name', 'android.support.multidex.MultiDexApplication')
-        if ret:
-            return ret
-    else:
-        smaliPath = os.path.join(decompliePath, 'smali')
-        applicationFile = file_utils.getPackagePath(smaliPath, application)
-        applicationFile += '.smali'
-        ret = changeApplicationDex(applicationFile)
-        if ret:
-            return ret
-
-    return splitSmali(game, sdk, subChannel, config, application)
-
-def changeApplicationDex(file):
-    '''
-    修改application的smali文件,增加MultiDex操作
-    '''
-    index = file_utils.getApplicationSmaliIndex(file)
-    file_utils.insertApplicationSmali(file, index)
-    return 0
-
-def splitSmali(game, sdk, subChannel, config, application):
-    '''
-    如果函数上限超过限制,自动拆分smali,以便生成多个dex文件
-    '''
-    print('splitSmali...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    smaliPath = os.path.join(decompliePath, 'smali')
-
-    appPackage = None
-    if application:
-        appPackage = application[:application.rfind('.')]
-        appPackage = appPackage.replace('.', '/')
-
-    allFiles = []
-    allFiles = file_utils.list_files(smaliPath, allFiles)
-    
-    #print('file count is %d' % len(allFiles))
-
-    #maxFuncNum = 65535
-    # 留一点空间,防止计算误差
-    maxFuncNum = 64000
-    currFucNum = 0
-    totalFucNum = 0
-
-    currDexIndex = 1
-
-    allRefs = []
-
-    #保证Application等类在第一个classex.dex文件中
-    for f in allFiles:
-        f = f.replace('\\', '/')
-        if (appPackage and appPackage in f) or '/android/support/multidex' in f:
-            currFucNum += smali_utils.get_smali_method_count(f, allRefs)
-
-    totalFucNum = currFucNum
-    for f in allFiles:
-        f = f.replace('\\', '/')
-        if not f.endswith('.smali'):
-            continue
-
-        if (appPackage and appPackage in f) or '/android/support/multidex' in f:
-            continue
-
-        thisFucNum = smali_utils.get_smali_method_count(f, allRefs)
-        totalFucNum += thisFucNum
-
-        #print('%d # %d ==> %s' % (thisFucNum, currDexIndex, f))
-        #print('totalFucNum is %d' % totalFucNum)
-        if currFucNum + thisFucNum >= maxFuncNum:
-            currFucNum = thisFucNum
-            currDexIndex += 1
-            newDexPath = os.path.join(decompliePath, 'smali_classes%d' % currDexIndex)
-            os.makedirs(newDexPath)
-        else:
-            currFucNum += thisFucNum
-
-        if currDexIndex > 1:
-            newDexPath = os.path.join(decompliePath, 'smali_classes%d' % currDexIndex)
-            targetFile = newDexPath + f[len(smaliPath):]
-            file_utils.copyFile(f, targetFile, True)
-    return 0
-
-def changeVersion(game, sdk, subChannel, config):
-    '''
-    更改版本号
-    '''
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    yml = os.path.join(decompliePath, 'apktool.yml')
-
-    versionCode = None
-    versionName = None
-    targetSdkVersion = None
-    if 'versionCode' in config:
-        versionCode = config['versionCode']
-    if 'versionName' in config:
-        versionName = config['versionName']
-    if 'targetSdkVersion' in config:
-        targetSdkVersion = config['targetSdkVersion']
-    else:
-        targetSdkVersion = 26
-    print('changeVersion versionCode=%s,versionName=%s,targetSdkVersion=%s' % (versionCode, versionName, targetSdkVersion))
-
-    return file_utils.changeVersion(yml, versionCode, versionName, targetSdkVersion)
-
-def recomplie(game, sdk, subChannel, config):
-    '''
-    回编译
-    '''
-    print('recomplie apk...')
-    apktoolPath = file_utils.getApkToolPath()
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    outApk = file_utils.getOutApkPath(game, sdk, subChannel, config['cache'])
-
-    useAppt2 = ' --use-aapt2'
-    if config['aapt2disable']:
-        useAppt2 = ''
-
-    return file_utils.execJarCmd(apktoolPath, 'b -f "%s" -o "%s"%s' % (decompliePath, outApk, useAppt2))
-
-def alignApk(game, sdk, subChannel, config):
-    '''
-    对齐apk
-    '''
-    print('align apk...')
-    outApk = file_utils.getOutApkPath(game, sdk, subChannel, config['cache'])
-    alignApk = file_utils.getAlignApkPath(game, sdk, subChannel, config['cache'])
-    alignapkTool = file_utils.getAlignPath()
-    if os.path.exists(alignApk):
-        os.remove(alignApk)
-
-    ret = file_utils.getExecPermission(alignapkTool)
-    if ret:
-        return ret
-
-    # zipalign.exe -v -p 4 input.apk output.apk
-    return file_utils.execFormatCmd('"%s" -f -p 4 "%s" "%s"' % (alignapkTool, outApk, alignApk))
-
-def apksignerApk(game, sdk, subChannel, config):
-    '''
-    签名apk
-    '''
-    print('sign apk...')
-    print('game = %s, sdk = %s, subChannel = %s, ...' % (game,sdk,subChannel))
-    path = os.path.join(file_utils.getCurrentPath(), 'keystore', 'key.json')
-    jsonText = file_utils.readFile(path)
-    signConfig = json.loads(jsonText)
-    keystore = {}
-    for key in signConfig.keys():
-        print(key)
-        if game.find(key) > -1:
-            if sdk in signConfig[key]:
-                keystore = signConfig[key][sdk]
-            else:
-                keystore = signConfig['default']
-        else:
-            keystore = signConfig['default']
-
-    # if game in signConfig:
-    #     if sdk in signConfig[game]:
-    #         keystore = signConfig[game][sdk]
-    #     else:
-    #         keystore = signConfig['default']
-    # else:
-    #     keystore = signConfig['default']
-
-    print('storeFile is "%s"' % keystore['storeFile'])
-    
-    apksigner = file_utils.getApksignerPath()
-    alignApk = file_utils.getAlignApkPath(game, sdk, subChannel, config['cache'])
-    signedApk = file_utils.getSignApkPath(game, sdk, subChannel, config['cache'])
-    storeFile = os.path.join(file_utils.getCurrentPath(), 'keystore', keystore['storeFile'])
-
-    if 'outName' in config and 'outPath' in config:
-        if not os.path.exists(config['outPath']):
-            os.makedirs(config['outPath'])
-
-        signedApk = os.path.join(config['outPath'], config['outName'] + '.apk')
-    elif 'outName' in config:
-        signedApk = file_utils.getRenameApkPath(game, sdk, config['cache'], config['outName'])
-    
-    # java -jar apksigner.jar sign --ks key.jks --ks-key-alias releasekey --ks-pass pass:pp123456 --key-pass pass:pp123456 --out output.apk input.apk
-    v2disable = ''
-    if 'v2disable' in config and config['v2disable']:
-        v2disable = ' --v2-signing-enabled=false'
-        
-    return file_utils.execJarCmd(apksigner, 'sign%s --ks "%s" --ks-key-alias %s --ks-pass pass:%s --key-pass pass:%s --out "%s" "%s"' % (v2disable, storeFile, keystore['keyAlias'], keystore['storePassword'], keystore['keyPassword'], signedApk, alignApk))
-
-def addChannel(game, sdk, subChannel, config):
-    '''
-    添加渠道信息
-    '''
-    if 'v2disable' in config and config['v2disable']:
-        return 0
-    
-    walle = file_utils.getWallePath()
-    signedApk = file_utils.getSignApkPath(game, sdk, subChannel, config['cache'])
-    if 'outName' in config and 'outPath' in config:
-        signedApk = os.path.join(config['outPath'], config['outName'] + '.apk')
-    elif 'outName' in config:
-        signedApk = file_utils.getRenameApkPath(game, sdk, config['cache'], config['outName'])
-
-    properties = config['properties']
-
-    appid = ''
-    appkey = ''
-    host = ''
-    if 'appid' in properties:
-        appid = properties['appid']
-    if 'appkey' in properties:
-        appkey = properties['appkey']
-    if 'host' in properties:
-        host = properties['host']
-
-    return file_utils.execJarCmd(walle, 'put -e version=%s,agent=%s,appid=%s,appkey=%s,host=%s "%s" "%s"' % (config_utils.getDate(), properties['agent'], appid, appkey, host, signedApk, signedApk))
-
-def clearTemp(game, sdk, subChannel, config):
-    '''
-    清空中间产生的文件
-    '''
-    print('clear temp...')
-    alignApk = file_utils.getAlignApkPath(game, sdk, subChannel, config['cache'])
-    outApk = file_utils.getOutApkPath(game, sdk, subChannel, config['cache'])
-    if os.path.exists(alignApk):
-        os.remove(alignApk)
-    if os.path.exists(outApk):
-        os.remove(outApk)
-
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    file_utils.deleteFolder(decompliePath)
-
-    print('clear temp end')
-
-def packConsoleInput():
-    '''
-    控制台打包
-    '''
-    if len(sys.argv) < 3:
-        print('argument is missing')
-        return 1
-
-    # 校验参数
-    game = sys.argv[1]
-    sdk = sys.argv[2]
-    # 可选参数,没有则默认打全部渠道
-    subChannel = None
-    if len(sys.argv) > 3:
-        subChannel = sys.argv[3]
-        
-    return packConsole(game, sdk, subChannel)
-
-def packConsole(game, sdk, subChannel):
-    '''
-    控制台打包
-    '''
-    print('--------- yfsdk ---------')
-
-    if not os.path.exists(file_utils.getFullGameApk(game)):
-        print('game "%s" not exists' % game)
-        return 1
-    # if not os.path.exists(file_utils.getFullSDKPath(sdk)):
-    #     print('sdk "%s" not exists' % sdk)
-    #     return 1
-    global  startTime
-    startTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
-
-    # 读取配置
-    channelPath = file_utils.getChannelPath(game, sdk)
-    configPath = os.path.join(channelPath, 'config.json')
-    if not os.path.exists(configPath):
-        print('%s not exists' % configPath)
-        return 1
-    
-    jsonText = file_utils.readFile(configPath)
-    config = json.loads(jsonText)
-
-    # 检查参数
-    if not config_utils.checkConfig(config):
-        return 1
-
-    # 处理参数
-    config_utils.replaceArgs(config)
-
-    successCount = 0
-    failureCount = 0
-    if type(config) == dict:
-        if subChannel is None or config['subChannel'] == subChannel:
-            ret = pack(game, sdk, config)
-            if ret:
-                failureCount += 1
-            else:
-                successCount += 1
-        else:
-            print('subChannel "%s" no found' % subChannel)
-            return 1
-    elif type(config) == list:
-        found = False
-        for itemConfig in config:
-            if subChannel is None or itemConfig['subChannel'] == subChannel:
-                found = True
-                ret = pack(game, sdk, itemConfig)
-                if ret:
-                    failureCount += 1
-                else:
-                    successCount += 1
-
-        if not found:
-            print('subChannel "%s" no found' % subChannel)
-            return 1
-
-    print('success %d, failure %d' % (successCount, failureCount))
-        
+# 安卓游戏打包脚本
+# 1.用apktool解包
+# 2.复制res资源、assets资源、jniLib资源
+# 3.修改包名、app名、渠道文件
+# 4.添加app icon、合并AndroidManifest文件
+# 5.添加app启动图,修改AndroidManifest文件
+# 6.生成新的R文件
+# 7.将新的R文件编译,生成dex,再用baksmali生成smali,替换旧的R文件
+# 8.将jar资源打包成dex,再用baksmali生成smali,拷贝到smali目录下
+# 9.统计方法量,并分割dex(将smali文件拷贝到目录smali_classes2)
+# 10.用apktool回包
+# 11.重新签名
+import file_utils
+import xml_utils
+import smali_utils
+import config_utils
+import game_utils
+import os
+import os.path
+import json
+import sys
+import importlib
+import uuid
+import zipfile
+import time
+import datetime
+
+
+ignoreLauncher = ['jm_ysdk', 'jm_yijie', 'jm_quick', 'jm_beiyu', 'jm_xq_jrtt','jm_zy_ysdk']
+adaptApp = ['yjzx']
+startTime = ''
+
+def pack(game, sdk, config):
+    config['cache'] = uuid.uuid1()
+    subChannel = config['subChannel']
+    print('game = %s, sdk = %s, subChannel = %s, ...' % (game,sdk,subChannel))
+
+    # 解包
+    ret = decomplie(game, sdk, subChannel, config)
+    if ret:
+        return ret
+        # 删除旧代码
+    ret = removeOldCode(game, sdk, subChannel, config)
+    if ret:
+        return ret
+
+    # 复制app res资源
+    ret = copyAppRes(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 更改包名
+    if 'packageName' in config and config['packageName'] != '':
+        ret = changePackageName(game, sdk, subChannel, config)
+        if ret:
+            return ret
+    # 更改app名
+    if 'name' in config and config['name'] != '':
+        ret = changeAppName(game, sdk, subChannel, config)
+        if ret:
+            return ret
+    # 更改app icon
+    if config['changeIcon']:
+        ret = changeAppIcon(game, sdk, subChannel, config)
+        if ret:
+            return ret
+    # 添加启动图操作
+    if config['addLauncher']:
+        ret = addLauncher(game, sdk, subChannel, config)
+        if ret:
+            return ret
+
+    ret = copyIcon(game, sdk, subChannel, config)
+
+    ret = packJar(game, sdk, subChannel, config)
+    if ret:
+        return ret
+
+    # 增加配置文件
+    ret = createJmhyProperties(game, sdk, subChannel, config)
+    if ret:
+        return ret
+
+    # 更改版本号
+    ret = changeVersion(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 回编译
+    ret = recomplie(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 对齐apk
+    ret = alignApk(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 签名
+    ret = apksignerApk(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    # 清理产生的中间文件
+    if config['clearCache']:
+        clearTemp(game, sdk, subChannel, config)
+
+    endTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+    d1 = datetime.datetime.strptime(endTime, '%Y-%m-%d %H:%M:%S')
+    d2 = datetime.datetime.strptime(startTime,  '%Y-%m-%d %H:%M:%S')
+    d = d1 - d2
+    print ('开始时间:' + startTime)
+    print ('结束时间:' + endTime)
+    print ('用时:{}'.format(config_utils.getTime(d.seconds)))
+    return 0
+
+def decomplie(game, sdk, subChannel, config):
+    '''
+    解包
+    '''
+    apktoolPath = file_utils.getApkToolPath()
+    gamePath = file_utils.getFullGameApk(game)
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+
+    if os.path.exists(decompliePath):
+        print('delete decomplie folder...')
+        file_utils.deleteFolder(decompliePath)
+
+    print('decomplie apk...')
+
+    return file_utils.execJarCmd(apktoolPath, 'd -f "%s" -o "%s"' % (gamePath, decompliePath))
+
+def removeOldCode(game, sdk, subChannel, config):
+    '''
+    删除旧代码
+    '''
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    codePath = os.path.join(decompliePath, 'smali', 'com', 'Jcat', 'Adsdk')
+    #file_utils.deleteFolder(codePath)
+    allFiles = []
+    allFiles = file_utils.list_files(codePath, allFiles)
+    for f in allFiles:
+        fpath, fname = os.path.split(f)  #分离文件名和路径
+        if fname == 'R.smali' or fname.startswith('R$'):
+            continue
+        os.remove(f)
+        #print('remove %s' % f)
+    return 0
+
+def copyRes(game, sdk, subChannel, config):
+    '''
+    复制res资源
+    '''
+    # 拷贝sdk资源
+    print('copy res...')
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    sdkPath = file_utils.getFullSDKPath(sdk)
+    resPath = os.path.join(sdkPath, 'res')
+    decomplieResPath = file_utils.getFullPath(decompliePath, 'res')
+
+    for d in os.listdir(resPath):
+        copyResWithType(resPath, decomplieResPath, d)
+
+    # 拷贝assets
+    print('copy assets...')
+    assetsPath = file_utils.getFullPath(sdkPath, 'assets')
+    decomplieAssetsPath = file_utils.getFullPath(decompliePath, 'assets')
+    if os.path.exists(assetsPath):
+        ret = file_utils.copyFileAllDir(assetsPath, decomplieAssetsPath)
+        if ret:
+            return ret
+
+    # 拷贝jniLib
+    print('copy jniLibs...')
+    jniPath = file_utils.getFullPath(sdkPath, 'jniLibs')
+    decomplieJniPath = file_utils.getFullPath(decompliePath, 'lib')
+    abiFilters = []
+    if os.path.exists(decomplieJniPath):
+        for abi in os.listdir(decomplieJniPath):
+            if abi == 'armeabi-v7a' or abi == 'armeabi':
+                abiFilters.append(abi)
+    else:
+        abiFilters = ['armeabi-v7a']
+
+    if os.path.exists(jniPath):
+        ret = file_utils.copyFileAllDir(jniPath, decomplieJniPath, False, abiFilters)
+        if ret:
+            return ret
+    return 0
+
+def mergeDrawableRes(game, sdk, subChannel, config):
+    '''
+    合并Drawable-v4目录
+    '''
+    print('merge drawable path...')
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    resPath = os.path.join(decompliePath, 'res')
+
+    for path in os.listdir(resPath):
+        print('res path %s' % path)
+        if (path.startswith('drawable') or path.startswith('mipmap')) and path.endswith('-v4'):
+            print('merge path %s' % path)
+            v4DrawablePath = os.path.join(resPath, path)
+            drawablePath = os.path.join(resPath, path[:-3])
+
+            if os.path.exists(drawablePath):
+                ret = file_utils.copyFileAllDir(v4DrawablePath, drawablePath, True)
+                if ret:
+                    return ret
+            else:
+                os.rename(v4DrawablePath, drawablePath)
+    return 0
+
+def removeSameRes(game, sdk, subChannel, config):
+    '''
+    移除相同的资源
+    '''
+    # 读取sdk的资源
+    print('remove same res...')
+    sdkPath = file_utils.getFullSDKPath(sdk)
+    sdkResPath = os.path.join(sdkPath, 'res')
+    resList = []
+    for path in os.listdir(sdkResPath):
+        if not path.startswith('values'):
+            continue
+        absPath = os.path.join(sdkResPath, path)
+        for resFile in os.listdir(absPath):
+            '''if not resFile.startswith('jm_'):
+                continue'''
+            if resFile.endswith('.DS_Store'):
+                continue
+            #print('readAllRes -- > ' + os.path.join(absPath, resFile))
+
+            resList = xml_utils.readAllRes(os.path.join(absPath, resFile), resList)
+
+    if len(resList) == 0:
+        print('no same res found')
+        return 0
+
+    # 移除相同的资源
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    resPath = os.path.join(decompliePath, 'res')
+    for path in os.listdir(resPath):
+        if not path.startswith('values'):
+            continue
+
+        absPath = os.path.join(resPath, path)
+        for resFile in os.listdir(absPath):
+            xml_utils.removeSameRes(os.path.join(absPath, resFile), resList)
+
+    return 0
+
+def mergeManifestRes(game, sdk, subChannel, config):
+    '''
+    合并主文件
+    '''
+    print('merge AndroidManifest...')
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    sdkPath = file_utils.getFullSDKPath(sdk)
+    libManifest = file_utils.getFullPath(sdkPath, 'manifest.xml')
+    return xml_utils.mergeManifestRes(manifest, libManifest)
+
+def copyAppRes(game, sdk, subChannel, config):
+    '''
+    拷贝app的资源,比如app icon、启动图等
+    '''
+    channelPath = file_utils.getSubChannelPath(game, sdk, subChannel)
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+
+    # assets
+    print('copy assets...')
+    #适配一剑斩仙
+    if game in adaptApp:
+        print('适配一剑斩仙...')
+        decomplieAssetsPath = file_utils.getFullPath(decompliePath, 'assets')
+        skinZipPath = os.path.join(decomplieAssetsPath, 'skin.zip')
+        skinPath = os.path.join(decomplieAssetsPath, 'skin')
+        if os.path.exists(skinZipPath):
+            with zipfile.ZipFile(skinZipPath) as zf:
+                zf.extractall(decomplieAssetsPath)
+                print('create unzip skin' )
+            assetsPath = file_utils.getFullPath(channelPath, 'assets')
+            decomplieAssetsPath = file_utils.getFullPath(decompliePath, 'assets')
+            if os.path.exists(assetsPath):
+                ret = file_utils.copyFileAllDir(assetsPath, decomplieAssetsPath)
+            with zipfile.ZipFile(skinZipPath, 'w') as z:
+                for root, dirs, files in os.walk(skinPath):
+                    for single_file in files:
+                        filepath = os.path.join(root, single_file)
+                        print ('create zip ---> ' + filepath)
+                        temPath = 'skin/' + single_file
+                        z.write(filepath, temPath)
+            z.close()
+        else:
+            print('normal copy assets...')
+            assetsPath = file_utils.getFullPath(channelPath, 'assets')
+            decomplieAssetsPath = file_utils.getFullPath(decompliePath, 'assets')
+            if os.path.exists(assetsPath):
+                ret = file_utils.copyFileAllDir(assetsPath, decomplieAssetsPath)
+                if ret:
+                    return ret
+    else:
+        print('normal copy assets...')
+        assetsPath = file_utils.getFullPath(channelPath, 'assets')
+        decomplieAssetsPath = file_utils.getFullPath(decompliePath, 'assets')
+        if os.path.exists(assetsPath):
+            ret = file_utils.copyFileAllDir(assetsPath, decomplieAssetsPath)
+            if ret:
+                return ret
+
+    # icon
+    print('copy icon...')
+    ret = copyAppResWithType(decompliePath, channelPath, 'icon')
+    if ret:
+        return ret
+    # 启动图
+    print('copy splash...')
+    ret = copyAppResWithType(decompliePath, channelPath, 'splash')
+    if ret:
+        return ret
+    # 其他图片
+    print('copy image...')
+    ret = copyAppResWithType(decompliePath, channelPath, 'image')
+    if ret:
+        return ret
+    return 0
+    
+def copyAppResWithType(decompliePath, channelPath, typeName):
+    decomplieResPath = os.path.join(decompliePath, 'res')
+    iconPath = os.path.join(channelPath, typeName)
+    if not os.path.exists(iconPath):
+        print('dir "%s" not exists' % iconPath)
+        return 0
+    for d in os.listdir(iconPath):
+        ret = copyResWithType(iconPath, decomplieResPath, d)
+        if ret:
+            return ret
+
+    return 0
+
+def copyResWithType(resPath, decomplieResPath, typeName):
+    # appt的打包目录会带-v4后缀
+    resDir = os.path.join(resPath, typeName)
+    target = os.path.join(decomplieResPath, typeName)
+    targetV4 = os.path.join(decomplieResPath, typeName + '-v4')
+    if not os.path.exists(target) and not os.path.exists(targetV4):
+        os.makedirs(target)
+        return file_utils.copyFileAllDir(resDir, target, False)
+    elif not os.path.exists(target):
+        return file_utils.copyFileAllDir(resDir, targetV4, False)
+    else:
+        return file_utils.copyFileAllDir(resDir, target, False)
+
+def removeNoSupportAttr(game, sdk, subChannel, config):
+    '''
+    删除一些不支持的属性
+    '''
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    
+    xml_utils.removeRootAttr(manifest, 'compileSdkVersion')
+    xml_utils.removeRootAttr(manifest, 'compileSdkVersionCodename')
+    
+    return 0
+
+def fixUnSupportConfig(game, sdk, subChannel, config):
+    '''
+    删除一些不支持的配置
+    '''
+    # 检查minSdkVersion
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    yml = os.path.join(decompliePath, 'apktool.yml')
+
+    minSdkVersion = 15
+    file_utils.changeMinSdkVersion(yml, minSdkVersion)
+
+    resPath = os.path.join(decompliePath, 'res')
+
+    tag = '-v'
+    for res in os.listdir(resPath):
+        #print('res = ' + res)
+        if res.startswith('values') and tag in res:
+            start = res.index(tag)
+            version = res[start+len(tag):]
+            if not version.isdigit():
+                continue
+            
+            version = int(version)
+            print('version = %d' % version)
+            if version < minSdkVersion:
+                unSopportPath = os.path.join(resPath, res)
+                print('unSopportPath = ' + unSopportPath)
+                file_utils.deleteFolder(unSopportPath)
+                print('deleteFolder = ' + unSopportPath)
+    
+    return 0
+
+def changePackageName(game, sdk, subChannel, config):
+    '''
+    更改包名
+    '''
+    # 全局替换AndroidManifest里面的包名
+    newPackageName = config['packageName']
+
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    packageName = xml_utils.getPackageName(manifest)
+    
+    xml_utils.changePackageName(manifest, newPackageName)
+    print('change package name %s --> %s' % (packageName, newPackageName))
+    return 0
+
+def changeAppName(game, sdk, subChannel, config):
+    '''
+    更改app名
+    '''
+    # 生成string.xml文件
+    name = config['name']
+
+    resName = 'common_sdk_name'
+    if 'outName' in config:
+        resName = resName + '_' + config['outName']
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    stringFile = os.path.join(decompliePath, 'res', 'values', 'sdk_strings_temp.xml')
+    content = '<?xml version="1.0" encoding="utf-8"?><resources><string name="%s">%s</string></resources>' % (resName, name)
+    file_utils.createFile(stringFile, content)
+
+    # 修改主文件的app名的值
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    xml_utils.changeAppName(manifest, '@string/%s' % resName)
+    print('change app name %s' % name)
+    return 0
+
+def changeAppIcon(game, sdk, subChannel, config):
+    '''
+    更改app icon
+    '''
+    print('change app icon...')
+    resName = 'common_sdk_icon'
+
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    xml_utils.changeAppIcon(manifest, '@mipmap/%s' % resName)
+    return 0
+
+def addMetaData(game, sdk, subChannel, config):
+    '''
+    添加meta-data
+    '''
+    if 'metaData' not in config:
+        return 0
+
+    print('add meta-data...')
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    xml_utils.addMetaData(manifest, config['metaData'])
+    return 0
+
+def addConfig(game, sdk, subChannel, config):
+    '''
+    添加config.json
+    '''
+    if 'configData' not in config:
+        return 0
+
+    print('add jmad.properties...')
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    configJson = os.path.join(decompliePath, 'assets', 'jmad.properties')
+    jsonText = json.dumps(config['configData'], ensure_ascii=False)
+    file_utils.createFile(configJson, jsonText)
+    return 0
+
+def createJmhyProperties(game, sdk, subChannel, config):
+    '''
+    创建jmhy.properties
+    '''
+    print('create jmad.properties...')
+    propValue = config['properties']
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    properties = os.path.join(decompliePath, 'assets', 'jmad.properties')
+    content = ''
+    for key in propValue:
+        content = '%s%s=%s\n' % (content, key, propValue[key])
+    file_utils.createFile(properties, content)
+    return 0
+
+def changePlaceholders(game, sdk, subChannel, config):
+    '''
+    处理掉占位符
+    '''
+    if 'placeholders' not in config:
+        return 0
+
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+
+    placeholders = config['placeholders']
+    for placeholder in placeholders:
+        oldText = '${%s}' % placeholder
+        newText = placeholders[placeholder]
+        print('change placeholder %s -> %s' % (oldText, newText))
+        file_utils.replaceContent(manifest, oldText, newText)
+
+    return 0
+
+def addLauncher(game, sdk, subChannel, config):
+    '''
+    添加启动图
+    '''
+    # ysdk的特殊处理
+    if sdk in ignoreLauncher:
+        return 0
+
+    channelPath = file_utils.getSubChannelPath(game, sdk, subChannel)
+    splashPath = os.path.join(channelPath, 'splash')
+    if len(os.listdir(splashPath)) == 0:
+        print('dir splash is empty')
+        return 0
+
+    print('add launcher...')
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    activity = xml_utils.getLauncherActivityName(manifest)
+    if activity == 'com.jmhy.sdk.template.LauncherActivity':
+        print('add launcher already exist...')
+        return 1
+    # 添加关联资源
+    internalPath = file_utils.getFullInternalPath()
+    ret = copyAppResWithType(decompliePath, internalPath, 'launcher_res')
+    if ret:
+        return ret
+
+    # 拷贝代码
+    print('copy launcher code...')
+    codePath = os.path.join(internalPath, 'launcher_code', 'smali')
+    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
+    ret = file_utils.copyFileAllDir(codePath, smaliPath)
+    if ret:
+        return ret
+
+    # 修改主文件信息
+    print('change launcher config...')
+    
+    orientation = xml_utils.getScreenOrientation(manifest)
+    activity = xml_utils.removeLauncherActivity(manifest)
+    xml_utils.addLauncherActivity(manifest, orientation, 'com.jmhy.sdk.template.LauncherActivity')
+
+    # 修改跳转的
+    launcherActivity = os.path.join(decompliePath, 'smali', 'com', 'jmhy', 'sdk', 'template', 'LauncherActivity.smali')
+    file_utils.replaceContent(launcherActivity, '{class}', activity)
+
+    print('change launcher %s to %s' % (activity, 'com.jmhy.sdk.template.LauncherActivity'))
+
+    # config['oldLauncher'] = activity
+
+    if 'launcherTime' in config:
+        timeHex = formatHex(config['launcherTime'])
+        file_utils.replaceContent(launcherActivity, '0x0BB8', timeHex)
+
+    return 0
+
+def addMoreIcon(game, sdk, subChannel, config):
+    '''
+    添加多个图标
+    '''
+    print('add more icon support...')
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    icon = '@mipmap/common_sdk_icon'
+    if not config['changeIcon']:
+        manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+        icon = xml_utils.getApplicationAttr(manifest, 'icon')
+
+    switchIcon = icon
+    if config['switchIcon']:
+        switchIcon = '@mipmap/common_sdk_icon2'
+
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    return xml_utils.addMoreIcon(manifest, icon, switchIcon)
+
+def copyIcon(game, sdk, subChannel, config):
+    '''
+    复制icon到res ,一键登录使用
+    '''
+    if config['changeIcon']:
+        decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+        decomplieResPath = file_utils.getFullPath(decompliePath, 'res')
+        iconPath = os.path.join(decomplieResPath, 'mipmap-xhdpi', 'common_sdk_icon.png')
+        desPath = os.path.join(decomplieResPath, 'drawable-hdpi', 'jm_cmcc_icon.png')
+        file_utils.copyFile(iconPath, desPath)
+    else:
+        decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+        decomplieResPath = file_utils.getFullPath(decompliePath, 'res')
+        desPath = os.path.join(decomplieResPath, 'drawable-hdpi', 'jm_cmcc_icon.png')
+
+        manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+        icon = xml_utils.getApplicationAttr(manifest, 'icon')
+        tag = icon[1:].split("/")
+        if len(tag) < 1:
+            return
+        hdpi = ['-xhdpi', '-xxhdpi', '-xxxhdpi']
+        for h in hdpi:
+            p1 = '%s%s' % (tag[0],h)
+            png = tag[1] + ".png"
+            iconPath = os.path.join(decomplieResPath, p1, png)
+            if os.path.exists(iconPath):
+                print ('iconPath = ' + iconPath)
+                file_utils.copyFile(iconPath, desPath)
+                break
+
+
+def formatHex(millisecond):
+    '''
+    将毫秒转为16进制,4位格式
+    '''
+    timeHex = str(hex(millisecond)).upper()
+    timeHex = timeHex[2:]
+    formatHex = ''
+    if len(timeHex) == 3:
+        formatHex = '0x0' + timeHexaddLauncher
+    elif len(timeHex) == 4:
+        formatHex = '0x' + timeHex
+    else:
+        formatHex = '0x0BB8'
+    return formatHex
+
+def doSDKPostScript(game, sdk, config):
+    '''
+    执行sdk相关特殊处理脚本
+    '''
+    sdkPath = file_utils.getFullSDKPath(sdk)
+    scriptPath = os.path.join(sdkPath, 'script')
+    targetScript = os.path.join(scriptPath, 'sdk_script.py')
+    if not os.path.exists(targetScript):
+        print('sdk_script no exists')
+        return 0
+
+    print('doSDKPostScript...')
+    sys.path.append(scriptPath)
+
+    module = importlib.import_module('sdk_script')
+    ret = module.execute(game, sdk, config)
+
+    sys.path.remove(scriptPath)
+
+    return ret
+
+def doGamePostScript(game, sdk, config):
+    '''
+    执行游戏相关特殊处理脚本
+    '''
+    channelPath = file_utils.getFullGamePath(game)
+    scriptPath = os.path.join(channelPath, 'script')
+    targetScript = os.path.join(scriptPath, 'game_script.py')
+    if not os.path.exists(targetScript):
+        print('game_script no exists')
+        return 0
+
+    print('doGamePostScript...')
+    sys.path.append(scriptPath)
+
+    module = importlib.import_module('game_script')
+    ret = module.execute(game, sdk, config)
+
+    sys.path.remove(scriptPath)
+
+    return ret
+
+def addLogSdk(game, sdk, subChannel, config, logSdk):
+    # 拷贝jniLibs
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    sdkPath = file_utils.getFullLogSDKPath(logSdk)
+
+    print('copy log jniLibs...')
+    jniPath = file_utils.getFullPath(sdkPath, 'jniLibs')
+    decomplieJniPath = file_utils.getFullPath(decompliePath, 'lib')
+    abiFilters = []
+    if os.path.exists(decomplieJniPath):
+        for abi in os.listdir(decomplieJniPath):
+            if abi == 'armeabi-v7a' or abi == 'armeabi':
+                abiFilters.append(abi)
+    else:
+        abiFilters = ['armeabi-v7a']
+
+    if os.path.exists(jniPath):
+        ret = file_utils.copyFileAllDir(jniPath, decomplieJniPath, False, abiFilters)
+        if ret:
+            return ret
+    
+    print('merge log AndroidManifest...')
+    libManifest = file_utils.getFullPath(sdkPath, 'manifest.xml')
+    if os.path.exists(libManifest):
+        manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+        ret = xml_utils.mergeManifestRes(manifest, libManifest)
+        if ret:
+            return ret
+
+    return packLogJar(game, sdk, subChannel, config, logSdk)
+
+def generateNewRFile(game, sdk, subChannel, config):
+    '''
+    生成新的R文件
+    '''
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    androidPlatforms = file_utils.getAndroidCompileToolPath()
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    decomplieResPath = file_utils.getFullPath(decompliePath, 'res')
+    compliePath = file_utils.getFullPath(decompliePath, 'gen')
+
+    if not os.path.exists(compliePath):
+        os.makedirs(compliePath)
+
+    # 生成R文件
+    print('生成R文件 ...')
+    if config['aapt2disable']:
+        aapt = file_utils.getAAPTPath()
+        ret = file_utils.getExecPermission(aapt)
+        if ret:
+            return ret
+        createRCmd = '"%s" p -f -m -J "%s" -S "%s" -I "%s" -M "%s"' % (aapt, compliePath, decomplieResPath, androidPlatforms, manifest)
+        ret = file_utils.execFormatCmd(createRCmd)
+        if ret:
+            return ret
+    else:
+        # compile
+        aapt = file_utils.getAAPT2Path()
+        ret = file_utils.getExecPermission(aapt)
+        if ret:
+            return ret
+
+        print('compiled res ...')
+        complieResPath = os.path.join(compliePath, 'compiled')
+        complieResCmd = '"%s" compile --dir "%s" -o "%s"' % (aapt, decomplieResPath, complieResPath)
+        file_utils.execFormatCmd(complieResCmd)
+
+        # unzip
+        print('unzip compiled res ...')
+        unzipResPath = os.path.join(compliePath, 'aapt2_res')
+        with zipfile.ZipFile(complieResPath) as zf:
+            zf.extractall(unzipResPath)
+            print('create unzip %s' % unzipResPath)
+
+        # link
+        print('link res ...')
+        outApk = os.path.join(compliePath, 'res.apk')
+        linkResCmd = '"%s" link -o "%s" -I "%s" --manifest "%s" --java "%s" --auto-add-overlay' % (aapt, outApk, androidPlatforms, manifest, compliePath)
+        for filename in os.listdir(unzipResPath):
+            linkResCmd += ' %s' % filename
+        print('link cmd len is %s' % len(linkResCmd))
+        ret = file_utils.execFormatCmd(linkResCmd, unzipResPath)
+        if ret:
+            return ret
+
+    # 编译R文件
+    print('complie R.java ...')
+    packageName = xml_utils.getPackageName(manifest)
+    packagePath = file_utils.getPackagePath(compliePath, packageName)
+    RSourceFile = os.path.join(packagePath, 'R.java')
+    complieRCmd = 'javac -source 1.8 -target 1.8 -encoding UTF-8 "%s"' % RSourceFile
+    ret = file_utils.execFormatCmd(complieRCmd)
+    if ret:
+        return ret
+
+    # 生成dex
+    print('dex R.class ...')
+    outDex = os.path.join(compliePath, 'classes.dex')
+    if config['aapt2disable']:
+        dx = file_utils.getDxPath()
+        dexCmd = '--dex --no-warning --output="%s" "%s"' % (outDex, compliePath)
+    else:
+        dx = file_utils.getD8Path()
+        clazz = os.path.join(packagePath, '*.class')
+        dexCmd = '--lib "%s" --output "%s" %s' % (androidPlatforms, compliePath, clazz)
+    ret = file_utils.execJarCmd(dx, dexCmd)
+    if ret:
+        return ret
+
+    # 反向dex生成smali
+    # 存放在out目录
+    print('baksmali classes.dex ...')
+    baksmaliPath = file_utils.getBaksmaliPath()
+    outPath = file_utils.getFullPath(decompliePath, 'out')
+
+    ret = file_utils.execJarCmd(baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
+    if ret:
+        return ret
+
+    # 将生成的文件拷贝到目标目录
+    print('copy R.smali ...')
+    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
+    file_utils.copyFileAllDir(outPath, smaliPath)
+    return 0
+
+def packJar(game, sdk, subChannel, config):
+    '''
+    打包所有的jar
+    '''
+    splitDex = config['splitDex']
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    outPath = file_utils.getFullPath(decompliePath, 'gen')
+
+    if not os.path.exists(outPath):
+        os.makedirs(outPath)
+    if config['aapt2disable']:
+        dx = file_utils.getDxPath()
+        dexCmd = '--dex --multi-dex --no-warning --output="%s"' % outPath
+    else:
+        dx = file_utils.getD8Path()
+        androidPlatforms = file_utils.getAndroidCompileToolPath()
+        dexCmd = '--lib "%s" --output "%s"' % (androidPlatforms, outPath)
+
+    # 找到所有lib依赖
+    sdkPath = file_utils.getFullSDKPath(sdk)
+    print('sdkpath --> ' + sdkPath)
+    libs = os.path.join(sdkPath, 'libs')
+    libConfig = os.path.join(libs, 'config.json')
+
+    # 存在配置文件
+    if os.path.exists(libConfig):
+        jsonText = file_utils.readFile(libConfig)
+        libConf = json.loads(jsonText)
+        if 'libConfig' in config and config['libConfig'] in libConf:
+            conf = config['libConfig']
+            libList = libConf[conf]
+            for jar in libList:
+                dexCmd += ' ' + os.path.join(libs, jar)
+        elif 'default' in libConf:
+            libList = libConf['default']
+            for jar in libList:
+                dexCmd += ' ' + os.path.join(libs, jar)
+        else:
+            for jar in os.listdir(libs):
+                if not jar.endswith('.jar'):
+                    continue
+                dexCmd += ' ' + os.path.join(libs, jar)
+    else:
+        for jar in os.listdir(libs):
+            if not jar.endswith('.jar'):
+                continue
+            dexCmd += ' ' + os.path.join(libs, jar)
+
+    # multidex.jar
+    if splitDex:
+        dexCmd += ' ' + file_utils.getMultiDexPath()
+
+    # sdk实现类
+    print('packageing all jar ...')
+    #dexCmd += ' ' + os.path.join(sdkPath, '%s.jar' % sdk)
+    ret = file_utils.execJarCmd(dx, dexCmd)
+    if ret:
+        return ret
+
+    # 反向dex生成smali
+    # 存放在out目录
+    print('baksmali classes.dex ...')
+    outDex = os.path.join(outPath, 'classes.dex')
+    baksmaliPath = file_utils.getBaksmaliPath()
+    outPath = file_utils.getFullPath(decompliePath, 'out')
+    
+    ret = file_utils.execJarCmd(baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
+    if ret:
+        return ret
+
+    # 将生成的文件拷贝到目标目录
+    print('copy all smali ...')
+    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
+    ret = file_utils.copyFileAllDir(outPath, smaliPath, True)
+    if ret:
+        return ret
+
+    return 0
+
+def packLogJar(game, sdk, subChannel, config, logSdk):
+    '''
+    打包Log jar
+    '''
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    outPath = file_utils.getFullPath(decompliePath, 'gen')
+
+    if not os.path.exists(outPath):
+        os.makedirs(outPath)
+
+    if config['aapt2disable']:
+        dx = file_utils.getDxPath()
+        dexCmd = '--dex --multi-dex --no-warning --output="%s"' % outPath
+    else:
+        dx = file_utils.getD8Path()
+        androidPlatforms = file_utils.getAndroidCompileToolPath()
+        dexCmd = '--lib "%s" --output "%s"' % (androidPlatforms, outPath)
+
+    # 找到所有lib依赖
+    sdkPath = file_utils.getFullLogSDKPath(logSdk)
+    libs = os.path.join(sdkPath, 'libs')
+    libConfig = os.path.join(libs, 'config.json')
+
+    # 存在配置文件
+    if os.path.exists(libConfig):
+        jsonText = file_utils.readFile(libConfig)
+        libList = json.loads(jsonText)
+        for jar in libList:
+            if not jar.endswith('.jar'):
+                continue
+            dexCmd += ' ' + os.path.join(libs, jar)
+    else:
+        for jar in os.listdir(libs):
+            if not jar.endswith('.jar'):
+                continue
+            dexCmd += ' ' + os.path.join(libs, jar)
+
+    # sdk实现类
+    print('packageing all log jar ...')
+    dexCmd += ' ' + os.path.join(sdkPath, '%s.jar' % logSdk)
+    ret = file_utils.execJarCmd(dx, dexCmd)
+    if ret:
+        return ret
+
+    # 反向dex生成smali
+    # 存放在out目录
+    print('baksmali classes.dex ...')
+    outDex = os.path.join(outPath, 'classes.dex')
+    baksmaliPath = file_utils.getBaksmaliPath()
+    outPath = file_utils.getFullPath(decompliePath, 'out')
+    
+    ret = file_utils.execJarCmd(baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
+    if ret:
+        return ret
+
+    # 将生成的文件拷贝到目标目录
+    print('copy all log smali ...')
+    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
+    ret = file_utils.copyFileAllDir(outPath, smaliPath, True)
+    if ret:
+        return ret
+
+    return 0
+
+
+
+
+def packReativeJar(game, sdk, subChannel, config, logSdk):
+    '''
+    打包Reative jar
+    '''
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    outPath = file_utils.getFullPath(decompliePath, 'gen')
+
+    if not os.path.exists(outPath):
+        os.makedirs(outPath)
+
+    if config['aapt2disable']:
+        dx = file_utils.getDxPath()
+        dexCmd = '--dex --multi-dex --no-warning --output="%s"' % outPath
+    else:
+        dx = file_utils.getD8Path()
+        androidPlatforms = file_utils.getAndroidCompileToolPath()
+        dexCmd = '--lib "%s" --output "%s"' % (androidPlatforms, outPath)
+
+    # 找到所有lib依赖
+    sdkPath = file_utils.getFullLogSDKPath(logSdk)
+    libs = os.path.join(sdkPath, 'libs')
+    libConfig = os.path.join(libs, 'config.json')
+
+    # 存在配置文件
+    if os.path.exists(libConfig):
+        jsonText = file_utils.readFile(libConfig)
+        libList = json.loads(jsonText)
+        for jar in libList:
+            if not jar.endswith('.jar'):
+                continue
+            dexCmd += ' ' + os.path.join(libs, jar)
+    else:
+        for jar in os.listdir(libs):
+            if not jar.endswith('.jar'):
+                continue
+            dexCmd += ' ' + os.path.join(libs, jar)
+
+    # sdk实现类
+    print('packageing all log jar ...')
+    dexCmd += ' ' + os.path.join(sdkPath, '%s.jar' % logSdk)
+    ret = file_utils.execJarCmd(dx, dexCmd)
+    if ret:
+        return ret
+
+    # 反向dex生成smali
+    # 存放在out目录
+    print('baksmali classes.dex ...')
+    outDex = os.path.join(outPath, 'classes.dex')
+    baksmaliPath = file_utils.getBaksmaliPath()
+    outPath = file_utils.getFullPath(decompliePath, 'out')
+
+    ret = file_utils.execJarCmd(baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
+    if ret:
+        return ret
+
+    # 将生成的文件拷贝到目标目录
+    print('copy all log smali ...')
+    smaliPath = file_utils.getFullPath(decompliePath, 'smali')
+    ret = file_utils.copyFileAllDir(outPath, smaliPath, True)
+    if ret:
+        return ret
+
+    return 0
+
+def splitDex(game, sdk, subChannel, config):
+    '''
+    分割dex
+    '''
+    # 判断是否已经存在application
+    # 存在,则往原application添加内容
+    # 不存在,则拷贝一个默认的android.support.multidex.MultiDexApplication
+    print('add MultiDex support...')
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    application = xml_utils.getApplicationAttr(manifest, 'name')
+    if application is None:
+        ret = xml_utils.changeApplicationAttr(manifest, 'name', 'android.support.multidex.MultiDexApplication')
+        if ret:
+            return ret
+    else:
+        smaliPath = os.path.join(decompliePath, 'smali')
+        applicationFile = file_utils.getPackagePath(smaliPath, application)
+        applicationFile += '.smali'
+        ret = changeApplicationDex(applicationFile)
+        if ret:
+            return ret
+
+    return splitSmali(game, sdk, subChannel, config, application)
+
+def changeApplicationDex(file):
+    '''
+    修改application的smali文件,增加MultiDex操作
+    '''
+    index = file_utils.getApplicationSmaliIndex(file)
+    file_utils.insertApplicationSmali(file, index)
+    return 0
+
+def splitSmali(game, sdk, subChannel, config, application):
+    '''
+    如果函数上限超过限制,自动拆分smali,以便生成多个dex文件
+    '''
+    print('splitSmali...')
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    smaliPath = os.path.join(decompliePath, 'smali')
+
+    appPackage = None
+    if application:
+        appPackage = application[:application.rfind('.')]
+        appPackage = appPackage.replace('.', '/')
+
+    allFiles = []
+    allFiles = file_utils.list_files(smaliPath, allFiles)
+    
+    #print('file count is %d' % len(allFiles))
+
+    #maxFuncNum = 65535
+    # 留一点空间,防止计算误差
+    maxFuncNum = 64000
+    currFucNum = 0
+    totalFucNum = 0
+
+    currDexIndex = 1
+
+    allRefs = []
+
+    #保证Application等类在第一个classex.dex文件中
+    for f in allFiles:
+        f = f.replace('\\', '/')
+        if (appPackage and appPackage in f) or '/android/support/multidex' in f:
+            currFucNum += smali_utils.get_smali_method_count(f, allRefs)
+
+    totalFucNum = currFucNum
+    for f in allFiles:
+        f = f.replace('\\', '/')
+        if not f.endswith('.smali'):
+            continue
+
+        if (appPackage and appPackage in f) or '/android/support/multidex' in f:
+            continue
+
+        thisFucNum = smali_utils.get_smali_method_count(f, allRefs)
+        totalFucNum += thisFucNum
+
+        #print('%d # %d ==> %s' % (thisFucNum, currDexIndex, f))
+        #print('totalFucNum is %d' % totalFucNum)
+        if currFucNum + thisFucNum >= maxFuncNum:
+            currFucNum = thisFucNum
+            currDexIndex += 1
+            newDexPath = os.path.join(decompliePath, 'smali_classes%d' % currDexIndex)
+            os.makedirs(newDexPath)
+        else:
+            currFucNum += thisFucNum
+
+        if currDexIndex > 1:
+            newDexPath = os.path.join(decompliePath, 'smali_classes%d' % currDexIndex)
+            targetFile = newDexPath + f[len(smaliPath):]
+            file_utils.copyFile(f, targetFile, True)
+    return 0
+
+def changeVersion(game, sdk, subChannel, config):
+    '''
+    更改版本号
+    '''
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    yml = os.path.join(decompliePath, 'apktool.yml')
+
+    versionCode = None
+    versionName = None
+    targetSdkVersion = None
+    if 'versionCode' in config:
+        versionCode = config['versionCode']
+    if 'versionName' in config:
+        versionName = config['versionName']
+    if 'targetSdkVersion' in config:
+        targetSdkVersion = config['targetSdkVersion']
+    else:
+        targetSdkVersion = 26
+    print('changeVersion versionCode=%s,versionName=%s,targetSdkVersion=%s' % (versionCode, versionName, targetSdkVersion))
+
+    return file_utils.changeVersion(yml, versionCode, versionName, targetSdkVersion)
+
+def recomplie(game, sdk, subChannel, config):
+    '''
+    回编译
+    '''
+    print('recomplie apk...')
+    apktoolPath = file_utils.getApkToolPath()
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    outApk = file_utils.getOutApkPath(game, sdk, subChannel, config['cache'])
+
+    useAppt2 = ' --use-aapt2'
+    if config['aapt2disable']:
+        useAppt2 = ''
+
+    return file_utils.execJarCmd(apktoolPath, 'b -f "%s" -o "%s"%s' % (decompliePath, outApk, useAppt2))
+
+def alignApk(game, sdk, subChannel, config):
+    '''
+    对齐apk
+    '''
+    print('align apk...')
+    outApk = file_utils.getOutApkPath(game, sdk, subChannel, config['cache'])
+    alignApk = file_utils.getAlignApkPath(game, sdk, subChannel, config['cache'])
+    alignapkTool = file_utils.getAlignPath()
+    if os.path.exists(alignApk):
+        os.remove(alignApk)
+
+    ret = file_utils.getExecPermission(alignapkTool)
+    if ret:
+        return ret
+
+    # zipalign.exe -v -p 4 input.apk output.apk
+    return file_utils.execFormatCmd('"%s" -f -p 4 "%s" "%s"' % (alignapkTool, outApk, alignApk))
+
+def apksignerApk(game, sdk, subChannel, config):
+    '''
+    签名apk
+    '''
+    print('sign apk...')
+    print('game = %s, sdk = %s, subChannel = %s, ...' % (game,sdk,subChannel))
+    path = os.path.join(file_utils.getCurrentPath(), 'keystore', 'key.json')
+    jsonText = file_utils.readFile(path)
+    signConfig = json.loads(jsonText)
+    keystore = {}
+    for key in signConfig.keys():
+        print(key)
+        if game.find(key) > -1:
+            if sdk in signConfig[key]:
+                keystore = signConfig[key][sdk]
+            else:
+                keystore = signConfig['default']
+        else:
+            keystore = signConfig['default']
+
+    # if game in signConfig:
+    #     if sdk in signConfig[game]:
+    #         keystore = signConfig[game][sdk]
+    #     else:
+    #         keystore = signConfig['default']
+    # else:
+    #     keystore = signConfig['default']
+
+    print('storeFile is "%s"' % keystore['storeFile'])
+    
+    apksigner = file_utils.getApksignerPath()
+    alignApk = file_utils.getAlignApkPath(game, sdk, subChannel, config['cache'])
+    signedApk = file_utils.getSignApkPath(game, sdk, subChannel, config['cache'])
+    storeFile = os.path.join(file_utils.getCurrentPath(), 'keystore', keystore['storeFile'])
+
+    if 'outName' in config and 'outPath' in config:
+        if not os.path.exists(config['outPath']):
+            os.makedirs(config['outPath'])
+
+        signedApk = os.path.join(config['outPath'], config['outName'] + '.apk')
+    elif 'outName' in config:
+        signedApk = file_utils.getRenameApkPath(game, sdk, config['cache'], config['outName'])
+    
+    # java -jar apksigner.jar sign --ks key.jks --ks-key-alias releasekey --ks-pass pass:pp123456 --key-pass pass:pp123456 --out output.apk input.apk
+    v2disable = ''
+    if 'v2disable' in config and config['v2disable']:
+        v2disable = ' --v2-signing-enabled=false'
+        
+    return file_utils.execJarCmd(apksigner, 'sign%s --ks "%s" --ks-key-alias %s --ks-pass pass:%s --key-pass pass:%s --out "%s" "%s"' % (v2disable, storeFile, keystore['keyAlias'], keystore['storePassword'], keystore['keyPassword'], signedApk, alignApk))
+
+def addChannel(game, sdk, subChannel, config):
+    '''
+    添加渠道信息
+    '''
+    if 'v2disable' in config and config['v2disable']:
+        return 0
+    
+    walle = file_utils.getWallePath()
+    signedApk = file_utils.getSignApkPath(game, sdk, subChannel, config['cache'])
+    if 'outName' in config and 'outPath' in config:
+        signedApk = os.path.join(config['outPath'], config['outName'] + '.apk')
+    elif 'outName' in config:
+        signedApk = file_utils.getRenameApkPath(game, sdk, config['cache'], config['outName'])
+
+    properties = config['properties']
+
+    appid = ''
+    appkey = ''
+    host = ''
+    if 'appid' in properties:
+        appid = properties['appid']
+    if 'appkey' in properties:
+        appkey = properties['appkey']
+    if 'host' in properties:
+        host = properties['host']
+
+    return file_utils.execJarCmd(walle, 'put -e version=%s,agent=%s,appid=%s,appkey=%s,host=%s "%s" "%s"' % (config_utils.getDate(), properties['agent'], appid, appkey, host, signedApk, signedApk))
+
+def clearTemp(game, sdk, subChannel, config):
+    '''
+    清空中间产生的文件
+    '''
+    print('clear temp...')
+    alignApk = file_utils.getAlignApkPath(game, sdk, subChannel, config['cache'])
+    outApk = file_utils.getOutApkPath(game, sdk, subChannel, config['cache'])
+    if os.path.exists(alignApk):
+        os.remove(alignApk)
+    if os.path.exists(outApk):
+        os.remove(outApk)
+
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    file_utils.deleteFolder(decompliePath)
+
+    print('clear temp end')
+
+def packConsoleInput():
+    '''
+    控制台打包
+    '''
+    if len(sys.argv) < 3:
+        print('argument is missing')
+        return 1
+
+    # 校验参数
+    game = sys.argv[1]
+    sdk = sys.argv[2]
+    # 可选参数,没有则默认打全部渠道
+    subChannel = None
+    if len(sys.argv) > 3:
+        subChannel = sys.argv[3]
+        
+    return packConsole(game, sdk, subChannel)
+
+def packConsole(game, sdk, subChannel):
+    '''
+    控制台打包
+    '''
+    print('--------- yfsdk ---------')
+
+    if not os.path.exists(file_utils.getFullGameApk(game)):
+        print('game "%s" not exists' % game)
+        return 1
+    # if not os.path.exists(file_utils.getFullSDKPath(sdk)):
+    #     print('sdk "%s" not exists' % sdk)
+    #     return 1
+    global  startTime
+    startTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+
+    # 读取配置
+    channelPath = file_utils.getChannelPath(game, sdk)
+    configPath = os.path.join(channelPath, 'config.json')
+    if not os.path.exists(configPath):
+        print('%s not exists' % configPath)
+        return 1
+    
+    jsonText = file_utils.readFile(configPath)
+    config = json.loads(jsonText)
+
+    # 检查参数
+    if not config_utils.checkConfig(config):
+        return 1
+
+    # 处理参数
+    config_utils.replaceArgs(config)
+
+    successCount = 0
+    failureCount = 0
+    if type(config) == dict:
+        if subChannel is None or config['subChannel'] == subChannel:
+            ret = pack(game, sdk, config)
+            if ret:
+                failureCount += 1
+            else:
+                successCount += 1
+        else:
+            print('subChannel "%s" no found' % subChannel)
+            return 1
+    elif type(config) == list:
+        found = False
+        for itemConfig in config:
+            if subChannel is None or itemConfig['subChannel'] == subChannel:
+                found = True
+                ret = pack(game, sdk, itemConfig)
+                if ret:
+                    failureCount += 1
+                else:
+                    successCount += 1
+
+        if not found:
+            print('subChannel "%s" no found' % subChannel)
+            return 1
+
+    print('success %d, failure %d' % (successCount, failureCount))
+        
     return 0

+ 361 - 298
package_web.py

@@ -1,298 +1,361 @@
-import file_utils
-import package_utils
-import package_web_record
-import package_web_shanshen
-import package_web_yfsdk
-import os.path
-import sys
-import json
-import importlib
-
-sdkMapping = {
-    'ysdk':'jm_ysdk',
-    'ziyun': {
-        'default': 'jm_zy',
-        'ysdk': 'jm_zy_ysdk',
-    },
-    'xunqu':{
-        'default':'jm_xq',
-        'xiaomi':'jm_xq_mi',
-        'jrtt':'jm_xq_jrtt'
-    },
-    'jingqi':'jm_jq',
-    'qytx':{
-        'default':'jm_qytx',
-        'cangyu':'jm_qytx2',
-        'cangyu_new':'jm_cangyu'
-    },
-    'jmsdk':'jm',
-    'oppo':'jm_oppo',
-    'quick':'jm_quick',
-    'beiyu':'jm_beiyu',
-    'yijie':'jm_yijie',
-    'gzjysdk':'gzjysdk',
-    'record':'record',
-    'float':'float',
-    'yfsdk':'yfsdk'
-}
-
-scriptMapping = {
-    'jm_xq_mi':'jm_xq',
-    'jm_xq_jrtt':'jm_xq',
-    'jm_qytx2':'jm_qytx',
-    'jm_cangyu':'jm_qytx'
-}
-
-newSdk = ["shanshen", "gzjysdk"]
-recordSdk = ["record", "float"]
-yanfaSdk = ["yfsdk"]  #研发sdk打包
-
-def packageWeb():
-    if len(sys.argv) < 2:
-        print('argument is missing')
-        return 1
-
-    # 打包配置的路径
-    packageConfig = sys.argv[1]
-    jsonText = file_utils.readFile(packageConfig)
-    config = json.loads(jsonText)
-    print('*************config*****************')
-    print(jsonText)
-    print('************************************')
-
-    sdk = getMappingSdk(config)
-    if sdk in recordSdk:
-        package_web_record.package(config, sdk)
-    elif sdk in newSdk:
-        package_web_shanshen.package(config, sdk)
-    elif sdk in yanfaSdk:
-        package_web_yfsdk.package(config, sdk)
-    else:
-        package(config, sdk)
-
-def package(config, sdk):
-    print('use script 1st')
-    jsonConfig = {}
-    game = config['app']
-    subChannel = None
-
-    if 'subChannel' in config:
-        subChannel = config['subChannel']
-        jsonConfig['subChannel'] = config['subChannel']
-
-    # 必须参数
-    jsonConfig['packageName'] = config['packageName']
-    jsonConfig['name'] = config['name']
-
-    # 可选参数
-    if 'outName' in config:
-        jsonConfig['outName'] = config['outName']
-
-    if 'outPath' in config:
-        jsonConfig['outPath'] = config['outPath']
-
-    if 'changeIcon' in config:
-        jsonConfig['changeIcon'] = toBoolean(config['changeIcon'])
-
-    if 'addLauncher' in config:
-        jsonConfig['addLauncher'] = toBoolean(config['addLauncher'])
-
-    if 'versionCode' in config:
-        jsonConfig['versionCode'] = config['versionCode']
-
-    if 'versionName' in config:
-        jsonConfig['versionName'] = config['versionName']
-
-    if 'targetSdkVersion' in config:
-        jsonConfig['targetSdkVersion'] = config['targetSdkVersion']
-        
-    if 'v2disable' in config:
-        jsonConfig['v2disable'] = toBoolean(config['v2disable'])
-
-    if 'aapt2disable' in config:
-        jsonConfig['aapt2disable'] = toBoolean(config['aapt2disable'])
-
-    # sdk相关参数
-    if 'properties' in config:
-        jsonConfig['properties'] = config['properties']
-        jsonConfig['properties']['isDebugMode'] = 'false'
-
-    jsonConfig['logSdk'] = ['jrtt', 'gdt']
-
-    #广点通参数
-    if 'gdt_params' in config:
-        gdt = { 'gdt':config['gdt_params']}
-        if 'configData' in jsonConfig:
-            configData = jsonConfig['configData']
-            configData['channel_sdk_list'] = gdt
-        else:
-            jsonConfig['configData'] = {
-                'channel_sdk_list':gdt
-            }
-
-    # 获取sdk相关配置
-    getSdkConfig(sdk, jsonConfig, config)
-
-    # 生成配置文件
-    createOrUpdateConfigFile(game, sdk, jsonConfig)
-
-    # 拷贝资源
-    copyRes(game, sdk, subChannel, config)
-
-    # 打包
-    package_utils.packConsole(game, sdk, subChannel)
-
-def toBoolean(booleanStr):
-    if type(booleanStr) == bool:
-        return booleanStr
-
-    if booleanStr == 'true':
-        return True
-    return False
-
-def getSdkConfig(sdk, jsonConfig, config):
-    scriptPath = os.path.join(file_utils.getCurrentPath(), 'sdk_script')
-    sdkScript = getScriptMapping(sdk)
-    targetScript = os.path.join(scriptPath, '%s.py' % sdkScript)
-    if not os.path.exists(targetScript):
-        print('%s no exists' % targetScript)
-        return 0
-    print('sdk_script -- > %s' % targetScript)
-    sys.path.append(scriptPath)
-    module = importlib.import_module(sdkScript)# 动态导入相应模块
-    module.getSdkConfig(jsonConfig, config)# 执行脚本功能
-    sys.path.remove(scriptPath)
-
-def createOrUpdateConfigFile(game, sdk, jsonConfig):
-    '''
-    更新配置文件
-    '''
-    if 'subChannel' not in jsonConfig:
-        return 0
-
-    print('createOrUpdateConfigFile ...')
-
-    channelPath = file_utils.getChannelPath(game, sdk)
-    configPath = os.path.join(channelPath, 'config.json')
-    #configPath = os.path.join(file_utils.getCurrentPath(), 'test', 'test.json')
-
-    if os.path.exists(configPath):
-        # 更新数据
-        jsonText = file_utils.readFile(configPath)
-        config = json.loads(jsonText)
-
-        count = 0
-        if type(config) == list:
-            for item in config:
-                if item['subChannel'] == jsonConfig['subChannel']:
-                    print('find same config ...')
-                    del config[count]
-                    break
-
-                count += 1
-
-            config.append(jsonConfig)
-
-            createConfigFile(config, configPath)
-        elif type(config) == dict:
-            if config['subChannel'] == jsonConfig['subChannel']:
-                print('find same config ...')
-                createConfigFile(jsonConfig, configPath)
-            else:
-                print('add a new config ...')
-                config = [config, jsonConfig]
-
-                createConfigFile(config, configPath)
-    else:
-        print('create a new config ...')
-        createConfigFile([jsonConfig], configPath)
-
-def createConfigFile(jsonConfig, configPath):
-    '''
-    创建配置文件
-    '''
-    jsonStr = json.dumps(jsonConfig, ensure_ascii=False)
-    print('*************out config*************')
-    print(jsonStr)
-    print('************************************')
-    file_utils.createFile(configPath, jsonStr)
-
-def copyRes(game, sdk, subChannel, config):
-    '''
-    拷贝资源
-    '''
-    if subChannel is None:
-        return 0
-
-    channelPath = file_utils.getChannelPath(game, sdk)
-    subChannelPath = os.path.join(channelPath, subChannel)
-    if 'icon' in config and os.path.exists(config['icon']):
-        mipmapSupport = ['mipmap-xhdpi', 'mipmap-xxhdpi', 'mipmap-xxxhdpi']
-        for mipmap in mipmapSupport:
-            iconPath = os.path.join(subChannelPath, 'icon', mipmap, 'common_sdk_icon.png')
-            file_utils.copyFile(config['icon'], iconPath)
-
-    '''if 'switchIcon' in config and os.path.exists(config['switchIcon']):
-        mipmapSupport = ['mipmap-xhdpi', 'mipmap-xxhdpi', 'mipmap-xxxhdpi']
-        for mipmap in mipmapSupport:
-            iconPath = os.path.join(subChannelPath, 'icon', mipmap, 'common_sdk_icon2.png')
-            file_utils.copyFile(config['switchIcon'], iconPath)'''
-
-    if 'splash' in config and os.path.exists(config['splash']):
-        splashPath = os.path.join(subChannelPath, 'splash', 'drawable-hdpi', 'common_sdk_launcher_bg.jpg')
-        file_utils.copyFile(config['splash'], splashPath)
-
-    if 'copyList' in config:
-        for item in config['copyList']:
-            if item['toFile'] == '':
-                continue
-
-            if not os.path.exists(item['fromFile']):
-                continue
-
-            toFile = item['toFile']
-            if toFile[:3] == 'res':
-                toFile = 'image' + toFile[3:]
-                
-            resPath = getPackagePath(subChannelPath, toFile)
-            file_utils.copyFile(item['fromFile'], resPath)
-
-    if 'package' in config and os.path.exists(config['package']):
-        newGameApk = config['package']
-        gameApk = file_utils.getFullGameApk(game)
-        file_utils.copyFile(newGameApk, gameApk)
-
-def getPackagePath(basePath, packageName):
-    '''
-    包名对应的目录
-    '''
-    packageNameSplit = packageName.replace('\\', '/').split('/')
-    newPath = basePath
-    for item in packageNameSplit:
-        newPath = os.path.join(newPath, item)
-    return newPath
-
-def getMappingSdk(config):
-    sdk = config['sdk']
-    mapping = sdk
-    if sdk in sdkMapping:
-        mapping = sdkMapping[sdk]
-    else:
-        return 'jm_' + sdk
-
-    if type(mapping) == dict:
-        sdkConfig = config[sdk]
-        if 'SUB_CHANNEL' in sdkConfig and sdkConfig['SUB_CHANNEL'] != '':
-            subChannel = sdkConfig['SUB_CHANNEL']
-        else:
-            subChannel = 'default'
-        return mapping[subChannel]
-    else:
-        return mapping
-
-def getScriptMapping(sdk):
-    if sdk in scriptMapping:
-        return scriptMapping[sdk]
-    return sdk
-
-packageWeb()
+import file_utils
+import package_utils
+import package_web_record
+import package_web_shanshen
+import package_web_yfsdk
+import os.path
+import sys
+import json
+import importlib
+import common_utils
+
+sdkMapping = {
+    'ysdk': 'jm_ysdk',
+    'ziyun': {
+        'default': 'jm_zy',
+        'ysdk': 'jm_zy_ysdk',
+    },
+    'xunqu': {
+        'default': 'jm_xq',
+        'xiaomi': 'jm_xq_mi',
+        'jrtt': 'jm_xq_jrtt'
+    },
+    'jingqi': 'jm_jq',
+    'qytx': {
+        'default': 'jm_qytx',
+        'cangyu': 'jm_qytx2',
+        'cangyu_new': 'jm_cangyu'
+    },
+    'jmsdk': 'jm',
+    'oppo': 'jm_oppo',
+    'quick': 'jm_quick',
+    'beiyu': 'jm_beiyu',
+    'yijie': 'jm_yijie',
+    'gzjysdk': 'gzjysdk',
+    'record': 'record',
+    'float': 'float',
+    'yfsdk': 'yfsdk'
+}
+
+scriptMapping = {
+    'jm_xq_mi': 'jm_xq',
+    'jm_xq_jrtt': 'jm_xq',
+    'jm_qytx2': 'jm_qytx',
+    'jm_cangyu': 'jm_qytx'
+}
+
+newSdk = ["shanshen", "gzjysdk"]
+recordSdk = ["record", "float"]
+yanfaSdk = ["yfsdk"]  # 研发sdk打包
+
+
+def packageWeb():
+    if len(sys.argv) < 2:
+        print('argument is missing')
+        return 1
+
+    # 打包配置的路径
+    packageConfig = sys.argv[1]
+    jsonText = file_utils.readFile(packageConfig)
+    config = json.loads(jsonText)
+    print('*************config*****************')
+    print(jsonText)
+    print('************************************')
+
+    sdk = getMappingSdk(config)
+    if sdk in recordSdk:
+        package_web_record.package(config, sdk)
+    elif sdk in newSdk:
+        package_web_shanshen.package(config, sdk)
+    elif sdk in yanfaSdk:
+        package_web_yfsdk.package(config, sdk)
+    else:
+        package(config, sdk)
+
+
+def package(config, sdk):
+    print('use script 1st')
+    jsonConfig = {}
+    game = config['app']
+    subChannel = None
+
+    if 'subChannel' in config:
+        subChannel = config['subChannel']
+        jsonConfig['subChannel'] = config['subChannel']
+    config['random'] = common_utils.getRandomNumber(6)
+    outName = config['random']
+
+    channelPath = file_utils.getChannelPath(game, outName, sdk)
+    subChannelPath = os.path.join(channelPath, subChannel)
+    print('打包开始,删除缓存目录 %s ' % subChannelPath)
+    file_utils.deleteFolder(subChannelPath)
+
+    # 必须参数
+    jsonConfig['packageName'] = config['packageName']
+    jsonConfig['name'] = config['name']
+    jsonConfig['random'] = config['random']
+    # 可选参数
+    if 'outName' in config:
+        jsonConfig['outName'] = config['outName']
+
+    if 'outPath' in config:
+        jsonConfig['outPath'] = config['outPath']
+
+    if 'changeIcon' in config:
+        jsonConfig['changeIcon'] = toBoolean(config['changeIcon'])
+
+    if 'addLauncher' in config:
+        jsonConfig['addLauncher'] = toBoolean(config['addLauncher'])
+
+    if 'versionCode' in config:
+        jsonConfig['versionCode'] = config['versionCode']
+
+    if 'versionName' in config:
+        jsonConfig['versionName'] = config['versionName']
+
+    if 'targetSdkVersion' in config:
+        jsonConfig['targetSdkVersion'] = config['targetSdkVersion']
+
+    if 'v2disable' in config:
+        jsonConfig['v2disable'] = toBoolean(config['v2disable'])
+
+    if 'aapt2disable' in config:
+        jsonConfig['aapt2disable'] = toBoolean(config['aapt2disable'])
+
+    # sdk相关参数
+    if 'properties' in config:
+        jsonConfig['properties'] = config['properties']
+        jsonConfig['properties']['isDebugMode'] = 'false'
+
+    #   jsonConfig['logSdk'] = ['jrtt', 'gdt', 'ks', 'uc']
+
+    # 广点通参数
+    if 'gdt_params' in config:
+        jsonConfig['logSdk'] = ['gdt']
+        gdt = {'gdt': config['gdt_params']}
+        if 'configData' in jsonConfig:
+            configData = jsonConfig['configData']
+            configData['channel_sdk_list'] = gdt
+        else:
+            jsonConfig['configData'] = {
+                'channel_sdk_list': gdt
+            }
+    # uc广告参数
+    if 'uc_params' in config:
+        jsonConfig['logSdk'] = ['uc']
+        uc = {'uc': config['uc_params']}
+        if 'configData' in jsonConfig:
+            configData = jsonConfig['configData']
+            configData['channel_sdk_list'] = uc
+        else:
+            jsonConfig['configData'] = {
+                'channel_sdk_list': uc
+            }
+    # baidu广告参数
+    if 'bd_params' in config:
+        jsonConfig['logSdk'] = ['bd']
+        bd = {'bd': config['bd_params']}
+        if 'configData' in jsonConfig:
+            configData = jsonConfig['configData']
+            configData['channel_sdk_list'] = bd
+        else:
+            jsonConfig['configData'] = {
+                'channel_sdk_list': bd
+            }
+    if 'tt_params' in config:
+        jsonConfig['logSdk'] = ['jrtt']
+        jrtt = {'jrtt': config['tt_params']}
+        if 'configData' in jsonConfig:
+            configData = jsonConfig['configData']
+            configData['channel_sdk_list'] = jrtt
+        else:
+            jsonConfig['configData'] = {
+                'channel_sdk_list': jrtt
+            }
+    if 'ks_params' in config:
+        jsonConfig['logSdk'] = ['ks']
+    # 获取sdk相关配置
+    getSdkConfig(sdk, jsonConfig, config)
+
+    # 生成配置文件
+    createOrUpdateConfigFile(game, sdk, jsonConfig)
+
+    # 拷贝资源
+    copyRes(game, sdk, subChannel, config)
+
+    # 打包
+    package_utils.packConsole(game, sdk, config, subChannel)
+
+
+def toBoolean(booleanStr):
+    if type(booleanStr) == bool:
+        return booleanStr
+
+    if booleanStr == 'true':
+        return True
+    return False
+
+
+def getSdkConfig(sdk, jsonConfig, config):
+    scriptPath = os.path.join(file_utils.getCurrentPath(), 'sdk_script')
+    sdkScript = getScriptMapping(sdk)
+    targetScript = os.path.join(scriptPath, '%s.py' % sdkScript)
+    if not os.path.exists(targetScript):
+        print('%s no exists' % targetScript)
+        return 0
+    print('sdk_script -- > %s' % targetScript)
+    sys.path.append(scriptPath)
+    module = importlib.import_module(sdkScript)  # 动态导入相应模块
+    module.getSdkConfig(jsonConfig, config)  # 执行脚本功能
+    sys.path.remove(scriptPath)
+
+
+def createOrUpdateConfigFile(game, sdk, jsonConfig):
+    '''
+    更新配置文件
+    '''
+    if 'subChannel' not in jsonConfig:
+        return 0
+
+    print('createOrUpdateConfigFile ...')
+
+    random = jsonConfig['random']
+
+    channelPath = file_utils.getChannelPath(game, random, sdk)
+    configPath = os.path.join(channelPath, 'config.json')
+    # configPath = os.path.join(file_utils.getCurrentPath(), 'test', 'test.json')
+    print("configPath%s" % configPath)
+    print("channelPath%s" % channelPath)
+    if os.path.exists(configPath):
+        # 更新数据
+        jsonText = file_utils.readFile(configPath)
+        config = json.loads(jsonText)
+
+        count = 0
+        if type(config) == list:
+            for item in config:
+                if item['subChannel'] == jsonConfig['subChannel']:
+                    print('find same config ...')
+                    del config[count]
+                    break
+
+                count += 1
+
+            config.append(jsonConfig)
+
+            createConfigFile(config, configPath)
+        elif type(config) == dict:
+            if config['subChannel'] == jsonConfig['subChannel']:
+                print('find same config ...')
+                createConfigFile(jsonConfig, configPath)
+            else:
+                print('add a new config ...')
+                config = [config, jsonConfig]
+
+                createConfigFile(config, configPath)
+    else:
+        print('create a new config ...')
+        createConfigFile([jsonConfig], configPath)
+
+
+def createConfigFile(jsonConfig, configPath):
+    '''
+    创建配置文件
+    '''
+    jsonStr = json.dumps(jsonConfig, ensure_ascii=False)
+    print('*************out config*************')
+    print(jsonStr)
+    print('************************************')
+    file_utils.createFile(configPath, jsonStr)
+
+
+def copyRes(game, sdk, subChannel, config):
+    '''
+    拷贝资源
+    '''
+    if subChannel is None:
+        return 0
+    random = config['random']
+    channelPath = file_utils.getChannelPath(game, random, sdk)
+    subChannelPath = os.path.join(channelPath, subChannel)
+    if 'icon' in config and os.path.exists(config['icon']):
+        mipmapSupport = ['mipmap-xhdpi', 'mipmap-xxhdpi', 'mipmap-xxxhdpi']
+        for mipmap in mipmapSupport:
+            iconPath = os.path.join(
+                subChannelPath, 'icon', mipmap, 'common_sdk_icon.png')
+            file_utils.copyFile(config['icon'], iconPath)
+
+    '''if 'switchIcon' in config and os.path.exists(config['switchIcon']):
+        mipmapSupport = ['mipmap-xhdpi', 'mipmap-xxhdpi', 'mipmap-xxxhdpi']
+        for mipmap in mipmapSupport:
+            iconPath = os.path.join(subChannelPath, 'icon', mipmap, 'common_sdk_icon2.png')
+            file_utils.copyFile(config['switchIcon'], iconPath)'''
+
+    if 'splash' in config and os.path.exists(config['splash']):
+        splashPath = os.path.join(
+            subChannelPath, 'splash', 'drawable-hdpi', 'common_sdk_launcher_bg.jpg')
+        file_utils.copyFile(config['splash'], splashPath)
+
+    # print('------subChannelPath 目录清空:%s  -------' % subChannelPath)
+    # file_utils.deleteFolder(subChannelPath)
+    if 'copyList' in config:
+
+        for item in config['copyList']:
+            if item['toFile'] == '':
+                continue
+
+            if not os.path.exists(item['fromFile']):
+                continue
+
+            toFile = item['toFile']
+            if toFile[:3] == 'res':
+                toFile = 'image' + toFile[3:]
+
+            resPath = getPackagePath(subChannelPath, toFile)
+            file_utils.copyFile(item['fromFile'], resPath)
+
+    if 'package' in config and os.path.exists(config['package']):
+        newGameApk = config['package']
+        gameApk = file_utils.getFullGameApk(game)
+        cacheGameApk = file_utils.getCacheGameApk(game, random, sdk)
+        file_utils.copyFile(newGameApk, cacheGameApk)
+        return 1
+
+
+def getPackagePath(basePath, packageName):
+    '''
+    包名对应的目录
+    '''
+    packageNameSplit = packageName.replace('\\', '/').split('/')
+    newPath = basePath
+    for item in packageNameSplit:
+        newPath = os.path.join(newPath, item)
+    return newPath
+
+
+def getMappingSdk(config):
+    sdk = config['sdk']
+    mapping = sdk
+    if sdk in sdkMapping:
+        mapping = sdkMapping[sdk]
+    else:
+        return 'jm_' + sdk
+
+    if type(mapping) == dict:
+        sdkConfig = config[sdk]
+        if 'SUB_CHANNEL' in sdkConfig and sdkConfig['SUB_CHANNEL'] != '':
+            subChannel = sdkConfig['SUB_CHANNEL']
+        else:
+            subChannel = 'default'
+        return mapping[subChannel]
+    else:
+        return mapping
+
+
+def getScriptMapping(sdk):
+    if sdk in scriptMapping:
+        return scriptMapping[sdk]
+    return sdk
+
+
+packageWeb()

+ 313 - 313
package_web_record.py

@@ -1,314 +1,314 @@
-import file_utils
-import package_utils_record
-import os.path
-import sys
-import json
-import importlib
-from PIL import Image, ImageDraw
-
-def packageWeb():
-    if len(sys.argv) < 2:
-        print('argument is missing')
-        return 1
-
-    # 打包配置的路径
-    packageConfig = sys.argv[1]
-
-    jsonText = file_utils.readFile(packageConfig)
-    config = json.loads(jsonText)
-
-    print('*************config*****************')
-    print(jsonText)
-    print('************************************')
-
-    package(config, config['sdk'])
-
-def package(config, sdk):
-    print('use script 3rd')
-    jsonConfig = {}
-    game = config['app']
-    subChannel = None
-
-    if 'subChannel' in config:
-        subChannel = config['subChannel']
-        jsonConfig['subChannel'] = config['subChannel']
-
-    # 必须参数
-    jsonConfig['packageName'] = config['packageName']
-    jsonConfig['name'] = config['name']
-
-    # 可选参数
-    if 'outName' in config:
-        jsonConfig['outName'] = config['outName']
-
-    if 'outPath' in config:
-        jsonConfig['outPath'] = config['outPath']
-
-    if 'changeIcon' in config:
-        jsonConfig['changeIcon'] = toBoolean(config['changeIcon'])
-
-    if 'addLauncher' in config:
-        jsonConfig['addLauncher'] = toBoolean(config['addLauncher'])
-
-    if 'versionCode' in config:
-        jsonConfig['versionCode'] = config['versionCode']
-
-    if 'versionName' in config:
-        jsonConfig['versionName'] = config['versionName']
-
-    if 'targetSdkVersion' in config:
-        jsonConfig['targetSdkVersion'] = config['targetSdkVersion']
-        
-    if 'v2disable' in config:
-        jsonConfig['v2disable'] = toBoolean(config['v2disable'])
-
-    if 'aapt2disable' in config:
-        jsonConfig['aapt2disable'] = toBoolean(config['aapt2disable'])
-
-    # sdk相关参数
-    if 'properties' in config:
-        jsonConfig['properties'] = config['properties']
-
-    jsonConfig['bgMusic'] = config['bgMusic']
-    if 'recordConfig' in config:
-        recordConfig = config['recordConfig']
-        setRecordConfig(jsonConfig, recordConfig)
-
-        userIcon = recordConfig['userIcon']
-        suffix = userIcon[userIcon.index('.'):]
-        item = {'fromFile':userIcon, 'toFile':'res/drawable/float_sdk_user_icon' + suffix}
-
-        if 'copyList' in config:
-            copyList = config['copyList']
-            copyList.append(item)
-        else:
-            config['copyList'] = [item]
-
-    configData = jsonConfig['configData']
-    properties = jsonConfig['properties']
-    configData['agent'] = properties['agent']
-    configData['buildTime'] = properties['version']
-    configData['appId'] = properties['appid']
-    configData['appkey'] = properties['appkey']
-    if 'host' in properties:
-        configData['host'] = properties['host']
-
-    if 'deleteList' in config:
-        jsonConfig['deleteList'] = config['deleteList']
-
-    
-
-    # 获取sdk相关配置
-    getSdkConfig(sdk, jsonConfig, config)
-
-    # 生成配置文件
-    createOrUpdateConfigFile(game, sdk, jsonConfig)
-
-    # 拷贝资源
-    copyRes(game, sdk, subChannel, config)
-
-    # 打包
-    package_utils_record.packConsole(game, sdk, subChannel)
-
-def setRecordConfig(config, recordConfig):
-    configData = None
-    if 'configData' in config:
-        configData = config['configData']
-        configData['bgMusic'] = 'bg_music.mp3'
-        configData['gameId'] = recordConfig['gameId']
-        configData['gameName'] = recordConfig['gameName']
-        configData['gameIcon'] = recordConfig['gameIcon']
-        configData['gameUrl'] = recordConfig['gameUrl']
-        configData['skinId'] = recordConfig['skinId']
-        configData['host'] = recordConfig['host']
-        configData['appDownUrl'] = recordConfig['appDownUrl']
-        configData['userId'] = recordConfig['userId']
-        configData['userName'] = recordConfig['userName']
-        configData['userDesc'] = recordConfig['userDesc']
-    else:
-        config['configData'] = {
-            'bgMusic':'bg_music.mp3',
-            'gameId':recordConfig['gameId'],
-            'gameName':recordConfig['gameName'],
-            'gameIcon':recordConfig['gameIcon'],
-            'gameUrl':recordConfig['gameUrl'],
-            'skinId':recordConfig['skinId'],
-            'host':recordConfig['host'],
-            'appDownUrl':recordConfig['appDownUrl'],
-            'userId':recordConfig['userId'],
-            'userName':recordConfig['userName'],
-            'userDesc':recordConfig['userDesc']
-        }
-
-def toBoolean(booleanStr):
-    if type(booleanStr) == bool:
-        return booleanStr
-
-    if booleanStr == 'true':
-        return True
-    return False
-
-def getSdkConfig(sdk, jsonConfig, config):
-    scriptPath = os.path.join(file_utils.getCurrentPath(), 'sdk_script')
-    sdkScript = getScriptMapping(sdk)
-    targetScript = os.path.join(scriptPath, '%s.py' % sdkScript)
-    if not os.path.exists(targetScript):
-        print('%s no exists' % targetScript)
-        return 0
-
-    sys.path.append(scriptPath)
-    module = importlib.import_module(sdkScript)# 动态导入相应模块
-    module.getSdkConfig(jsonConfig, config)# 执行脚本功能
-    sys.path.remove(scriptPath)
-
-def createOrUpdateConfigFile(game, sdk, jsonConfig):
-    '''
-    更新配置文件
-    '''
-    if 'subChannel' not in jsonConfig:
-        return 0
-
-    print('createOrUpdateConfigFile ...')
-
-    channelPath = file_utils.getChannelPath(game, sdk)
-    configPath = os.path.join(channelPath, 'config.json')
-    #configPath = os.path.join(file_utils.getCurrentPath(), 'test', 'test.json')
-
-    if os.path.exists(configPath):
-        # 更新数据
-        jsonText = file_utils.readFile(configPath)
-        config = json.loads(jsonText)
-
-        count = 0
-        if type(config) == list:
-            for item in config:
-                if item['subChannel'] == jsonConfig['subChannel']:
-                    print('find same config ...')
-                    del config[count]
-                    break
-
-                count += 1
-
-            config.append(jsonConfig)
-
-            createConfigFile(config, configPath)
-        elif type(config) == dict:
-            if config['subChannel'] == jsonConfig['subChannel']:
-                print('find same config ...')
-                createConfigFile(jsonConfig, configPath)
-            else:
-                print('add a new config ...')
-                config = [config, jsonConfig]
-
-                createConfigFile(config, configPath)
-    else:
-        print('create a new config ...')
-        createConfigFile([jsonConfig], configPath)
-
-def createConfigFile(jsonConfig, configPath):
-    '''
-    创建配置文件
-    '''
-    jsonStr = json.dumps(jsonConfig, ensure_ascii=False)
-    print('*************out config*************')
-    print(jsonStr)
-    print('************************************')
-    file_utils.createFile(configPath, jsonStr)
-
-def copyRes(game, sdk, subChannel, config):
-    '''
-    拷贝资源
-    '''
-    if subChannel is None:
-        return 0
-
-    channelPath = file_utils.getChannelPath(game, sdk)
-    subChannelPath = os.path.join(channelPath, subChannel)
-    if 'icon' in config and os.path.exists(config['icon']):
-        mipmapSupport = ['mipmap-xhdpi', 'mipmap-xxhdpi', 'mipmap-xxxhdpi']
-        for mipmap in mipmapSupport:
-            mipmapPath = os.path.join(subChannelPath, 'icon', mipmap)
-            if not os.path.exists(mipmapPath):
-                os.makedirs(mipmapPath)
-            iconPath = os.path.join(subChannelPath, 'icon', mipmap, 'record_sdk_icon.png')
-            if not os.path.exists(iconPath):
-                file_utils.createFile(iconPath, '')
-            if mipmap == 'mipmap-xhdpi':
-                size = 96
-            elif mipmap == 'mipmap-xxhdpi':
-                size = 144
-            else:
-                size = 192
-            roundRectangleIcon(config['icon'], iconPath, size)
-            #file_utils.copyFile(config['icon'], iconPath)
-
-    if 'splash' in config and os.path.exists(config['splash']):
-        splashPath = os.path.join(subChannelPath, 'splash', 'drawable-hdpi', 'shanshen_sdk_launcher_bg.jpg')
-        file_utils.copyFile(config['splash'], splashPath)
-
-    if 'bgMusic' in config and os.path.exists(config['bgMusic']):
-        musicPath = os.path.join(subChannelPath, 'assets', 'bg_music.mp3')
-        file_utils.copyFile(config['bgMusic'], musicPath)
-
-    if 'copyList' in config:
-        for item in config['copyList']:
-            if item['toFile'] == '':
-                continue
-
-            if not os.path.exists(item['fromFile']):
-                continue
-
-            toFile = item['toFile']
-            if toFile[:3] == 'res':
-                toFile = 'image' + toFile[3:]
-                
-            resPath = getPackagePath(subChannelPath, toFile)
-            file_utils.copyFile(item['fromFile'], resPath)
-
-    if 'package' in config and os.path.exists(config['package']):
-        newGameApk = config['package']
-        gameApk = file_utils.getFullGameApk(game)
-        file_utils.copyFile(newGameApk, gameApk)
-
-    if 'languageList' in config:
-        for item in config['languageList']:
-            languagePath = os.path.join(subChannelPath, 'merge', item['apkLanguage'])
-            file_utils.copyFile(item['language'], languagePath)
-
-def roundRectangleIcon(iconPath, outPath, outSize):
-    markerPath = os.path.join(file_utils.getFullInternalPath(), 'marker', 'marker.png')
-    img = Image.open(iconPath).resize((192, 192)).convert("RGBA")
-    marker = Image.open(markerPath).resize((192, 192)).convert("RGBA")
-    img.paste(marker, (0, 0), marker)
-
-    rad = 30  # 设置半径 
-    circle = Image.new('L', (rad * 2, rad * 2), 0)
-    draw = ImageDraw.Draw(circle)
-    draw.ellipse((0, 0, rad * 2, rad * 2), fill=255)
-    alpha = Image.new('L', img.size, 255)
-    w, h = img.size
-    alpha.paste(circle.crop((0, 0, rad, rad)), (0, 0))
-    alpha.paste(circle.crop((0, rad, rad, rad * 2)), (0, h - rad))
-    alpha.paste(circle.crop((rad, 0, rad * 2, rad)), (w - rad, 0))
-    alpha.paste(circle.crop((rad, rad, rad * 2, rad * 2)), (w - rad, h - rad))
-    img.putalpha(alpha)
-
-    img.resize((outSize, outSize)).save(outPath, 'png')
-
-def getPackagePath(basePath, packageName):
-    '''
-    包名对应的目录
-    '''
-    packageNameSplit = packageName.replace('\\', '/').split('/')
-    newPath = basePath
-    for item in packageNameSplit:
-        newPath = os.path.join(newPath, item)
-    return newPath
-
-def getMappingSdk(config):
-    return config['sdk']
-
-def getScriptMapping(sdk):
-    return sdk
-
+import file_utils
+import package_utils_record
+import os.path
+import sys
+import json
+import importlib
+from PIL import Image, ImageDraw
+
+def packageWeb():
+    if len(sys.argv) < 2:
+        print('argument is missing')
+        return 1
+
+    # 打包配置的路径
+    packageConfig = sys.argv[1]
+
+    jsonText = file_utils.readFile(packageConfig)
+    config = json.loads(jsonText)
+
+    print('*************config*****************')
+    print(jsonText)
+    print('************************************')
+
+    package(config, config['sdk'])
+
+def package(config, sdk):
+    print('use script 3rd')
+    jsonConfig = {}
+    game = config['app']
+    subChannel = None
+
+    if 'subChannel' in config:
+        subChannel = config['subChannel']
+        jsonConfig['subChannel'] = config['subChannel']
+
+    # 必须参数
+    jsonConfig['packageName'] = config['packageName']
+    jsonConfig['name'] = config['name']
+
+    # 可选参数
+    if 'outName' in config:
+        jsonConfig['outName'] = config['outName']
+
+    if 'outPath' in config:
+        jsonConfig['outPath'] = config['outPath']
+
+    if 'changeIcon' in config:
+        jsonConfig['changeIcon'] = toBoolean(config['changeIcon'])
+
+    if 'addLauncher' in config:
+        jsonConfig['addLauncher'] = toBoolean(config['addLauncher'])
+
+    if 'versionCode' in config:
+        jsonConfig['versionCode'] = config['versionCode']
+
+    if 'versionName' in config:
+        jsonConfig['versionName'] = config['versionName']
+
+    if 'targetSdkVersion' in config:
+        jsonConfig['targetSdkVersion'] = config['targetSdkVersion']
+        
+    if 'v2disable' in config:
+        jsonConfig['v2disable'] = toBoolean(config['v2disable'])
+
+    if 'aapt2disable' in config:
+        jsonConfig['aapt2disable'] = toBoolean(config['aapt2disable'])
+
+    # sdk相关参数
+    if 'properties' in config:
+        jsonConfig['properties'] = config['properties']
+
+    jsonConfig['bgMusic'] = config['bgMusic']
+    if 'recordConfig' in config:
+        recordConfig = config['recordConfig']
+        setRecordConfig(jsonConfig, recordConfig)
+
+        userIcon = recordConfig['userIcon']
+        suffix = userIcon[userIcon.index('.'):]
+        item = {'fromFile':userIcon, 'toFile':'res/drawable/float_sdk_user_icon' + suffix}
+
+        if 'copyList' in config:
+            copyList = config['copyList']
+            copyList.append(item)
+        else:
+            config['copyList'] = [item]
+
+    configData = jsonConfig['configData']
+    properties = jsonConfig['properties']
+    configData['agent'] = properties['agent']
+    configData['buildTime'] = properties['version']
+    configData['appId'] = properties['appid']
+    configData['appkey'] = properties['appkey']
+    if 'host' in properties:
+        configData['host'] = properties['host']
+
+    if 'deleteList' in config:
+        jsonConfig['deleteList'] = config['deleteList']
+
+    
+
+    # 获取sdk相关配置
+    getSdkConfig(sdk, jsonConfig, config)
+
+    # 生成配置文件
+    createOrUpdateConfigFile(game, sdk, jsonConfig)
+
+    # 拷贝资源
+    copyRes(game, sdk, subChannel, config)
+
+    # 打包
+    package_utils_record.packConsole(game, sdk, subChannel)
+
+def setRecordConfig(config, recordConfig):
+    configData = None
+    if 'configData' in config:
+        configData = config['configData']
+        configData['bgMusic'] = 'bg_music.mp3'
+        configData['gameId'] = recordConfig['gameId']
+        configData['gameName'] = recordConfig['gameName']
+        configData['gameIcon'] = recordConfig['gameIcon']
+        configData['gameUrl'] = recordConfig['gameUrl']
+        configData['skinId'] = recordConfig['skinId']
+        configData['host'] = recordConfig['host']
+        configData['appDownUrl'] = recordConfig['appDownUrl']
+        configData['userId'] = recordConfig['userId']
+        configData['userName'] = recordConfig['userName']
+        configData['userDesc'] = recordConfig['userDesc']
+    else:
+        config['configData'] = {
+            'bgMusic':'bg_music.mp3',
+            'gameId':recordConfig['gameId'],
+            'gameName':recordConfig['gameName'],
+            'gameIcon':recordConfig['gameIcon'],
+            'gameUrl':recordConfig['gameUrl'],
+            'skinId':recordConfig['skinId'],
+            'host':recordConfig['host'],
+            'appDownUrl':recordConfig['appDownUrl'],
+            'userId':recordConfig['userId'],
+            'userName':recordConfig['userName'],
+            'userDesc':recordConfig['userDesc']
+        }
+
+def toBoolean(booleanStr):
+    if type(booleanStr) == bool:
+        return booleanStr
+
+    if booleanStr == 'true':
+        return True
+    return False
+
+def getSdkConfig(sdk, jsonConfig, config):
+    scriptPath = os.path.join(file_utils.getCurrentPath(), 'sdk_script')
+    sdkScript = getScriptMapping(sdk)
+    targetScript = os.path.join(scriptPath, '%s.py' % sdkScript)
+    if not os.path.exists(targetScript):
+        print('%s no exists' % targetScript)
+        return 0
+
+    sys.path.append(scriptPath)
+    module = importlib.import_module(sdkScript)# 动态导入相应模块
+    module.getSdkConfig(jsonConfig, config)# 执行脚本功能
+    sys.path.remove(scriptPath)
+
+def createOrUpdateConfigFile(game, sdk, jsonConfig):
+    '''
+    更新配置文件
+    '''
+    if 'subChannel' not in jsonConfig:
+        return 0
+
+    print('createOrUpdateConfigFile ...')
+
+    channelPath = file_utils.getChannelPath(game, sdk)
+    configPath = os.path.join(channelPath, 'config.json')
+    #configPath = os.path.join(file_utils.getCurrentPath(), 'test', 'test.json')
+
+    if os.path.exists(configPath):
+        # 更新数据
+        jsonText = file_utils.readFile(configPath)
+        config = json.loads(jsonText)
+
+        count = 0
+        if type(config) == list:
+            for item in config:
+                if item['subChannel'] == jsonConfig['subChannel']:
+                    print('find same config ...')
+                    del config[count]
+                    break
+
+                count += 1
+
+            config.append(jsonConfig)
+
+            createConfigFile(config, configPath)
+        elif type(config) == dict:
+            if config['subChannel'] == jsonConfig['subChannel']:
+                print('find same config ...')
+                createConfigFile(jsonConfig, configPath)
+            else:
+                print('add a new config ...')
+                config = [config, jsonConfig]
+
+                createConfigFile(config, configPath)
+    else:
+        print('create a new config ...')
+        createConfigFile([jsonConfig], configPath)
+
+def createConfigFile(jsonConfig, configPath):
+    '''
+    创建配置文件
+    '''
+    jsonStr = json.dumps(jsonConfig, ensure_ascii=False)
+    print('*************out config*************')
+    print(jsonStr)
+    print('************************************')
+    file_utils.createFile(configPath, jsonStr)
+
+def copyRes(game, sdk, subChannel, config):
+    '''
+    拷贝资源
+    '''
+    if subChannel is None:
+        return 0
+
+    channelPath = file_utils.getChannelPath(game, sdk)
+    subChannelPath = os.path.join(channelPath, subChannel)
+    if 'icon' in config and os.path.exists(config['icon']):
+        mipmapSupport = ['mipmap-xhdpi', 'mipmap-xxhdpi', 'mipmap-xxxhdpi']
+        for mipmap in mipmapSupport:
+            mipmapPath = os.path.join(subChannelPath, 'icon', mipmap)
+            if not os.path.exists(mipmapPath):
+                os.makedirs(mipmapPath)
+            iconPath = os.path.join(subChannelPath, 'icon', mipmap, 'record_sdk_icon.png')
+            if not os.path.exists(iconPath):
+                file_utils.createFile(iconPath, '')
+            if mipmap == 'mipmap-xhdpi':
+                size = 96
+            elif mipmap == 'mipmap-xxhdpi':
+                size = 144
+            else:
+                size = 192
+            roundRectangleIcon(config['icon'], iconPath, size)
+            #file_utils.copyFile(config['icon'], iconPath)
+
+    if 'splash' in config and os.path.exists(config['splash']):
+        splashPath = os.path.join(subChannelPath, 'splash', 'drawable-hdpi', 'shanshen_sdk_launcher_bg.jpg')
+        file_utils.copyFile(config['splash'], splashPath)
+
+    if 'bgMusic' in config and os.path.exists(config['bgMusic']):
+        musicPath = os.path.join(subChannelPath, 'assets', 'bg_music.mp3')
+        file_utils.copyFile(config['bgMusic'], musicPath)
+
+    if 'copyList' in config:
+        for item in config['copyList']:
+            if item['toFile'] == '':
+                continue
+
+            if not os.path.exists(item['fromFile']):
+                continue
+
+            toFile = item['toFile']
+            if toFile[:3] == 'res':
+                toFile = 'image' + toFile[3:]
+                
+            resPath = getPackagePath(subChannelPath, toFile)
+            file_utils.copyFile(item['fromFile'], resPath)
+
+    if 'package' in config and os.path.exists(config['package']):
+        newGameApk = config['package']
+        gameApk = file_utils.getFullGameApk(game)
+        file_utils.copyFile(newGameApk, gameApk)
+
+    if 'languageList' in config:
+        for item in config['languageList']:
+            languagePath = os.path.join(subChannelPath, 'merge', item['apkLanguage'])
+            file_utils.copyFile(item['language'], languagePath)
+
+def roundRectangleIcon(iconPath, outPath, outSize):
+    markerPath = os.path.join(file_utils.getFullInternalPath(), 'marker', 'marker.png')
+    img = Image.open(iconPath).resize((192, 192)).convert("RGBA")
+    marker = Image.open(markerPath).resize((192, 192)).convert("RGBA")
+    img.paste(marker, (0, 0), marker)
+
+    rad = 30  # 设置半径 
+    circle = Image.new('L', (rad * 2, rad * 2), 0)
+    draw = ImageDraw.Draw(circle)
+    draw.ellipse((0, 0, rad * 2, rad * 2), fill=255)
+    alpha = Image.new('L', img.size, 255)
+    w, h = img.size
+    alpha.paste(circle.crop((0, 0, rad, rad)), (0, 0))
+    alpha.paste(circle.crop((0, rad, rad, rad * 2)), (0, h - rad))
+    alpha.paste(circle.crop((rad, 0, rad * 2, rad)), (w - rad, 0))
+    alpha.paste(circle.crop((rad, rad, rad * 2, rad * 2)), (w - rad, h - rad))
+    img.putalpha(alpha)
+
+    img.resize((outSize, outSize)).save(outPath, 'png')
+
+def getPackagePath(basePath, packageName):
+    '''
+    包名对应的目录
+    '''
+    packageNameSplit = packageName.replace('\\', '/').split('/')
+    newPath = basePath
+    for item in packageNameSplit:
+        newPath = os.path.join(newPath, item)
+    return newPath
+
+def getMappingSdk(config):
+    return config['sdk']
+
+def getScriptMapping(sdk):
+    return sdk
+
 #packageWeb()

+ 212 - 212
package_web_shanshen.py

@@ -1,213 +1,213 @@
-import file_utils
-import package_utils_shanshen
-import os.path
-import sys
-import json
-import importlib
-
-def packageWeb():
-    if len(sys.argv) < 2:
-        print('argument is missing')
-        return 1
-
-    # 打包配置的路径
-    packageConfig = sys.argv[1]
-
-    jsonText = file_utils.readFile(packageConfig)
-    config = json.loads(jsonText)
-
-    print('*************config*****************')
-    print(jsonText)
-    print('************************************')
-
-    package(config, config['sdk'])
-
-def package(config, sdk):
-    print('use script 2nd')
-    jsonConfig = {}
-    game = config['app']
-    subChannel = None
-
-    if 'subChannel' in config:
-        subChannel = config['subChannel']
-        jsonConfig['subChannel'] = config['subChannel']
-
-    # 必须参数
-    jsonConfig['packageName'] = config['packageName']
-    jsonConfig['name'] = config['name']
-
-    # 可选参数
-    if 'outName' in config:
-        jsonConfig['outName'] = config['outName']
-
-    if 'outPath' in config:
-        jsonConfig['outPath'] = config['outPath']
-
-    if 'changeIcon' in config:
-        jsonConfig['changeIcon'] = toBoolean(config['changeIcon'])
-
-    if 'addLauncher' in config:
-        jsonConfig['addLauncher'] = toBoolean(config['addLauncher'])
-
-    if 'versionCode' in config:
-        jsonConfig['versionCode'] = config['versionCode']
-
-    if 'versionName' in config:
-        jsonConfig['versionName'] = config['versionName']
-
-    if 'targetSdkVersion' in config:
-        jsonConfig['targetSdkVersion'] = config['targetSdkVersion']
-        
-    if 'v2disable' in config:
-        jsonConfig['v2disable'] = toBoolean(config['v2disable'])
-
-    if 'aapt2disable' in config:
-        jsonConfig['aapt2disable'] = toBoolean(config['aapt2disable'])
-
-    # sdk相关参数
-    if 'properties' in config:
-        jsonConfig['properties'] = config['properties']
-
-    # 获取sdk相关配置
-    getSdkConfig(sdk, jsonConfig, config)
-
-    # 生成配置文件
-    createOrUpdateConfigFile(game, sdk, jsonConfig)
-
-    # 拷贝资源
-    copyRes(game, sdk, subChannel, config)
-
-    # 打包
-    package_utils_shanshen.packConsole(game, sdk, subChannel)
-
-def toBoolean(booleanStr):
-    if type(booleanStr) == bool:
-        return booleanStr
-
-    if booleanStr == 'true':
-        return True
-    return False
-
-def getSdkConfig(sdk, jsonConfig, config):
-    scriptPath = os.path.join(file_utils.getCurrentPath(), 'sdk_script')
-    sdkScript = getScriptMapping(sdk)
-    targetScript = os.path.join(scriptPath, '%s.py' % sdkScript)
-    if not os.path.exists(targetScript):
-        print('%s no exists' % targetScript)
-        return 0
-
-    sys.path.append(scriptPath)
-    module = importlib.import_module(sdkScript)# 动态导入相应模块
-    module.getSdkConfig(jsonConfig, config)# 执行脚本功能
-    sys.path.remove(scriptPath)
-
-def createOrUpdateConfigFile(game, sdk, jsonConfig):
-    '''
-    更新配置文件
-    '''
-    if 'subChannel' not in jsonConfig:
-        return 0
-
-    print('createOrUpdateConfigFile ...')
-
-    channelPath = file_utils.getChannelPath(game, sdk)
-    configPath = os.path.join(channelPath, 'config.json')
-    #configPath = os.path.join(file_utils.getCurrentPath(), 'test', 'test.json')
-
-    if os.path.exists(configPath):
-        # 更新数据
-        jsonText = file_utils.readFile(configPath)
-        config = json.loads(jsonText)
-
-        count = 0
-        if type(config) == list:
-            for item in config:
-                if item['subChannel'] == jsonConfig['subChannel']:
-                    print('find same config ...')
-                    del config[count]
-                    break
-
-                count += 1
-
-            config.append(jsonConfig)
-
-            createConfigFile(config, configPath)
-        elif type(config) == dict:
-            if config['subChannel'] == jsonConfig['subChannel']:
-                print('find same config ...')
-                createConfigFile(jsonConfig, configPath)
-            else:
-                print('add a new config ...')
-                config = [config, jsonConfig]
-
-                createConfigFile(config, configPath)
-    else:
-        print('create a new config ...')
-        createConfigFile([jsonConfig], configPath)
-
-def createConfigFile(jsonConfig, configPath):
-    '''
-    创建配置文件
-    '''
-    jsonStr = json.dumps(jsonConfig, ensure_ascii=False)
-    print('*************out config*************')
-    print(jsonStr)
-    print('************************************')
-    file_utils.createFile(configPath, jsonStr)
-
-def copyRes(game, sdk, subChannel, config):
-    '''
-    拷贝资源
-    '''
-    if subChannel is None:
-        return 0
-
-    channelPath = file_utils.getChannelPath(game, sdk)
-    subChannelPath = os.path.join(channelPath, subChannel)
-    if 'icon' in config and os.path.exists(config['icon']):
-        mipmapSupport = ['mipmap-xhdpi', 'mipmap-xxhdpi', 'mipmap-xxxhdpi']
-        for mipmap in mipmapSupport:
-            iconPath = os.path.join(subChannelPath, 'icon', mipmap, 'shanshen_sdk_icon.png')
-            file_utils.copyFile(config['icon'], iconPath)
-
-    if 'splash' in config and os.path.exists(config['splash']):
-        splashPath = os.path.join(subChannelPath, 'splash', 'drawable-hdpi', 'shanshen_sdk_launcher_bg.jpg')
-        file_utils.copyFile(config['splash'], splashPath)
-
-    if 'copyList' in config:
-        for item in config['copyList']:
-            if item['toFile'] == '':
-                continue
-
-            if not os.path.exists(item['fromFile']):
-                continue
-
-            toFile = item['toFile']
-            if toFile[:3] == 'res':
-                toFile = 'image' + toFile[3:]
-                
-            resPath = getPackagePath(subChannelPath, toFile)
-            file_utils.copyFile(item['fromFile'], resPath)
-
-    if 'package' in config and os.path.exists(config['package']):
-        newGameApk = config['package']
-        gameApk = file_utils.getFullGameApk(game)
-        file_utils.copyFile(newGameApk, gameApk)
-
-def getPackagePath(basePath, packageName):
-    '''
-    包名对应的目录
-    '''
-    packageNameSplit = packageName.replace('\\', '/').split('/')
-    newPath = basePath
-    for item in packageNameSplit:
-        newPath = os.path.join(newPath, item)
-    return newPath
-
-def getMappingSdk(config):
-    return config['sdk']
-
-def getScriptMapping(sdk):
-    return sdk
-
+import file_utils
+import package_utils_shanshen
+import os.path
+import sys
+import json
+import importlib
+
+def packageWeb():
+    if len(sys.argv) < 2:
+        print('argument is missing')
+        return 1
+
+    # 打包配置的路径
+    packageConfig = sys.argv[1]
+
+    jsonText = file_utils.readFile(packageConfig)
+    config = json.loads(jsonText)
+
+    print('*************config*****************')
+    print(jsonText)
+    print('************************************')
+
+    package(config, config['sdk'])
+
+def package(config, sdk):
+    print('use script 2nd')
+    jsonConfig = {}
+    game = config['app']
+    subChannel = None
+
+    if 'subChannel' in config:
+        subChannel = config['subChannel']
+        jsonConfig['subChannel'] = config['subChannel']
+
+    # 必须参数
+    jsonConfig['packageName'] = config['packageName']
+    jsonConfig['name'] = config['name']
+
+    # 可选参数
+    if 'outName' in config:
+        jsonConfig['outName'] = config['outName']
+
+    if 'outPath' in config:
+        jsonConfig['outPath'] = config['outPath']
+
+    if 'changeIcon' in config:
+        jsonConfig['changeIcon'] = toBoolean(config['changeIcon'])
+
+    if 'addLauncher' in config:
+        jsonConfig['addLauncher'] = toBoolean(config['addLauncher'])
+
+    if 'versionCode' in config:
+        jsonConfig['versionCode'] = config['versionCode']
+
+    if 'versionName' in config:
+        jsonConfig['versionName'] = config['versionName']
+
+    if 'targetSdkVersion' in config:
+        jsonConfig['targetSdkVersion'] = config['targetSdkVersion']
+        
+    if 'v2disable' in config:
+        jsonConfig['v2disable'] = toBoolean(config['v2disable'])
+
+    if 'aapt2disable' in config:
+        jsonConfig['aapt2disable'] = toBoolean(config['aapt2disable'])
+
+    # sdk相关参数
+    if 'properties' in config:
+        jsonConfig['properties'] = config['properties']
+
+    # 获取sdk相关配置
+    getSdkConfig(sdk, jsonConfig, config)
+
+    # 生成配置文件
+    createOrUpdateConfigFile(game, sdk, jsonConfig)
+
+    # 拷贝资源
+    copyRes(game, sdk, subChannel, config)
+
+    # 打包
+    package_utils_shanshen.packConsole(game, sdk, subChannel)
+
+def toBoolean(booleanStr):
+    if type(booleanStr) == bool:
+        return booleanStr
+
+    if booleanStr == 'true':
+        return True
+    return False
+
+def getSdkConfig(sdk, jsonConfig, config):
+    scriptPath = os.path.join(file_utils.getCurrentPath(), 'sdk_script')
+    sdkScript = getScriptMapping(sdk)
+    targetScript = os.path.join(scriptPath, '%s.py' % sdkScript)
+    if not os.path.exists(targetScript):
+        print('%s no exists' % targetScript)
+        return 0
+
+    sys.path.append(scriptPath)
+    module = importlib.import_module(sdkScript)# 动态导入相应模块
+    module.getSdkConfig(jsonConfig, config)# 执行脚本功能
+    sys.path.remove(scriptPath)
+
+def createOrUpdateConfigFile(game, sdk, jsonConfig):
+    '''
+    更新配置文件
+    '''
+    if 'subChannel' not in jsonConfig:
+        return 0
+
+    print('createOrUpdateConfigFile ...')
+
+    channelPath = file_utils.getChannelPath(game, sdk)
+    configPath = os.path.join(channelPath, 'config.json')
+    #configPath = os.path.join(file_utils.getCurrentPath(), 'test', 'test.json')
+
+    if os.path.exists(configPath):
+        # 更新数据
+        jsonText = file_utils.readFile(configPath)
+        config = json.loads(jsonText)
+
+        count = 0
+        if type(config) == list:
+            for item in config:
+                if item['subChannel'] == jsonConfig['subChannel']:
+                    print('find same config ...')
+                    del config[count]
+                    break
+
+                count += 1
+
+            config.append(jsonConfig)
+
+            createConfigFile(config, configPath)
+        elif type(config) == dict:
+            if config['subChannel'] == jsonConfig['subChannel']:
+                print('find same config ...')
+                createConfigFile(jsonConfig, configPath)
+            else:
+                print('add a new config ...')
+                config = [config, jsonConfig]
+
+                createConfigFile(config, configPath)
+    else:
+        print('create a new config ...')
+        createConfigFile([jsonConfig], configPath)
+
+def createConfigFile(jsonConfig, configPath):
+    '''
+    创建配置文件
+    '''
+    jsonStr = json.dumps(jsonConfig, ensure_ascii=False)
+    print('*************out config*************')
+    print(jsonStr)
+    print('************************************')
+    file_utils.createFile(configPath, jsonStr)
+
+def copyRes(game, sdk, subChannel, config):
+    '''
+    拷贝资源
+    '''
+    if subChannel is None:
+        return 0
+
+    channelPath = file_utils.getChannelPath(game, sdk)
+    subChannelPath = os.path.join(channelPath, subChannel)
+    if 'icon' in config and os.path.exists(config['icon']):
+        mipmapSupport = ['mipmap-xhdpi', 'mipmap-xxhdpi', 'mipmap-xxxhdpi']
+        for mipmap in mipmapSupport:
+            iconPath = os.path.join(subChannelPath, 'icon', mipmap, 'shanshen_sdk_icon.png')
+            file_utils.copyFile(config['icon'], iconPath)
+
+    if 'splash' in config and os.path.exists(config['splash']):
+        splashPath = os.path.join(subChannelPath, 'splash', 'drawable-hdpi', 'shanshen_sdk_launcher_bg.jpg')
+        file_utils.copyFile(config['splash'], splashPath)
+
+    if 'copyList' in config:
+        for item in config['copyList']:
+            if item['toFile'] == '':
+                continue
+
+            if not os.path.exists(item['fromFile']):
+                continue
+
+            toFile = item['toFile']
+            if toFile[:3] == 'res':
+                toFile = 'image' + toFile[3:]
+                
+            resPath = getPackagePath(subChannelPath, toFile)
+            file_utils.copyFile(item['fromFile'], resPath)
+
+    if 'package' in config and os.path.exists(config['package']):
+        newGameApk = config['package']
+        gameApk = file_utils.getFullGameApk(game)
+        file_utils.copyFile(newGameApk, gameApk)
+
+def getPackagePath(basePath, packageName):
+    '''
+    包名对应的目录
+    '''
+    packageNameSplit = packageName.replace('\\', '/').split('/')
+    newPath = basePath
+    for item in packageNameSplit:
+        newPath = os.path.join(newPath, item)
+    return newPath
+
+def getMappingSdk(config):
+    return config['sdk']
+
+def getScriptMapping(sdk):
+    return sdk
+
 #packageWeb()

+ 204 - 204
package_web_yfsdk.py

@@ -1,205 +1,205 @@
-import file_utils
-import package_utils_yfsdk
-import os.path
-import sys
-import json
-import importlib
-
-def packageWeb():
-    if len(sys.argv) < 2:
-        print('argument is missing')
-        return 1
-
-    # 打包配置的路径
-    packageConfig = sys.argv[1]
-
-    jsonText = file_utils.readFile(packageConfig)
-    config = json.loads(jsonText)
-
-    print('*************config*****************')
-    print(jsonText)
-    print('************************************')
-
-    package(config, config['sdk'])
-
-def package(config, sdk):
-    print('use script yfsdk')
-    jsonConfig = {}
-    game = config['app']
-    subChannel = None
-
-    if 'subChannel' in config:
-        subChannel = config['subChannel']
-        jsonConfig['subChannel'] = config['subChannel']
-
-    # 必须参数
-    jsonConfig['packageName'] = config['packageName']
-    jsonConfig['name'] = config['name']
-
-    # 可选参数
-    if 'outName' in config:
-        jsonConfig['outName'] = config['outName']
-
-    if 'outPath' in config:
-        jsonConfig['outPath'] = config['outPath']
-
-    if 'changeIcon' in config:
-        jsonConfig['changeIcon'] = toBoolean(config['changeIcon'])
-
-    if 'addLauncher' in config:
-        jsonConfig['addLauncher'] = toBoolean(config['addLauncher'])
-
-    if 'versionCode' in config:
-        jsonConfig['versionCode'] = config['versionCode']
-
-    if 'versionName' in config:
-        jsonConfig['versionName'] = config['versionName']
-
-    if 'targetSdkVersion' in config:
-        jsonConfig['targetSdkVersion'] = config['targetSdkVersion']
-
-    if 'v2disable' in config:
-        jsonConfig['v2disable'] = toBoolean(config['v2disable'])
-
-    if 'aapt2disable' in config:
-        jsonConfig['aapt2disable'] = toBoolean(config['aapt2disable'])
-
-        # sdk相关参数
-    if 'properties' in config:
-        jsonConfig['properties'] = config['properties']
-
-    # 生成配置文件
-    createOrUpdateConfigFile(game, sdk, jsonConfig)
-
-    # 拷贝资源
-    copyRes(game, sdk, subChannel, config)
-
-    # 打包
-    package_utils_yfsdk.packConsole(game, sdk, subChannel)
-
-def toBoolean(booleanStr):
-    if type(booleanStr) == bool:
-        return booleanStr
-
-    if booleanStr == 'true':
-        return True
-    return False
-
-
-def createOrUpdateConfigFile(game, sdk, jsonConfig):
-    '''
-    更新配置文件
-    '''
-    if 'subChannel' not in jsonConfig:
-        return 0
-
-    print('createOrUpdateConfigFile ...')
-
-    channelPath = file_utils.getChannelPath(game, sdk)
-    configPath = os.path.join(channelPath, 'config.json')
-    # configPath = os.path.join(file_utils.getCurrentPath(), 'test', 'test.json')
-
-    if os.path.exists(configPath):
-        # 更新数据
-        jsonText = file_utils.readFile(configPath)
-        config = json.loads(jsonText)
-
-        count = 0
-        if type(config) == list:
-            for item in config:
-                if item['subChannel'] == jsonConfig['subChannel']:
-                    print('find same config ...')
-                    del config[count]
-                    break
-
-                count += 1
-
-            config.append(jsonConfig)
-
-            createConfigFile(config, configPath)
-        elif type(config) == dict:
-            if config['subChannel'] == jsonConfig['subChannel']:
-                print('find same config ...')
-                createConfigFile(jsonConfig, configPath)
-            else:
-                print('add a new config ...')
-                config = [config, jsonConfig]
-
-                createConfigFile(config, configPath)
-    else:
-        print('create a new config ...')
-        createConfigFile([jsonConfig], configPath)
-
-
-def createConfigFile(jsonConfig, configPath):
-    '''
-    创建配置文件
-    '''
-    jsonStr = json.dumps(jsonConfig, ensure_ascii=False)
-    print('*************out config*************')
-    print(jsonStr)
-    print('************************************')
-    file_utils.createFile(configPath, jsonStr)
-
-
-def copyRes(game, sdk, subChannel, config):
-    '''
-    拷贝资源
-    '''
-    if subChannel is None:
-        return 0
-
-    channelPath = file_utils.getChannelPath(game, sdk)
-    subChannelPath = os.path.join(channelPath, subChannel)
-    if 'icon' in config and os.path.exists(config['icon']):
-        mipmapSupport = ['mipmap-xhdpi', 'mipmap-xxhdpi', 'mipmap-xxxhdpi']
-        for mipmap in mipmapSupport:
-            iconPath = os.path.join(subChannelPath, 'icon', mipmap, 'common_sdk_icon.png')
-            print('yfsdk copyRes from--> ' + config['icon'])
-            print('yfsdk copyRes to--> ' + iconPath)
-            file_utils.copyFile(config['icon'], iconPath)
-
-    '''if 'switchIcon' in config and os.path.exists(config['switchIcon']):
-        mipmapSupport = ['mipmap-xhdpi', 'mipmap-xxhdpi', 'mipmap-xxxhdpi']
-        for mipmap in mipmapSupport:
-            iconPath = os.path.join(subChannelPath, 'icon', mipmap, 'common_sdk_icon2.png')
-            file_utils.copyFile(config['switchIcon'], iconPath)'''
-
-    if 'splash' in config and os.path.exists(config['splash']):
-        splashPath = os.path.join(subChannelPath, 'splash', 'drawable-hdpi', 'common_sdk_launcher_bg.jpg')
-        file_utils.copyFile(config['splash'], splashPath)
-
-    if 'copyList' in config:
-        for item in config['copyList']:
-            if item['toFile'] == '':
-                continue
-
-            if not os.path.exists(item['fromFile']):
-                continue
-
-            toFile = item['toFile']
-            if toFile[:3] == 'res':
-                toFile = 'image' + toFile[3:]
-
-            resPath = getPackagePath(subChannelPath, toFile)
-            file_utils.copyFile(item['fromFile'], resPath)
-
-    if 'package' in config and os.path.exists(config['package']):
-        newGameApk = config['package']
-        gameApk = file_utils.getFullGameApk(game)
-        file_utils.copyFile(newGameApk, gameApk)
-
-
-def getPackagePath(basePath, packageName):
-    '''
-    包名对应的目录
-    '''
-    packageNameSplit = packageName.replace('\\', '/').split('/')
-    newPath = basePath
-    for item in packageNameSplit:
-        newPath = os.path.join(newPath, item)
-    return newPath
-
-
-
+import file_utils
+import package_utils_yfsdk
+import os.path
+import sys
+import json
+import importlib
+
+def packageWeb():
+    if len(sys.argv) < 2:
+        print('argument is missing')
+        return 1
+
+    # 打包配置的路径
+    packageConfig = sys.argv[1]
+
+    jsonText = file_utils.readFile(packageConfig)
+    config = json.loads(jsonText)
+
+    print('*************config*****************')
+    print(jsonText)
+    print('************************************')
+
+    package(config, config['sdk'])
+
+def package(config, sdk):
+    print('use script yfsdk')
+    jsonConfig = {}
+    game = config['app']
+    subChannel = None
+
+    if 'subChannel' in config:
+        subChannel = config['subChannel']
+        jsonConfig['subChannel'] = config['subChannel']
+
+    # 必须参数
+    jsonConfig['packageName'] = config['packageName']
+    jsonConfig['name'] = config['name']
+
+    # 可选参数
+    if 'outName' in config:
+        jsonConfig['outName'] = config['outName']
+
+    if 'outPath' in config:
+        jsonConfig['outPath'] = config['outPath']
+
+    if 'changeIcon' in config:
+        jsonConfig['changeIcon'] = toBoolean(config['changeIcon'])
+
+    if 'addLauncher' in config:
+        jsonConfig['addLauncher'] = toBoolean(config['addLauncher'])
+
+    if 'versionCode' in config:
+        jsonConfig['versionCode'] = config['versionCode']
+
+    if 'versionName' in config:
+        jsonConfig['versionName'] = config['versionName']
+
+    if 'targetSdkVersion' in config:
+        jsonConfig['targetSdkVersion'] = config['targetSdkVersion']
+
+    if 'v2disable' in config:
+        jsonConfig['v2disable'] = toBoolean(config['v2disable'])
+
+    if 'aapt2disable' in config:
+        jsonConfig['aapt2disable'] = toBoolean(config['aapt2disable'])
+
+        # sdk相关参数
+    if 'properties' in config:
+        jsonConfig['properties'] = config['properties']
+
+    # 生成配置文件
+    createOrUpdateConfigFile(game, sdk, jsonConfig)
+
+    # 拷贝资源
+    copyRes(game, sdk, subChannel, config)
+
+    # 打包
+    package_utils_yfsdk.packConsole(game, sdk, subChannel)
+
+def toBoolean(booleanStr):
+    if type(booleanStr) == bool:
+        return booleanStr
+
+    if booleanStr == 'true':
+        return True
+    return False
+
+
+def createOrUpdateConfigFile(game, sdk, jsonConfig):
+    '''
+    更新配置文件
+    '''
+    if 'subChannel' not in jsonConfig:
+        return 0
+
+    print('createOrUpdateConfigFile ...')
+
+    channelPath = file_utils.getChannelPath(game, sdk)
+    configPath = os.path.join(channelPath, 'config.json')
+    # configPath = os.path.join(file_utils.getCurrentPath(), 'test', 'test.json')
+
+    if os.path.exists(configPath):
+        # 更新数据
+        jsonText = file_utils.readFile(configPath)
+        config = json.loads(jsonText)
+
+        count = 0
+        if type(config) == list:
+            for item in config:
+                if item['subChannel'] == jsonConfig['subChannel']:
+                    print('find same config ...')
+                    del config[count]
+                    break
+
+                count += 1
+
+            config.append(jsonConfig)
+
+            createConfigFile(config, configPath)
+        elif type(config) == dict:
+            if config['subChannel'] == jsonConfig['subChannel']:
+                print('find same config ...')
+                createConfigFile(jsonConfig, configPath)
+            else:
+                print('add a new config ...')
+                config = [config, jsonConfig]
+
+                createConfigFile(config, configPath)
+    else:
+        print('create a new config ...')
+        createConfigFile([jsonConfig], configPath)
+
+
+def createConfigFile(jsonConfig, configPath):
+    '''
+    创建配置文件
+    '''
+    jsonStr = json.dumps(jsonConfig, ensure_ascii=False)
+    print('*************out config*************')
+    print(jsonStr)
+    print('************************************')
+    file_utils.createFile(configPath, jsonStr)
+
+
+def copyRes(game, sdk, subChannel, config):
+    '''
+    拷贝资源
+    '''
+    if subChannel is None:
+        return 0
+
+    channelPath = file_utils.getChannelPath(game, sdk)
+    subChannelPath = os.path.join(channelPath, subChannel)
+    if 'icon' in config and os.path.exists(config['icon']):
+        mipmapSupport = ['mipmap-xhdpi', 'mipmap-xxhdpi', 'mipmap-xxxhdpi']
+        for mipmap in mipmapSupport:
+            iconPath = os.path.join(subChannelPath, 'icon', mipmap, 'common_sdk_icon.png')
+            print('yfsdk copyRes from--> ' + config['icon'])
+            print('yfsdk copyRes to--> ' + iconPath)
+            file_utils.copyFile(config['icon'], iconPath)
+
+    '''if 'switchIcon' in config and os.path.exists(config['switchIcon']):
+        mipmapSupport = ['mipmap-xhdpi', 'mipmap-xxhdpi', 'mipmap-xxxhdpi']
+        for mipmap in mipmapSupport:
+            iconPath = os.path.join(subChannelPath, 'icon', mipmap, 'common_sdk_icon2.png')
+            file_utils.copyFile(config['switchIcon'], iconPath)'''
+
+    if 'splash' in config and os.path.exists(config['splash']):
+        splashPath = os.path.join(subChannelPath, 'splash', 'drawable-hdpi', 'common_sdk_launcher_bg.jpg')
+        file_utils.copyFile(config['splash'], splashPath)
+
+    if 'copyList' in config:
+        for item in config['copyList']:
+            if item['toFile'] == '':
+                continue
+
+            if not os.path.exists(item['fromFile']):
+                continue
+
+            toFile = item['toFile']
+            if toFile[:3] == 'res':
+                toFile = 'image' + toFile[3:]
+
+            resPath = getPackagePath(subChannelPath, toFile)
+            file_utils.copyFile(item['fromFile'], resPath)
+
+    if 'package' in config and os.path.exists(config['package']):
+        newGameApk = config['package']
+        gameApk = file_utils.getFullGameApk(game)
+        file_utils.copyFile(newGameApk, gameApk)
+
+
+def getPackagePath(basePath, packageName):
+    '''
+    包名对应的目录
+    '''
+    packageNameSplit = packageName.replace('\\', '/').split('/')
+    newPath = basePath
+    for item in packageNameSplit:
+        newPath = os.path.join(newPath, item)
+    return newPath
+
+
+
 #packageWeb()

+ 2 - 2
package_yfsdk.py

@@ -1,3 +1,3 @@
-import package_utils_yfsdk
-
+import package_utils_yfsdk
+
 package_utils_yfsdk.packConsoleInput()

+ 15 - 15
readme.txt

@@ -1,16 +1,16 @@
-game:
-游戏目录,放游戏母包
-internal:
-内部目录,放置内部的资源
-sdk:
-sdk目录,放各种sdk
-gen:
-解包目录,放置apk的解包文件
-out:
-各类库反向生成samil的目录
-target:
-最种打包输出的目录
-keystore:
-签名文件目录,放置各签名文件
-test:
+game:
+游戏目录,放游戏母包
+internal:
+内部目录,放置内部的资源
+sdk:
+sdk目录,放各种sdk
+gen:
+解包目录,放置apk的解包文件
+out:
+各类库反向生成samil的目录
+target:
+最种打包输出的目录
+keystore:
+签名文件目录,放置各签名文件
+test:
 测试目录,可以忽略

+ 235 - 235
sdk/jm_zy_ysdk/script/sdk_script.py

@@ -1,235 +1,235 @@
-import file_utils
-import xml_utils
-import package_utils
-import os.path
-import xml.etree.ElementTree as ET
-
-namespaces = {'android' : 'http://schemas.android.com/apk/res/android'}
-encoding = 'UTF-8'
-
-def execute(game, sdk, config):
-    if not checkConfig(config):
-        return 1
-    #config['splitDex'] = False
-
-    subChannel = config['subChannel']
-
-    createJmhyProperties(game, sdk, subChannel, config)
-    createProperties(game, sdk, subChannel, config)
-    createSdkProperties(game, sdk, subChannel, config)
-
-    orientation = getScreenOrientation(game, sdk, subChannel, config)
-    if orientation is None:
-        orientation = 'landscape'
-    config['screenOrientation'] = orientation
-
-    changePlaceholders(game, sdk, subChannel, config)
-
-    ret = deleteSplash(game, sdk, subChannel, config)
-    if ret:
-        return ret
-    
-    return copyWechatCode(game, sdk, subChannel, config)
-
-def checkConfig(config):
-    '''
-    检查配置
-    '''
-    if 'properties' not in config:
-        print('properties not exists in config')
-        return False
-
-    if 'ysdk' not in config:
-        print('ysdk not exists in config')
-        return False
-
-    properties = config['properties']
-    
-    if 'agent' not in properties or 'version' not in properties:
-        print('agent or version not exists in properties')
-        return False
-
-    '''if 'appid' not in config or 'appkey' not in config:
-        print('appid or appkey not exists in config')
-        return False'''
-
-    return True
-
-def createJmhyProperties(game, sdk, subChannel, config):
-    '''
-    创建jmhy.properties
-    '''
-    print('create jmhy.properties')
-    propValue = config['properties']
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    properties = os.path.join(decompliePath, 'assets', 'jmhy.properties')
-    content = ''
-    for key in propValue:
-        content = '%s%s=%s\n' % (content, key, propValue[key])
-    file_utils.createFile(properties, content)
-    return 0
-
-def createProperties(game, sdk, subChannel, config):
-    '''
-    创建ysdkconf.ini
-    '''
-    print('create ysdkconf.ini')
-    ysdkConfig = config['ysdk']
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    properties = os.path.join(decompliePath, 'assets', 'ysdkconf.ini')
-    content = ''
-    for key in ysdkConfig:
-        content = '%s%s=%s\n' % (content, key, ysdkConfig[key])
-    file_utils.createFile(properties, content)
-    return 0
-
-
-def createSdkProperties(game, sdk, subChannel, config):
-    '''
-    创建sdk.properties
-    '''
-    print('create sdk.properties')
-    zysdkConfig = config['zysdk_properties']
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    properties = os.path.join(decompliePath, 'assets', 'sdk.properties')
-    content = ''
-    for key in zysdkConfig:
-        content = '%s%s=%s\n' % (content, key, zysdkConfig[key])
-    file_utils.createFile(properties, content)
-    return 0
-
-def copyWechatCode(game, sdk, subChannel, config):
-    '''
-    拷贝微信sdk的代码
-    '''
-    print('copy WXEntryActivity.smali')
-    sdkPath = file_utils.getFullSDKPath(sdk)
-
-    WXEntryActivity = 'WXEntryActivity.smali'
-
-    wxFile = os.path.join(sdkPath, 'smali', WXEntryActivity)
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    smaliPath = os.path.join(decompliePath, 'smali')
-    targetPath = file_utils.getPackagePath(smaliPath, config['packageName'])
-    targetFile = os.path.join(targetPath, 'wxapi', WXEntryActivity)
-    ret = file_utils.copyFile(wxFile, targetFile)
-    if ret:
-        return ret
-
-    file_utils.replaceContent(targetFile, '${packageName}', config['packageName'].replace('.', '/'))
-
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    changeLauncherLaunchMode(manifest)
-    xml_utils.changeLauncherAttr(manifest, 'configChanges', 'orientation|screenSize|keyboardHidden')
-
-    return 0
-
-def deleteSplash(game, sdk, subChannel, config):
-    '''
-    删除闪屏
-    '''
-    if game != 'wzjh':
-        return 0
-    channelPath = file_utils.getSubChannelPath(game, sdk, subChannel)
-    print('delete Splash...')
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    activity = xml_utils.getLauncherActivityName(manifest)
-    activity = xml_utils.removeLauncherActivity(manifest)
-    xml_utils.deleteActivityByName(manifest,'com.hugenstar.nanobox.NaNoUnityContext')
-    addLauncherActivity(manifest, config['screenOrientation'], 'com.hugenstar.nanobox.NaNoUnityContext')
-    return 0
-
-def changeLauncherLaunchMode(manifest):
-    '''
-    修改启动的activity的launchMode
-    '''
-    for key in namespaces:
-        ET.register_namespace(key, namespaces[key])
-
-    tree = ET.parse(manifest)
-    root = tree.getroot()
-
-    launcherActivity = xml_utils.getLauncherActivity(root)
-    if launcherActivity is None:
-        return 1
-
-    attrName = xml_utils.getNamespacesFormat('android:launchMode', namespaces)
-    if attrName not in launcherActivity.attrib or 'standard' == launcherActivity.attrib[attrName]:
-        launcherActivity.attrib[attrName] = 'singleTop'
-        tree.write(manifest, encoding)
-    
-    return 0
-
-def getScreenOrientation(game, sdk, subChannel, config):
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-    return getLauncherAttr(manifest, 'screenOrientation')
-
-def getLauncherAttr(manifest, attrType):
-    '''
-    获取启动的activity的属性
-    '''
-    for key in namespaces:
-        ET.register_namespace(key, namespaces[key])
-
-    tree = ET.parse(manifest)
-    root = tree.getroot()
-
-    launcherActivity = xml_utils.getLauncherActivity(root)
-    if launcherActivity is None:
-        return None
-
-    attrName = xml_utils.getNamespacesFormat('android:%s' % attrType, namespaces)
-    if attrName in launcherActivity.attrib:
-        return launcherActivity.attrib[attrName]
-
-    return None
-
-def changePlaceholders(game, sdk, subChannel, config):
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
-
-    file_utils.replaceContent(manifest, '${screenOrientation}', config['screenOrientation'])
-
-def addLauncherActivity(manifest, screenOrientation, activity):
-    '''
-    添加启动的activity
-    '''
-    for key in namespaces:
-        ET.register_namespace(key, namespaces[key])
-
-    tree = ET.parse(manifest)
-    root = tree.getroot()
-
-    # activity
-    '''<activity android:name=".LauncherActivity"
-            android:theme="@style/LauncherStyle">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>'''
-
-    activity = ET.Element('activity', {'android:name' : activity,
-    'android:theme' : '@android:style/Theme.Holo.Light.NoActionBar.Fullscreen',
-    'android:launchMode' : 'singleTop',
-    'android:configChanges' : 'orientation|screenSize|keyboardHidden',
-    'android:screenOrientation' : screenOrientation})
-    intent = ET.Element('intent-filter')
-    action = ET.Element('action', {'android:name' : 'android.intent.action.MAIN'})
-    category = ET.Element('category', {'android:name' : 'android.intent.category.LAUNCHER'})
-    intent.append(action)
-    intent.append(category)
-    activity.append(intent)
-    intent2 = ET.Element('intent-filter')
-    category = ET.Element('category', {'android:name' : 'android.intent.category.LEANBACK_LAUNCHER'})
-    intent2.append(category)
-    activity.append(intent2)
-
-    application = root.find('application')
-    application.insert(0, activity)
-
-    tree.write(manifest, encoding)
-
-
+import file_utils
+import xml_utils
+import package_utils
+import os.path
+import xml.etree.ElementTree as ET
+
+namespaces = {'android' : 'http://schemas.android.com/apk/res/android'}
+encoding = 'UTF-8'
+
+def execute(game, sdk, config):
+    if not checkConfig(config):
+        return 1
+    #config['splitDex'] = False
+
+    subChannel = config['subChannel']
+
+    createJmhyProperties(game, sdk, subChannel, config)
+    createProperties(game, sdk, subChannel, config)
+    createSdkProperties(game, sdk, subChannel, config)
+
+    orientation = getScreenOrientation(game, sdk, subChannel, config)
+    if orientation is None:
+        orientation = 'landscape'
+    config['screenOrientation'] = orientation
+
+    changePlaceholders(game, sdk, subChannel, config)
+
+    ret = deleteSplash(game, sdk, subChannel, config)
+    if ret:
+        return ret
+    
+    return copyWechatCode(game, sdk, subChannel, config)
+
+def checkConfig(config):
+    '''
+    检查配置
+    '''
+    if 'properties' not in config:
+        print('properties not exists in config')
+        return False
+
+    if 'ysdk' not in config:
+        print('ysdk not exists in config')
+        return False
+
+    properties = config['properties']
+    
+    if 'agent' not in properties or 'version' not in properties:
+        print('agent or version not exists in properties')
+        return False
+
+    '''if 'appid' not in config or 'appkey' not in config:
+        print('appid or appkey not exists in config')
+        return False'''
+
+    return True
+
+def createJmhyProperties(game, sdk, subChannel, config):
+    '''
+    创建jmhy.properties
+    '''
+    print('create jmhy.properties')
+    propValue = config['properties']
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    properties = os.path.join(decompliePath, 'assets', 'jmhy.properties')
+    content = ''
+    for key in propValue:
+        content = '%s%s=%s\n' % (content, key, propValue[key])
+    file_utils.createFile(properties, content)
+    return 0
+
+def createProperties(game, sdk, subChannel, config):
+    '''
+    创建ysdkconf.ini
+    '''
+    print('create ysdkconf.ini')
+    ysdkConfig = config['ysdk']
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    properties = os.path.join(decompliePath, 'assets', 'ysdkconf.ini')
+    content = ''
+    for key in ysdkConfig:
+        content = '%s%s=%s\n' % (content, key, ysdkConfig[key])
+    file_utils.createFile(properties, content)
+    return 0
+
+
+def createSdkProperties(game, sdk, subChannel, config):
+    '''
+    创建sdk.properties
+    '''
+    print('create sdk.properties')
+    zysdkConfig = config['zysdk_properties']
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    properties = os.path.join(decompliePath, 'assets', 'sdk.properties')
+    content = ''
+    for key in zysdkConfig:
+        content = '%s%s=%s\n' % (content, key, zysdkConfig[key])
+    file_utils.createFile(properties, content)
+    return 0
+
+def copyWechatCode(game, sdk, subChannel, config):
+    '''
+    拷贝微信sdk的代码
+    '''
+    print('copy WXEntryActivity.smali')
+    sdkPath = file_utils.getFullSDKPath(sdk)
+
+    WXEntryActivity = 'WXEntryActivity.smali'
+
+    wxFile = os.path.join(sdkPath, 'smali', WXEntryActivity)
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    smaliPath = os.path.join(decompliePath, 'smali')
+    targetPath = file_utils.getPackagePath(smaliPath, config['packageName'])
+    targetFile = os.path.join(targetPath, 'wxapi', WXEntryActivity)
+    ret = file_utils.copyFile(wxFile, targetFile)
+    if ret:
+        return ret
+
+    file_utils.replaceContent(targetFile, '${packageName}', config['packageName'].replace('.', '/'))
+
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    changeLauncherLaunchMode(manifest)
+    xml_utils.changeLauncherAttr(manifest, 'configChanges', 'orientation|screenSize|keyboardHidden')
+
+    return 0
+
+def deleteSplash(game, sdk, subChannel, config):
+    '''
+    删除闪屏
+    '''
+    if game != 'wzjh':
+        return 0
+    channelPath = file_utils.getSubChannelPath(game, sdk, subChannel)
+    print('delete Splash...')
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    activity = xml_utils.getLauncherActivityName(manifest)
+    activity = xml_utils.removeLauncherActivity(manifest)
+    xml_utils.deleteActivityByName(manifest,'com.hugenstar.nanobox.NaNoUnityContext')
+    addLauncherActivity(manifest, config['screenOrientation'], 'com.hugenstar.nanobox.NaNoUnityContext')
+    return 0
+
+def changeLauncherLaunchMode(manifest):
+    '''
+    修改启动的activity的launchMode
+    '''
+    for key in namespaces:
+        ET.register_namespace(key, namespaces[key])
+
+    tree = ET.parse(manifest)
+    root = tree.getroot()
+
+    launcherActivity = xml_utils.getLauncherActivity(root)
+    if launcherActivity is None:
+        return 1
+
+    attrName = xml_utils.getNamespacesFormat('android:launchMode', namespaces)
+    if attrName not in launcherActivity.attrib or 'standard' == launcherActivity.attrib[attrName]:
+        launcherActivity.attrib[attrName] = 'singleTop'
+        tree.write(manifest, encoding)
+    
+    return 0
+
+def getScreenOrientation(game, sdk, subChannel, config):
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    return getLauncherAttr(manifest, 'screenOrientation')
+
+def getLauncherAttr(manifest, attrType):
+    '''
+    获取启动的activity的属性
+    '''
+    for key in namespaces:
+        ET.register_namespace(key, namespaces[key])
+
+    tree = ET.parse(manifest)
+    root = tree.getroot()
+
+    launcherActivity = xml_utils.getLauncherActivity(root)
+    if launcherActivity is None:
+        return None
+
+    attrName = xml_utils.getNamespacesFormat('android:%s' % attrType, namespaces)
+    if attrName in launcherActivity.attrib:
+        return launcherActivity.attrib[attrName]
+
+    return None
+
+def changePlaceholders(game, sdk, subChannel, config):
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+
+    file_utils.replaceContent(manifest, '${screenOrientation}', config['screenOrientation'])
+
+def addLauncherActivity(manifest, screenOrientation, activity):
+    '''
+    添加启动的activity
+    '''
+    for key in namespaces:
+        ET.register_namespace(key, namespaces[key])
+
+    tree = ET.parse(manifest)
+    root = tree.getroot()
+
+    # activity
+    '''<activity android:name=".LauncherActivity"
+            android:theme="@style/LauncherStyle">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>'''
+
+    activity = ET.Element('activity', {'android:name' : activity,
+    'android:theme' : '@android:style/Theme.Holo.Light.NoActionBar.Fullscreen',
+    'android:launchMode' : 'singleTop',
+    'android:configChanges' : 'orientation|screenSize|keyboardHidden',
+    'android:screenOrientation' : screenOrientation})
+    intent = ET.Element('intent-filter')
+    action = ET.Element('action', {'android:name' : 'android.intent.action.MAIN'})
+    category = ET.Element('category', {'android:name' : 'android.intent.category.LAUNCHER'})
+    intent.append(action)
+    intent.append(category)
+    activity.append(intent)
+    intent2 = ET.Element('intent-filter')
+    category = ET.Element('category', {'android:name' : 'android.intent.category.LEANBACK_LAUNCHER'})
+    intent2.append(category)
+    activity.append(intent2)
+
+    application = root.find('application')
+    application.insert(0, activity)
+
+    tree.write(manifest, encoding)
+
+

+ 47 - 47
sdk/shanshen/script/sdk_script.py

@@ -1,48 +1,48 @@
-import file_utils
-import common_utils
-import os.path
-
-def execute(game, sdk, config):
-    if not checkConfig(config):
-        return 1
-
-    subChannel = config['subChannel']
-
-    createJmhyProperties(game, sdk, subChannel, config)
-    
-    common_utils.changeApplication(game, sdk, subChannel, config, 'com.shanshen.sdk.common.ShanShenApplication')
-    return 0
-
-def checkConfig(config):
-    '''
-    检查配置
-    '''
-    if 'properties' not in config:
-        print('properties not exists in config')
-        return False
-
-    properties = config['properties']
-    
-    if 'agent' not in properties or 'version' not in properties:
-        print('agent or version not exists in properties')
-        return False
-
-    '''if 'appid' not in config or 'appkey' not in config:
-        print('appid or appkey not exists in config')
-        return False'''
-
-    return True
-
-def createJmhyProperties(game, sdk, subChannel, config):
-    '''
-    创建jmhy.properties
-    '''
-    print('create shanshen.properties')
-    propValue = config['properties']
-    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
-    properties = os.path.join(decompliePath, 'assets', 'shanshen.properties')
-    content = ''
-    for key in propValue:
-        content = '%s%s=%s\n' % (content, key, propValue[key])
-    file_utils.createFile(properties, content)
+import file_utils
+import common_utils
+import os.path
+
+def execute(game, sdk, config):
+    if not checkConfig(config):
+        return 1
+
+    subChannel = config['subChannel']
+
+    createJmhyProperties(game, sdk, subChannel, config)
+    
+    common_utils.changeApplication(game, sdk, subChannel, config, 'com.shanshen.sdk.common.ShanShenApplication')
+    return 0
+
+def checkConfig(config):
+    '''
+    检查配置
+    '''
+    if 'properties' not in config:
+        print('properties not exists in config')
+        return False
+
+    properties = config['properties']
+    
+    if 'agent' not in properties or 'version' not in properties:
+        print('agent or version not exists in properties')
+        return False
+
+    '''if 'appid' not in config or 'appkey' not in config:
+        print('appid or appkey not exists in config')
+        return False'''
+
+    return True
+
+def createJmhyProperties(game, sdk, subChannel, config):
+    '''
+    创建jmhy.properties
+    '''
+    print('create shanshen.properties')
+    propValue = config['properties']
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    properties = os.path.join(decompliePath, 'assets', 'shanshen.properties')
+    content = ''
+    for key in propValue:
+        content = '%s%s=%s\n' % (content, key, propValue[key])
+    file_utils.createFile(properties, content)
     return 0

+ 6 - 6
sdk_script/jm.py

@@ -1,7 +1,7 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig jmsdk...')
-    
-    placeholders = {
-        'applicationId':config['packageName']
-    }
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig jmsdk...')
+    
+    placeholders = {
+        'applicationId':config['packageName']
+    }
     jsonConfig['placeholders'] = placeholders

+ 27 - 27
sdk_script/jm_baidu.py

@@ -1,28 +1,28 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig baidu...')
-
-    if 'baidu' in config:
-        baidu = config['baidu']
-
-
-        if 'configData' in jsonConfig:
-            configData = jsonConfig['configData']
-        else:
-            configData = {}
-
-        placeholders = {
-            'applicationId':config['packageName']
-        }
-        configData['AppID'] = baidu['AppID']
-        configData['AppKey'] = baidu['AppKey']
-
-        jsonConfig['placeholders'] = placeholders
-        jsonConfig['configData'] = configData
-
-        if 'includeOtherPay' in baidu:
-            if baidu['includeOtherPay'] == 0:
-                jsonConfig['libConfig'] = 'nopay'
-            else:
-                jsonConfig['libConfig'] = 'default'
-        else:
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig baidu...')
+
+    if 'baidu' in config:
+        baidu = config['baidu']
+
+
+        if 'configData' in jsonConfig:
+            configData = jsonConfig['configData']
+        else:
+            configData = {}
+
+        placeholders = {
+            'applicationId':config['packageName']
+        }
+        configData['AppID'] = baidu['AppID']
+        configData['AppKey'] = baidu['AppKey']
+
+        jsonConfig['placeholders'] = placeholders
+        jsonConfig['configData'] = configData
+
+        if 'includeOtherPay' in baidu:
+            if baidu['includeOtherPay'] == 0:
+                jsonConfig['libConfig'] = 'nopay'
+            else:
+                jsonConfig['libConfig'] = 'default'
+        else:
             jsonConfig['libConfig'] = 'default'

+ 26 - 26
sdk_script/jm_bamen.py

@@ -1,27 +1,27 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig bamen...')
-
-    if 'bamen' in config:
-        moye = config['bamen']
-
-
-        if 'configData' in jsonConfig:
-            configData = jsonConfig['configData']
-        else:
-            configData = {}
-
-        placeholders = {
-            'applicationId':config['packageName']
-        }
-        configData['APPID'] = moye['APPID']
-
-        jsonConfig['placeholders'] = placeholders
-        jsonConfig['configData'] = configData
-
-        if 'includeOtherPay' in moye:
-            if moye['includeOtherPay'] == 0:
-                jsonConfig['libConfig'] = 'nopay'
-            else:
-                jsonConfig['libConfig'] = 'default'
-        else:
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig bamen...')
+
+    if 'bamen' in config:
+        moye = config['bamen']
+
+
+        if 'configData' in jsonConfig:
+            configData = jsonConfig['configData']
+        else:
+            configData = {}
+
+        placeholders = {
+            'applicationId':config['packageName']
+        }
+        configData['APPID'] = moye['APPID']
+
+        jsonConfig['placeholders'] = placeholders
+        jsonConfig['configData'] = configData
+
+        if 'includeOtherPay' in moye:
+            if moye['includeOtherPay'] == 0:
+                jsonConfig['libConfig'] = 'nopay'
+            else:
+                jsonConfig['libConfig'] = 'default'
+        else:
             jsonConfig['libConfig'] = 'default'

+ 25 - 25
sdk_script/jm_beiyu.py

@@ -1,26 +1,26 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig beiyu...')
-    
-    if 'beiyu' in config:
-        beiyu = config['beiyu']
-        
-        if 'metaData' in jsonConfig:
-            metaData = jsonConfig['metaData']
-        else:
-            metaData = {}
-        metaData['ANY_APPID'] = beiyu['app_id']
-        metaData['ANY_APPKEY'] = beiyu['app_key']
-        metaData['ANY_JUNIORID'] = beiyu['junior_id']
-        metaData['ANY_JUNIORAPPID'] = beiyu['junior_app_id']
-        metaData['ZK_APPID'] = beiyu['junior_app_id']
-        metaData['ZK_APPKEY'] = beiyu['junior_app_key']
-
-        jsonConfig['metaData'] = metaData
-
-        if 'includeOtherPay' in beiyu:
-            if beiyu['includeOtherPay'] == 0:
-                jsonConfig['libConfig'] = 'nopay'
-            else:
-                jsonConfig['libConfig'] = 'default'
-        else:
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig beiyu...')
+    
+    if 'beiyu' in config:
+        beiyu = config['beiyu']
+        
+        if 'metaData' in jsonConfig:
+            metaData = jsonConfig['metaData']
+        else:
+            metaData = {}
+        metaData['ANY_APPID'] = beiyu['app_id']
+        metaData['ANY_APPKEY'] = beiyu['app_key']
+        metaData['ANY_JUNIORID'] = beiyu['junior_id']
+        metaData['ANY_JUNIORAPPID'] = beiyu['junior_app_id']
+        metaData['ZK_APPID'] = beiyu['junior_app_id']
+        metaData['ZK_APPKEY'] = beiyu['junior_app_key']
+
+        jsonConfig['metaData'] = metaData
+
+        if 'includeOtherPay' in beiyu:
+            if beiyu['includeOtherPay'] == 0:
+                jsonConfig['libConfig'] = 'nopay'
+            else:
+                jsonConfig['libConfig'] = 'default'
+        else:
             jsonConfig['libConfig'] = 'default'

+ 7 - 0
sdk_script/jm_beta_sdk.py

@@ -0,0 +1,7 @@
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig jmsdk...')
+    
+    placeholders = {
+        'applicationId':config['packageName']
+    }
+    jsonConfig['placeholders'] = placeholders

+ 22 - 22
sdk_script/jm_erjiuyouaz.py

@@ -1,23 +1,23 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig erjiuyouaz...')
-    
-    if 'erjiuyouaz' in config:
-        erjiuyouaz = config['erjiuyouaz']
-        if 'metaData' in jsonConfig:
-            meta = jsonConfig['metaData']
-        else:
-            meta = {}
-        meta['appId'] = erjiuyouaz['appId']
-        meta['appKey'] = erjiuyouaz['appKey']
-
-
-        jsonConfig['metaData'] = meta
-        jsonConfig['channel_id'] = erjiuyouaz['channel_id']
-
-        if 'includeOtherPay' in erjiuyouaz:
-            if erjiuyouaz['includeOtherPay'] == 0:
-                jsonConfig['libConfig'] = 'nopay'
-            else:
-                jsonConfig['libConfig'] = 'default'
-        else:
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig erjiuyouaz...')
+    
+    if 'erjiuyouaz' in config:
+        erjiuyouaz = config['erjiuyouaz']
+        if 'metaData' in jsonConfig:
+            meta = jsonConfig['metaData']
+        else:
+            meta = {}
+        meta['appId'] = erjiuyouaz['appId']
+        meta['appKey'] = erjiuyouaz['appKey']
+
+
+        jsonConfig['metaData'] = meta
+        jsonConfig['channel_id'] = erjiuyouaz['channel_id']
+
+        if 'includeOtherPay' in erjiuyouaz:
+            if erjiuyouaz['includeOtherPay'] == 0:
+                jsonConfig['libConfig'] = 'nopay'
+            else:
+                jsonConfig['libConfig'] = 'default'
+        else:
             jsonConfig['libConfig'] = 'default'

+ 27 - 27
sdk_script/jm_guopan.py

@@ -1,28 +1,28 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig guopan...')
-
-    if 'guopan' in config:
-        guopan = config['guopan']
-
-
-        if 'configData' in jsonConfig:
-            configData = jsonConfig['configData']
-        else:
-            configData = {}
-
-        placeholders = {
-            'applicationId':config['packageName']
-        }
-        configData['APPID'] = guopan['APPID']
-        configData['APPKEY'] = guopan['APPKEY']
-
-        jsonConfig['placeholders'] = placeholders
-        jsonConfig['configData'] = configData
-
-        if 'includeOtherPay' in guopan:
-            if guopan['includeOtherPay'] == 0:
-                jsonConfig['libConfig'] = 'nopay'
-            else:
-                jsonConfig['libConfig'] = 'default'
-        else:
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig guopan...')
+
+    if 'guopan' in config:
+        guopan = config['guopan']
+
+
+        if 'configData' in jsonConfig:
+            configData = jsonConfig['configData']
+        else:
+            configData = {}
+
+        placeholders = {
+            'applicationId':config['packageName']
+        }
+        configData['APPID'] = guopan['APPID']
+        configData['APPKEY'] = guopan['APPKEY']
+
+        jsonConfig['placeholders'] = placeholders
+        jsonConfig['configData'] = configData
+
+        if 'includeOtherPay' in guopan:
+            if guopan['includeOtherPay'] == 0:
+                jsonConfig['libConfig'] = 'nopay'
+            else:
+                jsonConfig['libConfig'] = 'default'
+        else:
             jsonConfig['libConfig'] = 'default'

+ 28 - 28
sdk_script/jm_haixin.py

@@ -1,29 +1,29 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig haixin...')
-
-    if 'haixin' in config:
-        haixin = config['haixin']
-
-
-        if 'configData' in jsonConfig:
-            configData = jsonConfig['configData']
-        else:
-            configData = {}
-
-        placeholders = {
-            'applicationId':config['packageName']
-        }
-        configData['appKey'] = haixin['appKey']
-        configData['appSecret'] = haixin['appSecret']
-        configData['md5Key'] = haixin['md5Key']
-
-        jsonConfig['placeholders'] = placeholders
-        jsonConfig['configData'] = configData
-
-        if 'includeOtherPay' in haixin:
-            if haixin['includeOtherPay'] == 0:
-                jsonConfig['libConfig'] = 'nopay'
-            else:
-                jsonConfig['libConfig'] = 'default'
-        else:
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig haixin...')
+
+    if 'haixin' in config:
+        haixin = config['haixin']
+
+
+        if 'configData' in jsonConfig:
+            configData = jsonConfig['configData']
+        else:
+            configData = {}
+
+        placeholders = {
+            'applicationId':config['packageName']
+        }
+        configData['appKey'] = haixin['appKey']
+        configData['appSecret'] = haixin['appSecret']
+        configData['md5Key'] = haixin['md5Key']
+
+        jsonConfig['placeholders'] = placeholders
+        jsonConfig['configData'] = configData
+
+        if 'includeOtherPay' in haixin:
+            if haixin['includeOtherPay'] == 0:
+                jsonConfig['libConfig'] = 'nopay'
+            else:
+                jsonConfig['libConfig'] = 'default'
+        else:
             jsonConfig['libConfig'] = 'default'

+ 24 - 24
sdk_script/jm_hongshouzhi.py

@@ -1,25 +1,25 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig hongshouzhi...')
-    
-    if 'hongshouzhi' in config:
-        hongshouzhi = config['hongshouzhi']
-        if 'metaData' in jsonConfig:
-            meta = jsonConfig['metaData']
-        else:
-            meta = {}
-        meta['HS_APPID'] = hongshouzhi['app_id']
-        meta['HS_CLIENTID'] = hongshouzhi['client_id']
-        meta['HS_CLIENTKEY'] = hongshouzhi['client_key']
-        meta['HS_AGENT'] = 'default'
-
-
-
-        jsonConfig['metaData'] = meta
-
-        if 'includeOtherPay' in hongshouzhi:
-            if hongshouzhi['includeOtherPay'] == 0:
-                jsonConfig['libConfig'] = 'nopay'
-            else:
-                jsonConfig['libConfig'] = 'default'
-        else:
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig hongshouzhi...')
+    
+    if 'hongshouzhi' in config:
+        hongshouzhi = config['hongshouzhi']
+        if 'metaData' in jsonConfig:
+            meta = jsonConfig['metaData']
+        else:
+            meta = {}
+        meta['HS_APPID'] = hongshouzhi['app_id']
+        meta['HS_CLIENTID'] = hongshouzhi['client_id']
+        meta['HS_CLIENTKEY'] = hongshouzhi['client_key']
+        meta['HS_AGENT'] = 'default'
+
+
+
+        jsonConfig['metaData'] = meta
+
+        if 'includeOtherPay' in hongshouzhi:
+            if hongshouzhi['includeOtherPay'] == 0:
+                jsonConfig['libConfig'] = 'nopay'
+            else:
+                jsonConfig['libConfig'] = 'default'
+        else:
             jsonConfig['libConfig'] = 'default'

+ 27 - 27
sdk_script/jm_huawei.py

@@ -1,27 +1,27 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig huawei...')
-
-    if 'huawei' in config:
-        huawei = config['huawei']
-
-
-        if 'configData' in jsonConfig:
-            configData = jsonConfig['configData']
-        else:
-            configData = {}
-
-        placeholders = {
-            'applicationId': config['packageName']
-        }
-
-
-        jsonConfig['placeholders'] = placeholders
-        jsonConfig['configData'] = configData
-
-        if 'includeOtherPay' in huawei:
-            if huawei['includeOtherPay'] == 0:
-                jsonConfig['libConfig'] = 'nopay'
-            else:
-                jsonConfig['libConfig'] = 'default'
-        else:
-            jsonConfig['libConfig'] = 'default'
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig huawei...')
+
+    if 'huawei' in config:
+        huawei = config['huawei']
+
+
+        if 'configData' in jsonConfig:
+            configData = jsonConfig['configData']
+        else:
+            configData = {}
+
+        placeholders = {
+            'applicationId': config['packageName']
+        }
+
+
+        jsonConfig['placeholders'] = placeholders
+        jsonConfig['configData'] = configData
+
+        if 'includeOtherPay' in huawei:
+            if huawei['includeOtherPay'] == 0:
+                jsonConfig['libConfig'] = 'nopay'
+            else:
+                jsonConfig['libConfig'] = 'default'
+        else:
+            jsonConfig['libConfig'] = 'default'

+ 20 - 20
sdk_script/jm_jianguo.py

@@ -1,20 +1,20 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig jianguo...')
-
-    if 'jianguo' in config:
-        jianguo = config['jianguo']
-
-        if 'configData' in jsonConfig:
-            configData = jsonConfig['configData']
-        else:
-            configData = {}
-
-        jsonConfig['configData'] = configData
-
-        if 'includeOtherPay' in jianguo:
-            if jianguo['includeOtherPay'] == 0:
-                jsonConfig['libConfig'] = 'nopay'
-            else:
-                jsonConfig['libConfig'] = 'default'
-        else:
-            jsonConfig['libConfig'] = 'default'
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig jianguo...')
+
+    if 'jianguo' in config:
+        jianguo = config['jianguo']
+
+        if 'configData' in jsonConfig:
+            configData = jsonConfig['configData']
+        else:
+            configData = {}
+
+        jsonConfig['configData'] = configData
+
+        if 'includeOtherPay' in jianguo:
+            if jianguo['includeOtherPay'] == 0:
+                jsonConfig['libConfig'] = 'nopay'
+            else:
+                jsonConfig['libConfig'] = 'default'
+        else:
+            jsonConfig['libConfig'] = 'default'

+ 27 - 27
sdk_script/jm_jinli.py

@@ -1,28 +1,28 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig jinli...')
-
-    if 'jinli' in config:
-        jinli = config['jinli']
-
-
-        if 'configData' in jsonConfig:
-            configData = jsonConfig['configData']
-        else:
-            configData = {}
-
-        placeholders = {
-            'applicationId':config['packageName']
-        }
-        configData['APIKey'] = jinli['APIKey']
-        configData['PrivateKey'] = jinli['PrivateKey']
-
-        jsonConfig['placeholders'] = placeholders
-        jsonConfig['configData'] = configData
-
-        if 'includeOtherPay' in jinli:
-            if jinli['includeOtherPay'] == 0:
-                jsonConfig['libConfig'] = 'nopay'
-            else:
-                jsonConfig['libConfig'] = 'default'
-        else:
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig jinli...')
+
+    if 'jinli' in config:
+        jinli = config['jinli']
+
+
+        if 'configData' in jsonConfig:
+            configData = jsonConfig['configData']
+        else:
+            configData = {}
+
+        placeholders = {
+            'applicationId':config['packageName']
+        }
+        configData['APIKey'] = jinli['APIKey']
+        configData['PrivateKey'] = jinli['PrivateKey']
+
+        jsonConfig['placeholders'] = placeholders
+        jsonConfig['configData'] = configData
+
+        if 'includeOtherPay' in jinli:
+            if jinli['includeOtherPay'] == 0:
+                jsonConfig['libConfig'] = 'nopay'
+            else:
+                jsonConfig['libConfig'] = 'default'
+        else:
             jsonConfig['libConfig'] = 'default'

+ 24 - 24
sdk_script/jm_jq.py

@@ -1,25 +1,25 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig jingqi...')
-    
-    if 'jingqi' in config:
-        jq = config['jingqi']
-
-        if 'metaData' in jsonConfig:
-            meta = jsonConfig['metaData']
-        else:
-            meta = {}
-        meta['AppId'] = jq['AppId']
-        placeholders = {
-            'applicationId':config['packageName']
-        }
-
-        jsonConfig['metaData'] = meta
-        jsonConfig['placeholders'] = placeholders
-
-        if 'includeOtherPay' in jq:
-            if jq['includeOtherPay'] == 0:
-                jsonConfig['libConfig'] = 'nopay'
-            else:
-                jsonConfig['libConfig'] = 'default'
-        else:
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig jingqi...')
+    
+    if 'jingqi' in config:
+        jq = config['jingqi']
+
+        if 'metaData' in jsonConfig:
+            meta = jsonConfig['metaData']
+        else:
+            meta = {}
+        meta['AppId'] = jq['AppId']
+        placeholders = {
+            'applicationId':config['packageName']
+        }
+
+        jsonConfig['metaData'] = meta
+        jsonConfig['placeholders'] = placeholders
+
+        if 'includeOtherPay' in jq:
+            if jq['includeOtherPay'] == 0:
+                jsonConfig['libConfig'] = 'nopay'
+            else:
+                jsonConfig['libConfig'] = 'default'
+        else:
             jsonConfig['libConfig'] = 'default'

+ 27 - 27
sdk_script/jm_kupai.py

@@ -1,28 +1,28 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig kupai...')
-
-    if 'kupai' in config:
-        kupai = config['kupai']
-
-
-        if 'configData' in jsonConfig:
-            configData = jsonConfig['configData']
-        else:
-            configData = {}
-
-        placeholders = {
-            'applicationId':config['packageName']
-        }
-        configData['AppID'] = kupai['AppID']
-        configData['PayKey'] = kupai['PayKey']
-
-        jsonConfig['placeholders'] = placeholders
-        jsonConfig['configData'] = configData
-
-        if 'includeOtherPay' in kupai:
-            if kupai['includeOtherPay'] == 0:
-                jsonConfig['libConfig'] = 'nopay'
-            else:
-                jsonConfig['libConfig'] = 'default'
-        else:
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig kupai...')
+
+    if 'kupai' in config:
+        kupai = config['kupai']
+
+
+        if 'configData' in jsonConfig:
+            configData = jsonConfig['configData']
+        else:
+            configData = {}
+
+        placeholders = {
+            'applicationId':config['packageName']
+        }
+        configData['AppID'] = kupai['AppID']
+        configData['PayKey'] = kupai['PayKey']
+
+        jsonConfig['placeholders'] = placeholders
+        jsonConfig['configData'] = configData
+
+        if 'includeOtherPay' in kupai:
+            if kupai['includeOtherPay'] == 0:
+                jsonConfig['libConfig'] = 'nopay'
+            else:
+                jsonConfig['libConfig'] = 'default'
+        else:
             jsonConfig['libConfig'] = 'default'

+ 19 - 19
sdk_script/jm_landie.py

@@ -1,20 +1,20 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig landie...')
-    
-    if 'landie' in config:
-        landie = config['landie']
-
-        placeholders = {
-            'applicationId':config['packageName'],
-            'AppId':landie['appId']
-        }
-
-        jsonConfig['placeholders'] = placeholders
-
-        if 'includeOtherPay' in landie:
-            if landie['includeOtherPay'] == 0:
-                jsonConfig['libConfig'] = 'nopay'
-            else:
-                jsonConfig['libConfig'] = 'default'
-        else:
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig landie...')
+    
+    if 'landie' in config:
+        landie = config['landie']
+
+        placeholders = {
+            'applicationId':config['packageName'],
+            'AppId':landie['appId']
+        }
+
+        jsonConfig['placeholders'] = placeholders
+
+        if 'includeOtherPay' in landie:
+            if landie['includeOtherPay'] == 0:
+                jsonConfig['libConfig'] = 'nopay'
+            else:
+                jsonConfig['libConfig'] = 'default'
+        else:
             jsonConfig['libConfig'] = 'default'

+ 26 - 26
sdk_script/jm_lianxiang.py

@@ -1,27 +1,27 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig lianxiang...')
-
-    if 'lianxiang' in config:
-        lianxiang = config['lianxiang']
-
-
-        if 'configData' in jsonConfig:
-            configData = jsonConfig['configData']
-        else:
-            configData = {}
-
-        placeholders = {
-            'applicationId':config['packageName']
-        }
-        configData['OPENAPPID'] = lianxiang['OPENAPPID']
-
-        jsonConfig['placeholders'] = placeholders
-        jsonConfig['configData'] = configData
-
-        if 'includeOtherPay' in lianxiang:
-            if lianxiang['includeOtherPay'] == 0:
-                jsonConfig['libConfig'] = 'nopay'
-            else:
-                jsonConfig['libConfig'] = 'default'
-        else:
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig lianxiang...')
+
+    if 'lianxiang' in config:
+        lianxiang = config['lianxiang']
+
+
+        if 'configData' in jsonConfig:
+            configData = jsonConfig['configData']
+        else:
+            configData = {}
+
+        placeholders = {
+            'applicationId':config['packageName']
+        }
+        configData['OPENAPPID'] = lianxiang['OPENAPPID']
+
+        jsonConfig['placeholders'] = placeholders
+        jsonConfig['configData'] = configData
+
+        if 'includeOtherPay' in lianxiang:
+            if lianxiang['includeOtherPay'] == 0:
+                jsonConfig['libConfig'] = 'nopay'
+            else:
+                jsonConfig['libConfig'] = 'default'
+        else:
             jsonConfig['libConfig'] = 'default'

+ 27 - 27
sdk_script/jm_meizu.py

@@ -1,28 +1,28 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig meizu...')
-
-    if 'meizu' in config:
-        meizu = config['meizu']
-
-
-        if 'configData' in jsonConfig:
-            configData = jsonConfig['configData']
-        else:
-            configData = {}
-
-        placeholders = {
-            'applicationId':config['packageName']
-        }
-        configData['Appid'] = meizu['Appid']
-        configData['Appkey'] = meizu['Appkey']
-
-        jsonConfig['placeholders'] = placeholders
-        jsonConfig['configData'] = configData
-
-        if 'includeOtherPay' in meizu:
-            if meizu['includeOtherPay'] == 0:
-                jsonConfig['libConfig'] = 'nopay'
-            else:
-                jsonConfig['libConfig'] = 'default'
-        else:
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig meizu...')
+
+    if 'meizu' in config:
+        meizu = config['meizu']
+
+
+        if 'configData' in jsonConfig:
+            configData = jsonConfig['configData']
+        else:
+            configData = {}
+
+        placeholders = {
+            'applicationId':config['packageName']
+        }
+        configData['Appid'] = meizu['Appid']
+        configData['Appkey'] = meizu['Appkey']
+
+        jsonConfig['placeholders'] = placeholders
+        jsonConfig['configData'] = configData
+
+        if 'includeOtherPay' in meizu:
+            if meizu['includeOtherPay'] == 0:
+                jsonConfig['libConfig'] = 'nopay'
+            else:
+                jsonConfig['libConfig'] = 'default'
+        else:
             jsonConfig['libConfig'] = 'default'

+ 26 - 26
sdk_script/jm_moye.py

@@ -1,27 +1,27 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig moye...')
-
-    if 'moye' in config:
-        moye = config['moye']
-
-
-        if 'configData' in jsonConfig:
-            configData = jsonConfig['configData']
-        else:
-            configData = {}
-
-        placeholders = {
-            'applicationId':config['packageName']
-        }
-        configData['APPID'] = moye['APPID']
-
-        jsonConfig['placeholders'] = placeholders
-        jsonConfig['configData'] = configData
-
-        if 'includeOtherPay' in moye:
-            if moye['includeOtherPay'] == 0:
-                jsonConfig['libConfig'] = 'nopay'
-            else:
-                jsonConfig['libConfig'] = 'default'
-        else:
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig moye...')
+
+    if 'moye' in config:
+        moye = config['moye']
+
+
+        if 'configData' in jsonConfig:
+            configData = jsonConfig['configData']
+        else:
+            configData = {}
+
+        placeholders = {
+            'applicationId':config['packageName']
+        }
+        configData['APPID'] = moye['APPID']
+
+        jsonConfig['placeholders'] = placeholders
+        jsonConfig['configData'] = configData
+
+        if 'includeOtherPay' in moye:
+            if moye['includeOtherPay'] == 0:
+                jsonConfig['libConfig'] = 'nopay'
+            else:
+                jsonConfig['libConfig'] = 'default'
+        else:
             jsonConfig['libConfig'] = 'default'

+ 26 - 26
sdk_script/jm_oppo.py

@@ -1,27 +1,27 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig oppo...')
-    
-    if 'oppo' in config:
-        oppo = config['oppo']
-        if 'metaData' in jsonConfig:
-            meta = jsonConfig['metaData']
-        else:
-            meta = {}
-        meta['app_key'] = oppo['appkey']
-
-        if 'configData' in jsonConfig:
-            conf = jsonConfig['configData']
-        else:
-            conf = {}
-        conf['oppo_appsecret'] = oppo['appsecret']
-
-        jsonConfig['metaData'] = meta
-        jsonConfig['configData'] = conf
-
-        if 'includeOtherPay' in oppo:
-            if oppo['includeOtherPay'] == 0:
-                jsonConfig['libConfig'] = 'nopay'
-            else:
-                jsonConfig['libConfig'] = 'default'
-        else:
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig oppo...')
+    
+    if 'oppo' in config:
+        oppo = config['oppo']
+        if 'metaData' in jsonConfig:
+            meta = jsonConfig['metaData']
+        else:
+            meta = {}
+        meta['app_key'] = oppo['appkey']
+
+        if 'configData' in jsonConfig:
+            conf = jsonConfig['configData']
+        else:
+            conf = {}
+        conf['oppo_appsecret'] = oppo['appsecret']
+
+        jsonConfig['metaData'] = meta
+        jsonConfig['configData'] = conf
+
+        if 'includeOtherPay' in oppo:
+            if oppo['includeOtherPay'] == 0:
+                jsonConfig['libConfig'] = 'nopay'
+            else:
+                jsonConfig['libConfig'] = 'default'
+        else:
             jsonConfig['libConfig'] = 'nopay'

+ 21 - 21
sdk_script/jm_quick.py

@@ -1,22 +1,22 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig quick...')
-    
-    if 'quick' in config:
-        quick = config['quick']
-        
-        if 'configData' in jsonConfig:
-            configData = jsonConfig['configData']
-        else:
-            configData = {}
-        configData['quick_appid'] = quick['productCode']
-        configData['quick_appkey'] = quick['productKey']
-
-        jsonConfig['configData'] = configData
-
-        if 'includeOtherPay' in quick:
-            if quick['includeOtherPay'] == 0:
-                jsonConfig['libConfig'] = 'nopay'
-            else:
-                jsonConfig['libConfig'] = 'default'
-        else:
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig quick...')
+    
+    if 'quick' in config:
+        quick = config['quick']
+        
+        if 'configData' in jsonConfig:
+            configData = jsonConfig['configData']
+        else:
+            configData = {}
+        configData['quick_appid'] = quick['productCode']
+        configData['quick_appkey'] = quick['productKey']
+
+        jsonConfig['configData'] = configData
+
+        if 'includeOtherPay' in quick:
+            if quick['includeOtherPay'] == 0:
+                jsonConfig['libConfig'] = 'nopay'
+            else:
+                jsonConfig['libConfig'] = 'default'
+        else:
             jsonConfig['libConfig'] = 'default'

+ 27 - 27
sdk_script/jm_qytx.py

@@ -1,28 +1,28 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig qytx...')
-    
-    if 'qytx' in config:
-        qytx = config['qytx']
-        jsonSdk = {
-            'version':qytx['version'],
-            'agent':qytx['agent']
-        }
-
-        if 'configData' in jsonConfig:
-            configData = jsonConfig['configData']
-        else:
-            configData = {}
-
-        configData['qytxAppId'] = qytx['qytxAppId']
-        configData['qytxAppKey'] = qytx['qytxAppKey']
-
-        jsonConfig['qytx'] = jsonSdk
-        jsonConfig['configData'] = configData
-
-        if 'includeOtherPay' in qytx:
-            if qytx['includeOtherPay'] == 0:
-                jsonConfig['libConfig'] = 'nopay'
-            else:
-                jsonConfig['libConfig'] = 'default'
-        else:
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig qytx...')
+    
+    if 'qytx' in config:
+        qytx = config['qytx']
+        jsonSdk = {
+            'version':qytx['version'],
+            'agent':qytx['agent']
+        }
+
+        if 'configData' in jsonConfig:
+            configData = jsonConfig['configData']
+        else:
+            configData = {}
+
+        configData['qytxAppId'] = qytx['qytxAppId']
+        configData['qytxAppKey'] = qytx['qytxAppKey']
+
+        jsonConfig['qytx'] = jsonSdk
+        jsonConfig['configData'] = configData
+
+        if 'includeOtherPay' in qytx:
+            if qytx['includeOtherPay'] == 0:
+                jsonConfig['libConfig'] = 'nopay'
+            else:
+                jsonConfig['libConfig'] = 'default'
+        else:
             jsonConfig['libConfig'] = 'default'

+ 30 - 30
sdk_script/jm_tianyu.py

@@ -1,31 +1,31 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig tianyu...')
-    
-    if 'tianyu' in config:
-        tianyu = config['tianyu']
-
-
-        if 'configData' in jsonConfig:
-            configData = jsonConfig['configData']
-        else:
-            configData = {}
-
-        configData['ty_appid'] = tianyu['appid']
-        configData['ty_appkey'] = tianyu['appkey']
-        configData['ty_sign'] = tianyu['sign']
-
-        jsonConfig['configData'] = configData
-
-        placeholders = {
-            'appid': tianyu['appid']
-        }
-
-        jsonConfig['placeholders'] = placeholders
-
-        if 'includeOtherPay' in tianyu:
-            if tianyu['includeOtherPay'] == 0:
-                jsonConfig['libConfig'] = 'nopay'
-            else:
-                jsonConfig['libConfig'] = 'default'
-        else:
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig tianyu...')
+    
+    if 'tianyu' in config:
+        tianyu = config['tianyu']
+
+
+        if 'configData' in jsonConfig:
+            configData = jsonConfig['configData']
+        else:
+            configData = {}
+
+        configData['ty_appid'] = tianyu['appid']
+        configData['ty_appkey'] = tianyu['appkey']
+        configData['ty_sign'] = tianyu['sign']
+
+        jsonConfig['configData'] = configData
+
+        placeholders = {
+            'appid': tianyu['appid']
+        }
+
+        jsonConfig['placeholders'] = placeholders
+
+        if 'includeOtherPay' in tianyu:
+            if tianyu['includeOtherPay'] == 0:
+                jsonConfig['libConfig'] = 'nopay'
+            else:
+                jsonConfig['libConfig'] = 'default'
+        else:
             jsonConfig['libConfig'] = 'default'

+ 45 - 45
sdk_script/jm_tianyuyou.py

@@ -1,46 +1,46 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig tianyuyou...')
-    
-    if 'tianyuyou' in config:
-        tianyuyou = config['tianyuyou']
-
-        akJson = {}
-        akJson['cp_game_id'] = tianyuyou['cp_game_id']
-        akJson['a'] = tianyuyou['a']
-        akJson['k'] = tianyuyou['k']
-        akJson['game_name'] = config['name']
-
-
-        pJson = {}
-        splash_sc = {}
-        sub_sdk_param = {}
-
-        pJson['splash_land'] = 'tyr_splash_land.png'
-        pJson['splash_port'] = 'tyr_splash_port.png'
-        pJson['splash_bgc'] = 'splash_bgc'
-
-        splash_sc['setScaleType'] = False
-        splash_sc['type'] = 0
-        pJson['splash_sc'] = splash_sc
-
-        pJson['agent_id'] = tianyuyou['agent_id']
-        pJson['agent_app_id'] = tianyuyou['agent_app_id']
-
-        sub_sdk_param['TY_APPID'] = tianyuyou['TY_APPID']
-        sub_sdk_param['TY_CLIENTID'] = tianyuyou['TY_CLIENTID']
-        sub_sdk_param['TY_CLIENTKEY'] = tianyuyou['TY_CLIENTKEY']
-        sub_sdk_param['URL_ID'] = tianyuyou['URL_ID']
-
-        pJson['sub_sdk_param'] = sub_sdk_param
-
-        jsonConfig['akJson'] = akJson
-        jsonConfig['pJson'] = pJson
-
-
-        if 'includeOtherPay' in tianyuyou:
-            if tianyuyou['includeOtherPay'] == 0:
-                jsonConfig['libConfig'] = 'nopay'
-            else:
-                jsonConfig['libConfig'] = 'default'
-        else:
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig tianyuyou...')
+    
+    if 'tianyuyou' in config:
+        tianyuyou = config['tianyuyou']
+
+        akJson = {}
+        akJson['cp_game_id'] = tianyuyou['cp_game_id']
+        akJson['a'] = tianyuyou['a']
+        akJson['k'] = tianyuyou['k']
+        akJson['game_name'] = config['name']
+
+
+        pJson = {}
+        splash_sc = {}
+        sub_sdk_param = {}
+
+        pJson['splash_land'] = 'tyr_splash_land.png'
+        pJson['splash_port'] = 'tyr_splash_port.png'
+        pJson['splash_bgc'] = 'splash_bgc'
+
+        splash_sc['setScaleType'] = False
+        splash_sc['type'] = 0
+        pJson['splash_sc'] = splash_sc
+
+        pJson['agent_id'] = tianyuyou['agent_id']
+        pJson['agent_app_id'] = tianyuyou['agent_app_id']
+
+        sub_sdk_param['TY_APPID'] = tianyuyou['TY_APPID']
+        sub_sdk_param['TY_CLIENTID'] = tianyuyou['TY_CLIENTID']
+        sub_sdk_param['TY_CLIENTKEY'] = tianyuyou['TY_CLIENTKEY']
+        sub_sdk_param['URL_ID'] = tianyuyou['URL_ID']
+
+        pJson['sub_sdk_param'] = sub_sdk_param
+
+        jsonConfig['akJson'] = akJson
+        jsonConfig['pJson'] = pJson
+
+
+        if 'includeOtherPay' in tianyuyou:
+            if tianyuyou['includeOtherPay'] == 0:
+                jsonConfig['libConfig'] = 'nopay'
+            else:
+                jsonConfig['libConfig'] = 'default'
+        else:
             jsonConfig['libConfig'] = 'default'

+ 26 - 26
sdk_script/jm_tt.py

@@ -1,27 +1,27 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig tt...')
-
-    if 'tt' in config:
-        tt = config['tt']
-
-
-        if 'configData' in jsonConfig:
-            configData = jsonConfig['configData']
-        else:
-            configData = {}
-
-        placeholders = {
-            'applicationId':config['packageName']
-        }
-        configData['GAMEID'] = tt['GAMEID']
-
-        jsonConfig['placeholders'] = placeholders
-        jsonConfig['configData'] = configData
-
-        if 'includeOtherPay' in tt:
-            if tt['includeOtherPay'] == 0:
-                jsonConfig['libConfig'] = 'nopay'
-            else:
-                jsonConfig['libConfig'] = 'default'
-        else:
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig tt...')
+
+    if 'tt' in config:
+        tt = config['tt']
+
+
+        if 'configData' in jsonConfig:
+            configData = jsonConfig['configData']
+        else:
+            configData = {}
+
+        placeholders = {
+            'applicationId':config['packageName']
+        }
+        configData['GAMEID'] = tt['GAMEID']
+
+        jsonConfig['placeholders'] = placeholders
+        jsonConfig['configData'] = configData
+
+        if 'includeOtherPay' in tt:
+            if tt['includeOtherPay'] == 0:
+                jsonConfig['libConfig'] = 'nopay'
+            else:
+                jsonConfig['libConfig'] = 'default'
+        else:
             jsonConfig['libConfig'] = 'default'

+ 28 - 28
sdk_script/jm_xiaoqi.py

@@ -1,29 +1,29 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig xiaoqi...')
-    
-    if 'xiaoqi' in config:
-        xiaoqi = config['xiaoqi']
-
-
-        if 'configData' in jsonConfig:
-            configData = jsonConfig['configData']
-        else:
-            configData = {}
-
-        configData['appkey'] = xiaoqi['appkey']
-
-        jsonConfig['configData'] = configData
-
-        placeholders = {
-            'applicationId': config['packageName']
-        }
-
-        jsonConfig['placeholders'] = placeholders
-
-        if 'includeOtherPay' in xiaoqi:
-            if xiaoqi['includeOtherPay'] == 0:
-                jsonConfig['libConfig'] = 'nopay'
-            else:
-                jsonConfig['libConfig'] = 'default'
-        else:
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig xiaoqi...')
+    
+    if 'xiaoqi' in config:
+        xiaoqi = config['xiaoqi']
+
+
+        if 'configData' in jsonConfig:
+            configData = jsonConfig['configData']
+        else:
+            configData = {}
+
+        configData['appkey'] = xiaoqi['appkey']
+
+        jsonConfig['configData'] = configData
+
+        placeholders = {
+            'applicationId': config['packageName']
+        }
+
+        jsonConfig['placeholders'] = placeholders
+
+        if 'includeOtherPay' in xiaoqi:
+            if xiaoqi['includeOtherPay'] == 0:
+                jsonConfig['libConfig'] = 'nopay'
+            else:
+                jsonConfig['libConfig'] = 'default'
+        else:
             jsonConfig['libConfig'] = 'default'

+ 28 - 28
sdk_script/jm_xingmuyou.py

@@ -1,29 +1,29 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig xingmuyou...')
-    
-    if 'xingmuyou' in config:
-        xingmuyou = config['xingmuyou']
-        if 'metaData' in jsonConfig:
-            meta = jsonConfig['metaData']
-        else:
-            meta = {}
-        meta['fusion_splash_pic'] = xingmuyou['fusion_splash_pic']
-        meta['fusion_package_id'] = xingmuyou['fusion_package_id']
-        meta['fusion_game_id'] = xingmuyou['fusion_game_id']
-        meta['fusion_app_key'] = xingmuyou['fusion_app_key']
-        meta['fusion_pf_gameid'] = xingmuyou['fusion_pf_gameid']
-
-        placeholders = {
-            'package_Name':config['name']
-        }
-
-        jsonConfig['metaData'] = meta
-        jsonConfig['placeholders'] = placeholders
-
-        if 'includeOtherPay' in xingmuyou:
-            if xingmuyou['includeOtherPay'] == 0:
-                jsonConfig['libConfig'] = 'nopay'
-            else:
-                jsonConfig['libConfig'] = 'default'
-        else:
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig xingmuyou...')
+    
+    if 'xingmuyou' in config:
+        xingmuyou = config['xingmuyou']
+        if 'metaData' in jsonConfig:
+            meta = jsonConfig['metaData']
+        else:
+            meta = {}
+        meta['fusion_splash_pic'] = xingmuyou['fusion_splash_pic']
+        meta['fusion_package_id'] = xingmuyou['fusion_package_id']
+        meta['fusion_game_id'] = xingmuyou['fusion_game_id']
+        meta['fusion_app_key'] = xingmuyou['fusion_app_key']
+        meta['fusion_pf_gameid'] = xingmuyou['fusion_pf_gameid']
+
+        placeholders = {
+            'package_Name':config['name']
+        }
+
+        jsonConfig['metaData'] = meta
+        jsonConfig['placeholders'] = placeholders
+
+        if 'includeOtherPay' in xingmuyou:
+            if xingmuyou['includeOtherPay'] == 0:
+                jsonConfig['libConfig'] = 'nopay'
+            else:
+                jsonConfig['libConfig'] = 'default'
+        else:
             jsonConfig['libConfig'] = 'default'

+ 38 - 38
sdk_script/jm_xq.py

@@ -1,39 +1,39 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig xunqu...')
-    
-    if 'xunqu' in config:
-        xq = config['xunqu']
-        meta = {
-            'XQ_APPKEY':xq['XQ_APPKEY'],
-            'XQ_PAYSIGN':xq['XQ_PAYSIGN'],
-            'XQ_Channel':xq['XQ_Channel'],
-            'XQ_DEBUG':xq['XQ_DEBUG']
-        }
-
-        if 'SUB_CHANNEL' in xq:
-            if 'xiaomi' == xq['SUB_CHANNEL']:
-                if 'configData' in jsonConfig:
-                    configData = jsonConfig['configData']
-                else:
-                    configData = {}
-                configData['xiaomi_appid'] = xq['xiaomi_appid']
-                configData['xiaomi_appkey'] = xq['xiaomi_appkey']
-                jsonConfig['configData'] = configData
-            elif 'jrtt' == xq['SUB_CHANNEL']:
-                meta['TT_NAME'] = 'default'
-                meta['TT_APP_ID'] = 'default'
-
-        placeholders = {
-            'applicationId':config['packageName']
-        }
-        
-        jsonConfig['metaData'] = meta
-        jsonConfig['placeholders'] = placeholders
-
-        if 'includeOtherPay' in xq:
-            if xq['includeOtherPay'] == 0:
-                jsonConfig['libConfig'] = 'nopay'
-            else:
-                jsonConfig['libConfig'] = 'default'
-        else:
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig xunqu...')
+    
+    if 'xunqu' in config:
+        xq = config['xunqu']
+        meta = {
+            'XQ_APPKEY':xq['XQ_APPKEY'],
+            'XQ_PAYSIGN':xq['XQ_PAYSIGN'],
+            'XQ_Channel':xq['XQ_Channel'],
+            'XQ_DEBUG':xq['XQ_DEBUG']
+        }
+
+        if 'SUB_CHANNEL' in xq:
+            if 'xiaomi' == xq['SUB_CHANNEL']:
+                if 'configData' in jsonConfig:
+                    configData = jsonConfig['configData']
+                else:
+                    configData = {}
+                configData['xiaomi_appid'] = xq['xiaomi_appid']
+                configData['xiaomi_appkey'] = xq['xiaomi_appkey']
+                jsonConfig['configData'] = configData
+            elif 'jrtt' == xq['SUB_CHANNEL']:
+                meta['TT_NAME'] = 'default'
+                meta['TT_APP_ID'] = 'default'
+
+        placeholders = {
+            'applicationId':config['packageName']
+        }
+        
+        jsonConfig['metaData'] = meta
+        jsonConfig['placeholders'] = placeholders
+
+        if 'includeOtherPay' in xq:
+            if xq['includeOtherPay'] == 0:
+                jsonConfig['libConfig'] = 'nopay'
+            else:
+                jsonConfig['libConfig'] = 'default'
+        else:
             jsonConfig['libConfig'] = 'default'

+ 20 - 20
sdk_script/jm_yaodian.py

@@ -1,21 +1,21 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig yaodian...')
-    
-    if 'yaodian' in config:
-        yaodian = config['yaodian']
-        if 'metaData' in jsonConfig:
-            meta = jsonConfig['metaData']
-        else:
-            meta = {}
-        meta['modousdk_gameId'] = yaodian['modousdk_gameId']
-        meta['modousdk_appKey'] = yaodian['modousdk_appKey']
-
-        jsonConfig['metaData'] = meta
-
-        if 'includeOtherPay' in yaodian:
-            if yaodian['includeOtherPay'] == 0:
-                jsonConfig['libConfig'] = 'nopay'
-            else:
-                jsonConfig['libConfig'] = 'default'
-        else:
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig yaodian...')
+    
+    if 'yaodian' in config:
+        yaodian = config['yaodian']
+        if 'metaData' in jsonConfig:
+            meta = jsonConfig['metaData']
+        else:
+            meta = {}
+        meta['modousdk_gameId'] = yaodian['modousdk_gameId']
+        meta['modousdk_appKey'] = yaodian['modousdk_appKey']
+
+        jsonConfig['metaData'] = meta
+
+        if 'includeOtherPay' in yaodian:
+            if yaodian['includeOtherPay'] == 0:
+                jsonConfig['libConfig'] = 'nopay'
+            else:
+                jsonConfig['libConfig'] = 'default'
+        else:
             jsonConfig['libConfig'] = 'default'

+ 20 - 20
sdk_script/jm_yijie.py

@@ -1,21 +1,21 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig yijie...')
-    
-    if 'yijie' in config:
-        yijie = config['yijie']
-        
-        if 'metaData' in jsonConfig:
-            meta = jsonConfig['metaData']
-        else:
-            meta = {}
-        meta['com.snowfish.appid'] = yijie['appid']
-
-        jsonConfig['metaData'] = meta
-
-        if 'includeOtherPay' in yijie:
-            if yijie['includeOtherPay'] == 0:
-                jsonConfig['libConfig'] = 'nopay'
-            else:
-                jsonConfig['libConfig'] = 'default'
-        else:
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig yijie...')
+    
+    if 'yijie' in config:
+        yijie = config['yijie']
+        
+        if 'metaData' in jsonConfig:
+            meta = jsonConfig['metaData']
+        else:
+            meta = {}
+        meta['com.snowfish.appid'] = yijie['appid']
+
+        jsonConfig['metaData'] = meta
+
+        if 'includeOtherPay' in yijie:
+            if yijie['includeOtherPay'] == 0:
+                jsonConfig['libConfig'] = 'nopay'
+            else:
+                jsonConfig['libConfig'] = 'default'
+        else:
             jsonConfig['libConfig'] = 'default'

+ 30 - 30
sdk_script/jm_yiwan.py

@@ -1,31 +1,31 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig yiwan...')
-    
-    if 'yiwan' in config:
-        yiwan = config['yiwan']
-
-
-        if 'configData' in jsonConfig:
-            configData = jsonConfig['configData']
-        else:
-            configData = {}
-
-        configData['AppId'] = yiwan['AppId']
-        configData['PacketId'] = yiwan['PacketId']
-        configData['SignKey'] = yiwan['SignKey']
-
-        jsonConfig['configData'] = configData
-
-        placeholders = {
-            'applicationId': config['packageName']
-        }
-
-        jsonConfig['placeholders'] = placeholders
-
-        if 'includeOtherPay' in yiwan:
-            if yiwan['includeOtherPay'] == 0:
-                jsonConfig['libConfig'] = 'nopay'
-            else:
-                jsonConfig['libConfig'] = 'default'
-        else:
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig yiwan...')
+    
+    if 'yiwan' in config:
+        yiwan = config['yiwan']
+
+
+        if 'configData' in jsonConfig:
+            configData = jsonConfig['configData']
+        else:
+            configData = {}
+
+        configData['AppId'] = yiwan['AppId']
+        configData['PacketId'] = yiwan['PacketId']
+        configData['SignKey'] = yiwan['SignKey']
+
+        jsonConfig['configData'] = configData
+
+        placeholders = {
+            'applicationId': config['packageName']
+        }
+
+        jsonConfig['placeholders'] = placeholders
+
+        if 'includeOtherPay' in yiwan:
+            if yiwan['includeOtherPay'] == 0:
+                jsonConfig['libConfig'] = 'nopay'
+            else:
+                jsonConfig['libConfig'] = 'default'
+        else:
             jsonConfig['libConfig'] = 'default'

+ 38 - 38
sdk_script/jm_ysdk.py

@@ -1,39 +1,39 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig ysdk...')
-    
-    if 'ysdk' in config:
-        ysdk = config['ysdk']
-        jsonSdk = {
-            'QQ_APP_ID':ysdk['QQ_APP_ID'],
-            'WX_APP_ID':ysdk['WX_APP_ID'],
-            'OFFER_ID':ysdk['OFFER_ID'],
-            'YSDK_URL':ysdk['YSDK_URL'],
-            'YSDK_ICON_SWITCH':'true',
-            'YSDK_IMMERSIVE_ICON_SWITCH':'true',
-            'YSDK_MSG_BOX_SWITCH':'true',
-            'YSDK_ICON_CAPTURE_SWITCH':'true',
-            'YSDK_ANTIADDICTION_SWITCH':'true'
-        }
-        placeholders = {
-            'wechatAppId':ysdk['WX_APP_ID'],
-            'qqAppId':ysdk['QQ_APP_ID'],
-            'applicationId':config['packageName']
-        }
-
-        '''if 'screenOrientation' in config:
-            placeholders['screenOrientation'] = config['screenOrientation']
-        else:
-            placeholders['screenOrientation'] = 'landscape'
-            '''
-
-        jsonConfig['ysdk'] = jsonSdk
-        jsonConfig['placeholders'] = placeholders
-        #jsonConfig['addLauncher'] = False
-
-        if 'includeOtherPay' in ysdk:
-            if ysdk['includeOtherPay'] == 0:
-                jsonConfig['libConfig'] = 'nopay'
-            else:
-                jsonConfig['libConfig'] = 'default'
-        else:
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig ysdk...')
+    
+    if 'ysdk' in config:
+        ysdk = config['ysdk']
+        jsonSdk = {
+            'QQ_APP_ID':ysdk['QQ_APP_ID'],
+            'WX_APP_ID':ysdk['WX_APP_ID'],
+            'OFFER_ID':ysdk['OFFER_ID'],
+            'YSDK_URL':ysdk['YSDK_URL'],
+            'YSDK_ICON_SWITCH':'true',
+            'YSDK_IMMERSIVE_ICON_SWITCH':'true',
+            'YSDK_MSG_BOX_SWITCH':'true',
+            'YSDK_ICON_CAPTURE_SWITCH':'true',
+            'YSDK_ANTIADDICTION_SWITCH':'true'
+        }
+        placeholders = {
+            'wechatAppId':ysdk['WX_APP_ID'],
+            'qqAppId':ysdk['QQ_APP_ID'],
+            'applicationId':config['packageName']
+        }
+
+        '''if 'screenOrientation' in config:
+            placeholders['screenOrientation'] = config['screenOrientation']
+        else:
+            placeholders['screenOrientation'] = 'landscape'
+            '''
+
+        jsonConfig['ysdk'] = jsonSdk
+        jsonConfig['placeholders'] = placeholders
+        #jsonConfig['addLauncher'] = False
+
+        if 'includeOtherPay' in ysdk:
+            if ysdk['includeOtherPay'] == 0:
+                jsonConfig['libConfig'] = 'nopay'
+            else:
+                jsonConfig['libConfig'] = 'default'
+        else:
             jsonConfig['libConfig'] = 'default'

+ 54 - 54
sdk_script/jm_zy_ysdk.py

@@ -1,55 +1,55 @@
-def getSdkConfig(jsonConfig, config):
-    print('getSdkConfig ziyun_ysdk...')
-    
-    if 'ziyun' in config:
-        ziyun = config['ziyun']
-        jsonSdk = {
-            'QQ_APP_ID':ziyun['QQ_APP_ID'],
-            'WX_APP_ID':ziyun['WX_APP_ID'],
-            'OFFER_ID':ziyun['OFFER_ID'],
-            'YSDK_URL':ziyun['YSDK_URL'],
-            'YSDK_ICON_SWITCH':'true',
-            'YSDK_IMMERSIVE_ICON_SWITCH':'true',
-            'YSDK_MSG_BOX_SWITCH':'true',
-            'YSDK_ICON_CAPTURE_SWITCH':'true'
-        }
-        zysdk_properties = {
-            'qqKey':ziyun['qqappkey'],
-            'wxId':ziyun['WX_APP_ID'],
-            'wxKey':ziyun['wxappkey'],
-            'memberKey':"sdsdd"
-        }
-        if 'metaData' in jsonConfig:
-            meta = jsonConfig['metaData']
-        else:
-            meta = {}
-        meta['ziyun_appid'] = ziyun['ZY_APPID']
-        meta['ziyun_appkey'] = ziyun['ZY_APPKEY']
-        placeholders = {
-            'wechatAppId':ziyun['WX_APP_ID'],
-            'qqAppId':ziyun['QQ_APP_ID'],
-            'applicationId':config['packageName']
-        }
-
-        if 'screenOrientation' in config:
-            placeholders['screenOrientation'] = config['screenOrientation']
-        else:
-            placeholders['screenOrientation'] = 'landscape'
-
-        jsonConfig['metaData'] = meta
-        jsonConfig['ysdk'] = jsonSdk
-        jsonConfig['zysdk_properties'] = zysdk_properties
-        jsonConfig['placeholders'] = placeholders
-        #jsonConfig['addLauncher'] = False
-
-        if 'includeOtherPay' in ziyun:
-            if ziyun['includeOtherPay'] == 0:
-                jsonConfig['libConfig'] = 'nopay'
-            else:
-                jsonConfig['libConfig'] = 'default'
-        else:
-            jsonConfig['libConfig'] = 'default'
-
-        print("app ==== " + config['app'])
-        if config['app'] == 'ahlz':
+def getSdkConfig(jsonConfig, config):
+    print('getSdkConfig ziyun_ysdk...')
+    
+    if 'ziyun' in config:
+        ziyun = config['ziyun']
+        jsonSdk = {
+            'QQ_APP_ID':ziyun['QQ_APP_ID'],
+            'WX_APP_ID':ziyun['WX_APP_ID'],
+            'OFFER_ID':ziyun['OFFER_ID'],
+            'YSDK_URL':ziyun['YSDK_URL'],
+            'YSDK_ICON_SWITCH':'true',
+            'YSDK_IMMERSIVE_ICON_SWITCH':'true',
+            'YSDK_MSG_BOX_SWITCH':'true',
+            'YSDK_ICON_CAPTURE_SWITCH':'true'
+        }
+        zysdk_properties = {
+            'qqKey':ziyun['qqappkey'],
+            'wxId':ziyun['WX_APP_ID'],
+            'wxKey':ziyun['wxappkey'],
+            'memberKey':"sdsdd"
+        }
+        if 'metaData' in jsonConfig:
+            meta = jsonConfig['metaData']
+        else:
+            meta = {}
+        meta['ziyun_appid'] = ziyun['ZY_APPID']
+        meta['ziyun_appkey'] = ziyun['ZY_APPKEY']
+        placeholders = {
+            'wechatAppId':ziyun['WX_APP_ID'],
+            'qqAppId':ziyun['QQ_APP_ID'],
+            'applicationId':config['packageName']
+        }
+
+        if 'screenOrientation' in config:
+            placeholders['screenOrientation'] = config['screenOrientation']
+        else:
+            placeholders['screenOrientation'] = 'landscape'
+
+        jsonConfig['metaData'] = meta
+        jsonConfig['ysdk'] = jsonSdk
+        jsonConfig['zysdk_properties'] = zysdk_properties
+        jsonConfig['placeholders'] = placeholders
+        #jsonConfig['addLauncher'] = False
+
+        if 'includeOtherPay' in ziyun:
+            if ziyun['includeOtherPay'] == 0:
+                jsonConfig['libConfig'] = 'nopay'
+            else:
+                jsonConfig['libConfig'] = 'default'
+        else:
+            jsonConfig['libConfig'] = 'default'
+
+        print("app ==== " + config['app'])
+        if config['app'] == 'ahlz':
             jsonConfig['libConfig'] = 'ahlz'

+ 62 - 62
smali_utils.py

@@ -1,63 +1,63 @@
-import os
-import os.path
-
-def get_smali_method_count(smaliFile, allMethods):
-
-	if not os.path.exists(smaliFile):
-		return 0
-
-	f = open(smaliFile, 'r', encoding='UTF-8')
-	lines = f.readlines()
-	f.close()
-
-	classLine = lines[0]
-	classLine.strip()
-	if not classLine.startswith('.class'):
-		print(f + ' not startswith .class')
-		return 0
-
-	className = parse_class(classLine)
-
-	count = 0
-	for line in lines:
-		line = line.strip()
-
-		method = None
-		if line.startswith('.method'):
-			method = parse_method_default(className, line)
-		elif line.startswith('invoke-'):
-			method = parse_method_invoke(line)
-
-		if method is None:
-			continue
-
-		if method not in allMethods:
-			count = count + 1
-			allMethods.append(method)
-		else:
-			pass
-
-	return count
-
-def parse_class(line):
-	if not line.startswith('.class'):
-		print('line parse error. not startswith .class : '+line)
-		return None
-
-	blocks = line.split()
-	return blocks[len(blocks)-1]
-
-def parse_method_default(className, line):
-	if not line.startswith('.method'):
-		print('the line parse error in parse_method_default:'+line)
-		return None
-
-	blocks = line.split()
-	return className + '->' + blocks[len(blocks)-1]
-
-def parse_method_invoke(line):
-	if not line.startswith('invoke-'):
-		print('the line parse error in parse_method_invoke:'+line)
-
-	blocks = line.split()
+import os
+import os.path
+
+def get_smali_method_count(smaliFile, allMethods):
+
+	if not os.path.exists(smaliFile):
+		return 0
+
+	f = open(smaliFile, 'r', encoding='UTF-8')
+	lines = f.readlines()
+	f.close()
+
+	classLine = lines[0]
+	classLine.strip()
+	if not classLine.startswith('.class'):
+		print(f + ' not startswith .class')
+		return 0
+
+	className = parse_class(classLine)
+
+	count = 0
+	for line in lines:
+		line = line.strip()
+
+		method = None
+		if line.startswith('.method'):
+			method = parse_method_default(className, line)
+		elif line.startswith('invoke-'):
+			method = parse_method_invoke(line)
+
+		if method is None:
+			continue
+
+		if method not in allMethods:
+			count = count + 1
+			allMethods.append(method)
+		else:
+			pass
+
+	return count
+
+def parse_class(line):
+	if not line.startswith('.class'):
+		print('line parse error. not startswith .class : '+line)
+		return None
+
+	blocks = line.split()
+	return blocks[len(blocks)-1]
+
+def parse_method_default(className, line):
+	if not line.startswith('.method'):
+		print('the line parse error in parse_method_default:'+line)
+		return None
+
+	blocks = line.split()
+	return className + '->' + blocks[len(blocks)-1]
+
+def parse_method_invoke(line):
+	if not line.startswith('invoke-'):
+		print('the line parse error in parse_method_invoke:'+line)
+
+	blocks = line.split()
 	return blocks[len(blocks)-1]

BIN
tools/linux/lib64/libc++.so


+ 0 - 0
tools/macos/aapt


+ 0 - 0
tools/macos/aapt2


+ 0 - 0
tools/macos/zipalign


+ 649 - 649
xml_utils.py

@@ -1,650 +1,650 @@
-import xml.etree.ElementTree as ET
-import os.path
-
-namespaces = {'android' : 'http://schemas.android.com/apk/res/android'}
-encoding = 'UTF-8'
-
-def getPackageName(manifest):
-    '''
-    获取包名
-    '''
-    tree = ET.parse(manifest)
-    root = tree.getroot()
-    return root.attrib['package']
-
-def changePackageName(manifest, packageName):
-    '''
-    更改包名
-    '''
-    for key in namespaces:
-        ET.register_namespace(key, namespaces[key])
-
-    tree = ET.parse(manifest)
-    root = tree.getroot()
-    root.attrib['package'] = packageName
-    tree.write(manifest, encoding)
-
-def removeLauncherActivity(manifest):
-    '''
-    删除启动的activity
-    '''
-    for key in namespaces:
-        ET.register_namespace(key, namespaces[key])
-
-    tree = ET.parse(manifest)
-    root = tree.getroot()
-    
-    attrName = getNamespacesFormat('android:name', namespaces)
-    for node in root.findall('application/activity'):
-        if len(node.getchildren()) <= 0:
-            continue
-
-        for sub in node.getchildren():
-            if sub.tag != 'intent-filter':
-                continue
-
-            for sub2 in sub.getchildren():
-                if not (sub2.tag == 'category' and sub2.attrib[attrName] == 'android.intent.category.LAUNCHER'):
-                    continue
-
-                node.remove(sub)
-                tree.write(manifest, encoding)
-                return node.attrib[attrName]
-    return 0
-
-
-def removeLauncherActivityByName(manifest,name):
-    '''
-    删除启动的activity
-    '''
-    for key in namespaces:
-        ET.register_namespace(key, namespaces[key])
-
-    tree = ET.parse(manifest)
-    root = tree.getroot()
-
-    attrName = getNamespacesFormat('android:name', namespaces)
-    for node in root.findall('application/activity'):
-        print('node ----> ' + node.attrib[attrName])
-        if node.attrib[attrName] != name:
-            continue
-        for sub in node.getchildren():
-            if sub.tag != 'intent-filter':
-                continue
-
-            for sub2 in sub.getchildren():
-                if not (sub2.tag == 'category' and sub2.attrib[attrName] == 'android.intent.category.LAUNCHER'):
-                    continue
-                node.remove(sub)
-                tree.write(manifest, encoding)
-            return node.attrib[attrName]
-
-
-    return 0
-
-def getScreenOrientation(manifest):
-    '''
-    获取启动activity的方向
-    '''
-    for key in namespaces:
-        ET.register_namespace(key, namespaces[key])
-
-    tree = ET.parse(manifest)
-    root = tree.getroot()
-
-    attrName = getNamespacesFormat('android:name', namespaces)
-    attrOrientation = getNamespacesFormat('android:screenOrientation', namespaces)
-    for node in root.findall('application/activity'):
-        if len(node.getchildren()) <= 0:
-            continue
-
-        for sub in node.getchildren():
-            if sub.tag != 'intent-filter':
-                continue
-
-            for sub2 in sub.getchildren():
-                if not (sub2.tag == 'category' and sub2.attrib[attrName] == 'android.intent.category.LAUNCHER'):
-                    continue
-
-                return node.attrib[attrOrientation]
-    return 0
-
-def addLauncherActivity(manifest, screenOrientation, activity):
-    '''
-    添加启动的activity
-    '''
-    for key in namespaces:
-        ET.register_namespace(key, namespaces[key])
-
-    tree = ET.parse(manifest)
-    root = tree.getroot()
-
-    # activity
-    '''<activity android:name=".LauncherActivity"
-            android:theme="@style/LauncherStyle">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>'''
-
-    activity = ET.Element('activity', {'android:name' : activity,
-    'android:theme' : '@android:style/Theme.Holo.Light.NoActionBar.Fullscreen',
-    'android:launchMode' : 'singleTop',
-    'android:configChanges' : 'orientation|screenSize|keyboardHidden',
-    'android:screenOrientation' : screenOrientation})
-    intent = ET.Element('intent-filter')
-    action = ET.Element('action', {'android:name' : 'android.intent.action.MAIN'})
-    category = ET.Element('category', {'android:name' : 'android.intent.category.LAUNCHER'})
-    intent.append(action)
-    intent.append(category)
-    activity.append(intent)
-    
-    application = root.find('application')
-    application.insert(0, activity)
-
-    tree.write(manifest, encoding)
-
-def changeAppName(manifest, stringRes):
-    '''
-    更改app名
-    '''
-    # 移除主activity的label
-    removeLauncherAttr(manifest, 'label')
-    return changeApplicationAttr(manifest, 'label', stringRes)
-
-def getLauncherActivity(root):
-    '''
-    获取启动的activity
-    '''
-    attrName = getNamespacesFormat('android:name', namespaces)
-
-    for node in root.findall('application/activity'):
-        if len(node.getchildren()) <= 0:
-            continue
-
-        for sub in node.getchildren():
-            if sub.tag != 'intent-filter':
-                continue
-
-            for sub2 in sub.getchildren():
-                if sub2.tag == 'category' and sub2.attrib[attrName] == 'android.intent.category.LAUNCHER':
-                    return node
-
-    return None
-
-def getLauncherActivitys(manifest):
-    '''
-    获取启动的activity
-    '''
-    attrName = getNamespacesFormat('android:name', namespaces)
-    nodeList = []
-
-    tree = ET.parse(manifest)
-    root = tree.getroot()
-
-    for node in root.findall('application/activity'):
-        if len(node.getchildren()) <= 0:
-            continue
-
-        for sub in node.getchildren():
-            if sub.tag != 'intent-filter':
-                continue
-
-            for sub2 in sub.getchildren():
-                if sub2.tag == 'category' and sub2.attrib[attrName] == 'android.intent.category.LAUNCHER':
-                    nodeList.append(node)
-
-    return nodeList
-
-def getLauncherActivityName(manifest):
-    '''
-    获取启动的activity
-    '''
-    for key in namespaces:
-        ET.register_namespace(key, namespaces[key])
-
-    tree = ET.parse(manifest)
-    root = tree.getroot()
-
-    launcherActivity = getLauncherActivity(root)
-    attrName = getNamespacesFormat('android:name', namespaces)
-    activityName = launcherActivity.attrib[attrName]
-    return activityName
-
-def addMoreIcon(manifest, icon, switchIcon):
-    '''
-    添加多图标
-    '''
-    for key in namespaces:
-        ET.register_namespace(key, namespaces[key])
-
-    tree = ET.parse(manifest)
-    root = tree.getroot()
-
-    launcherActivity = getLauncherActivity(root)
-    if launcherActivity is None:
-        return 1
-
-    attrName = getNamespacesFormat('android:name', namespaces)
-    activityName = launcherActivity.attrib[attrName]
-
-    activityAlias = ET.Element('activity-alias', {'android:name' : 'com.jmhy.sdk.icon.normal',
-    'android:enabled' : 'false',
-    'android:icon' : icon,
-    'android:targetActivity' : activityName})
-
-    activityAlias2 = ET.Element('activity-alias', {'android:name' : 'com.jmhy.sdk.icon.switch',
-    'android:enabled' : 'false',
-    'android:icon' : switchIcon,
-    'android:targetActivity' : activityName})
-
-    for item in launcherActivity.getchildren():
-        activityAlias.append(item)
-        activityAlias2.append(item)
-
-    application = root.find('application')
-    application.append(activityAlias)
-    application.append(activityAlias2)
-    tree.write(manifest, encoding)
-    return 0
-
-def removeLauncherAttr(manifest, attrType):
-    '''
-    移除启动的activity的label
-    '''
-    for key in namespaces:
-        ET.register_namespace(key, namespaces[key])
-
-    tree = ET.parse(manifest)
-    root = tree.getroot()
-
-    launcherActivity = getLauncherActivity(root)
-    if launcherActivity is None:
-        return 1
-
-    attrName = getNamespacesFormat('android:%s' % attrType, namespaces)
-    if attrName in launcherActivity.attrib:
-        del launcherActivity.attrib[attrName]
-        tree.write(manifest, encoding)
-    
-    return 0
-
-def changeLauncherAttr(manifest, attrType, attrValue):
-    '''
-    更改启动的activity的属性
-    '''
-    for key in namespaces:
-        ET.register_namespace(key, namespaces[key])
-
-    tree = ET.parse(manifest)
-    root = tree.getroot()
-
-    launcherActivity = getLauncherActivity(root)
-    if launcherActivity is None:
-        return 1
-
-    attrName = getNamespacesFormat('android:%s' % attrType, namespaces)
-    if attrName in launcherActivity.attrib:
-        launcherActivity.attrib[attrName] = attrValue
-        tree.write(manifest, encoding)
-
-    return 0
-
-def changeAppIcon(manifest, iconRes):
-    '''
-    更改app icon
-    '''
-    # 移除主activity的图标
-    removeLauncherAttr(manifest, 'icon')
-    return changeApplicationAttr(manifest, 'icon', iconRes)
-
-def changeApplicationAttr(manifest, attrType, attrValue):
-    '''
-    更改Application的某个属性
-    '''
-    for key in namespaces:
-        ET.register_namespace(key, namespaces[key])
-
-    tree = ET.parse(manifest)
-    root = tree.getroot()
-    application = root.find('application')
-    # Namespaces
-    attrName = getNamespacesFormat('android:%s' % attrType, namespaces)
-    application.attrib[attrName] = attrValue
-    tree.write(manifest, encoding)
-    return 0
-
-
-def addApplicationAttr(manifest, attrType, attrValue):
-    '''
-    更改Application的某个属性
-    '''
-    for key in namespaces:
-        ET.register_namespace(key, namespaces[key])
-
-    tree = ET.parse(manifest)
-    root = tree.getroot()
-    application = root.find('application')
-    # Namespaces
-    attrName = getNamespacesFormat('android:%s' % attrType, namespaces)
-    application.set(attrName,attrValue)
-    tree.write(manifest, encoding)
-    return 0
-
-def getApplicationAttr(manifest, attrType):
-    '''
-    获取Application的某个属性
-    '''
-    for key in namespaces:
-        ET.register_namespace(key, namespaces[key])
-
-    tree = ET.parse(manifest)
-    root = tree.getroot()
-    application = root.find('application')
-    attrName = getNamespacesFormat('android:%s' % attrType, namespaces)
-    if attrName in application.attrib:
-        return application.attrib[attrName]
-            
-    return None
-
-def getNamespacesFormat(text, namespaces):
-    '''
-    格式化带namespaces的属性
-    '''
-    for key in namespaces:
-        text = text.replace('%s:' % key, '{%s}' % namespaces[key])
-    return text
-
-def mergeManifestRes(appManifest, libManifest):
-    '''
-    合并主文件
-    '''
-    if not os.path.exists(libManifest):
-        print('file "%s" not exists' % libManifest)
-        return 1
-
-    if not os.path.exists(appManifest):
-        print('file "%s" not exists' % appManifest)
-        return 1
-
-    libInfo = getLibManifestInfo(libManifest)
-    appPermission = getManifestPermission(appManifest)
-    diffPermission = mergeManifestPermission(appPermission, libInfo['permissionList'])
-
-    mergeManifest(appManifest, diffPermission, libInfo['activityList'])
-    return 0
-
-def getLibManifestInfo(libManifest):
-    '''
-    获取框架的主文件参数
-    '''
-    for key in namespaces:
-        ET.register_namespace(key, namespaces[key])
-
-    tree = ET.parse(libManifest)
-    root = tree.getroot()
-
-    permissionList = root.findall('permissions/*')
-    activityList = root.findall('application/*')
-
-    info = {'permissionList' : permissionList, 'activityList' : activityList}
-    return info
-
-def getManifestPermission(appManifest):
-    '''
-    获取主文件参数
-    '''
-    for key in namespaces:
-        ET.register_namespace(key, namespaces[key])
-
-    tree = ET.parse(appManifest)
-    root = tree.getroot()
-
-    return root.findall('uses-permission')
-
-def mergeManifestPermission(appPermission, libPermission):
-    '''
-    合并主文件参数
-    '''
-    newPermissionList = []
-
-    for permission in libPermission:
-        if contain(appPermission, permission):
-            continue
-        newPermissionList.append(permission)
-
-    return newPermissionList
-
-def contain(nodeList, item):
-    '''
-    是否存在
-    '''
-    attrName = getNamespacesFormat('android:name', namespaces)
-    for node in nodeList:
-        if node.attrib[attrName] == item.attrib[attrName]:
-            return True
-    return False
-
-def mergeManifest(appManifest, permissionList, activityList):
-    '''
-    将权限和activity加入到主文件
-    '''
-    for key in namespaces:
-        ET.register_namespace(key, namespaces[key])
-
-    tree = ET.parse(appManifest)
-    root = tree.getroot()
-
-    # 权限
-    for item in permissionList:
-        root.insert(0, item)
-
-    # activity
-    application = root.find('application')
-    # 删除不支持属性
-    attrName = getNamespacesFormat('android:roundIcon', namespaces)
-    if attrName in application.attrib:
-        del application.attrib[attrName]
-    # 删除不支持属性
-    attrName = getNamespacesFormat('android:testOnly', namespaces)
-    if attrName in application.attrib:
-        del application.attrib[attrName]
-    # 删除不支持属性
-    attrName = getNamespacesFormat('android:debuggable', namespaces)
-    if attrName in application.attrib:
-        del application.attrib[attrName]
-
-    # 覆盖
-    # 移除相同的标签
-    attrName = getNamespacesFormat('android:name', namespaces)
-    for item in application.getchildren():
-        if contain(activityList, item):
-            application.remove(item)
-
-    for item in activityList:
-        application.insert(1, item)
-
-    tree.write(appManifest, encoding)
-
-def addMetaData(manifest, meta):
-    '''
-    添加meta-data
-    '''
-    for key in namespaces:
-        ET.register_namespace(key, namespaces[key])
-
-    tree = ET.parse(manifest)
-    root = tree.getroot()
-
-    application = root.find('application')
-    for key in meta:
-        val = meta[key]
-        '''if type(val) == str and val.isdigit():
-            element = ET.Element('meta-data', {'android:name' : key, 'android:value' : '\\ ' + val})
-        else:
-            element = ET.Element('meta-data', {'android:name' : key, 'android:value' : val})'''
-        element = ET.Element('meta-data', {'android:name' : key, 'android:value' : val})
-        application.append(element)
-
-    tree.write(manifest, encoding)
-
-def readAllRes(resFile, resList):
-    '''
-    读取资源文件
-    '''
-    tree = ET.parse(resFile)
-    root = tree.getroot()
-
-    resList += root.getchildren()
-    return resList
-
-def removeIdFromPublic(pubFile, removeList):
-    '''
-    删除重复的资源
-    '''
-    tree = ET.parse(pubFile)
-    root = tree.getroot()
-
-    same = False
-    for node in root.getchildren():
-        if containPublic(node, removeList):
-            print('delete public node : type is %s, name is %s' % (node.attrib['type'], node.attrib['name']))
-            root.remove(node)
-            same = True
-    if same:
-        tree.write(pubFile, encoding)
-
-def removeSameRes2(resFile, resList, removeList):
-    '''
-    删除重复的资源
-    '''
-    tree = ET.parse(resFile)
-    root = tree.getroot()
-
-    same = False
-    for node in root.getchildren():
-        if containRes(node, resList):
-            #print('delete node : tag is %s, name is %s' % (node.tag, node.attrib['name']))
-            root.remove(node)
-            removeList.append(node)
-            same = True
-
-    if same:
-        tree.write(resFile, encoding)
-    return removeList
-
-def removeSameRes(resFile, resList):
-    '''
-    删除重复的资源
-    '''
-    tree = ET.parse(resFile)
-    root = tree.getroot()
-
-    same = False
-    for node in root.getchildren():
-        if containRes(node, resList):
-            #print('delete node : tag is %s, name is %s' % (node.tag, node.attrib['name']))
-            root.remove(node)
-            same = True
-
-    if same:
-        tree.write(resFile, encoding)
-
-def containRes(node, resList):
-    '''
-    是否重复
-    '''
-    for item in resList:
-         if item.tag == node.tag and item.attrib['name'] == node.attrib['name']:
-            return True
-
-    return False
-
-def containPublic(node, removeList):
-    '''
-    是否重复
-    '''
-    for item in removeList:
-         if item.tag == node.attrib['type'] and item.attrib['name'] == node.attrib['name']:
-            return True
-
-    return False
-
-
-def removeRootAttr(manifest, attrType):
-    for key in namespaces:
-        ET.register_namespace(key, namespaces[key])
-
-    tree = ET.parse(manifest)
-    root = tree.getroot()
-
-    attrName = getNamespacesFormat('android:%s' % attrType, namespaces)
-    if attrName in root.attrib:
-        del root.attrib[attrName]
-        tree.write(manifest, encoding)
-    
-    return 0
-
-
-def deleteActivityByName(manifest,activityName):
-    '''
-    删除activity
-    '''
-    attrName = getNamespacesFormat('android:name', namespaces)
-    for key in namespaces:
-        ET.register_namespace(key, namespaces[key])
-
-    targetTree = ET.parse(manifest)
-    targetRoot = targetTree.getroot()
-    appNode = targetRoot.find('application')
-    activitys = appNode.findall('activity')
-    for activity in activitys:
-        if activity.attrib[attrName] == activityName:
-            print('delete ------------------> ' + activityName)
-            appNode.remove(activity)
-            targetTree.write(manifest, encoding)
-            break
-
-
-def getActivityByName(root,activityName):
-    '''
-    获取activity
-    '''
-    attrName = getNamespacesFormat('android:name', namespaces)
-
-    for node in root.findall('application/activity'):
-        print ('activity name = ' + node.attrib[attrName])
-        if node.attrib[attrName] == activityName:
-            return node
-    return None
-
-
-
-def formatXml(manifest): # elemnt为传进来的Elment类,参数indent用于缩进,newline用于换行
-    indent = '\t'
-    newline = '\n'
-
-    tree = ET.parse(manifest)
-    root = tree.getroot()  # 得到根元素,Element类
-    prettyXml(root, indent, newline, level=0)  # 对子元素进行递归操作
-
-    ET.dump(root)
-    return 0
-
-
-def prettyXml(element, indent, newline, level = 0): # elemnt为传进来的Elment类,参数indent用于缩进,newline用于换行
-    if element:  # 判断element是否有子元素
-        if element.text == None or element.text.isspace(): # 如果element的text没有内容
-            element.text = newline + indent * (level + 1)
-        else:
-            element.text = newline + indent * (level + 1) + element.text.strip() + newline + indent * (level + 1)
-    #else:  # 此处两行如果把注释去掉,Element的text也会另起一行
-        #element.text = newline + indent * (level + 1) + element.text.strip() + newline + indent * level
-    temp = list(element) # 将elemnt转成list
-    for subelement in temp:
-        if temp.index(subelement) < (len(temp) - 1): # 如果不是list的最后一个元素,说明下一个行是同级别元素的起始,缩进应一致
-            subelement.tail = newline + indent * (level + 1)
-        else:  # 如果是list的最后一个元素, 说明下一行是母元素的结束,缩进应该少一个
-            subelement.tail = newline + indent * level
+import xml.etree.ElementTree as ET
+import os.path
+
+namespaces = {'android' : 'http://schemas.android.com/apk/res/android'}
+encoding = 'UTF-8'
+
+def getPackageName(manifest):
+    '''
+    获取包名
+    '''
+    tree = ET.parse(manifest)
+    root = tree.getroot()
+    return root.attrib['package']
+
+def changePackageName(manifest, packageName):
+    '''
+    更改包名
+    '''
+    for key in namespaces:
+        ET.register_namespace(key, namespaces[key])
+
+    tree = ET.parse(manifest)
+    root = tree.getroot()
+    root.attrib['package'] = packageName
+    tree.write(manifest, encoding)
+
+def removeLauncherActivity(manifest):
+    '''
+    删除启动的activity
+    '''
+    for key in namespaces:
+        ET.register_namespace(key, namespaces[key])
+
+    tree = ET.parse(manifest)
+    root = tree.getroot()
+    
+    attrName = getNamespacesFormat('android:name', namespaces)
+    for node in root.findall('application/activity'):
+        if len(node.getchildren()) <= 0:
+            continue
+
+        for sub in node.getchildren():
+            if sub.tag != 'intent-filter':
+                continue
+
+            for sub2 in sub.getchildren():
+                if not (sub2.tag == 'category' and sub2.attrib[attrName] == 'android.intent.category.LAUNCHER'):
+                    continue
+
+                node.remove(sub)
+                tree.write(manifest, encoding)
+                return node.attrib[attrName]
+    return 0
+
+
+def removeLauncherActivityByName(manifest,name):
+    '''
+    删除启动的activity
+    '''
+    for key in namespaces:
+        ET.register_namespace(key, namespaces[key])
+
+    tree = ET.parse(manifest)
+    root = tree.getroot()
+
+    attrName = getNamespacesFormat('android:name', namespaces)
+    for node in root.findall('application/activity'):
+        print('node ----> ' + node.attrib[attrName])
+        if node.attrib[attrName] != name:
+            continue
+        for sub in node.getchildren():
+            if sub.tag != 'intent-filter':
+                continue
+
+            for sub2 in sub.getchildren():
+                if not (sub2.tag == 'category' and sub2.attrib[attrName] == 'android.intent.category.LAUNCHER'):
+                    continue
+                node.remove(sub)
+                tree.write(manifest, encoding)
+            return node.attrib[attrName]
+
+
+    return 0
+
+def getScreenOrientation(manifest):
+    '''
+    获取启动activity的方向
+    '''
+    for key in namespaces:
+        ET.register_namespace(key, namespaces[key])
+
+    tree = ET.parse(manifest)
+    root = tree.getroot()
+
+    attrName = getNamespacesFormat('android:name', namespaces)
+    attrOrientation = getNamespacesFormat('android:screenOrientation', namespaces)
+    for node in root.findall('application/activity'):
+        if len(node.getchildren()) <= 0:
+            continue
+
+        for sub in node.getchildren():
+            if sub.tag != 'intent-filter':
+                continue
+
+            for sub2 in sub.getchildren():
+                if not (sub2.tag == 'category' and sub2.attrib[attrName] == 'android.intent.category.LAUNCHER'):
+                    continue
+
+                return node.attrib[attrOrientation]
+    return 0
+
+def addLauncherActivity(manifest, screenOrientation, activity):
+    '''
+    添加启动的activity
+    '''
+    for key in namespaces:
+        ET.register_namespace(key, namespaces[key])
+
+    tree = ET.parse(manifest)
+    root = tree.getroot()
+
+    # activity
+    '''<activity android:name=".LauncherActivity"
+            android:theme="@style/LauncherStyle">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>'''
+
+    activity = ET.Element('activity', {'android:name' : activity,
+    'android:theme' : '@android:style/Theme.Holo.Light.NoActionBar.Fullscreen',
+    'android:launchMode' : 'singleTop',
+    'android:configChanges' : 'orientation|screenSize|keyboardHidden',
+    'android:screenOrientation' : screenOrientation})
+    intent = ET.Element('intent-filter')
+    action = ET.Element('action', {'android:name' : 'android.intent.action.MAIN'})
+    category = ET.Element('category', {'android:name' : 'android.intent.category.LAUNCHER'})
+    intent.append(action)
+    intent.append(category)
+    activity.append(intent)
+    
+    application = root.find('application')
+    application.insert(0, activity)
+
+    tree.write(manifest, encoding)
+
+def changeAppName(manifest, stringRes):
+    '''
+    更改app名
+    '''
+    # 移除主activity的label
+    removeLauncherAttr(manifest, 'label')
+    return changeApplicationAttr(manifest, 'label', stringRes)
+
+def getLauncherActivity(root):
+    '''
+    获取启动的activity
+    '''
+    attrName = getNamespacesFormat('android:name', namespaces)
+
+    for node in root.findall('application/activity'):
+        if len(node.getchildren()) <= 0:
+            continue
+
+        for sub in node.getchildren():
+            if sub.tag != 'intent-filter':
+                continue
+
+            for sub2 in sub.getchildren():
+                if sub2.tag == 'category' and sub2.attrib[attrName] == 'android.intent.category.LAUNCHER':
+                    return node
+
+    return None
+
+def getLauncherActivitys(manifest):
+    '''
+    获取启动的activity
+    '''
+    attrName = getNamespacesFormat('android:name', namespaces)
+    nodeList = []
+
+    tree = ET.parse(manifest)
+    root = tree.getroot()
+
+    for node in root.findall('application/activity'):
+        if len(node.getchildren()) <= 0:
+            continue
+
+        for sub in node.getchildren():
+            if sub.tag != 'intent-filter':
+                continue
+
+            for sub2 in sub.getchildren():
+                if sub2.tag == 'category' and sub2.attrib[attrName] == 'android.intent.category.LAUNCHER':
+                    nodeList.append(node)
+
+    return nodeList
+
+def getLauncherActivityName(manifest):
+    '''
+    获取启动的activity
+    '''
+    for key in namespaces:
+        ET.register_namespace(key, namespaces[key])
+
+    tree = ET.parse(manifest)
+    root = tree.getroot()
+
+    launcherActivity = getLauncherActivity(root)
+    attrName = getNamespacesFormat('android:name', namespaces)
+    activityName = launcherActivity.attrib[attrName]
+    return activityName
+
+def addMoreIcon(manifest, icon, switchIcon):
+    '''
+    添加多图标
+    '''
+    for key in namespaces:
+        ET.register_namespace(key, namespaces[key])
+
+    tree = ET.parse(manifest)
+    root = tree.getroot()
+
+    launcherActivity = getLauncherActivity(root)
+    if launcherActivity is None:
+        return 1
+
+    attrName = getNamespacesFormat('android:name', namespaces)
+    activityName = launcherActivity.attrib[attrName]
+
+    activityAlias = ET.Element('activity-alias', {'android:name' : 'com.jmhy.sdk.icon.normal',
+    'android:enabled' : 'false',
+    'android:icon' : icon,
+    'android:targetActivity' : activityName})
+
+    activityAlias2 = ET.Element('activity-alias', {'android:name' : 'com.jmhy.sdk.icon.switch',
+    'android:enabled' : 'false',
+    'android:icon' : switchIcon,
+    'android:targetActivity' : activityName})
+
+    for item in launcherActivity.getchildren():
+        activityAlias.append(item)
+        activityAlias2.append(item)
+
+    application = root.find('application')
+    application.append(activityAlias)
+    application.append(activityAlias2)
+    tree.write(manifest, encoding)
+    return 0
+
+def removeLauncherAttr(manifest, attrType):
+    '''
+    移除启动的activity的label
+    '''
+    for key in namespaces:
+        ET.register_namespace(key, namespaces[key])
+
+    tree = ET.parse(manifest)
+    root = tree.getroot()
+
+    launcherActivity = getLauncherActivity(root)
+    if launcherActivity is None:
+        return 1
+
+    attrName = getNamespacesFormat('android:%s' % attrType, namespaces)
+    if attrName in launcherActivity.attrib:
+        del launcherActivity.attrib[attrName]
+        tree.write(manifest, encoding)
+    
+    return 0
+
+def changeLauncherAttr(manifest, attrType, attrValue):
+    '''
+    更改启动的activity的属性
+    '''
+    for key in namespaces:
+        ET.register_namespace(key, namespaces[key])
+
+    tree = ET.parse(manifest)
+    root = tree.getroot()
+
+    launcherActivity = getLauncherActivity(root)
+    if launcherActivity is None:
+        return 1
+
+    attrName = getNamespacesFormat('android:%s' % attrType, namespaces)
+    if attrName in launcherActivity.attrib:
+        launcherActivity.attrib[attrName] = attrValue
+        tree.write(manifest, encoding)
+
+    return 0
+
+def changeAppIcon(manifest, iconRes):
+    '''
+    更改app icon
+    '''
+    # 移除主activity的图标
+    removeLauncherAttr(manifest, 'icon')
+    return changeApplicationAttr(manifest, 'icon', iconRes)
+
+def changeApplicationAttr(manifest, attrType, attrValue):
+    '''
+    更改Application的某个属性
+    '''
+    for key in namespaces:
+        ET.register_namespace(key, namespaces[key])
+
+    tree = ET.parse(manifest)
+    root = tree.getroot()
+    application = root.find('application')
+    # Namespaces
+    attrName = getNamespacesFormat('android:%s' % attrType, namespaces)
+    application.attrib[attrName] = attrValue
+    tree.write(manifest, encoding)
+    return 0
+
+
+def addApplicationAttr(manifest, attrType, attrValue):
+    '''
+    更改Application的某个属性
+    '''
+    for key in namespaces:
+        ET.register_namespace(key, namespaces[key])
+
+    tree = ET.parse(manifest)
+    root = tree.getroot()
+    application = root.find('application')
+    # Namespaces
+    attrName = getNamespacesFormat('android:%s' % attrType, namespaces)
+    application.set(attrName,attrValue)
+    tree.write(manifest, encoding)
+    return 0
+
+def getApplicationAttr(manifest, attrType):
+    '''
+    获取Application的某个属性
+    '''
+    for key in namespaces:
+        ET.register_namespace(key, namespaces[key])
+
+    tree = ET.parse(manifest)
+    root = tree.getroot()
+    application = root.find('application')
+    attrName = getNamespacesFormat('android:%s' % attrType, namespaces)
+    if attrName in application.attrib:
+        return application.attrib[attrName]
+            
+    return None
+
+def getNamespacesFormat(text, namespaces):
+    '''
+    格式化带namespaces的属性
+    '''
+    for key in namespaces:
+        text = text.replace('%s:' % key, '{%s}' % namespaces[key])
+    return text
+
+def mergeManifestRes(appManifest, libManifest):
+    '''
+    合并主文件
+    '''
+    if not os.path.exists(libManifest):
+        print('file "%s" not exists' % libManifest)
+        return 1
+
+    if not os.path.exists(appManifest):
+        print('file "%s" not exists' % appManifest)
+        return 1
+
+    libInfo = getLibManifestInfo(libManifest)
+    appPermission = getManifestPermission(appManifest)
+    diffPermission = mergeManifestPermission(appPermission, libInfo['permissionList'])
+
+    mergeManifest(appManifest, diffPermission, libInfo['activityList'])
+    return 0
+
+def getLibManifestInfo(libManifest):
+    '''
+    获取框架的主文件参数
+    '''
+    for key in namespaces:
+        ET.register_namespace(key, namespaces[key])
+
+    tree = ET.parse(libManifest)
+    root = tree.getroot()
+
+    permissionList = root.findall('permissions/*')
+    activityList = root.findall('application/*')
+
+    info = {'permissionList' : permissionList, 'activityList' : activityList}
+    return info
+
+def getManifestPermission(appManifest):
+    '''
+    获取主文件参数
+    '''
+    for key in namespaces:
+        ET.register_namespace(key, namespaces[key])
+
+    tree = ET.parse(appManifest)
+    root = tree.getroot()
+
+    return root.findall('uses-permission')
+
+def mergeManifestPermission(appPermission, libPermission):
+    '''
+    合并主文件参数
+    '''
+    newPermissionList = []
+
+    for permission in libPermission:
+        if contain(appPermission, permission):
+            continue
+        newPermissionList.append(permission)
+
+    return newPermissionList
+
+def contain(nodeList, item):
+    '''
+    是否存在
+    '''
+    attrName = getNamespacesFormat('android:name', namespaces)
+    for node in nodeList:
+        if node.attrib[attrName] == item.attrib[attrName]:
+            return True
+    return False
+
+def mergeManifest(appManifest, permissionList, activityList):
+    '''
+    将权限和activity加入到主文件
+    '''
+    for key in namespaces:
+        ET.register_namespace(key, namespaces[key])
+
+    tree = ET.parse(appManifest)
+    root = tree.getroot()
+
+    # 权限
+    for item in permissionList:
+        root.insert(0, item)
+
+    # activity
+    application = root.find('application')
+    # 删除不支持属性
+    attrName = getNamespacesFormat('android:roundIcon', namespaces)
+    if attrName in application.attrib:
+        del application.attrib[attrName]
+    # 删除不支持属性
+    attrName = getNamespacesFormat('android:testOnly', namespaces)
+    if attrName in application.attrib:
+        del application.attrib[attrName]
+    # 删除不支持属性
+    attrName = getNamespacesFormat('android:debuggable', namespaces)
+    if attrName in application.attrib:
+        del application.attrib[attrName]
+
+    # 覆盖
+    # 移除相同的标签
+    attrName = getNamespacesFormat('android:name', namespaces)
+    for item in application.getchildren():
+        if contain(activityList, item):
+            application.remove(item)
+
+    for item in activityList:
+        application.insert(1, item)
+
+    tree.write(appManifest, encoding)
+
+def addMetaData(manifest, meta):
+    '''
+    添加meta-data
+    '''
+    for key in namespaces:
+        ET.register_namespace(key, namespaces[key])
+
+    tree = ET.parse(manifest)
+    root = tree.getroot()
+
+    application = root.find('application')
+    for key in meta:
+        val = meta[key]
+        '''if type(val) == str and val.isdigit():
+            element = ET.Element('meta-data', {'android:name' : key, 'android:value' : '\\ ' + val})
+        else:
+            element = ET.Element('meta-data', {'android:name' : key, 'android:value' : val})'''
+        element = ET.Element('meta-data', {'android:name' : key, 'android:value' : val})
+        application.append(element)
+
+    tree.write(manifest, encoding)
+
+def readAllRes(resFile, resList):
+    '''
+    读取资源文件
+    '''
+    tree = ET.parse(resFile)
+    root = tree.getroot()
+
+    resList += root.getchildren()
+    return resList
+
+def removeIdFromPublic(pubFile, removeList):
+    '''
+    删除重复的资源
+    '''
+    tree = ET.parse(pubFile)
+    root = tree.getroot()
+
+    same = False
+    for node in root.getchildren():
+        if containPublic(node, removeList):
+            print('delete public node : type is %s, name is %s' % (node.attrib['type'], node.attrib['name']))
+            root.remove(node)
+            same = True
+    if same:
+        tree.write(pubFile, encoding)
+
+def removeSameRes2(resFile, resList, removeList):
+    '''
+    删除重复的资源
+    '''
+    tree = ET.parse(resFile)
+    root = tree.getroot()
+
+    same = False
+    for node in root.getchildren():
+        if containRes(node, resList):
+            #print('delete node : tag is %s, name is %s' % (node.tag, node.attrib['name']))
+            root.remove(node)
+            removeList.append(node)
+            same = True
+
+    if same:
+        tree.write(resFile, encoding)
+    return removeList
+
+def removeSameRes(resFile, resList):
+    '''
+    删除重复的资源
+    '''
+    tree = ET.parse(resFile)
+    root = tree.getroot()
+
+    same = False
+    for node in root.getchildren():
+        if containRes(node, resList):
+            #print('delete node : tag is %s, name is %s' % (node.tag, node.attrib['name']))
+            root.remove(node)
+            same = True
+
+    if same:
+        tree.write(resFile, encoding)
+
+def containRes(node, resList):
+    '''
+    是否重复
+    '''
+    for item in resList:
+         if item.tag == node.tag and item.attrib['name'] == node.attrib['name']:
+            return True
+
+    return False
+
+def containPublic(node, removeList):
+    '''
+    是否重复
+    '''
+    for item in removeList:
+         if item.tag == node.attrib['type'] and item.attrib['name'] == node.attrib['name']:
+            return True
+
+    return False
+
+
+def removeRootAttr(manifest, attrType):
+    for key in namespaces:
+        ET.register_namespace(key, namespaces[key])
+
+    tree = ET.parse(manifest)
+    root = tree.getroot()
+
+    attrName = getNamespacesFormat('android:%s' % attrType, namespaces)
+    if attrName in root.attrib:
+        del root.attrib[attrName]
+        tree.write(manifest, encoding)
+    
+    return 0
+
+
+def deleteActivityByName(manifest,activityName):
+    '''
+    删除activity
+    '''
+    attrName = getNamespacesFormat('android:name', namespaces)
+    for key in namespaces:
+        ET.register_namespace(key, namespaces[key])
+
+    targetTree = ET.parse(manifest)
+    targetRoot = targetTree.getroot()
+    appNode = targetRoot.find('application')
+    activitys = appNode.findall('activity')
+    for activity in activitys:
+        if activity.attrib[attrName] == activityName:
+            print('delete ------------------> ' + activityName)
+            appNode.remove(activity)
+            targetTree.write(manifest, encoding)
+            break
+
+
+def getActivityByName(root,activityName):
+    '''
+    获取activity
+    '''
+    attrName = getNamespacesFormat('android:name', namespaces)
+
+    for node in root.findall('application/activity'):
+        print ('activity name = ' + node.attrib[attrName])
+        if node.attrib[attrName] == activityName:
+            return node
+    return None
+
+
+
+def formatXml(manifest): # elemnt为传进来的Elment类,参数indent用于缩进,newline用于换行
+    indent = '\t'
+    newline = '\n'
+
+    tree = ET.parse(manifest)
+    root = tree.getroot()  # 得到根元素,Element类
+    prettyXml(root, indent, newline, level=0)  # 对子元素进行递归操作
+
+    ET.dump(root)
+    return 0
+
+
+def prettyXml(element, indent, newline, level = 0): # elemnt为传进来的Elment类,参数indent用于缩进,newline用于换行
+    if element:  # 判断element是否有子元素
+        if element.text == None or element.text.isspace(): # 如果element的text没有内容
+            element.text = newline + indent * (level + 1)
+        else:
+            element.text = newline + indent * (level + 1) + element.text.strip() + newline + indent * (level + 1)
+    #else:  # 此处两行如果把注释去掉,Element的text也会另起一行
+        #element.text = newline + indent * (level + 1) + element.text.strip() + newline + indent * level
+    temp = list(element) # 将elemnt转成list
+    for subelement in temp:
+        if temp.index(subelement) < (len(temp) - 1): # 如果不是list的最后一个元素,说明下一个行是同级别元素的起始,缩进应一致
+            subelement.tail = newline + indent * (level + 1)
+        else:  # 如果是list的最后一个元素, 说明下一行是母元素的结束,缩进应该少一个
+            subelement.tail = newline + indent * level
         prettyXml(subelement, indent, newline, level = level + 1) # 对子元素进行递归操作