前言
从零搭建一个项目,如果只是让android studio新建,往往缺少很多内容,缺少比如自定义Application、各个插件的引入、lib包的位置等。本文将简单的介绍一个项目可能用到的gradle设置与新建一个项目需要注意的地方,主要给自己做一个记录总结。
一、application注意点
通常一个应用会引入其他第三方sdk,一般来说都会讲sdk的初始化放到application的onCreate方法中,这样就能保证在进入客户端之前就将sdk初始化完成,从而让功能使用不出现因sdk未初始化导致异常。所以在实际项目中基本每个应用都会有属于自己的application。
另外一个,application的生命周期是同整个应用进行绑定,因此一些和整个应用生命周期有强相关的内容也会在这里进行缓存或实例化。
同时,在application中还可注册监听所有activity的生命周期方法(registerActivityLifecycleCallbacks(ActivityLifecycleCallbacks)),对应用的activity管理非常方便
1.创建与使用
新建一个application很简单,只需要创建一个类,并让该类继承Application即可,然后实行onCreate方法。
但这仅仅只是创建了,整个应用还没和自定义的application类进行绑定,绑定也很简单:只需要在清单文件AndroidManifest.xml中写入即可
<application android:name=“自定义application类路径”>
拓展一下:
在这里,我们仅仅是简单的继承了Application,但还有一个常用的Application子类可继承——MultiDexApplication 。
使用该类我们需要先引入库
api ‘androidx.multidex:multidex:2.0.1’
同步后在在主包的build.gradle中需要:
android {
...
defaultConfig {
...
multiDexEnabled true
}
}
之后创建一个类继承MultiDexApplication即可
关于这个类的作用:为了解决dex内方法数超出报65536问题。
个人关于MultiDexApplication使用建议:如果是一个大型项目推荐使用
2.application需要注意的点
由于启动一个app,会先执行application中的onCreate方法,所有通常将sdk的初始化放到这里面,但是也恰恰因此会导致我们的应用启动速度变慢,所以由此得到以下几点注意事项:
a. 尽量不要在onCreate中执行耗时操作
不要将所有的sdk初始化都放到oncreate中,可以将不重要的sdk延迟初始化,能放入子线程的放到子线程中去进行初始化。而这也正是优化应用启动速度的方向之一
b. 初始化sdk放入主进程中执行,避免多次初始化
一般来讲,一个app中只会存在一个进程,但在实际项目开发中,会引入第三方库或由于功能需要创建新进程。因此,application的onCreate方法执行次数在一次启动中很可能不止一次,为了避免引入的第三方sdk重复初始化,导致无效操作和启动时长增加,我们只需要将sdk放到主进程去初始化即可(一般放入主进程,如果某个sdk是其他进程所需要的,自然需要在对应进程去初始化)
判断方法:
在application中添加以下方法:
protected open fun getProcessName(pid: Int): String? {
var reader: BufferedReader? = null
try {
reader = BufferedReader(FileReader("/proc/$pid/cmdline"))
var processName = reader.readLine()
if (!TextUtils.isEmpty(processName)) {
processName = processName.trim { it <= ' ' }
}
return processName
} catch (throwable: Throwable) {
throwable.printStackTrace()
} finally {
try {
reader?.close()
} catch (exception: IOException) {
exception.printStackTrace()
}
}
return null
}
fun isMainProcess(): Boolean {
val processName = getProcessName(Process.myPid())
return processName == null || processName == packageName
}
override fun onCreate() {
super.onCreate()
if (isMainProcess()) {
//sdk的初始化方法
}
}
二、三方库文件位置及使用
一些三方sdk是aar包或者jar包与so文件,刚开始接触往往不清楚这些文件应该放在哪里以及该如何引入使用。
1 .so文件
.so文件是由C/C++代码构成,在安卓中,为了能使java代码能与C/C++代码进行交互使用的是一种叫JNI的技术,我们这里不探讨该技术,而仅说明其文件应该置于项目何处。
android中提供了一个默认文件jniLibs/jni,在main目录下。
一般架构(armeabi、armeabi-v7a、arm64-v8a、x86、x86_64等)不同.so文件也会不同,所以在实际项目中根据项目需求在jni文件夹下建立对应架构的子文件夹,并将对应架构下的.so文件放置其中
然后,我们需要在build.gradle中声明本项目所支持的架构
ndk {
abiFilters ‘armeabi’, ‘arm64-v8a’ //用逗号分割
}
最后android系统会根据手机架构去加载对应文件夹下的.so文件,保证功能的正常使用。
拓展一下
实际项目中,.so可能并不会放在系统提供的文件夹下,而是自定义一个位置,因此就需要在build.gradle中声明文件位置:
android {
...
sourceSets {
main {
jniLibs.srcDirs = ['库文件位置'] //例子:['libs']
//资源文件也可自定义位置,如下
res.srcDirs = ['资源文件地址1','资源文件地址2',...] //例子:'src/main/res'
}
}
}
2. jar包或aar包
可直接放与src同级下的libs文件夹下,然后在build.gradle引入中引用即可,引用方法有指定引用与通用引用
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
//implementation files('libs/xxx.jar')
//implementation files('libs/xxx.aar')
}
三、打包中混淆文件的使用与设置
通过build.gradle可以控制不同方式的打包是否需要混淆以及对应的混淆文件、签名文件等设置
buildTypes {
release {
minifyEnabled true //是否混淆
shrinkResources true //资源文件是否压缩处理
//签名文件配置,需要在外面android下定义设值,包含签名文件的keyPassword、keyAlias、storePassword、storeFile
signingConfig signingConfigs.config
//混淆文件
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
manifestPlaceholders = rootProject.ext.fastManifestPlaceholdersRelease
debuggable false
}
debug {
minifyEnabled false
shrinkResources false
signingConfig signingConfigs.config
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
manifestPlaceholders = rootProject.ext.fastManifestPlaceholdersDebug
debuggable true
}
}
拓展一下
关于签名文件配置signingConfigs.config
- 首先在最外层(和项目级build.gradle同级)建立keystore.properties文件
ReleaseKeyPassword = XXXX
ReleaseKeyAlias = XXXX
ReleaseStorePassword = XXXX
ReleaseStoreFile = 签名文件(.jks)在项目中的相对路径
- 将签名文件放到app包下
- 在app包下的build.gradle中设值signingConfigs.config
android {
File keystorePropertiesFile = rootProject.file("keystore.properties")
if (keystorePropertiesFile.exists()) {
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
signingConfigs {
config {
keyAlias keystoreProperties['ReleaseKeyAlias']
keyPassword keystoreProperties['ReleaseKeyPassword']
storeFile file(keystoreProperties['ReleaseStoreFile'])
storePassword keystoreProperties['ReleaseStorePassword']
}
}
}
}
结语
欢迎在评论中提出更多基础配置项,有新的了解后也会加入进来,持续更新中…