Android Studio - 第四十五期 Gradle manifestPlaceholders
最近在学习撸撸的代码规范和写法,有些心得,准备好好写一写~包括了多渠道打版(以前有写过方法),工厂模式,mvp,以及最近刚封装出来的多渠道多版本展示不同页面的manifestPlaceholders的配置方法,大家应该也碰到过线上和线下环境的切换换地址,换私钥的头大问题,本篇就来解决这些问题。
先在androidmanifest文件配置一个节点,这里以极光为例:
<meta-data android:name="JPUSH_APPKEY" android:value="${jush_appkey_value}" /> <meta-data android:name="SHOUCANG_CONFIG0" android:value="${SHOUCANG_CONFIG_VALUE0}" />
build.gradle:
buildTypes { release { //自定义buildconfig字段 buildConfigField("boolean", "APP_ENV", "true") //指定签名为release signingConfig signingConfig.release //是否开启混淆 minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' //是否zip优化 zipAlignEnabled true //删除一些无用资源 shrinkResources false // manifestPlaceholders = [ "jush_appkey_value": "release key" ] } debug { //自定义buildconfig字段 buildConfigField("boolean", "APP_ENV", "true") //指定签名为release signingConfig signingConfig.release //是否开启混淆 minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' //是否zip优化 zipAlignEnabled true //删除一些无用资源 shrinkResources false // manifestPlaceholders = [ "jush_appkey_value": "debug key" ] } }
在bulidtypes节点下有release节点和debug节点,正式签名时就会走release节点的下编译脚本,调试签名时就会走debug节点。主要点就是manifestPlaceholders的用法,jpush_appkey对应的就是之前在androidmanifest文件配置的${jush_appkey_value}的这个值。
在程序入口出打上log,用来输出key的值:
/** * 在程序入口出打上log,用来输出key的值bufen */ private void jpush_key_manifest_xml_string() { String jpush_appkey; try { ApplicationInfo appInfo = getPackageManager() .getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA); jpush_appkey = appInfo.metaData.getString("JPUSH_APPKEY"); Log.e("jpush_appkey", "jpush_appkey=" + jpush_appkey); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } }
接下来给大家介绍多版本多页面多apk的配置切换方法:举个例子:如果你要一次性打七个版本,而且七个版本都是不同的页面,但是页面各个模块大体一样,只是顺序和大小不同,你要怎么做,别告诉我写七个页面分别打版哈~太low了~you know~这里就利用多版本打版和manifestPlaceholders来实现需求。
首先是build.gradle:
apply plugin: 'com.android.application' apply plugin: 'android-apt' def demo = '0000';//DemoAPK def demo1 = '0001';//DemoAPK1 def demo2 = '0002';//DemoAPK2 def demo3 = '0003';//DemoAPK3 def demo4 = '0004';//DemoAPK4 def demo5 = '0005';//DemoAPK5 def demo6 = '0006';//DemoAPK6 android { signingConfigs { debug { keyAlias '****' keyPassword '****' storeFile file('签名文件.jks路径') storePassword '****' } release { keyAlias '****' keyPassword '****' storeFile file('签名文件.jks路径') storePassword '****' } } compileSdkVersion 25 buildToolsVersion "25.0.2" sourceSets { main { jniLibs.srcDirs = ['libs'] } } packagingOptions { exclude 'META-INF/DEPENDENCIES' exclude 'META-INF/NOTICE' exclude 'META-INF/LICENSE' exclude 'META-INF/LICENSE.txt' exclude 'META-INF/NOTICE.txt' } defaultConfig { applicationId "com.shining.p010_recycleviewall" minSdkVersion 18 targetSdkVersion 23 versionCode 1 versionName "1.0" multiDexEnabled true renderscriptTargetApi 19 renderscriptSupportModeEnabled true ndk { moduleName "native-modbus-jni,libxmediaplayer" ldLibs "log", "z", "m", "android", "c" abiFilters "armeabi", "armeabi-v7a", "x86" } sourceSets.main { jni.srcDirs = [] //LOCAL_LDFLAGS += -fuse-ld=bfd //jni.srcDirs 'src/main/jni' jniLibs.srcDir 'src/main/libs' } signingConfig signingConfigs.debug manifestPlaceholders = [ SHOUCANG_CONFIG_VALUE0: ".shoucang.factorys.ShoucangFactory0" ] } buildTypes { release { minifyEnabled true zipAlignEnabled true shrinkResources false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' signingConfig signingConfigs.debug } } def int minSdk = 18; def int targetSdk = 23; def String appId = 'com.shining.p010_recycleviewall'; def int vCode = 1; def String vNameCode = vCode + ""; productFlavors { //demo DemoAPK { minSdkVersion minSdk applicationId appId targetSdkVersion targetSdk versionCode vCode versionName "DemoAPK_" + "T_" + demo multiDexEnabled true renderscriptTargetApi 19 renderscriptSupportModeEnabled true ndk { moduleName "native-modbus-jni,libxmediaplayer" ldLibs "log", "z", "m", "android", "c" abiFilters "armeabi", "armeabi-v7a", "x86" } sourceSets.main { jni.srcDirs = [] jniLibs.srcDir 'src/main/libs' } signingConfig signingConfigs.debug } //demo1 DemoAPK1 { minSdkVersion minSdk applicationId appId targetSdkVersion targetSdk versionCode vCode versionName "DemoAPK1_" + "T_" + demo1 multiDexEnabled true renderscriptTargetApi 19 renderscriptSupportModeEnabled true ndk { moduleName "native-modbus-jni,libxmediaplayer" ldLibs "log", "z", "m", "android", "c" abiFilters "armeabi", "armeabi-v7a", "x86" } sourceSets.main { jni.srcDirs = [] jniLibs.srcDir 'src/main/libs' } signingConfig signingConfigs.debug } //demo2 DemoAPK2 { minSdkVersion minSdk applicationId appId targetSdkVersion targetSdk versionCode vCode versionName "DemoAPK2_" + "T_" + demo2 multiDexEnabled true renderscriptTargetApi 19 renderscriptSupportModeEnabled true ndk { moduleName "native-modbus-jni,libxmediaplayer" ldLibs "log", "z", "m", "android", "c" abiFilters "armeabi", "armeabi-v7a", "x86" } sourceSets.main { jni.srcDirs = [] jniLibs.srcDir 'src/main/libs' } signingConfig signingConfigs.debug } //demo3 DemoAPK3 { minSdkVersion minSdk applicationId appId targetSdkVersion targetSdk versionCode vCode versionName "DemoAPK3_" + "T_" + demo3 multiDexEnabled true renderscriptTargetApi 19 renderscriptSupportModeEnabled true ndk { moduleName "native-modbus-jni,libxmediaplayer" ldLibs "log", "z", "m", "android", "c" abiFilters "armeabi", "armeabi-v7a", "x86" } sourceSets.main { jni.srcDirs = [] jniLibs.srcDir 'src/main/libs' } signingConfig signingConfigs.debug } //demo4 DemoAPK4 { minSdkVersion minSdk applicationId appId targetSdkVersion targetSdk versionCode vCode versionName "DemoAPK4_" + "T_" + demo4 multiDexEnabled true renderscriptTargetApi 19 renderscriptSupportModeEnabled true ndk { moduleName "native-modbus-jni,libxmediaplayer" ldLibs "log", "z", "m", "android", "c" abiFilters "armeabi", "armeabi-v7a", "x86" } sourceSets.main { jni.srcDirs = [] jniLibs.srcDir 'src/main/libs' } signingConfig signingConfigs.debug } //demo5 DemoAPK5 { minSdkVersion minSdk applicationId appId targetSdkVersion targetSdk versionCode vCode versionName "DemoAPK5_" + "T_" + demo5 multiDexEnabled true renderscriptTargetApi 19 renderscriptSupportModeEnabled true ndk { moduleName "native-modbus-jni,libxmediaplayer" ldLibs "log", "z", "m", "android", "c" abiFilters "armeabi", "armeabi-v7a", "x86" } sourceSets.main { jni.srcDirs = [] jniLibs.srcDir 'src/main/libs' } signingConfig signingConfigs.debug } //demo6 DemoAPK6 { minSdkVersion minSdk applicationId appId targetSdkVersion targetSdk versionCode vCode versionName "DemoAPK6_" + "D_" + demo6 multiDexEnabled true renderscriptTargetApi 19 renderscriptSupportModeEnabled true ndk { moduleName "native-modbus-jni,libxmediaplayer" ldLibs "log", "z", "m", "android", "c" abiFilters "armeabi", "armeabi-v7a", "x86" } sourceSets.main { jni.srcDirs = [] jniLibs.srcDir 'src/main/libs' } signingConfig signingConfigs.debug } } // 自定义输出配置 applicationVariants.all { variant -> variant.outputs.each { output -> def outputFile = output.outputFile if (outputFile != null && outputFile.name.endsWith('.apk')) { // def fileName = "UerbT_v${variant.versionName}_${releaseTime()}_${variant.flavorName}.apk" def fileName = "${variant.versionName}.apk" output.outputFile = new File(outputFile.parent, fileName) } } } productFlavors.all { flavor -> def currentMode = flavor.versionName.split("_")[2] def currentEnvironment = flavor.versionName.split("_")[1] def stValue = true // t == currentEnvironment 以前的判断条件 if (currentEnvironment.endsWith("T")) {//判断是否为测试版 是否以T结尾 stValue = false } else { stValue = true } if (currentMode == demo) { flavor.manifestPlaceholders = [SHOUCANG_CONFIG_VALUE: ".shoucang.factorys.ShoucangFactory", STATISTICS_VALUE: stValue] } else if (currentMode == demo1) { flavor.manifestPlaceholders = [SHOUCANG_CONFIG_VALUE: ".shoucang.factorys.ShoucangFactory1", STATISTICS_VALUE: stValue] } else if (currentMode == demo2) { flavor.manifestPlaceholders = [SHOUCANG_CONFIG_VALUE: ".shoucang.factorys.ShoucangFactory2", STATISTICS_VALUE: stValue] } else if (currentMode == demo3) { flavor.manifestPlaceholders = [SHOUCANG_CONFIG_VALUE: ".shoucang.factorys.ShoucangFactory3", STATISTICS_VALUE: stValue] } else if (currentMode == demo4) { flavor.manifestPlaceholders = [SHOUCANG_CONFIG_VALUE: ".shoucang.factorys.ShoucangFactory4", STATISTICS_VALUE: stValue] } else if (currentMode == demo5) { flavor.manifestPlaceholders = [SHOUCANG_CONFIG_VALUE: ".shoucang.factorys.ShoucangFactory5", STATISTICS_VALUE: stValue] } else if (currentMode == demo6) { flavor.manifestPlaceholders = [SHOUCANG_CONFIG_VALUE: ".shoucang.factorys.ShoucangFactory6", STATISTICS_VALUE: stValue] } } } dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:25.3.0' compile 'com.android.support:recyclerview-v7:25.3.0' compile 'com.android.support:design:25.3.0' compile 'com.android.support:cardview-v7:25.3.0' // local jar file compile files('libs/alipay-sdk-java20161226110022.jar') compile files('libs/alipay-sdk-java20161226110022-source.jar') compile files('libs/commons-logging-1.1.1.jar') compile files('libs/commons-logging-1.1.1-sources.jar') //the third file compile 'com.jakewharton:butterknife:8.2.1' apt 'com.jakewharton:butterknife-compiler:8.2.1' testCompile 'junit:junit:4.12' compile 'com.geeklx:library_hios:1.0.4' compile project(':glin') compile 'com.github.bumptech.glide:glide:3.7.0' compile 'com.alibaba:fastjson:1.2.17' compile 'com.squareup.okio:okio:1.9.0' compile 'com.squareup.okhttp3:okhttp:3.4.1' compile 'com.nineoldandroids:library:2.4.0' compile files('libs/libammsdk.jar') }
接着就是多版本的代码判断书写:
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { //TODO 多版本切换 写此方法bufen which_version(); // ShoucangConfig0.config();//manifestPlaceholders的妙用 super.onCreate(savedInstanceState); } private void which_version() { if (ConstantNetUtil.VERSION_APK == NetConfig.version_name0) { ShoucangConfig.config(); } else if (ConstantNetUtil.VERSION_APK == NetConfig.version_name1) { ShoucangConfig1.config(); } else if (ConstantNetUtil.VERSION_APK == NetConfig.version_name2) { ShoucangConfig2.config(); } else if (ConstantNetUtil.VERSION_APK == NetConfig.version_name3) { ShoucangConfig3.config(); } else if (ConstantNetUtil.VERSION_APK == NetConfig.version_name4) { ShoucangConfig4.config(); } else if (ConstantNetUtil.VERSION_APK == NetConfig.version_name5) { ShoucangConfig5.config(); } else if (ConstantNetUtil.VERSION_APK == NetConfig.version_name6) { ShoucangConfig6.config(); } } //TODO 多版本模式bufen SparseArrayCompat<Class<? extends BaseFragment>> array = which_version_fragment_config();//demo private SparseArrayCompat<Class<? extends BaseFragment>> which_version_fragment_config() { if (ConstantNetUtil.VERSION_APK == NetConfig.version_name0) { return ShoucangConfig.getFragments(); } else if (ConstantNetUtil.VERSION_APK == NetConfig.version_name1) { return ShoucangConfig1.getFragments(); } else if (ConstantNetUtil.VERSION_APK == NetConfig.version_name2) { return ShoucangConfig2.getFragments(); } else if (ConstantNetUtil.VERSION_APK == NetConfig.version_name3) { return ShoucangConfig3.getFragments(); } else if (ConstantNetUtil.VERSION_APK == NetConfig.version_name4) { return ShoucangConfig4.getFragments(); } else if (ConstantNetUtil.VERSION_APK == NetConfig.version_name5) { return ShoucangConfig5.getFragments(); } else if (ConstantNetUtil.VERSION_APK == NetConfig.version_name6) { return ShoucangConfig6.getFragments(); } return ShoucangConfig.getFragments(); }
这样跑完apk你会发现会有神奇的事情发生,如下图:(不同的apk版本出来的页面也是不同的,但是只用了一份代码。)
图1:
图2:
这样做的好处在于,如果你的apk版本很多,需要给很多合作厂商提供定制化页面,就可以用上了~
卧槽,今天喷了好多,希望大家回去自己细化一下,能帮到你~
地址:https://github.com/geeklx/MyApplication/tree/master/p027_daojishi_manifestPlaceholders
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
我必须得告诉大家的MySQL优化原理
说起MySQL的查询优化,相信大家收藏了一堆奇淫技巧:不能使用SELECT *、不使用NULL字段、合理创建索引、为字段选择合适的数据类型..... 你是否真的理解这些优化技巧?是否理解其背后的工作原理?在实际场景下性能真有提升吗?我想未必。因而理解这些优化建议背后的原理就尤为重要,希望本文能让你重新审视这些优化建议,并在实际业务场景下合理的运用。 MySQL逻辑架构 如果能在头脑中构建一幅MySQL各组件之间如何协同工作的架构图,有助于深入理解MySQL服务器。下图展示了MySQL的逻辑架构图。 MySQL逻辑架构整体分为三层,最上层为客户端层,并非MySQL所独有,诸如:连接处理、授权认证、安全等功能均在这一层处理。 MySQL大多数核心服务均在中间这一层,包括查询解析、分析、优化、缓存、内置函数(比如:时间、数学、加密等函数)。所有的跨存储引擎的功能也在这一层实现:存储过程、触发器、视图等。 最下层为存储引擎,其负责MySQL中的数据存储和提取。和Linux下的文件系统类似,每种存储引擎都有其优势和劣势。中间的服务层通过API与存储引擎通信,这些API接口屏蔽了不同存储引擎间的差...
- 下一篇
从运维角度看中大型网站架构的演变之路
网上有很多文章类似于今天要分享的主题,有架构师写的,有运维写的,还有开发写的,偏重点各不同!今天我以运维角度讲解中大型网站架构演变之路。 一个成熟的网站架构并不是一开始设计就具备高可用、高伸缩、高性能等特性的,它是随着用户量和业务线不断增加,基础架构才逐渐健壮的。在发展初期,一般都是从0到1,不会一上来就整一些大而全的架构! 适用业务:电商/门户/招聘网站 开发语言:PHP和JAVA Web服务:Nginx/Tomcat8 数据库:MySQL 操作系统:CentOS 物理服务器:Dell R730/R430 视频版:https://ke.qq.com/course/219551 一、单台服务器部署 项目开发完成上线,用户访问量寥寥无几。 二、WEB与数据库独立部署 有一定用户访问量,单台服务器性能有些吃力,想提高并发能力,增加一台服务器,将HTTP请求与SQL操作负载分散不同服务器。 三、动静分离-初期 什么是动静分离?静态页面与动态页面分离部署。 四、数据库主从与查询缓存 uRedisCache 使用Redis缓存数据库查询结果,将热数据放到内存中,提高查询速度,减少数据库请求。 ...
相关文章
文章评论
共有0条评论来说两句吧...