最近在学习撸撸的代码规范和写法,有些心得,准备好好写一写~包括了多渠道打版(以前有写过方法),工厂模式,mvp,以及最近刚封装出来的多渠道多版本展示不同页面的manifestPlaceholders的配置方法,大家应该也碰到过线上和线下环境的切换换地址,换私钥的头大问题,本篇就来解决这些问题。

    先在androidmanifest文件配置一个节点,这里以极光为例:

  1. <meta-data
  2.             android:name="JPUSH_APPKEY"
  3.             android:value="${jush_appkey_value}" />
  4. <meta-data
  5.             android:name="SHOUCANG_CONFIG0"
  6.             android:value="${SHOUCANG_CONFIG_VALUE0}" />

    build.gradle:

  1. buildTypes {
  2.     release {
  3.         //自定义buildconfig字段
  4.         buildConfigField("boolean""APP_ENV""true")
  5.         //指定签名为release
  6.         signingConfig signingConfig.release
  7.         //是否开启混淆
  8.         minifyEnabled false
  9.         proguardFiles getDefaultProguardFile('proguard-android.txt')'proguard-rules.pro'
  10.         //是否zip优化
  11.         zipAlignEnabled true
  12.         //删除一些无用资源
  13.         shrinkResources false
  14.         //
  15.         manifestPlaceholders = [
  16.                 "jush_appkey_value""release key"
  17.         ]
  18.     }
  19.     debug {
  20.         //自定义buildconfig字段
  21.         buildConfigField("boolean""APP_ENV""true")
  22.         //指定签名为release
  23.         signingConfig signingConfig.release
  24.         //是否开启混淆
  25.         minifyEnabled false
  26.         proguardFiles getDefaultProguardFile('proguard-android.txt')'proguard-rules.pro'
  27.         //是否zip优化
  28.         zipAlignEnabled true
  29.         //删除一些无用资源
  30.         shrinkResources false
  31.         //
  32.         manifestPlaceholders = [
  33.                 "jush_appkey_value""debug key"
  34.         ]
  35.     }
  36. }

    在bulidtypes节点下有release节点和debug节点,正式签名时就会走release节点的下编译脚本,调试签名时就会走debug节点。主要点就是manifestPlaceholders的用法,jpush_appkey对应的就是之前在androidmanifest文件配置的${jush_appkey_value}的这个值。

    在程序入口出打上log,用来输出key的值:

  1. /**
  2.  * 在程序入口出打上log,用来输出key的值bufen
  3.  */
  4. private void jpush_key_manifest_xml_string() {
  5.     String jpush_appkey;
  6.     try {
  7.         ApplicationInfo appInfo = getPackageManager()
  8.                 .getApplicationInfo(getPackageName(),
  9.                         PackageManager.GET_META_DATA);
  10.         jpush_appkey = appInfo.metaData.getString("JPUSH_APPKEY");
  11.         Log.e("jpush_appkey""jpush_appkey=" + jpush_appkey);
  12.     } catch (PackageManager.NameNotFoundException e) {
  13.         e.printStackTrace();
  14.     }
  15. }

    接下来给大家介绍多版本多页面多apk的配置切换方法:举个例子:如果你要一次性打七个版本,而且七个版本都是不同的页面,但是页面各个模块大体一样,只是顺序和大小不同,你要怎么做,别告诉我写七个页面分别打版哈~太low了~you know~这里就利用多版本打版和manifestPlaceholders来实现需求。

    首先是build.gradle:

  1. apply plugin: 'com.android.application'
  2. apply plugin: 'android-apt'
  3. def demo = '0000';//DemoAPK
  4. def demo1 = '0001';//DemoAPK1
  5. def demo2 = '0002';//DemoAPK2
  6. def demo3 = '0003';//DemoAPK3
  7. def demo4 = '0004';//DemoAPK4
  8. def demo5 = '0005';//DemoAPK5
  9. def demo6 = '0006';//DemoAPK6
  10. android {
  11.     signingConfigs {
  12.         debug {
  13.             keyAlias '****'
  14.             keyPassword '****'
  15.             storeFile file('签名文件.jks路径')
  16.             storePassword '****'
  17.         }
  18.         release {
  19.             keyAlias '****'
  20.             keyPassword '****'
  21.             storeFile file('签名文件.jks路径')
  22.             storePassword '****'
  23.         }
  24.     }
  25.     compileSdkVersion 25
  26.     buildToolsVersion "25.0.2"
  27.     sourceSets {
  28.         main {
  29.             jniLibs.srcDirs = ['libs']
  30.         }
  31.     }
  32.     packagingOptions {
  33.         exclude 'META-INF/DEPENDENCIES'
  34.         exclude 'META-INF/NOTICE'
  35.         exclude 'META-INF/LICENSE'
  36.         exclude 'META-INF/LICENSE.txt'
  37.         exclude 'META-INF/NOTICE.txt'
  38.     }
  39.     defaultConfig {
  40.         applicationId "com.shining.p010_recycleviewall"
  41.         minSdkVersion 18
  42.         targetSdkVersion 23
  43.         versionCode 1
  44.         versionName "1.0"
  45.         multiDexEnabled true
  46.         renderscriptTargetApi 19
  47.         renderscriptSupportModeEnabled true
  48.         ndk {
  49.             moduleName "native-modbus-jni,libxmediaplayer"
  50.             ldLibs "log""z""m""android""c"
  51.             abiFilters "armeabi""armeabi-v7a""x86"
  52.         }
  53.         sourceSets.main {
  54.             jni.srcDirs = []
  55.             //LOCAL_LDFLAGS += -fuse-ld=bfd
  56.             //jni.srcDirs 'src/main/jni'
  57.             jniLibs.srcDir 'src/main/libs'
  58.         }
  59.         signingConfig signingConfigs.debug
  60.         manifestPlaceholders = [
  61.                 SHOUCANG_CONFIG_VALUE0: ".shoucang.factorys.ShoucangFactory0"
  62.         ]
  63.     }
  64.     buildTypes {
  65.         release {
  66.             minifyEnabled true
  67.             zipAlignEnabled true
  68.             shrinkResources false
  69.             proguardFiles getDefaultProguardFile('proguard-android.txt')'proguard-rules.pro'
  70.             signingConfig signingConfigs.debug
  71.         }
  72.     }
  73.     def int minSdk = 18;
  74.     def int targetSdk = 23;
  75.     def String appId = 'com.shining.p010_recycleviewall';
  76.     def int vCode = 1;
  77.     def String vNameCode = vCode + "";
  78.     productFlavors {
  79.         //demo
  80.         DemoAPK {
  81.             minSdkVersion minSdk
  82.             applicationId appId
  83.             targetSdkVersion targetSdk
  84.             versionCode vCode
  85.             versionName "DemoAPK_" + "T_" + demo
  86.             multiDexEnabled true
  87.             renderscriptTargetApi 19
  88.             renderscriptSupportModeEnabled true
  89.             ndk {
  90.                 moduleName "native-modbus-jni,libxmediaplayer"
  91.                 ldLibs "log""z""m""android""c"
  92.                 abiFilters "armeabi""armeabi-v7a""x86"
  93.             }
  94.             sourceSets.main {
  95.                 jni.srcDirs = []
  96.                 jniLibs.srcDir 'src/main/libs'
  97.             }
  98.             signingConfig signingConfigs.debug
  99.         }
  100.         //demo1
  101.         DemoAPK1 {
  102.             minSdkVersion minSdk
  103.             applicationId appId
  104.             targetSdkVersion targetSdk
  105.             versionCode vCode
  106.             versionName "DemoAPK1_" + "T_" + demo1
  107.             multiDexEnabled true
  108.             renderscriptTargetApi 19
  109.             renderscriptSupportModeEnabled true
  110.             ndk {
  111.                 moduleName "native-modbus-jni,libxmediaplayer"
  112.                 ldLibs "log""z""m""android""c"
  113.                 abiFilters "armeabi""armeabi-v7a""x86"
  114.             }
  115.             sourceSets.main {
  116.                 jni.srcDirs = []
  117.                 jniLibs.srcDir 'src/main/libs'
  118.             }
  119.             signingConfig signingConfigs.debug
  120.         }
  121.         //demo2
  122.         DemoAPK2 {
  123.             minSdkVersion minSdk
  124.             applicationId appId
  125.             targetSdkVersion targetSdk
  126.             versionCode vCode
  127.             versionName "DemoAPK2_" + "T_" + demo2
  128.             multiDexEnabled true
  129.             renderscriptTargetApi 19
  130.             renderscriptSupportModeEnabled true
  131.             ndk {
  132.                 moduleName "native-modbus-jni,libxmediaplayer"
  133.                 ldLibs "log""z""m""android""c"
  134.                 abiFilters "armeabi""armeabi-v7a""x86"
  135.             }
  136.             sourceSets.main {
  137.                 jni.srcDirs = []
  138.                 jniLibs.srcDir 'src/main/libs'
  139.             }
  140.             signingConfig signingConfigs.debug
  141.         }
  142.         //demo3
  143.         DemoAPK3 {
  144.             minSdkVersion minSdk
  145.             applicationId appId
  146.             targetSdkVersion targetSdk
  147.             versionCode vCode
  148.             versionName "DemoAPK3_" + "T_" + demo3
  149.             multiDexEnabled true
  150.             renderscriptTargetApi 19
  151.             renderscriptSupportModeEnabled true
  152.             ndk {
  153.                 moduleName "native-modbus-jni,libxmediaplayer"
  154.                 ldLibs "log""z""m""android""c"
  155.                 abiFilters "armeabi""armeabi-v7a""x86"
  156.             }
  157.             sourceSets.main {
  158.                 jni.srcDirs = []
  159.                 jniLibs.srcDir 'src/main/libs'
  160.             }
  161.             signingConfig signingConfigs.debug
  162.         }
  163.         //demo4
  164.         DemoAPK4 {
  165.             minSdkVersion minSdk
  166.             applicationId appId
  167.             targetSdkVersion targetSdk
  168.             versionCode vCode
  169.             versionName "DemoAPK4_" + "T_" + demo4
  170.             multiDexEnabled true
  171.             renderscriptTargetApi 19
  172.             renderscriptSupportModeEnabled true
  173.             ndk {
  174.                 moduleName "native-modbus-jni,libxmediaplayer"
  175.                 ldLibs "log""z""m""android""c"
  176.                 abiFilters "armeabi""armeabi-v7a""x86"
  177.             }
  178.             sourceSets.main {
  179.                 jni.srcDirs = []
  180.                 jniLibs.srcDir 'src/main/libs'
  181.             }
  182.             signingConfig signingConfigs.debug
  183.         }
  184.         //demo5
  185.         DemoAPK5 {
  186.             minSdkVersion minSdk
  187.             applicationId appId
  188.             targetSdkVersion targetSdk
  189.             versionCode vCode
  190.             versionName "DemoAPK5_" + "T_" + demo5
  191.             multiDexEnabled true
  192.             renderscriptTargetApi 19
  193.             renderscriptSupportModeEnabled true
  194.             ndk {
  195.                 moduleName "native-modbus-jni,libxmediaplayer"
  196.                 ldLibs "log""z""m""android""c"
  197.                 abiFilters "armeabi""armeabi-v7a""x86"
  198.             }
  199.             sourceSets.main {
  200.                 jni.srcDirs = []
  201.                 jniLibs.srcDir 'src/main/libs'
  202.             }
  203.             signingConfig signingConfigs.debug
  204.         }
  205.         //demo6
  206.         DemoAPK6 {
  207.             minSdkVersion minSdk
  208.             applicationId appId
  209.             targetSdkVersion targetSdk
  210.             versionCode vCode
  211.             versionName "DemoAPK6_" + "D_" + demo6
  212.             multiDexEnabled true
  213.             renderscriptTargetApi 19
  214.             renderscriptSupportModeEnabled true
  215.             ndk {
  216.                 moduleName "native-modbus-jni,libxmediaplayer"
  217.                 ldLibs "log""z""m""android""c"
  218.                 abiFilters "armeabi""armeabi-v7a""x86"
  219.             }
  220.             sourceSets.main {
  221.                 jni.srcDirs = []
  222.                 jniLibs.srcDir 'src/main/libs'
  223.             }
  224.             signingConfig signingConfigs.debug
  225.         }
  226.     }
  227.     // 自定义输出配置
  228.     applicationVariants.all { variant ->
  229.         variant.outputs.each { output ->
  230.             def outputFile = output.outputFile
  231.             if (outputFile != null && outputFile.name.endsWith('.apk')) {
  232. //                def fileName = "UerbT_v${variant.versionName}_${releaseTime()}_${variant.flavorName}.apk"
  233.                 def fileName = "${variant.versionName}.apk"
  234.                 output.outputFile = new File(outputFile.parent, fileName)
  235.             }
  236.         }
  237.     }
  238.     productFlavors.all { flavor ->
  239.         def currentMode = flavor.versionName.split("_")[2]
  240.         def currentEnvironment = flavor.versionName.split("_")[1]
  241.         def stValue = true
  242.         // t == currentEnvironment 以前的判断条件
  243.         if (currentEnvironment.endsWith("T")) {//判断是否为测试版 是否以T结尾
  244.             stValue = false
  245.         } else {
  246.             stValue = true
  247.         }
  248.         if (currentMode == demo) {
  249.             flavor.manifestPlaceholders = [SHOUCANG_CONFIG_VALUE: ".shoucang.factorys.ShoucangFactory", STATISTICS_VALUE: stValue]
  250.         } else if (currentMode == demo1) {
  251.             flavor.manifestPlaceholders = [SHOUCANG_CONFIG_VALUE: ".shoucang.factorys.ShoucangFactory1", STATISTICS_VALUE: stValue]
  252.         } else if (currentMode == demo2) {
  253.             flavor.manifestPlaceholders = [SHOUCANG_CONFIG_VALUE: ".shoucang.factorys.ShoucangFactory2", STATISTICS_VALUE: stValue]
  254.         } else if (currentMode == demo3) {
  255.             flavor.manifestPlaceholders = [SHOUCANG_CONFIG_VALUE: ".shoucang.factorys.ShoucangFactory3", STATISTICS_VALUE: stValue]
  256.         } else if (currentMode == demo4) {
  257.             flavor.manifestPlaceholders = [SHOUCANG_CONFIG_VALUE: ".shoucang.factorys.ShoucangFactory4", STATISTICS_VALUE: stValue]
  258.         } else if (currentMode == demo5) {
  259.             flavor.manifestPlaceholders = [SHOUCANG_CONFIG_VALUE: ".shoucang.factorys.ShoucangFactory5", STATISTICS_VALUE: stValue]
  260.         } else if (currentMode == demo6) {
  261.             flavor.manifestPlaceholders = [SHOUCANG_CONFIG_VALUE: ".shoucang.factorys.ShoucangFactory6", STATISTICS_VALUE: stValue]
  262.         }
  263.     }
  264. }
  265. dependencies {
  266.     compile fileTree(include: ['*.jar'], dir: 'libs')
  267.     androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
  268.         exclude group: 'com.android.support'module'support-annotations'
  269.     })
  270.     compile 'com.android.support:appcompat-v7:25.3.0'
  271.     compile 'com.android.support:recyclerview-v7:25.3.0'
  272.     compile 'com.android.support:design:25.3.0'
  273.     compile 'com.android.support:cardview-v7:25.3.0'
  274.     // local jar file
  275.     compile files('libs/alipay-sdk-java20161226110022.jar')
  276.     compile files('libs/alipay-sdk-java20161226110022-source.jar')
  277.     compile files('libs/commons-logging-1.1.1.jar')
  278.     compile files('libs/commons-logging-1.1.1-sources.jar')
  279.     //the third file
  280.     compile 'com.jakewharton:butterknife:8.2.1'
  281.     apt 'com.jakewharton:butterknife-compiler:8.2.1'
  282.     testCompile 'junit:junit:4.12'
  283.     compile 'com.geeklx:library_hios:1.0.4'
  284.     compile project(':glin')
  285.     compile 'com.github.bumptech.glide:glide:3.7.0'
  286.     compile 'com.alibaba:fastjson:1.2.17'
  287.     compile 'com.squareup.okio:okio:1.9.0'
  288.     compile 'com.squareup.okhttp3:okhttp:3.4.1'
  289.     compile 'com.nineoldandroids:library:2.4.0'
  290.     compile files('libs/libammsdk.jar')
  291. }

    接着就是多版本的代码判断书写:

  1.     @Override
  2.     protected void onCreate(@Nullable Bundle savedInstanceState) {
  3.         //TODO 多版本切换 写此方法bufen
  4.         which_version();
  5. //        ShoucangConfig0.config();//manifestPlaceholders的妙用
  6.         super.onCreate(savedInstanceState);
  7.     }
  8.     
  9.     
  10.     private void which_version() {
  11.     if (ConstantNetUtil.VERSION_APK == NetConfig.version_name0) {
  12.         ShoucangConfig.config();
  13.     } else if (ConstantNetUtil.VERSION_APK == NetConfig.version_name1) {
  14.         ShoucangConfig1.config();
  15.     } else if (ConstantNetUtil.VERSION_APK == NetConfig.version_name2) {
  16.         ShoucangConfig2.config();
  17.     } else if (ConstantNetUtil.VERSION_APK == NetConfig.version_name3) {
  18.         ShoucangConfig3.config();
  19.     } else if (ConstantNetUtil.VERSION_APK == NetConfig.version_name4) {
  20.         ShoucangConfig4.config();
  21.     } else if (ConstantNetUtil.VERSION_APK == NetConfig.version_name5) {
  22.         ShoucangConfig5.config();
  23.     } else if (ConstantNetUtil.VERSION_APK == NetConfig.version_name6) {
  24.         ShoucangConfig6.config();
  25.     }
  26. }
  27.     //TODO 多版本模式bufen
  28. SparseArrayCompat<Class<? extends BaseFragment>> array = which_version_fragment_config();//demo
  29.     private SparseArrayCompat<Class<? extends BaseFragment>> which_version_fragment_config() {
  30.     if (ConstantNetUtil.VERSION_APK == NetConfig.version_name0) {
  31.         return ShoucangConfig.getFragments();
  32.     } else if (ConstantNetUtil.VERSION_APK == NetConfig.version_name1) {
  33.         return ShoucangConfig1.getFragments();
  34.     } else if (ConstantNetUtil.VERSION_APK == NetConfig.version_name2) {
  35.         return ShoucangConfig2.getFragments();
  36.     } else if (ConstantNetUtil.VERSION_APK == NetConfig.version_name3) {
  37.         return ShoucangConfig3.getFragments();
  38.     } else if (ConstantNetUtil.VERSION_APK == NetConfig.version_name4) {
  39.         return ShoucangConfig4.getFragments();
  40.     } else if (ConstantNetUtil.VERSION_APK == NetConfig.version_name5) {
  41.         return ShoucangConfig5.getFragments();
  42.     } else if (ConstantNetUtil.VERSION_APK == NetConfig.version_name6) {
  43.         return ShoucangConfig6.getFragments();
  44.     }
  45.     return ShoucangConfig.getFragments();
  46. }

    这样跑完apk你会发现会有神奇的事情发生,如下图:(不同的apk版本出来的页面也是不同的,但是只用了一份代码。)

    图1:

wKioL1l5c6aCAbdJAAEIYRkyE5o544.png

    图2:

wKioL1l5c8jDsbnCAAEFluNEz6s494.png

    这样做的好处在于,如果你的apk版本很多,需要给很多合作厂商提供定制化页面,就可以用上了~

    卧槽,今天喷了好多,希望大家回去自己细化一下,能帮到你~

    wKiom1l5dRTRUWpqAAOaFWzNfo4818.png

    地址:https://github.com/geeklx/MyApplication/tree/master/p027_daojishi_manifestPlaceholders