Browse Source

first upload code

huangkq 6 years ago
parent
commit
35534a6076
100 changed files with 5907 additions and 0 deletions
  1. 104 0
      common_utils.py
  2. 103 0
      config_utils.py
  3. 73 0
      config_utils_shanshen.py
  4. 502 0
      file_utils.py
  5. 59 0
      game_utils.py
  6. 80 0
      internal/launcher_code/smali/com/jmhy/sdk/template/LauncherActivity$LaunchHandler.smali
  7. 115 0
      internal/launcher_code/smali/com/jmhy/sdk/template/LauncherActivity.smali
  8. 13 0
      internal/launcher_res/layout/common_sdk_launcher_template.xml
  9. 80 0
      internal_shanshen/launcher_code/smali/com/shanshen/sdk/template/LauncherActivity$LaunchHandler.smali
  10. 115 0
      internal_shanshen/launcher_code/smali/com/shanshen/sdk/template/LauncherActivity.smali
  11. 12 0
      internal_shanshen/launcher_res/layout/shanshen_sdk_launcher_template.xml
  12. 8 0
      keystore/key.json
  13. BIN
      keystore/susu.keystore
  14. BIN
      log_sdk/gdt/gdt.jar
  15. BIN
      log_sdk/gdt/libs/GDTActionSDK.min.1.3.0.jar
  16. 10 0
      log_sdk/gdt/manifest.xml
  17. BIN
      log_sdk/jrtt/jniLibs/arm64-v8a/libttEncrypt.so
  18. BIN
      log_sdk/jrtt/jniLibs/armeabi-v7a/libttEncrypt.so
  19. BIN
      log_sdk/jrtt/jniLibs/armeabi/libttEncrypt.so
  20. BIN
      log_sdk/jrtt/jrtt.jar
  21. BIN
      log_sdk/jrtt/jrtt_test.jar
  22. BIN
      log_sdk/jrtt/libs/jrtt_logsdk.jar
  23. 10 0
      log_sdk/jrtt/manifest.xml
  24. 3 0
      package.py
  25. 178 0
      package_channel.py
  26. 3 0
      package_shanshen.py
  27. 66 0
      package_test.py
  28. 1125 0
      package_utils.py
  29. 1018 0
      package_utils_shanshen.py
  30. 268 0
      package_web.py
  31. 210 0
      package_web_shanshen.py
  32. 16 0
      readme.txt
  33. 2 0
      sdk/gzjysdk/assets/ss.properties
  34. BIN
      sdk/gzjysdk/libs/android-support-v4.jar
  35. BIN
      sdk/gzjysdk/libs/commons-httpclient-3.1.jar
  36. BIN
      sdk/gzjysdk/libs/gzjysdk-1.0.2.jar
  37. BIN
      sdk/gzjysdk/libs/org.apache.http.legacy.jar
  38. BIN
      sdk/gzjysdk/libs/walle-reader-1.1.6.jar
  39. BIN
      sdk/gzjysdk/libs/walle.jar
  40. 54 0
      sdk/gzjysdk/manifest.xml
  41. BIN
      sdk/gzjysdk/res/drawable-hdpi/ss_account.png
  42. BIN
      sdk/gzjysdk/res/drawable-hdpi/ss_back.png
  43. BIN
      sdk/gzjysdk/res/drawable-hdpi/ss_cancel.png
  44. BIN
      sdk/gzjysdk/res/drawable-hdpi/ss_code.png
  45. BIN
      sdk/gzjysdk/res/drawable-hdpi/ss_float.png
  46. BIN
      sdk/gzjysdk/res/drawable-hdpi/ss_logo.png
  47. BIN
      sdk/gzjysdk/res/drawable-hdpi/ss_password.png
  48. BIN
      sdk/gzjysdk/res/drawable-hdpi/ss_phone.png
  49. BIN
      sdk/gzjysdk/res/drawable-hdpi/ss_toast.png
  50. BIN
      sdk/gzjysdk/res/drawable-hdpi/ss_urpulldown.png
  51. 12 0
      sdk/gzjysdk/res/drawable/ss_autologinb.xml
  52. 5 0
      sdk/gzjysdk/res/drawable/ss_button.xml
  53. 5 0
      sdk/gzjysdk/res/drawable/ss_button_disable.xml
  54. 5 0
      sdk/gzjysdk/res/drawable/ss_button_normal.xml
  55. 8 0
      sdk/gzjysdk/res/drawable/ss_dialog.xml
  56. 5 0
      sdk/gzjysdk/res/drawable/ss_dialog_ios_bg.xml
  57. 5 0
      sdk/gzjysdk/res/drawable/ss_exit_dialog_bg.xml
  58. 21 0
      sdk/gzjysdk/res/drawable/ss_float_bg.xml
  59. 5 0
      sdk/gzjysdk/res/drawable/ss_input_bg.xml
  60. 5 0
      sdk/gzjysdk/res/drawable/ss_login_account.xml
  61. 5 0
      sdk/gzjysdk/res/drawable/ss_login_phone.xml
  62. 5 0
      sdk/gzjysdk/res/drawable/ss_login_quick.xml
  63. 7 0
      sdk/gzjysdk/res/drawable/ss_loginb.xml
  64. 5 0
      sdk/gzjysdk/res/drawable/ss_message_tip.xml
  65. 25 0
      sdk/gzjysdk/res/drawable/ss_white_bg_buttom_more_count.xml
  66. 68 0
      sdk/gzjysdk/res/layout/ss_autologin.xml
  67. 12 0
      sdk/gzjysdk/res/layout/ss_community.xml
  68. 46 0
      sdk/gzjysdk/res/layout/ss_dialog_ios.xml
  69. 57 0
      sdk/gzjysdk/res/layout/ss_exitdialog.xml
  70. 29 0
      sdk/gzjysdk/res/layout/ss_float_view.xml
  71. 31 0
      sdk/gzjysdk/res/layout/ss_itemcountlist.xml
  72. 15 0
      sdk/gzjysdk/res/layout/ss_itemmoblielist.xml
  73. 142 0
      sdk/gzjysdk/res/layout/ss_login_main.xml
  74. 60 0
      sdk/gzjysdk/res/layout/ss_login_main_fragment.xml
  75. 13 0
      sdk/gzjysdk/res/layout/ss_loginbase.xml
  76. 21 0
      sdk/gzjysdk/res/layout/ss_notice.xml
  77. 199 0
      sdk/gzjysdk/res/layout/ss_phone_register.xml
  78. 22 0
      sdk/gzjysdk/res/layout/ss_popwindow.xml
  79. 123 0
      sdk/gzjysdk/res/layout/ss_setpwd.xml
  80. 138 0
      sdk/gzjysdk/res/layout/ss_setuser.xml
  81. 33 0
      sdk/gzjysdk/res/layout/ss_toast.xml
  82. 142 0
      sdk/gzjysdk/res/layout/ss_user_login.xml
  83. 162 0
      sdk/gzjysdk/res/layout/ss_user_register.xml
  84. 21 0
      sdk/gzjysdk/res/layout/ss_userinfo.xml
  85. 22 0
      sdk/gzjysdk/res/layout/ss_userp.xml
  86. 11 0
      sdk/gzjysdk/res/values-port/ss_dimens.xml
  87. 6 0
      sdk/gzjysdk/res/values/ss_attrs.xml
  88. 16 0
      sdk/gzjysdk/res/values/ss_colors.xml
  89. 34 0
      sdk/gzjysdk/res/values/ss_dimens.xml
  90. 4 0
      sdk/gzjysdk/res/values/ss_public.xml
  91. 59 0
      sdk/gzjysdk/res/values/ss_strings.xml
  92. 23 0
      sdk/gzjysdk/res/values/ss_styles.xml
  93. BIN
      sdk/gzjysdk/script/__pycache__/sdk_script.cpython-37.pyc
  94. 48 0
      sdk/gzjysdk/script/sdk_script.py
  95. BIN
      sdk/jm/jm.jar
  96. BIN
      sdk/jm/libs/alipaySdk-20180601.jar
  97. BIN
      sdk/jm/libs/android-support-v4.jar
  98. BIN
      sdk/jm/libs/commons-httpclient-3.1.jar
  99. BIN
      sdk/jm/libs/jm_sdk_20190301.jar
  100. BIN
      sdk/jm/libs/org.apache.http.legacy.jar

+ 104 - 0
common_utils.py

@@ -0,0 +1,104 @@
+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 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):
+    return file_utils.openFile(file, mode)

+ 103 - 0
config_utils.py

@@ -0,0 +1,103 @@
+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 '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()) 

+ 73 - 0
config_utils_shanshen.py

@@ -0,0 +1,73 @@
+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 '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()) 

+ 502 - 0
file_utils.py

@@ -0,0 +1,502 @@
+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 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):
+    '''
+    执行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)
+        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):
+        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)
+
+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 getAndroidCompileToolPath():
+    '''
+    获取android.jar
+    '''
+    return getFullToolPath('android.jar')
+
+def getDxPath():
+    '''
+    获取dx.jar
+    '''
+    return getFullToolPath('dx.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.3.4.jar')
+
+def getBaksmaliPath():
+    '''
+    获取baksmali.jar
+    '''
+    return getFullToolPath('baksmali-2.1.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'
+    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)

+ 59 - 0
game_utils.py

@@ -0,0 +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
+
+    tree.write(manifest, encoding)

+ 80 - 0
internal/launcher_code/smali/com/jmhy/sdk/template/LauncherActivity$LaunchHandler.smali

@@ -0,0 +1,80 @@
+.class Lcom/jmhy/sdk/template/LauncherActivity$LaunchHandler;
+.super Landroid/os/Handler;
+.source "LauncherActivity.java"
+
+
+# annotations
+.annotation system Ldalvik/annotation/EnclosingClass;
+    value = Lcom/jmhy/sdk/template/LauncherActivity;
+.end annotation
+
+.annotation system Ldalvik/annotation/InnerClass;
+    accessFlags = 0xa
+    name = "LaunchHandler"
+.end annotation
+
+
+# instance fields
+.field reference:Ljava/lang/ref/WeakReference;
+    .annotation system Ldalvik/annotation/Signature;
+        value = {
+            "Ljava/lang/ref/WeakReference<",
+            "Lcom/jmhy/sdk/template/LauncherActivity;",
+            ">;"
+        }
+    .end annotation
+.end field
+
+
+# direct methods
+.method constructor <init>(Lcom/jmhy/sdk/template/LauncherActivity;)V
+    .locals 1
+
+    .line 36
+    invoke-direct {p0}, Landroid/os/Handler;-><init>()V
+
+    .line 37
+    new-instance v0, Ljava/lang/ref/WeakReference;
+
+    invoke-direct {v0, p1}, Ljava/lang/ref/WeakReference;-><init>(Ljava/lang/Object;)V
+
+    iput-object v0, p0, Lcom/jmhy/sdk/template/LauncherActivity$LaunchHandler;->reference:Ljava/lang/ref/WeakReference;
+
+    return-void
+.end method
+
+
+# virtual methods
+.method public handleMessage(Landroid/os/Message;)V
+    .locals 2
+
+    .line 42
+    iget-object v0, p0, Lcom/jmhy/sdk/template/LauncherActivity$LaunchHandler;->reference:Ljava/lang/ref/WeakReference;
+
+    invoke-virtual {v0}, Ljava/lang/ref/WeakReference;->get()Ljava/lang/Object;
+
+    move-result-object v0
+
+    check-cast v0, Lcom/jmhy/sdk/template/LauncherActivity;
+
+    if-nez v0, :cond_0
+
+    return-void
+
+    .line 47
+    :cond_0
+    iget p1, p1, Landroid/os/Message;->what:I
+
+    const/4 v1, 0x1
+
+    if-eq p1, v1, :cond_1
+
+    goto :goto_0
+
+    .line 49
+    :cond_1
+    invoke-static {v0}, Lcom/jmhy/sdk/template/LauncherActivity;->access$000(Lcom/jmhy/sdk/template/LauncherActivity;)V
+
+    :goto_0
+    return-void
+.end method

+ 115 - 0
internal/launcher_code/smali/com/jmhy/sdk/template/LauncherActivity.smali

@@ -0,0 +1,115 @@
+.class public Lcom/jmhy/sdk/template/LauncherActivity;
+.super Landroid/app/Activity;
+.source "LauncherActivity.java"
+
+
+# annotations
+.annotation system Ldalvik/annotation/MemberClasses;
+    value = {
+        Lcom/jmhy/sdk/template/LauncherActivity$LaunchHandler;
+    }
+.end annotation
+
+
+# static fields
+.field private static final LAUNCH:I = 0x1
+
+
+# direct methods
+.method public constructor <init>()V
+    .locals 0
+
+    .line 12
+    invoke-direct {p0}, Landroid/app/Activity;-><init>()V
+
+    return-void
+.end method
+
+.method static synthetic access$000(Lcom/jmhy/sdk/template/LauncherActivity;)V
+    .locals 0
+    .param p0, "x0"    # Lcom/jmhy/sdk/template/LauncherActivity;
+
+    .line 12
+    invoke-direct {p0}, Lcom/jmhy/sdk/template/LauncherActivity;->launch()V
+
+    return-void
+.end method
+
+.method private launch()V
+    .locals 4
+
+    .line 26
+    new-instance v0, Landroid/content/Intent;
+
+    invoke-direct {v0}, Landroid/content/Intent;-><init>()V
+
+    .line 27
+    .local v0, "intent":Landroid/content/Intent;
+    new-instance v1, Landroid/content/ComponentName;
+
+    invoke-virtual {p0}, Lcom/jmhy/sdk/template/LauncherActivity;->getPackageName()Ljava/lang/String;
+
+    move-result-object v2
+
+    const-string v3, "{class}"
+
+    invoke-direct {v1, v2, v3}, Landroid/content/ComponentName;-><init>(Ljava/lang/String;Ljava/lang/String;)V
+
+    invoke-virtual {v0, v1}, Landroid/content/Intent;->setComponent(Landroid/content/ComponentName;)Landroid/content/Intent;
+
+    .line 28
+    invoke-virtual {p0, v0}, Lcom/jmhy/sdk/template/LauncherActivity;->startActivity(Landroid/content/Intent;)V
+
+    .line 30
+    invoke-virtual {p0}, Lcom/jmhy/sdk/template/LauncherActivity;->finish()V
+
+    .line 31
+    return-void
+.end method
+
+
+# virtual methods
+.method protected onCreate(Landroid/os/Bundle;)V
+    .locals 5
+    .param p1, "savedInstanceState"    # Landroid/os/Bundle;
+
+    .line 17
+    invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V
+
+    .line 18
+    invoke-virtual {p0}, Lcom/jmhy/sdk/template/LauncherActivity;->getResources()Landroid/content/res/Resources;
+
+    move-result-object v0
+
+    const-string v1, "common_sdk_launcher_template"
+
+    const-string v2, "layout"
+
+    invoke-virtual {p0}, Lcom/jmhy/sdk/template/LauncherActivity;->getPackageName()Ljava/lang/String;
+
+    move-result-object v3
+
+    invoke-virtual {v0, v1, v2, v3}, Landroid/content/res/Resources;->getIdentifier(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I
+
+    move-result v0
+
+    .line 19
+    .local v0, "id":I
+    invoke-virtual {p0, v0}, Lcom/jmhy/sdk/template/LauncherActivity;->setContentView(I)V
+
+    .line 21
+    new-instance v1, Lcom/jmhy/sdk/template/LauncherActivity$LaunchHandler;
+
+    invoke-direct {v1, p0}, Lcom/jmhy/sdk/template/LauncherActivity$LaunchHandler;-><init>(Lcom/jmhy/sdk/template/LauncherActivity;)V
+
+    .line 22
+    .local v1, "handler":Lcom/jmhy/sdk/template/LauncherActivity$LaunchHandler;
+    const/4 v2, 0x1
+
+    const-wide/16 v3, 0xbb8
+
+    invoke-virtual {v1, v2, v3, v4}, Lcom/jmhy/sdk/template/LauncherActivity$LaunchHandler;->sendEmptyMessageDelayed(IJ)Z
+
+    .line 23
+    return-void
+.end method

+ 13 - 0
internal/launcher_res/layout/common_sdk_launcher_template.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".LauncherActivity">
+    <ImageView
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+		android:scaleType="centerCrop"
+        android:src="@drawable/common_sdk_launcher_bg"/>
+</FrameLayout>

+ 80 - 0
internal_shanshen/launcher_code/smali/com/shanshen/sdk/template/LauncherActivity$LaunchHandler.smali

@@ -0,0 +1,80 @@
+.class Lcom/shanshen/sdk/template/LauncherActivity$LaunchHandler;
+.super Landroid/os/Handler;
+.source "LauncherActivity.java"
+
+
+# annotations
+.annotation system Ldalvik/annotation/EnclosingClass;
+    value = Lcom/shanshen/sdk/template/LauncherActivity;
+.end annotation
+
+.annotation system Ldalvik/annotation/InnerClass;
+    accessFlags = 0xa
+    name = "LaunchHandler"
+.end annotation
+
+
+# instance fields
+.field reference:Ljava/lang/ref/WeakReference;
+    .annotation system Ldalvik/annotation/Signature;
+        value = {
+            "Ljava/lang/ref/WeakReference<",
+            "Lcom/shanshen/sdk/template/LauncherActivity;",
+            ">;"
+        }
+    .end annotation
+.end field
+
+
+# direct methods
+.method constructor <init>(Lcom/shanshen/sdk/template/LauncherActivity;)V
+    .locals 1
+
+    .line 36
+    invoke-direct {p0}, Landroid/os/Handler;-><init>()V
+
+    .line 37
+    new-instance v0, Ljava/lang/ref/WeakReference;
+
+    invoke-direct {v0, p1}, Ljava/lang/ref/WeakReference;-><init>(Ljava/lang/Object;)V
+
+    iput-object v0, p0, Lcom/shanshen/sdk/template/LauncherActivity$LaunchHandler;->reference:Ljava/lang/ref/WeakReference;
+
+    return-void
+.end method
+
+
+# virtual methods
+.method public handleMessage(Landroid/os/Message;)V
+    .locals 2
+
+    .line 42
+    iget-object v0, p0, Lcom/shanshen/sdk/template/LauncherActivity$LaunchHandler;->reference:Ljava/lang/ref/WeakReference;
+
+    invoke-virtual {v0}, Ljava/lang/ref/WeakReference;->get()Ljava/lang/Object;
+
+    move-result-object v0
+
+    check-cast v0, Lcom/shanshen/sdk/template/LauncherActivity;
+
+    if-nez v0, :cond_0
+
+    return-void
+
+    .line 47
+    :cond_0
+    iget p1, p1, Landroid/os/Message;->what:I
+
+    const/4 v1, 0x1
+
+    if-eq p1, v1, :cond_1
+
+    goto :goto_0
+
+    .line 49
+    :cond_1
+    invoke-static {v0}, Lcom/shanshen/sdk/template/LauncherActivity;->access$000(Lcom/shanshen/sdk/template/LauncherActivity;)V
+
+    :goto_0
+    return-void
+.end method

+ 115 - 0
internal_shanshen/launcher_code/smali/com/shanshen/sdk/template/LauncherActivity.smali

@@ -0,0 +1,115 @@
+.class public Lcom/shanshen/sdk/template/LauncherActivity;
+.super Landroid/app/Activity;
+.source "LauncherActivity.java"
+
+
+# annotations
+.annotation system Ldalvik/annotation/MemberClasses;
+    value = {
+        Lcom/shanshen/sdk/template/LauncherActivity$LaunchHandler;
+    }
+.end annotation
+
+
+# static fields
+.field private static final LAUNCH:I = 0x1
+
+
+# direct methods
+.method public constructor <init>()V
+    .locals 0
+
+    .line 12
+    invoke-direct {p0}, Landroid/app/Activity;-><init>()V
+
+    return-void
+.end method
+
+.method static synthetic access$000(Lcom/shanshen/sdk/template/LauncherActivity;)V
+    .locals 0
+    .param p0, "x0"    # Lcom/shanshen/sdk/template/LauncherActivity;
+
+    .line 12
+    invoke-direct {p0}, Lcom/shanshen/sdk/template/LauncherActivity;->launch()V
+
+    return-void
+.end method
+
+.method private launch()V
+    .locals 4
+
+    .line 26
+    new-instance v0, Landroid/content/Intent;
+
+    invoke-direct {v0}, Landroid/content/Intent;-><init>()V
+
+    .line 27
+    .local v0, "intent":Landroid/content/Intent;
+    new-instance v1, Landroid/content/ComponentName;
+
+    invoke-virtual {p0}, Lcom/shanshen/sdk/template/LauncherActivity;->getPackageName()Ljava/lang/String;
+
+    move-result-object v2
+
+    const-string v3, "{class}"
+
+    invoke-direct {v1, v2, v3}, Landroid/content/ComponentName;-><init>(Ljava/lang/String;Ljava/lang/String;)V
+
+    invoke-virtual {v0, v1}, Landroid/content/Intent;->setComponent(Landroid/content/ComponentName;)Landroid/content/Intent;
+
+    .line 28
+    invoke-virtual {p0, v0}, Lcom/shanshen/sdk/template/LauncherActivity;->startActivity(Landroid/content/Intent;)V
+
+    .line 30
+    invoke-virtual {p0}, Lcom/shanshen/sdk/template/LauncherActivity;->finish()V
+
+    .line 31
+    return-void
+.end method
+
+
+# virtual methods
+.method protected onCreate(Landroid/os/Bundle;)V
+    .locals 5
+    .param p1, "savedInstanceState"    # Landroid/os/Bundle;
+
+    .line 17
+    invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V
+
+    .line 18
+    invoke-virtual {p0}, Lcom/shanshen/sdk/template/LauncherActivity;->getResources()Landroid/content/res/Resources;
+
+    move-result-object v0
+
+    const-string v1, "common_sdk_launcher_template"
+
+    const-string v2, "layout"
+
+    invoke-virtual {p0}, Lcom/shanshen/sdk/template/LauncherActivity;->getPackageName()Ljava/lang/String;
+
+    move-result-object v3
+
+    invoke-virtual {v0, v1, v2, v3}, Landroid/content/res/Resources;->getIdentifier(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I
+
+    move-result v0
+
+    .line 19
+    .local v0, "id":I
+    invoke-virtual {p0, v0}, Lcom/shanshen/sdk/template/LauncherActivity;->setContentView(I)V
+
+    .line 21
+    new-instance v1, Lcom/shanshen/sdk/template/LauncherActivity$LaunchHandler;
+
+    invoke-direct {v1, p0}, Lcom/shanshen/sdk/template/LauncherActivity$LaunchHandler;-><init>(Lcom/shanshen/sdk/template/LauncherActivity;)V
+
+    .line 22
+    .local v1, "handler":Lcom/shanshen/sdk/template/LauncherActivity$LaunchHandler;
+    const/4 v2, 0x1
+
+    const-wide/16 v3, 0xbb8
+
+    invoke-virtual {v1, v2, v3, v4}, Lcom/shanshen/sdk/template/LauncherActivity$LaunchHandler;->sendEmptyMessageDelayed(IJ)Z
+
+    .line 23
+    return-void
+.end method

+ 12 - 0
internal_shanshen/launcher_res/layout/shanshen_sdk_launcher_template.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <ImageView
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+		android:scaleType="centerCrop"
+        android:src="@drawable/shanshen_sdk_launcher_bg"/>
+</FrameLayout>

+ 8 - 0
keystore/key.json

@@ -0,0 +1,8 @@
+{
+	"default":{
+		"storeFile": "susu.keystore",
+		"storePassword":"susu123",
+		"keyAlias":"susu",
+		"keyPassword":"susu123"
+	}
+}

BIN
keystore/susu.keystore


BIN
log_sdk/gdt/gdt.jar


BIN
log_sdk/gdt/libs/GDTActionSDK.min.1.3.0.jar


+ 10 - 0
log_sdk/gdt/manifest.xml

@@ -0,0 +1,10 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+	<permissions>
+		<uses-permission android:name="android.permission.INTERNET" />
+		<uses-permission android:name="android.permission.READ_PHONE_STATE" />
+		<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+		<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+	</permissions>
+
+    <application/>
+</manifest>

BIN
log_sdk/jrtt/jniLibs/arm64-v8a/libttEncrypt.so


BIN
log_sdk/jrtt/jniLibs/armeabi-v7a/libttEncrypt.so


BIN
log_sdk/jrtt/jniLibs/armeabi/libttEncrypt.so


BIN
log_sdk/jrtt/jrtt.jar


BIN
log_sdk/jrtt/jrtt_test.jar


BIN
log_sdk/jrtt/libs/jrtt_logsdk.jar


+ 10 - 0
log_sdk/jrtt/manifest.xml

@@ -0,0 +1,10 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+	<permissions>
+		<uses-permission android:name="android.permission.INTERNET" />
+		<uses-permission android:name="android.permission.READ_PHONE_STATE" />
+		<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+		<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+	</permissions>
+
+    <application/>
+</manifest>

+ 3 - 0
package.py

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

+ 178 - 0
package_channel.py

@@ -0,0 +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
+
+packageChannel()

+ 3 - 0
package_shanshen.py

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

+ 66 - 0
package_test.py

@@ -0,0 +1,66 @@
+import package_utils
+import file_utils
+import xml_utils
+import config_utils
+import os
+import os.path
+import json
+
+def packTest():
+    '''
+    测试代码
+    '''
+    game = 'mxy'
+    sdk = 'jm'
+    subChannel = 'mxy'
+
+    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()

+ 1125 - 0
package_utils.py

@@ -0,0 +1,1125 @@
+# 安卓游戏打包脚本
+# 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
+
+ignoreLauncher = ['jm_ysdk', 'jm_yijie', 'jm_quick', 'jm_beiyu', 'jm_xq_jrtt']
+
+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
+    # 增加配置文件
+    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)
+    #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
+    # log sdk
+    if 'logSdk' in config:
+        for log in config['logSdk']:
+            ret = addLogSdk(game, sdk, subChannel, config, log)
+            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', 'jmhy', 'sdk')
+    file_utils.deleteFolder(codePath)
+    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):
+        if path.startswith('drawable') and path.endswith('-v4'):
+            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 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.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'])
+    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...')
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    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 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 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'])
+    aapt = file_utils.getAAPTPath()
+    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)
+
+    ret = file_utils.getExecPermission(aapt)
+    if ret:
+        return ret
+
+    # 生成R文件
+    print('create R.java ...')
+    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
+
+    # 编译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.7 -target 1.7 -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, '-o "%s" "%s"' % (outPath, outDex))
+    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')
+    dx = file_utils.getDxPath()
+
+    if not os.path.exists(outPath):
+        os.makedirs(outPath)
+
+    # --no-warning
+    dexCmd = '--dex --multi-dex --no-warning --output="%s"' % 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)
+        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, '-o "%s" "%s"' % (outPath, outDex))
+    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):
+    '''
+    打包所有的jar
+    '''
+    decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
+    outPath = file_utils.getFullPath(decompliePath, 'gen')
+    dx = file_utils.getDxPath()
+
+    if not os.path.exists(outPath):
+        os.makedirs(outPath)
+
+    # --no-warning
+    dexCmd = '--dex --multi-dex --no-warning --output="%s"' % outPath
+
+    # 找到所有lib依赖
+    sdkPath = file_utils.getFullLogSDKPath(logSdk)
+    libs = os.path.join(sdkPath, 'libs')
+    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, '-o "%s" "%s"' % (outPath, outDex))
+    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']
+
+    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'])
+
+    return file_utils.execJarCmd(apktoolPath, 'b -f "%s" -o "%s"' % (decompliePath, outApk))
+
+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.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.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

+ 1018 - 0
package_utils_shanshen.py

@@ -0,0 +1,1018 @@
+# 安卓游戏打包脚本
+# 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
+
+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)
+    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):
+        if path.startswith('drawable') and path.endswith('-v4'):
+            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.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'])
+    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...')
+    manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
+    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'])
+    aapt = file_utils.getAAPTPath()
+    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)
+
+    ret = file_utils.getExecPermission(aapt)
+    if ret:
+        return ret
+
+    # 生成R文件
+    print('create R.java ...')
+    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
+
+    # 编译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.7 -target 1.7 -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, '-o "%s" "%s"' % (outPath, outDex))
+    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')
+    dx = file_utils.getDxPath()
+
+    if not os.path.exists(outPath):
+        os.makedirs(outPath)
+
+    # --no-warning
+    dexCmd = '--dex --multi-dex --no-warning --output="%s"' % 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)
+        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, '-o "%s" "%s"' % (outPath, outDex))
+    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'])
+
+    return file_utils.execJarCmd(apktoolPath, 'b -f "%s" -o "%s"' % (decompliePath, outApk))
+
+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

+ 268 - 0
package_web.py

@@ -0,0 +1,268 @@
+import file_utils
+import package_utils
+import package_web_shanshen
+import os.path
+import sys
+import json
+import importlib
+
+sdkMapping = {
+    'ysdk':'jm_ysdk',
+    'xunqu':{
+        'default':'jm_xq',
+        'xiaomi':'jm_xq_mi',
+        'jrtt':'jm_xq_jrtt'
+    },
+    'jingqi':'jm_jq',
+    'qytx':{
+        'default':'jm_qytx',
+        'cangyu':'jm_qytx2'
+    },
+    'jmsdk':'jm',
+    'oppo':'jm_oppo',
+    'quick':'jm_quick',
+    'beiyu':'jm_beiyu',
+    'yijie':'jm_yijie',
+    'gzjysdk':'gzjysdk'
+}
+
+scriptMapping = {
+    'jm_xq_mi':'jm_xq',
+    'jm_xq_jrtt':'jm_xq',
+    'jm_qytx2':'jm_qytx'
+}
+
+newSdk = ["shanshen", "gzjysdk"]
+
+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 newSdk:
+        package_web_shanshen.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'])
+
+    # sdk相关参数
+    if 'properties' in config:
+        jsonConfig['properties'] = config['properties']
+
+    jsonConfig['logSdk'] = ['jrtt', '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
+
+    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()

+ 210 - 0
package_web_shanshen.py

@@ -0,0 +1,210 @@
+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'])
+
+    # 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()

+ 16 - 0
readme.txt

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

+ 2 - 0
sdk/gzjysdk/assets/ss.properties

@@ -0,0 +1,2 @@
+version=20190104
+agent=t22d2ij6

BIN
sdk/gzjysdk/libs/android-support-v4.jar


BIN
sdk/gzjysdk/libs/commons-httpclient-3.1.jar


BIN
sdk/gzjysdk/libs/gzjysdk-1.0.2.jar


BIN
sdk/gzjysdk/libs/org.apache.http.legacy.jar


BIN
sdk/gzjysdk/libs/walle-reader-1.1.6.jar


BIN
sdk/gzjysdk/libs/walle.jar


+ 54 - 0
sdk/gzjysdk/manifest.xml

@@ -0,0 +1,54 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+	<permissions>
+		<uses-permission android:name="android.permission.INTERNET" />
+		<uses-permission android:name="android.permission.READ_PHONE_STATE" />
+		<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+		<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+		<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+		<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+	</permissions>
+
+    <application>
+        <activity
+            android:name="com.shanshen.sdk.activity.LoginActivity"
+            android:screenOrientation="behind"
+            android:launchMode="singleTop"
+            android:theme="@style/ss_Transparent" />
+        <activity
+            android:name="com.shanshen.sdk.activity.AutoLoginActivity"
+            android:configChanges="orientation|keyboardHidden|screenSize"
+            android:screenOrientation="behind"
+            android:launchMode="singleTop"
+            android:theme="@style/ss_Transparent" />
+        <activity
+            android:name="com.shanshen.sdk.activity.UserinfoActivity"
+            android:configChanges="orientation|keyboardHidden|screenSize"
+            android:screenOrientation="behind"
+            android:launchMode="singleTop"
+            android:theme="@style/ss_Transparent" />
+        <activity
+            android:name="com.shanshen.sdk.activity.PayActivity"
+            android:configChanges="orientation|keyboardHidden|screenSize"
+            android:screenOrientation="behind"
+            android:launchMode="singleTop"
+            android:theme="@style/ss_Transparent" />
+        <activity
+            android:name="com.shanshen.sdk.activity.CommunityActivity"
+            android:screenOrientation="portrait"
+            android:launchMode="singleTop"
+            android:theme="@android:style/Theme.Holo.Light.NoActionBar.Fullscreen" />
+        <activity
+            android:name="com.shanshen.sdk.activity.PermissionActivity"
+            android:configChanges="orientation|keyboardHidden|screenSize"
+            android:screenOrientation="behind"
+            android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen" />
+        <activity
+            android:name="com.shanshen.sdk.activity.ForceActivity"
+            android:configChanges="orientation|keyboardHidden|screenSize"
+            android:screenOrientation="behind"
+            android:launchMode="singleTop"
+            android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen" />
+
+        <service android:name="com.shanshen.sdk.push.PushService" />
+    </application>
+</manifest>

BIN
sdk/gzjysdk/res/drawable-hdpi/ss_account.png


BIN
sdk/gzjysdk/res/drawable-hdpi/ss_back.png


BIN
sdk/gzjysdk/res/drawable-hdpi/ss_cancel.png


BIN
sdk/gzjysdk/res/drawable-hdpi/ss_code.png


BIN
sdk/gzjysdk/res/drawable-hdpi/ss_float.png


BIN
sdk/gzjysdk/res/drawable-hdpi/ss_logo.png


BIN
sdk/gzjysdk/res/drawable-hdpi/ss_password.png


BIN
sdk/gzjysdk/res/drawable-hdpi/ss_phone.png


BIN
sdk/gzjysdk/res/drawable-hdpi/ss_toast.png


BIN
sdk/gzjysdk/res/drawable-hdpi/ss_urpulldown.png


+ 12 - 0
sdk/gzjysdk/res/drawable/ss_autologinb.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
+            <!-- 填充颜色 -->
+    <solid android:color="#50000000"/>
+   
+    <!-- 线的宽度,颜色灰色 -->
+    <stroke android:width="1dp" android:color="#50000000"/>
+   
+    <!-- 矩形的圆角半径 -->
+    <corners android:radius="@dimen/ss_login_radius" />
+
+</shape>

+ 5 - 0
sdk/gzjysdk/res/drawable/ss_button.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/ss_button_normal" android:state_enabled="true"/>
+    <item android:drawable="@drawable/ss_button_disable" android:state_enabled="false"/>
+</selector>

+ 5 - 0
sdk/gzjysdk/res/drawable/ss_button_disable.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
+    <solid android:color="@color/ss_font_gray_light"/>
+    <corners android:radius="5dp"/>
+</shape>

+ 5 - 0
sdk/gzjysdk/res/drawable/ss_button_normal.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
+    <solid android:color="@color/ss_font_gray_dark"/>
+    <corners android:radius="5dp"/>
+</shape>

+ 8 - 0
sdk/gzjysdk/res/drawable/ss_dialog.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android" >
+    
+    <corners android:topLeftRadius="4.0dip" android:topRightRadius="4.0dip" android:bottomLeftRadius="4.0dip" android:bottomRightRadius="4.0dip" />
+    <gradient android:startColor="#fefefe" android:endColor="#F5F5F5" android:angle="270.0" />
+    <stroke android:width="0.5dip" android:color="#a0a0a0" />
+
+</shape>

+ 5 - 0
sdk/gzjysdk/res/drawable/ss_dialog_ios_bg.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
+    <solid android:color="@color/ss_font_white"/>
+    <corners android:radius="10dp"/>
+</shape>

+ 5 - 0
sdk/gzjysdk/res/drawable/ss_exit_dialog_bg.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
+    <solid android:color="@color/ss_exit_dialog_bg"/>
+    <corners android:radius="5dp"/>
+</shape>

+ 21 - 0
sdk/gzjysdk/res/drawable/ss_float_bg.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape>
+            <stroke
+                android:width="0.5dp"
+                android:color="@color/ss_font_blues" />
+
+            <solid android:color="#ffffff" />
+
+            <corners
+                android:topRightRadius="25dp"
+                android:topLeftRadius="25dp"
+                android:bottomRightRadius="25dp"
+                android:bottomLeftRadius="25dp"
+                />
+            
+        </shape>
+    </item>
+
+</selector>

+ 5 - 0
sdk/gzjysdk/res/drawable/ss_input_bg.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
+    <stroke android:color="@color/ss_font_gray_dark" android:width="1dp"/>
+    <corners android:radius="5dp"/>
+</shape>

+ 5 - 0
sdk/gzjysdk/res/drawable/ss_login_account.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
+    <solid android:color="#FE9900"/>
+    <size android:width="20dp" android:height="20dp"/>
+</shape>

+ 5 - 0
sdk/gzjysdk/res/drawable/ss_login_phone.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
+    <solid android:color="#0099FF"/>
+    <size android:width="20dp" android:height="20dp"/>
+</shape>

+ 5 - 0
sdk/gzjysdk/res/drawable/ss_login_quick.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
+    <solid android:color="#00CC99"/>
+    <size android:width="20dp" android:height="20dp"/>
+</shape>

+ 7 - 0
sdk/gzjysdk/res/drawable/ss_loginb.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
+            <!-- 填充颜色 -->
+    <solid android:color="@color/ss_font_white"/>
+    <!-- 矩形的圆角半径 -->
+    <corners android:radius="@dimen/ss_login_radius" />
+</shape>

+ 5 - 0
sdk/gzjysdk/res/drawable/ss_message_tip.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
+    <solid android:color="@color/ss_font_red"/>
+    <size android:width="@dimen/ss_float_tip_size" android:height="@dimen/ss_float_tip_size"/>
+</shape>

+ 25 - 0
sdk/gzjysdk/res/drawable/ss_white_bg_buttom_more_count.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<selector
+  xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="false">
+        <shape android:shape="rectangle">
+            <corners android:topLeftRadius="0.0dip" android:topRightRadius="0.0dip" android:bottomLeftRadius="8.0dip" android:bottomRightRadius="8.0dip" />
+            <gradient android:startColor="#fff" android:endColor="#fff" android:angle="270.0" />
+            <stroke android:width="0.5dip" android:color="#e2e6e9" />
+        </shape>
+    </item>
+    <item android:state_focused="true">
+        <shape android:shape="rectangle">
+            <corners android:topLeftRadius="0.0dip" android:topRightRadius="0.0dip" android:bottomLeftRadius="8.0dip" android:bottomRightRadius="8.0dip" />
+            <gradient android:startColor="#fff" android:endColor="#fff" android:angle="270.0" />
+            <stroke android:width="0.5dip" android:color="#e2e6e9" />
+        </shape>
+    </item>
+    <item>
+        <shape android:shape="rectangle">
+            <corners android:topLeftRadius="0.0dip" android:topRightRadius="0.0dip" android:bottomLeftRadius="8.0dip" android:bottomRightRadius="8.0dip" />
+            <gradient android:startColor="#fff" android:endColor="#fff" android:angle="270.0" />
+            <stroke android:width="0.5dip" android:color="#e2e6e9" />
+        </shape>
+    </item>
+</selector>

+ 68 - 0
sdk/gzjysdk/res/layout/ss_autologin.xml

@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/linear"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center"
+    android:orientation="vertical"
+    xmlns:tools="http://schemas.android.com/tools">
+
+    <LinearLayout
+        android:layout_width="@dimen/ss_login_width"
+        android:layout_height="@dimen/ss_auto_login_height"
+        android:background="@drawable/ss_autologinb"
+        android:orientation="vertical" >
+
+        <ImageView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_horizontal"
+            android:layout_marginTop="10dp"
+            android:src="@drawable/ss_logo" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_horizontal"
+            android:layout_marginTop="10dp"
+            android:padding="5sp"
+            android:text="@string/ss_auto_text_msg"
+            android:textColor="@color/ss_font_white"
+            android:textSize="22sp" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_horizontal"
+            android:layout_marginTop="10dp"
+            android:padding="5sp"
+            tools:text="m123456789"
+            android:id="@+id/tvusername"
+            android:textColor="@color/ss_font_white"
+            android:textSize="22sp" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_horizontal"
+            android:layout_marginTop="10dp"
+            android:padding="5sp"
+            android:text="@string/ss_auto_text_tip"
+            android:textColor="@color/ss_font_white"
+            android:textSize="16sp" />
+
+        <Button
+           
+            android:layout_width="180dp"
+            android:layout_height="45dp"
+            android:layout_gravity="center_horizontal"
+            android:layout_marginTop="10dp"
+            android:background="@drawable/ss_button"
+            android:text="@string/ss_auto_bt_msg"
+            android:textColor="@color/ss_font_blues"
+            android:id="@+id/btbacklogin"
+            android:textAllCaps="false"
+            android:textSize="18sp" />
+    </LinearLayout>
+
+</LinearLayout>

+ 12 - 0
sdk/gzjysdk/res/layout/ss_community.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center"
+    android:orientation="vertical" >
+
+        <WebView
+            android:id="@+id/webview"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" />
+</FrameLayout>

+ 46 - 0
sdk/gzjysdk/res/layout/ss_dialog_ios.xml

@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@drawable/ss_dialog_ios_bg"
+    xmlns:tools="http://schemas.android.com/tools">
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_margin="20dp"
+        android:gravity="center_horizontal"
+        android:orientation="vertical">
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textColor="@color/ss_font_black"
+            android:textSize="16sp"
+            android:textStyle="bold"
+            android:text="@string/ss_dialog_title"/>
+
+        <TextView
+            android:id="@+id/content"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="4dp"
+            android:textColor="@color/ss_font_black"
+            android:textSize="12sp"
+            tools:text="@string/ss_http_rror_msg"/>
+    </LinearLayout>
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="1px"
+        android:background="@color/ss_dialog_line"/>
+
+    <TextView
+        android:id="@+id/confirm"
+        android:layout_width="match_parent"
+        android:layout_height="40dp"
+        android:gravity="center"
+        android:layout_gravity="center_horizontal"
+        android:textColor="@color/ss_font_blues"
+        android:textSize="16sp"
+        android:text="@string/ss_confirm"/>
+    </LinearLayout>

+ 57 - 0
sdk/gzjysdk/res/layout/ss_exitdialog.xml

@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/linear"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center"
+    android:orientation="vertical" >
+
+    <LinearLayout
+        android:layout_width="320dp"
+        android:layout_height="150dp"
+        android:layout_gravity="center"
+        android:background="@drawable/ss_dialog"
+        android:gravity="center"
+        android:orientation="vertical" >
+
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="40dp"
+            android:gravity="center"
+            android:text="@string/ss_exit_title"
+            android:textColor="@color/ss_font_blues"
+            android:textSize="16sp" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="40dp"
+            android:layout_marginTop="30dp"
+            android:gravity="center"
+            android:orientation="horizontal" >
+
+            <Button
+                android:id="@+id/dialog_cancel"
+                android:layout_width="140dp"
+                android:layout_height="35dp"
+                android:textAllCaps="false"
+                android:background="@drawable/ss_button"
+                android:gravity="center"
+                android:text="@string/ss_exit_no"
+                android:textColor="@color/ss_font_white"
+                android:textSize="15sp" />
+
+            <Button
+                android:id="@+id/dialog_exit"
+                android:layout_width="140dp"
+                android:layout_height="35dp"
+                android:layout_marginLeft="15dp"
+                android:textAllCaps="false"
+                android:background="@drawable/ss_button"
+                android:gravity="center"
+                android:text="@string/ss_exit_yes"
+                android:textColor="@color/ss_font_blues"
+                android:textSize="15sp" />
+        </LinearLayout>
+    </LinearLayout>
+
+</LinearLayout>

+ 29 - 0
sdk/gzjysdk/res/layout/ss_float_view.xml

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="wrap_content"
+    android:layout_height="56dp">
+    <FrameLayout
+        android:id="@+id/float_view"
+        android:layout_width="56dp"
+        android:layout_height="56dp">
+        <ImageView
+            android:id="@+id/float_view_icon_imageView"
+            android:layout_width="56dp"
+            android:layout_height="56dp"
+            android:layout_gravity="start|center_vertical"
+            android:scaleType="fitCenter"
+            android:src="@drawable/ss_float" />
+
+        <ImageView
+            android:id="@+id/icon_tip"
+            android:layout_width="@dimen/ss_float_tip_size"
+            android:layout_height="@dimen/ss_float_tip_size"
+            android:layout_gravity="end"
+            android:layout_marginTop="2dp"
+            android:layout_marginRight="2dp"
+            android:src="@drawable/ss_message_tip"
+            android:visibility="gone"/>
+    </FrameLayout>
+
+</FrameLayout>

+ 31 - 0
sdk/gzjysdk/res/layout/ss_itemcountlist.xml

@@ -0,0 +1,31 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="horizontal"
+     >
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="1dp"
+        android:alpha="0.5"
+        android:background="#d6d6d6" />
+
+    <TextView
+        android:padding="5sp"
+        android:id="@+id/TextView"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentLeft="true"
+        android:layout_centerVertical="true"
+        android:textColor="@color/ss_font_black"
+        android:textSize="15sp" />
+
+    <ImageView
+        android:id="@+id/ibcancel"
+        android:layout_width="30dp"
+        android:layout_height="30dp"
+        android:layout_alignParentRight="true"
+        android:layout_centerVertical="true"
+        android:background="@drawable/ss_cancel" />
+
+</RelativeLayout>

+ 15 - 0
sdk/gzjysdk/res/layout/ss_itemmoblielist.xml

@@ -0,0 +1,15 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/linearl"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:padding="5dip">
+    
+	<TextView 
+	 	android:id="@+id/TextView"
+	    android:layout_width="wrap_content"
+	    android:layout_height="wrap_content"
+	    android:textSize="15sp"
+	    android:textColor="@color/ss_font_black"/>
+
+</LinearLayout>

+ 142 - 0
sdk/gzjysdk/res/layout/ss_login_main.xml

@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/content_view"
+    android:layout_width="@dimen/ss_login_width"
+    android:layout_height="@dimen/ss_login_height_old"
+    android:orientation="vertical"
+    android:background="@drawable/ss_loginb">
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="80dp"
+        android:orientation="vertical" >
+
+        <ImageView
+            android:id="@+id/back"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerVertical="true"
+            android:layout_marginLeft="25dp"
+            android:layout_marginTop="15dp"
+            android:src="@drawable/ss_back" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="40dp"
+            android:layout_centerHorizontal="true"
+            android:layout_centerVertical="true"
+            android:layout_marginTop="10dp"
+            android:padding="5sp"
+            android:text="@string/ss_moblie_login_title"
+            android:textColor="@color/ss_font_black"
+            android:textSize="22sp" />
+
+        <!--<TextView
+            android:id="@+id/ivregister"
+            android:layout_width="wrap_content"
+            android:layout_height="35dp"
+            android:layout_alignParentRight="true"
+            android:layout_centerVertical="true"
+            android:layout_marginRight="15dp"
+            android:padding="5dp"
+            android:text="@string/ss_moblie_text_register"
+            android:textColor="@color/ss_font_gray"
+            android:textSize="16sp" />-->
+    </RelativeLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:paddingLeft="@dimen/ss_login_content_padding"
+        android:paddingRight="@dimen/ss_login_content_padding"
+        android:orientation="vertical" >
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="40dp"
+            android:gravity="center_vertical"
+            android:background="@drawable/ss_input_bg">
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="20dp"
+                android:src="@drawable/ss_phone"/>
+
+            <EditText
+                android:id="@+id/edit_iphone"
+                android:layout_width="match_parent"
+                android:layout_height="35dp"
+                android:layout_marginLeft="13dp"
+                android:background="@null"
+                android:gravity="center_vertical"
+                android:hint="@string/ss_moblie_edit_hint"
+                android:imeOptions="flagNoExtractUi"
+                android:inputType="number"
+                android:maxLength="11"
+                android:cursorVisible="true"
+                android:textCursorDrawable="@null"
+                android:nextFocusForward="@+id/edit_code"
+                android:singleLine="true"
+                android:textColor="#000000"
+                android:textColorHint="#d5dad3"
+                android:textSize="16sp" >
+            </EditText>
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="40dp"
+            android:gravity="center_vertical"
+            android:layout_marginTop="10dp"
+            android:background="@drawable/ss_input_bg">
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="20dp"
+                android:src="@drawable/ss_code"/>
+
+            <EditText
+                android:id="@+id/edit_code"
+                android:layout_width="0dp"
+                android:layout_weight="1"
+                android:layout_height="35dp"
+                android:layout_marginLeft="13dp"
+                android:background="@null"
+                android:gravity="center_vertical"
+                android:hint="@string/ss_moblie_edit_code_hint"
+                android:imeOptions="flagNoExtractUi|actionDone"
+                android:inputType="text"
+                android:cursorVisible="true"
+                android:textCursorDrawable="@null"
+                android:maxLength="22"
+                android:singleLine="true"
+                android:textColor="#000000"
+                android:textColorHint="#d5dad3"
+                android:textSize="16sp" >
+            </EditText>
+
+            <Button
+                android:id="@+id/ibcode"
+                android:layout_width="80dp"
+                android:layout_height="40dp"
+                android:background="@drawable/ss_button"
+                android:text="@string/ss_moblie_bt_code"
+                android:textSize="12sp"
+                android:textColor="@color/ss_font_white" />
+        </LinearLayout>
+
+        <Button
+            android:id="@+id/mobilebt"
+            android:layout_width="match_parent"
+            android:layout_height="40dp"
+            android:layout_marginTop="10dp"
+            android:background="@drawable/ss_button"
+            android:text="@string/ss_user_bt_login"
+            android:textSize="14sp"
+            android:textColor="@color/ss_font_white" />
+    </LinearLayout>
+</LinearLayout>

+ 60 - 0
sdk/gzjysdk/res/layout/ss_login_main_fragment.xml

@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="@dimen/ss_login_width"
+    android:layout_height="@dimen/ss_login_height_old"
+    android:gravity="center_horizontal"
+    android:background="@drawable/ss_loginb">
+    <ImageView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="50dp"
+        android:src="@drawable/ss_logo"/>
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="40dp"
+        android:orientation="horizontal">
+        <TextView
+            android:id="@+id/quick"
+            android:layout_width="@dimen/ss_login_button"
+            android:layout_height="@dimen/ss_login_button"
+            android:layout_marginRight="@dimen/ss_login_button_margin"
+            android:background="@drawable/ss_login_quick"
+            android:gravity="center"
+            android:textColor="@color/ss_font_white"
+            android:textSize="14sp"
+            android:text="@string/ss_login_quick"/>
+
+        <TextView
+            android:id="@+id/account"
+            android:layout_width="@dimen/ss_login_button"
+            android:layout_height="@dimen/ss_login_button"
+            android:layout_marginRight="@dimen/ss_login_button_margin"
+            android:background="@drawable/ss_login_account"
+            android:gravity="center"
+            android:textColor="@color/ss_font_white"
+            android:textSize="14sp"
+            android:text="@string/ss_login_account"/>
+
+        <TextView
+            android:id="@+id/phone"
+            android:layout_width="@dimen/ss_login_button"
+            android:layout_height="@dimen/ss_login_button"
+            android:background="@drawable/ss_login_phone"
+            android:gravity="center"
+            android:textColor="@color/ss_font_white"
+            android:textSize="14sp"
+            android:text="@string/ss_login_phone"/>
+    </LinearLayout>
+
+    <TextView
+        android:id="@+id/service"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="40dp"
+        android:textColor="@color/ss_font_black"
+        android:textSize="14sp"
+        android:text="@string/ss_login_service"/>
+</LinearLayout>

+ 13 - 0
sdk/gzjysdk/res/layout/ss_loginbase.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center">
+
+    <FrameLayout
+        android:id="@+id/content"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        />
+
+</RelativeLayout>

+ 21 - 0
sdk/gzjysdk/res/layout/ss_notice.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center"
+    android:orientation="vertical" >
+
+    <com.shanshen.sdk.view.CornerCompatView
+        android:layout_width="@dimen/ss_notice_width"
+        android:layout_height="@dimen/ss_notice_height"
+        app:ss_radius="@dimen/ss_notice_radius"
+        android:background="@color/ss_font_white">
+
+        <WebView
+            android:id="@+id/webview"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" />
+
+    </com.shanshen.sdk.view.CornerCompatView>
+</LinearLayout>

+ 199 - 0
sdk/gzjysdk/res/layout/ss_phone_register.xml

@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/content_view"
+    android:layout_width="@dimen/ss_login_width"
+    android:layout_height="@dimen/ss_login_height_old"
+    android:background="@drawable/ss_loginb"
+    android:orientation="vertical" >
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="80dp"
+        android:orientation="vertical" >
+
+        <ImageView
+            android:id="@+id/back"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerVertical="true"
+            android:layout_marginLeft="25dp"
+            android:layout_marginTop="15dp"
+            android:src="@drawable/ss_back" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="40dp"
+            android:layout_centerHorizontal="true"
+            android:layout_centerVertical="true"
+            android:layout_margin="5dp"
+            android:layout_marginTop="10dp"
+            android:padding="5sp"
+            android:text="@string/ss_user_text_title"
+            android:textColor="@color/ss_font_black"
+            android:textSize="22sp" />
+    </RelativeLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingLeft="@dimen/ss_login_content_padding"
+        android:paddingRight="@dimen/ss_login_content_padding"
+        android:orientation="vertical">
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="40dp"
+            android:gravity="center_vertical"
+            android:background="@drawable/ss_input_bg">
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="20dp"
+                android:src="@drawable/ss_account"/>
+
+            <EditText
+                android:id="@+id/edit_account"
+                android:layout_width="match_parent"
+                android:layout_height="35dp"
+                android:layout_marginLeft="13dp"
+                android:background="@null"
+                android:gravity="center_vertical"
+                android:hint="@string/ss_user_edit_hint"
+                android:imeOptions="actionNext"
+                android:inputType="text"
+                android:maxLength="22"
+                android:nextFocusForward="@+id/edit_pwa"
+                android:singleLine="true"
+                android:textColor="#000000"
+                android:textColorHint="#d5dad3"
+                android:textSize="16sp" >
+            </EditText>
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="40dp"
+            android:layout_marginTop="10dp"
+            android:gravity="center_vertical"
+            android:background="@drawable/ss_input_bg">
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="20dp"
+                android:src="@drawable/ss_phone"/>
+
+            <EditText
+                android:id="@+id/edit_usera"
+                android:layout_width="match_parent"
+                android:layout_height="35dp"
+                android:layout_marginLeft="13dp"
+                android:background="@null"
+                android:gravity="center_vertical"
+                android:hint="@string/ss_moblie_edit_hint"
+                android:imeOptions="actionNext"
+                android:inputType="number"
+                android:maxLength="11"
+                android:nextFocusForward="@+id/edit_pwa"
+                android:singleLine="true"
+                android:textColor="#000000"
+                android:textColorHint="#d5dad3"
+                android:textSize="16sp" >
+            </EditText>
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="40dp"
+            android:gravity="center_vertical"
+            android:layout_marginTop="10dp"
+            android:background="@drawable/ss_input_bg">
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="20dp"
+                android:src="@drawable/ss_code"/>
+
+            <EditText
+                android:id="@+id/edit_code"
+                android:layout_width="0dp"
+                android:layout_weight="1"
+                android:layout_height="35dp"
+                android:layout_marginLeft="13dp"
+                android:background="@null"
+                android:gravity="center_vertical"
+                android:hint="@string/ss_moblie_edit_code_hint"
+                android:imeOptions="actionNext"
+                android:inputType="text"
+                android:maxLength="22"
+                android:nextFocusForward="@+id/edit_pwa"
+                android:singleLine="true"
+                android:textColor="#000000"
+                android:textColorHint="#d5dad3"
+                android:textSize="16sp" >
+            </EditText>
+
+            <Button
+                android:id="@+id/ibcode"
+                android:layout_width="80dp"
+                android:layout_height="40dp"
+                android:background="@drawable/ss_button"
+                android:textSize="12sp"
+                android:text="@string/ss_moblie_bt_code"
+                android:textColor="@color/ss_font_white" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="40dp"
+            android:gravity="center_vertical"
+            android:layout_marginTop="10dp"
+            android:background="@drawable/ss_input_bg">
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="20dp"
+                android:src="@drawable/ss_password"/>
+
+            <EditText
+                android:id="@+id/edit_pwa"
+                android:layout_width="match_parent"
+                android:layout_height="35dp"
+                android:layout_marginLeft="13dp"
+                android:background="@null"
+                android:gravity="center_vertical"
+                android:hint="@string/ss_user_edit_hint"
+                android:imeOptions="actionNext"
+                android:inputType="text"
+                android:maxLength="22"
+                android:nextFocusForward="@+id/edit_pwa"
+                android:singleLine="true"
+                android:textColor="#000000"
+                android:textColorHint="#d5dad3"
+                android:textSize="16sp" >
+            </EditText>
+        </LinearLayout>
+
+        <Button
+            android:id="@+id/btsubmit"
+            android:layout_width="match_parent"
+            android:layout_height="40dp"
+            android:layout_marginTop="10dp"
+            android:background="@drawable/ss_button"
+            android:text="@string/ss_register_button"
+            android:textColor="@color/ss_font_white" />
+
+        <TextView
+            android:id="@+id/service"
+            android:layout_width="wrap_content"
+            android:layout_height="25dp"
+            android:layout_marginTop="5dp"
+            tools:text="@string/ss_user_text_my"
+            android:textColor="@color/ss_font_gray"
+            android:textSize="16sp" />
+    </LinearLayout>
+</LinearLayout>

+ 22 - 0
sdk/gzjysdk/res/layout/ss_popwindow.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_marginLeft="1dp"
+    android:layout_marginRight="1dp"
+    android:background="@drawable/ss_white_bg_buttom_more_count"
+    android:orientation="vertical" >
+    
+    <ListView 
+        android:id="@+id/poplist"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="2dp"
+    	android:layout_marginRight="2dp"
+    	android:layout_marginBottom="3dp"
+        android:fadingEdge="none"
+        android:divider="#e2e6e9"
+        android:dividerHeight="0.5dp"         
+        android:cacheColorHint="#00000000" 
+        android:background="@color/ss_font_white"/>
+</LinearLayout>

+ 123 - 0
sdk/gzjysdk/res/layout/ss_setpwd.xml

@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/content_view"
+    android:layout_width="@dimen/ss_login_width"
+    android:layout_height="@dimen/ss_login_height_old"
+    android:background="@drawable/ss_loginb"
+    android:orientation="vertical" >
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="80dp"
+        android:orientation="vertical" >
+
+        <ImageView
+            android:id="@+id/back"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerVertical="true"
+            android:layout_marginLeft="25dp"
+            android:layout_marginTop="15dp"
+            android:background="@drawable/ss_back" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="40dp"
+            android:layout_centerHorizontal="true"
+            android:layout_centerVertical="true"
+            android:layout_margin="5dp"
+            android:layout_marginRight="25dp"
+            android:layout_marginTop="10dp"
+            android:padding="5sp"
+            android:text="@string/ss_setpwd_text_title"
+            android:textColor="@color/ss_font_black"
+            android:textSize="20sp" />
+    </RelativeLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingLeft="@dimen/ss_login_content_padding"
+        android:paddingRight="@dimen/ss_login_content_padding"
+        android:orientation="vertical">
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="40dp"
+            android:gravity="center_vertical"
+            android:layout_marginTop="10dp"
+            android:background="@drawable/ss_input_bg">
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="20dp"
+                android:src="@drawable/ss_account"/>
+
+            <TextView
+                android:id="@+id/tvmobile"
+                android:layout_width="match_parent"
+                android:layout_height="35dp"
+                android:layout_marginLeft="13dp"
+                android:background="@null"
+                android:gravity="center_vertical"
+                android:singleLine="true"
+                android:textColor="#000000"
+                android:textSize="16sp" >
+            </TextView>
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="40dp"
+            android:gravity="center_vertical"
+            android:layout_marginTop="10dp"
+            android:background="@drawable/ss_input_bg">
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="20dp"
+                android:src="@drawable/ss_password"/>
+
+            <EditText
+                android:id="@+id/edit_pwd"
+                android:layout_width="match_parent"
+                android:layout_height="35dp"
+                android:layout_marginLeft="13dp"
+                android:background="@null"
+                android:gravity="center_vertical"
+                android:hint="@string/ss_user_edit_pwdhint"
+                android:imeOptions="flagNoExtractUi|actionDone"
+                android:inputType="textPassword"
+                android:cursorVisible="true"
+                android:textCursorDrawable="@null"
+                android:maxLength="22"
+                android:singleLine="true"
+                android:textColor="#000000"
+                android:textColorHint="#d5dad3"
+                android:textSize="16sp" >
+            </EditText>
+        </LinearLayout>
+
+        <Button
+            android:id="@+id/iphonebtlg"
+            android:layout_width="match_parent"
+            android:layout_height="40dp"
+            android:layout_marginTop="10dp"
+            android:background="@drawable/ss_button"
+            android:text="@string/ss_setuser_bt_msg"
+            android:textColor="@color/ss_font_white"
+            android:textSize="16sp" />
+
+        <TextView
+            android:id="@+id/service"
+            android:layout_width="wrap_content"
+            android:layout_height="25dp"
+            android:layout_marginTop="5dp"
+            tools:text="@string/ss_user_text_my"
+            android:textColor="@color/ss_font_gray"
+            android:textSize="16sp" />
+    </LinearLayout>
+</LinearLayout>

+ 138 - 0
sdk/gzjysdk/res/layout/ss_setuser.xml

@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/linear"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center"
+    android:orientation="vertical" >
+
+    <LinearLayout
+        android:id="@+id/content_view"
+        android:layout_width="@dimen/ss_login_width"
+        android:layout_height="@dimen/ss_guest_height_old"
+        android:background="@drawable/ss_loginb"
+        android:orientation="vertical" >
+
+        <RelativeLayout
+            android:layout_width="match_parent"
+            android:layout_height="80dp"
+            android:orientation="vertical" >
+
+            <ImageView
+                android:id="@+id/back"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_centerVertical="true"
+                android:layout_marginLeft="25dp"
+                android:layout_marginTop="15dp"
+                android:background="@drawable/ss_back" />
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="40dp"
+                android:layout_centerHorizontal="true"
+                android:layout_centerVertical="true"
+                android:layout_margin="5dp"
+                android:layout_marginTop="10dp"
+                android:padding="5sp"
+                android:text="@string/ss_setuser_text_title"
+                android:textColor="@color/ss_font_black"
+                android:textSize="18sp" />
+
+            <TextView
+                android:id="@+id/save"
+                android:layout_width="wrap_content"
+                android:layout_height="35dp"
+                android:layout_alignParentRight="true"
+                android:layout_centerVertical="true"
+                android:layout_marginRight="15dp"
+                android:padding="5dp"
+                android:text="@string/ss_save"
+                android:textColor="@color/ss_font_gray"
+                android:textSize="16sp" />
+        </RelativeLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:paddingLeft="@dimen/ss_login_content_padding"
+            android:paddingRight="@dimen/ss_login_content_padding"
+            android:orientation="vertical" >
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="40dp"
+                android:gravity="center_vertical"
+                android:background="@drawable/ss_input_bg">
+
+                <ImageView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="20dp"
+                    android:src="@drawable/ss_account"/>
+
+                <EditText
+                    android:id="@+id/edit_user"
+                    android:layout_width="match_parent"
+                    android:layout_height="35dp"
+                    android:layout_marginLeft="13dp"
+                    android:background="@null"
+                    android:gravity="center_vertical"
+                    android:hint="@string/ss_user_edit_hint"
+                    android:imeOptions="flagNoExtractUi"
+                    android:inputType="text"
+                    android:maxLength="22"
+                    android:nextFocusForward="@+id/edit_pwd"
+                    android:cursorVisible="true"
+                    android:textCursorDrawable="@null"
+                    android:singleLine="true"
+                    android:textColor="#000000"
+                    android:textColorHint="#d5dad3"
+                    android:textSize="16sp" >
+                </EditText>
+            </LinearLayout>
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="40dp"
+                android:layout_marginTop="10dp"
+                android:gravity="center_vertical"
+                android:background="@drawable/ss_input_bg">
+
+                <ImageView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="20dp"
+                    android:src="@drawable/ss_password"/>
+
+                <EditText
+                    android:id="@+id/edit_pwd"
+                    android:layout_width="match_parent"
+                    android:layout_height="35dp"
+                    android:layout_marginLeft="13dp"
+                    android:background="@null"
+                    android:gravity="center_vertical"
+                    android:hint="@string/ss_user_edit_pwdhint"
+                    android:imeOptions="flagNoExtractUi|actionDone"
+                    android:cursorVisible="true"
+                    android:textCursorDrawable="@null"
+                    android:inputType="text"
+                    android:maxLength="22"
+                    android:singleLine="true"
+                    android:textColor="#000000"
+                    android:textColorHint="#d5dad3"
+                    android:textSize="16sp" >
+                </EditText>
+            </LinearLayout>
+
+            <Button
+                android:id="@+id/btgetgame"
+                android:layout_width="match_parent"
+                android:layout_height="40dp"
+                android:layout_marginTop="10dp"
+                android:background="@drawable/ss_button"
+                android:text="@string/ss_setuser_bt_msg"
+                android:textColor="@color/ss_font_white" />
+        </LinearLayout>
+    </LinearLayout>
+</LinearLayout>

+ 33 - 0
sdk/gzjysdk/res/layout/ss_toast.xml

@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="wrap_content"
+    android:layout_height="45dp"
+    android:padding="5dp"
+    android:background="@drawable/ss_autologinb"
+    >
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerHorizontal="true"
+        android:layout_centerVertical="true"
+        android:orientation="horizontal" >
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/ss_toast_welcome_msg"
+            android:textColor="@color/ss_font_white"
+            android:textSize="18sp" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"   
+             android:id="@+id/tvuser"
+            tools:text="12345678912"
+            android:textColor="@color/ss_font_white"
+            android:textSize="18sp" />
+    </LinearLayout>
+
+</RelativeLayout>

+ 142 - 0
sdk/gzjysdk/res/layout/ss_user_login.xml

@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/content_view"
+    android:layout_width="@dimen/ss_login_width"
+    android:layout_height="@dimen/ss_login_height_old"
+    android:orientation="vertical"
+    android:background="@drawable/ss_loginb">
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="80dp"
+        android:orientation="vertical" >
+
+        <ImageView
+            android:id="@+id/back"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerVertical="true"
+            android:layout_marginLeft="25dp"
+            android:layout_marginTop="15dp"
+            android:src="@drawable/ss_back" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="40dp"
+            android:layout_centerHorizontal="true"
+            android:layout_centerVertical="true"
+            android:layout_margin="5dp"
+            android:layout_marginTop="10dp"
+            android:padding="5sp"
+            android:text="@string/ss_moblie_bt_user"
+            android:textColor="@color/ss_font_black"
+            android:textSize="22sp" />
+
+        <TextView
+            android:id="@+id/ivregister"
+            android:layout_width="wrap_content"
+            android:layout_height="35dp"
+            android:layout_alignParentRight="true"
+            android:layout_centerVertical="true"
+            android:layout_marginRight="15dp"
+            android:padding="5dp"
+            android:text="@string/ss_moblie_text_register"
+            android:textColor="@color/ss_font_gray"
+            android:textSize="16sp" />
+    </RelativeLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:paddingLeft="@dimen/ss_login_content_padding"
+        android:paddingRight="@dimen/ss_login_content_padding"
+        android:orientation="vertical" >
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="40dp"
+            android:gravity="center_vertical"
+            android:background="@drawable/ss_input_bg">
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="20dp"
+                android:src="@drawable/ss_account"/>
+
+            <EditText
+                android:id="@+id/edit_user"
+                android:layout_width="0dp"
+                android:layout_weight="1"
+                android:layout_height="35dp"
+                android:layout_marginLeft="13dp"
+                android:background="@null"
+                android:gravity="center_vertical"
+                android:hint="@string/ss_user_edit_hint"
+                android:imeOptions="flagNoExtractUi"
+                android:cursorVisible="true"
+                android:textCursorDrawable="@null"
+                android:inputType="text"
+                android:maxLength="22"
+                android:nextFocusForward="@+id/edit_pwd"
+                android:singleLine="true"
+                android:textColor="#000000"
+                android:textColorHint="#d5dad3"
+                android:textSize="16sp" >
+            </EditText>
+
+            <ImageView
+                android:id="@+id/ibpulldown"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:scaleType="centerInside"
+                android:src="@drawable/ss_urpulldown" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="40dp"
+            android:gravity="center_vertical"
+            android:layout_marginTop="10dp"
+            android:background="@drawable/ss_input_bg">
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="20dp"
+                android:src="@drawable/ss_password"/>
+
+            <EditText
+                android:id="@+id/edit_pwd"
+                android:layout_width="match_parent"
+                android:layout_height="35dp"
+                android:layout_marginLeft="13dp"
+                android:background="@null"
+                android:gravity="center_vertical"
+                android:hint="@string/ss_user_edit_pwdhint"
+                android:imeOptions="flagNoExtractUi|actionDone"
+                android:cursorVisible="true"
+                android:textCursorDrawable="@null"
+                android:inputType="textPassword"
+                android:maxLength="22"
+                android:singleLine="true"
+                android:textColor="#000000"
+                android:textColorHint="#d5dad3"
+                android:textSize="16sp" >
+            </EditText>
+        </LinearLayout>
+
+        <Button
+            android:id="@+id/userloginbt"
+            android:layout_width="match_parent"
+            android:layout_height="40dp"
+            android:layout_marginTop="10dp"
+            android:background="@drawable/ss_button"
+            android:text="@string/ss_moblie_bt_login"
+            android:textColor="@color/ss_font_white"
+            android:textSize="16sp" />
+    </LinearLayout>
+
+</LinearLayout>

+ 162 - 0
sdk/gzjysdk/res/layout/ss_user_register.xml

@@ -0,0 +1,162 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/content_view"
+    android:layout_width="@dimen/ss_login_width"
+    android:layout_height="@dimen/ss_login_height_old"
+    android:background="@drawable/ss_loginb"
+    android:orientation="vertical" >
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="80dp"
+        android:orientation="vertical" >
+
+        <ImageView
+            android:id="@+id/back"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerVertical="true"
+            android:layout_marginLeft="25dp"
+            android:layout_marginTop="15dp"
+            android:src="@drawable/ss_back" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="40dp"
+            android:layout_centerHorizontal="true"
+            android:layout_centerVertical="true"
+            android:layout_margin="5dp"
+            android:layout_marginTop="10dp"
+            android:padding="5sp"
+            android:text="@string/ss_account_register"
+            android:textColor="@color/ss_font_black"
+            android:textSize="22sp" />
+    </RelativeLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingLeft="@dimen/ss_login_content_padding"
+        android:paddingRight="@dimen/ss_login_content_padding"
+        android:orientation="vertical">
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="40dp"
+            android:gravity="center_vertical"
+            android:background="@drawable/ss_input_bg">
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="20dp"
+                android:src="@drawable/ss_account"/>
+
+            <EditText
+                android:id="@+id/edit_usera"
+                android:layout_width="match_parent"
+                android:layout_height="35dp"
+                android:layout_marginLeft="13dp"
+                android:background="@null"
+                android:gravity="center_vertical"
+                android:hint="@string/ss_user_edit_hint"
+                android:imeOptions="flagNoExtractUi"
+                android:cursorVisible="true"
+                android:textCursorDrawable="@null"
+                android:inputType="text"
+                android:maxLength="22"
+                android:nextFocusForward="@+id/edit_pwa"
+                android:singleLine="true"
+                android:textColor="#000000"
+                android:textColorHint="#d5dad3"
+                android:textSize="16sp" >
+            </EditText>
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="40dp"
+            android:gravity="center_vertical"
+            android:layout_marginTop="10dp"
+            android:background="@drawable/ss_input_bg">
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="20dp"
+                android:src="@drawable/ss_password"/>
+
+            <EditText
+                android:id="@+id/edit_pwa"
+                android:layout_width="match_parent"
+                android:layout_height="35dp"
+                android:layout_marginLeft="13dp"
+                android:background="@null"
+                android:gravity="center_vertical"
+                android:hint="@string/ss_user_edit_pwdhint"
+                android:imeOptions="flagNoExtractUi"
+                android:cursorVisible="true"
+                android:textCursorDrawable="@null"
+                android:inputType="textPassword"
+                android:maxLength="22"
+                android:nextFocusForward="@+id/edit_pwa2"
+                android:singleLine="true"
+                android:textColor="#000000"
+                android:textColorHint="#d5dad3"
+                android:textSize="16sp" >
+            </EditText>
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="40dp"
+            android:gravity="center_vertical"
+            android:layout_marginTop="10dp"
+            android:background="@drawable/ss_input_bg">
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="20dp"
+                android:src="@drawable/ss_password"/>
+
+            <EditText
+                android:id="@+id/edit_pwa2"
+                android:layout_width="match_parent"
+                android:layout_height="35dp"
+                android:layout_marginLeft="13dp"
+                android:background="@null"
+                android:gravity="center_vertical"
+                android:hint="@string/ss_user_edit_pwdhint_again"
+                android:imeOptions="flagNoExtractUi|actionDone"
+                android:cursorVisible="true"
+                android:textCursorDrawable="@null"
+                android:inputType="textPassword"
+                android:maxLength="22"
+                android:singleLine="true"
+                android:textColor="#000000"
+                android:textColorHint="#d5dad3"
+                android:textSize="16sp" >
+            </EditText>
+        </LinearLayout>
+
+        <Button
+            android:id="@+id/btsubmit"
+            android:layout_width="match_parent"
+            android:layout_height="40dp"
+            android:layout_marginTop="10dp"
+            android:background="@drawable/ss_button"
+            android:text="@string/ss_register_button"
+            android:textColor="@color/ss_font_white" />
+
+        <TextView
+            android:id="@+id/service"
+            android:layout_width="wrap_content"
+            android:layout_height="25dp"
+            android:layout_marginTop="5dp"
+            tools:text="@string/ss_user_text_my"
+            android:textColor="@color/ss_font_gray"
+            android:textSize="16sp" />
+    </LinearLayout>
+</LinearLayout>

+ 21 - 0
sdk/gzjysdk/res/layout/ss_userinfo.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center"
+    android:orientation="vertical" >
+
+    <com.shanshen.sdk.view.CornerCompatView
+        android:layout_width="@dimen/ss_login_width"
+        android:layout_height="@dimen/ss_login_height_old"
+        app:ss_radius="@dimen/ss_webview_radius"
+        android:background="@color/ss_font_white">
+
+        <WebView
+            android:id="@+id/webview"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" />
+
+    </com.shanshen.sdk.view.CornerCompatView>
+</LinearLayout>

+ 22 - 0
sdk/gzjysdk/res/layout/ss_userp.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center"
+    android:orientation="vertical" >
+
+    <com.shanshen.sdk.view.CornerCompatView
+        android:layout_width="@dimen/ss_login_width"
+        android:layout_height="@dimen/ss_login_height_old"
+        app:ss_radius="@dimen/ss_login_radius"
+        android:background="@color/ss_font_white" >
+
+        <WebView
+            android:id="@+id/webview"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" />
+
+    </com.shanshen.sdk.view.CornerCompatView>
+
+</LinearLayout>

+ 11 - 0
sdk/gzjysdk/res/values-port/ss_dimens.xml

@@ -0,0 +1,11 @@
+<resources>
+    <dimen name="ss_login_width">334dp</dimen>
+    <dimen name="ss_login_height">378dp</dimen>
+    <dimen name="ss_login_height_old">378dp</dimen>
+    <dimen name="ss_register_height_old">314dp</dimen>
+    <dimen name="ss_guest_height_old">287dp</dimen>
+    <dimen name="ss_auto_login_height">300dp</dimen>
+    <dimen name="ss_exit_dialog_height">275dp</dimen>
+    <dimen name="ss_notice_width">338dp</dimen>
+    <dimen name="ss_notice_height">369dp</dimen>
+</resources>

+ 6 - 0
sdk/gzjysdk/res/values/ss_attrs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <declare-styleable name="CornerCompatView">
+        <attr name="ss_radius" format="dimension"/>
+    </declare-styleable>
+</resources>

+ 16 - 0
sdk/gzjysdk/res/values/ss_colors.xml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <color name="ss_transparent_background">#50000000</color>
+    <color name="ss_font_black">#000000</color>
+    <color name="ss_font_white">#ffffff</color>
+    <color name="ss_font_blues">#2abfff</color>
+    <color name="ss_font_gray">#343434</color>
+    <color name="ss_font_gray_dark">#333333</color>
+    <color name="ss_font_gray_light">#666666</color>
+    <color name="ss_font_red">#fe3837</color>
+    <color name="ss_other">#00000001</color>
+    <color name="ss_exit_dialog_bg">#94000000</color>
+    <color name="ss_dialog_line">#999999</color>
+    <color name="ss_transparent">@android:color/transparent</color>
+</resources>

+ 34 - 0
sdk/gzjysdk/res/values/ss_dimens.xml

@@ -0,0 +1,34 @@
+<resources>
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="ss_login_icon_width">20dp</dimen>
+    <dimen name="ss_login_icon_height">20dp</dimen>
+    <dimen name="ss_login_width">375dp</dimen>
+    <dimen name="ss_login_height">315dp</dimen>
+    <dimen name="ss_login_height_old">330dp</dimen>
+    <dimen name="ss_register_height_old">314dp</dimen>
+    <dimen name="ss_guest_height_old">287dp</dimen>
+    <dimen name="ss_auto_login_height">300dp</dimen>
+    <dimen name="ss_input_height">48dp</dimen>
+    <dimen name="ss_login_top_height">70dp</dimen>
+    <dimen name="ss_login_submit_margin_top">45dp</dimen>
+    <dimen name="ss_forget_text_margin_top">12dp</dimen>
+    <dimen name="ss_login_logo_width">30dp</dimen>
+    <dimen name="ss_login_logo_height">40dp</dimen>
+    <dimen name="ss_login_kefu_width">26dp</dimen>
+    <dimen name="ss_login_kefu_height">30dp</dimen>
+    <dimen name="ss_login_switch_width">60dp</dimen>
+    <dimen name="ss_login_switch_height">30dp</dimen>
+    <dimen name="ss_input_icon">30dp</dimen>
+    <dimen name="ss_input_icon_margin_right">8dp</dimen>
+    <dimen name="ss_float_icon_size">24dp</dimen>
+    <dimen name="ss_float_tip_size">10dp</dimen>
+    <dimen name="ss_exit_dialog_height">275dp</dimen>
+    <dimen name="ss_login_radius">12dp</dimen>
+    <dimen name="ss_webview_radius">12dp</dimen>
+    <dimen name="ss_notice_width">471dp</dimen>
+    <dimen name="ss_notice_height">314dp</dimen>
+    <dimen name="ss_notice_radius">8dp</dimen>
+    <dimen name="ss_login_button">60dp</dimen>
+    <dimen name="ss_login_button_margin">40dp</dimen>
+    <dimen name="ss_login_content_padding">30dp</dimen>
+</resources>

+ 4 - 0
sdk/gzjysdk/res/values/ss_public.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <public name="ss_radius" type="attr" id="0x7f011000"/>
+</resources>

+ 59 - 0
sdk/gzjysdk/res/values/ss_strings.xml

@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="ss_moblie_login_title">手机登录</string>
+    <string name="ss_moblie_edit_hint">请输入手机号码</string>
+    <string name="ss_moblie_text_msg">验证码</string>
+    <string name="ss_moblie_edit_code_hint">请输入短信验证码</string>
+    <string name="ss_moblie_bt_code">获取验证码</string>
+    <string name="ss_moblie_bt_user">帐号登录</string>
+    <string name="ss_moblie_bt_login">登录</string>
+    <string name="ss_moblie_text_visitor">游客登录</string>
+    <string name="ss_moblie_text_register">注册</string>
+    <string name="ss_save">保存</string>
+    <string name="ss_user_text_title">手机注册</string>
+    <string name="ss_register_button">立即注册</string>
+    <string name="ss_account_register">账号注册</string>
+    <string name="ss_user_text_msg">帐号</string>
+    <string name="ss_user_edit_hint">请输入帐号数字+字母组合</string>
+    <string name="ss_user_text_pwd">密码</string>
+    <string name="ss_user_edit_pwdhint">请输入密码6&#8211;22位</string>
+    <string name="ss_user_edit_pwdhint_again">请再次输入密码</string>
+    <string name="ss_user_text_my">注册即同意《服务条款》</string>
+    <string name="ss_user_bt_submit">提交</string>
+    <string name="ss_user_bt_login">直接登录</string>
+    <string name="ss_setuser_text_title">快速登录</string>
+    <string name="ss_setuser_text_tip">截图已保存到手机相册</string>
+    <string name="ss_setuser_bt_msg">立即登录</string>
+    <string name="ss_setpwd_text_title">设置密码</string>
+    <string name="ss_setpwd_text_msg">帐号:</string>
+    <string name="ss_auto_text_msg">欢迎您!</string>
+    <string name="ss_auto_text_tip">正在进入游戏&#8230;</string>
+    <string name="ss_auto_bt_msg">取消登录</string>
+    <string name="ss_toast_welcome_msg">欢迎回来,</string>
+    <string name="ss_float_user_msg">帐号</string>
+    <string name="ss_float_gift">礼包</string>
+    <string name="ss_float_kefu_msg">客服</string>
+    <string name="ss_http_rror_msg">网络连接失败,请检查您的网络连接!</string>
+    <string name="ss_user_hintcode_msg">请输入验证码!</string>
+    <string name="ss_user_hintuser_msg">请输入帐号!</string>
+    <string name="ss_user_hintpwd_msg">请输入密码!</string>
+    <string name="ss_user_forgot_msg">忘记密码</string>
+    <string name="ss_login_tip">亲,快点登陆吧!</string>
+    <string name="ss_function_not_open">此功能暂未开通</string>
+    <string name="ss_snapshot_save">截图已保存</string>
+    <string name="ss_exit_title">是否退出游戏?</string>
+    <string name="ss_exit_no">继续游戏</string>
+    <string name="ss_exit_yes">退出游戏</string>
+    <string name="ss_email_edit_hint">请输入邮箱账号</string>
+    <string name="ss_other_login">其他登录方式</string>
+    <string name="ss_permission_tip_init">需要授权存储空间读写权限,手机权限才能正常使用</string>
+    <string name="ss_permission_tip_float">需要授权显示在其他应用上层才能正常使用</string>
+    <string name="ss_confirm">确定</string>
+    <string name="ss_dialog_title">提示</string>
+    <string name="ss_no_install_wechat">请先安装微信</string>
+    <string name="ss_login_account">帐号\n登录</string>
+    <string name="ss_login_phone">手机\n登录</string>
+    <string name="ss_login_quick">快速\n登录</string>
+    <string name="ss_login_service">联系客服</string>
+    <string name="ss_password_equals">密码不一致</string>
+</resources>

+ 23 - 0
sdk/gzjysdk/res/values/ss_styles.xml

@@ -0,0 +1,23 @@
+<resources>
+    <style name="ss_Transparent">
+        <item name="android:windowBackground">@color/ss_transparent_background</item>
+        <item name="android:windowNoTitle">true</item>
+        <item name="android:windowIsTranslucent">true</item>
+        <item name="android:windowAnimationStyle">@android:style/Animation.Translucent</item>
+    </style>
+
+    <style name="ss_MyDialog" parent="android:Theme.Dialog">
+        <item name="android:windowFrame">@null</item>
+        <item name="android:windowNoTitle">true</item>
+        <item name="android:windowIsFloating">true</item>
+        <item name="android:windowBackground">@color/ss_other</item>
+        <item name="android:windowContentOverlay">@null</item>
+    </style>
+
+    <style name="ss_popwindow_anim_style">
+        <item name="android:windowEnterAnimation">@android:anim/fade_in</item>
+        <!-- 指定显示的动画xml -->
+        <item name="android:windowExitAnimation">@android:anim/fade_out</item>
+        <!-- 指定消失的动画xml -->
+    </style>
+</resources>

BIN
sdk/gzjysdk/script/__pycache__/sdk_script.cpython-37.pyc


+ 48 - 0
sdk/gzjysdk/script/sdk_script.py

@@ -0,0 +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)
+    return 0

BIN
sdk/jm/jm.jar


BIN
sdk/jm/libs/alipaySdk-20180601.jar


BIN
sdk/jm/libs/android-support-v4.jar


BIN
sdk/jm/libs/commons-httpclient-3.1.jar


BIN
sdk/jm/libs/jm_sdk_20190301.jar


BIN
sdk/jm/libs/org.apache.http.legacy.jar


Some files were not shown because too many files changed in this diff