Project Name | Stars | Downloads | Repos Using This | Packages Using This | Most Recent Commit | Total Releases | Latest Release | Open Issues | License | Language |
---|---|---|---|---|---|---|---|---|---|---|
Android Best Practices | 19,837 | 2 years ago | 30 | other | ||||||
Do's and Don'ts for Android development, by Futurice developers | ||||||||||
Androiddevtools | 7,528 | 15 days ago | 4 | |||||||
收集整理Android开发所需的Android SDK、开发中用到的工具、Android开发教程、Android设计规范,免费的设计素材等。 | ||||||||||
Shadow | 6,834 | a month ago | 249 | bsd-3-clause | Java | |||||
零反射全动态Android插件框架 | ||||||||||
Weiciyuan | 2,664 | 7 years ago | 63 | gpl-3.0 | Java | |||||
Sina Weibo Android Client | ||||||||||
Androidprocess | 2,640 | 4 years ago | 15 | apache-2.0 | Java | |||||
判断App位于前台或者后台的6种方法 | ||||||||||
Condom | 2,321 | 3 years ago | apache-2.0 | Java | ||||||
一个超轻超薄的Android工具库,阻止三方SDK中常见的有害行为,而不影响应用自身的功能。(例如严重影响用户体验的『链式唤醒』) | ||||||||||
Android Samples | 2,318 | 12 days ago | 6 | apache-2.0 | Java | |||||
Samples demonstrating how to use Maps SDK for Android | ||||||||||
Open Keychain | 1,882 | 5 days ago | 428 | gpl-3.0 | Java | |||||
OpenKeychain is an OpenPGP implementation for Android. | ||||||||||
Notifyutil | 1,631 | 3 years ago | 13 | apache-2.0 | Java | |||||
通知工具类 | ||||||||||
1,548 | 7 months ago | 12 | Java | |||||||
第三方新浪微博客户端 |
该项目演示了在 Android Studio 中使用 gradle 构建渠道包。已更新支持 Android Studio 3.x,Gradle 4.x。
以友盟 SDK 为例,打包多渠道:GooglePlay,小米,友盟,360,豌豆荚,应用宝。 在 AndroidManifest.xml 中加入渠道区分标识。
<meta-data
android:name="UMENG_CHANNEL"
android:value="${UMENG_CHANNEL_VALUE}" />
然后在 build.gradle(Module: app) 中加入渠道打包替换对应的 UMENG_CHANNEL_VALUE 代码。
// 渠道Flavors,配置不同的渠道
productFlavors {
GooglePlay {}
xiaomi {}
umeng {}
qihu360 {}
wandoujia {}
yingyongbao {}
//其他...
}
// 批量配置渠道
productFlavors.all {
flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
}
我们可以指定不同渠道号生成的 apk 的名字,这样方便打包出来区别哪个 apk 是对应哪个渠道的。
如下命名格式为:渠道名-v版本号-打包时间.apk
//打包重命名
applicationVariants.all { variant ->
if (variant.buildType.name == "release") {
variant.outputs.all { output ->
def fileName = output.outputFile.name
if (fileName.endsWith(".apk")) {
def apkName = "${variant.productFlavors[0].name}-v${variant.versionName}-${releaseTime()}.apk";
outputFileName = apkName
}
}
}
}
不同的渠道定义不同的 applicationId, versionCode, versionName
flavorDimensions "test","test1","test2"
//定义渠道
productFlavors {
main_test {
applicationId "com.jeanboy.app.flavors"
versionCode rootProject.ext.mainTestVersionCode
versionName rootProject.ext.mainTestVersionName
//定义manifest中替换值,如:渠道号
resValue("string", "test_app_id", "2017-8-14 12:09:35")
//定义混淆文件
proguardFiles getDefaultProguardFile('proguard-android.txt'), './src/main_test/proguard-rules.pro'
dimension "test"
}
main_test1 {
applicationId "com.jeanboy.app.flavorstest1"
versionCode rootProject.ext.mainTest1VersionCode
versionName rootProject.ext.mainTest1VersionName
resValue("string", "test_app_id", "2017-8-14 12:09:35")
proguardFiles getDefaultProguardFile('proguard-android.txt'), './src/main_test1/proguard-rules.pro'
dimension "test1"
}
main_test2 {
applicationId "com.jeanboy.app.flavorstest2"
versionCode rootProject.ext.mainTest2VersionCode
versionName rootProject.ext.mainTest2VersionName
resValue("string", "test_app_id", "2017-8-14 12:09:35")
proguardFiles getDefaultProguardFile('proguard-android.txt'), './src/main_test2/proguard-rules.pro'
dimension "test2"
}
}
定义渠道包签名文件
signingConfigs {
test {
storeFile file('../resources/test.jks')//密钥文件位置
storePassword 'test123'//密钥密码
keyAlias 'test'//密钥别名
keyPassword 'test123'//别名密码
}
test1 {
storeFile file('../resources/test1.jks')
storePassword 'test123'
keyAlias 'test'
keyPassword 'test123'
}
test2 {
storeFile file('../resources/test2.jks')
storePassword 'test123'
keyAlias 'test'
keyPassword 'test123'
}
}
指定不同渠道使用的签名文件
buildTypes {
debug {
minifyEnabled false
shrinkResources false
zipAlignEnabled true
versionNameSuffix "-debug"//版本命名后缀
buildConfigField "boolean", "LOG_DEBUG", "true"
//定义debug时使用的签名文件
signingConfig signingConfigs.test
signingConfig signingConfigs.test1
signingConfig signingConfigs.test2
}
release {
minifyEnabled true//是否开启代码混淆
shrinkResources true//移除无用的资源文件,依赖于minifyEnabled必须一起用
multiDexEnabled true//解决65535
zipAlignEnabled true//对齐zip
debuggable false // 是否debug
buildConfigField "boolean", "LOG_DEBUG", "false"
signingConfig signingConfigs.test
signingConfig signingConfigs.test1
signingConfig signingConfigs.test2
}
}
例如:不同渠道需要不同的应用名
|-app
|-src
|-main
| |-res
| |-values
| |-strings.xml
| |-<string name="app_name">Android-Flavors</string>
|-main_test
| |-res
| |-values
| |-strings.xml
| |-<string name="app_name">Android-Flavors-test</string>
|-main_test1
| |-res
| |-values
| |-strings.xml
| |-<string name="app_name">Android-Flavors-test1</string>
|-main_test2
| |-res
| |-values
| |-strings.xml
| |-<string name="app_name">Android-Flavors-test2</string>
在 src 下创建与 main 同级的渠道目录,里面可创建与 main 目录下对应的目录或文件,打包时会以增量或覆盖的方式替换。
res 目录下的文件可以同名覆盖,java 或其他代码目录中类名不允许重复。
编译某个渠道包的时候遵循以下4条准则:
例如:test1 渠道中需要使用某个 SDK,而其他渠道不需要使用。
android {
productFlavors {
test1 {
}
}
}
...
dependencies {
provided 'com.xxx.sdk:xxx:1.0'//提供 sdk
test1Compile 'com.xxx.sdk:xxx:1.0'//指定 test1 渠道编译
}
接下来,需要在代码中使用反射技术判断应用程序是否添加了该SDK,从而决定是否要使用 SDK。部分代码如下:
class MyActivity extends Activity {
private boolean useSdk;
@override
public void onCreate(Bundle savedInstanceState) {
try {
Class.forName("com.xxx.sdk.XXX");
useSdk = true;
} catch (ClassNotFoundException ignored) {
}
}
}
如果对你有帮助,请 star 一下,然后 follow 我,给我增加一下分享动力,谢谢!
如果你有什么疑问或者问题,可以提交 issue 和 request,发邮件给我 [email protected] 。
或者加入下面的 QQ 群来一起学习交流。
Copyright 2017 jeanboy
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.