Android Studio 如何更便捷开发系统 App
System App
最近接触系统App相关的开发,刚开始得知在系统源码中,开发系统应用,As 引用库的时候,居然不能代码联想,布局也不能预览,实在不习惯。后面搜了下网上的资源,有一些介绍,也不是特别完整,于是自己把这些零碎的点,整理出来,方面后续自己看看。
本文主要解决以下几个问题:
- 代码移植、资源移植
- 系统隐藏代码未找到
- aidl 代码问题
- protobuf 代码问题
- lint 警告提示
代码移植、资源移植
这一步,就是把系统App的代码拷贝出来(例如:/packages/apps/Settings),相当于移植到一个新的项目。创建一个新的 As 工程,然后按照源码的目录层级创建,记得包名跟源码一致,尽可能保存目录层级一致,接着就是各种 copy 操作了,把 src、res 等目录都搬过去新项目中。在移植的过程,需要将 Android.bp
文件里面依赖的库,按照 gradle 的方式来依赖进去。例如:
static_libs: [
"com.google.android.material_material",
"androidx.transition_transition",
"androidx-constraintlayout_constraintlayout",
"androidx.core_core",
"androidx.media_media",
"androidx.legacy_legacy-support-core-utils",
"androidx.legacy_legacy-support-core-ui",
"androidx.fragment_fragment",
"androidx.appcompat_appcompat",
"androidx.preference_preference",
"androidx.recyclerview_recyclerview",
"androidx.legacy_legacy-preference-v14",
"androidx.leanback_leanback",
"androidx.leanback_leanback-preference",
"androidx.lifecycle_lifecycle-extensions",
"androidx.lifecycle_lifecycle-common-java8",
"kotlin-stdlib",
"kotlinx-coroutines-android",
"androidx.navigation_navigation-common-ktx",
"androidx.navigation_navigation-fragment-ktx",
"androidx.navigation_navigation-runtime-ktx",
"androidx.navigation_navigation-ui-ktx",
]
对应到 gradle 代码,这个过程十分麻烦,因为很多资源缺失,需要一个个的寻找,以及代码的移植还会关联其他工程代码。而且库的版本也是需要注意的。所以需要耐心解决。
compileOnly files('libs/framework.jar')
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.1'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1'
implementation 'androidx.core:core-ktx:1.6.0'
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'com.google.android.material:material:1.4.0'
implementation 'com.android.support:multidex:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
implementation "com.google.protobuf:protobuf-javalite:3.13.0"
def nav_version = "2.3.5"
// Java language implementation
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
// Feature module Support
implementation "androidx.navigation:navigation-dynamic-features-fragment:$nav_version"
def lifecycle_version = "2.3.1"
def arch_version = "2.1.0"
// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
// LiveData
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
// Lifecycles only (without ViewModel or LiveData)
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
// ???
implementation "android.arch.lifecycle:extensions:1.1.1"
// Saved state module for ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"
// Annotation processor
kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
// alternately - if using Java8, use the following instead of lifecycle-compiler
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
// optional - helpers for implementing LifecycleOwner in a Service
implementation "androidx.lifecycle:lifecycle-service:$lifecycle_version"
// optional - ProcessLifecycleOwner provides a lifecycle for the whole application process
implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"
// optional - ReactiveStreams support for LiveData
implementation "androidx.lifecycle:lifecycle-reactivestreams-ktx:$lifecycle_version"
// optional - Test helpers for LiveData
testImplementation "androidx.arch.core:core-testing:$arch_version"
def leanback_version = "1.2.0-alpha01"
implementation "androidx.leanback:leanback:$leanback_version"
// leanback-preference is an add-on that provides a settings UI for TV apps.
implementation "androidx.leanback:leanback-preference:$leanback_version"
// leanback-paging is an add-on that simplifies adding paging support to a RecyclerView Adapter.
implementation "androidx.leanback:leanback-paging:1.1.0-alpha08"
// leanback-tab is an add-on that provides customized TabLayout to be used as the top navigation bar.
implementation "androidx.leanback:leanback-tab:1.1.0-beta01"
如果项目源码存在多个 src
目录,需要在 gradle 中指定 java
目录
sourceSets {
main {
java.srcDirs = ['src/main/src', 'src/main/src2', 'src/main/src_gen']
// 定义proto文件目录
proto {
// srcDir 'src/main/java'
srcDir 'src/main/src'
include '**/*.proto'
}
}
}
系统隐藏代码未找到
系统源码编译之后,找到/out/target/common/obj/JAVA_LIBRARIES/framework_intermediates 目录下的 classes.jar
文件,更名为 framework.jar
,按照jar包的引用方式,依赖进去工程。
同时需要更改jar的加载顺序,在工程目录的 gradle 添加如下代码
allprojects {
repositories {
google()
jcenter()
}
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
// options.compilerArgs.add('-Xbootclasspath/p:app/libs/framework.jar')
Set<File> fileSet = options.bootstrapClasspath.getFiles()
List<File> newFileList = new ArrayList<>();
//"../framework.jar" 为相对位置,需要参照着修改,或者用绝对位置
// 我这里用的是绝对路径,注意区分 linux 系统与 window 系统的反斜杠
newFileList.add(new File("/xxx/framework.jar"))
newFileList.addAll(fileSet)
options.bootstrapClasspath = files(newFileList.toArray())
// options.bootstrapClasspath.getFiles().forEach(new Consumer<File>() {
// @Override
// void accept(File file) {
// println(file.name)
// }
// })
//options.compilerArgs.add('-Xbootclasspath/p:app\\libs\\framework.jar')
}
}
}
aidl 代码问题
aidl 代码可以用两种方式处理,一种是直接拷贝aidl的生成物,本质还是java代码,另一种方式是按源码那样创建aidl文件。
protobuf 代码问题
需要正确引入对应的 protobuf 的版本,以及生成代码的目录,我记得我当时还因为版本不匹配导致一些错误,具体时间太久了,当时也没存记录。
plugins {
id 'com.android.application'
id 'com.google.protobuf'
id 'kotlin-android'
id 'kotlin-kapt'
}
protobuf {
protoc {
artifact = "com.google.protobuf:protoc:3.13.0"
}
generateProtoTasks {
all().each { task ->
task.builtins {
java {
option "lite"
}
}
}
}
}
···
// 工程 gradle 配置
buildscript {
ext.kotlin_version = "1.4.32"
repositories {
google()
jcenter()
}
dependencies {
classpath "com.android.tools.build:gradle:4.1.3"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.13"
}
}
lint 警告提示
源码中会使用一些过时的方法,在打包过程会导致失败。需要在 gradle 中配置,错误不中断
lintOptions {
abortOnError false
}
小结
整个过程,就是多次修改,拷贝,然后编译的过程,直到没有错误提示,能够成功生成apk的时候,就成功了。之后就可以愉快的关联代码,以及布局预览了。
链接:https://juejin.cn/post/7056403090706169886
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。