手機(jī)網(wǎng)站建設(shè)經(jīng)驗(yàn)seo發(fā)展前景怎么樣啊
作者:Jingle_zhang
第三方App使用
Jetpack
等開源框架非常流行,在Gradle文件簡單指定即可。然而ROM內(nèi)置的系統(tǒng)App在源碼環(huán)境下進(jìn)行開發(fā),與第三方App脫節(jié)嚴(yán)重,采用開源框架的情況并不常見。但如果系統(tǒng)App也集成了Jetpack或第三方框架,開發(fā)效率則會大大提高。
前言
系統(tǒng)App開發(fā)者,很少采用Jetpack 以及第三方框架的原因主要有幾點(diǎn):
-
導(dǎo)入麻煩:有的框架過于龐大,可能依賴的庫比較多,編譯文件的構(gòu)建比較繁瑣,沒有g(shù)radle那么智能
-
功能單一:系統(tǒng)App注重功能性,業(yè)務(wù)邏輯較少,依賴龐大庫文件的場景不多
-
license風(fēng)險(xiǎn):引用第三方框架的話,需要特別聲明license ,會盡量避免采用
但對于功能復(fù)雜,架構(gòu)龐大的系統(tǒng)App而言,集成第三方框架顯得尤為必要。比如Android系統(tǒng)里最核心的App SystemUI,就采用了知名的DI框架Dagger2 。Dagger2的引入使得功能龐雜的SystemUI管理各個依賴模塊變得游刃有余。
SystemUI將Dagger2集成的方式給了我啟發(fā),探索和總結(jié)了Android 源碼中如何配置Jetpack 以及第三方庫,希望能夠幫到大家。
源碼編譯說明
與Gradle不同,源碼環(huán)境里的編譯構(gòu)建都是配置在.mk或者.bp文件里的,配置起來較為繁瑣。
.bp文件::Android.bp是用來替換Android.mk的配置文件,它使用Blueprint框架來解析。Blueprint是生成、解析Android.bp的工具,是Soong的一部分。Soong則是專為Android編譯而設(shè)計(jì)的工具,Blueprint只是解析文件的形式,而Soong則解釋內(nèi)容的含義,最終轉(zhuǎn)換成Ninja文件。下文bp 就是指.bp的文件
**注意:**以下基于Android 11上進(jìn)行的演示,Android 10及之前部分Jetpack框架沒有集成進(jìn)源碼,需留意
gradle切換到bp
gradle和bp的對比
看一個使用aar和注解庫的例子。
看一個AndroidStudio(以下簡稱AS)下build.gradle 文件里包的導(dǎo)入代碼:
dependencies {implementation 'androidx.appcompat:appcompat:1.2.0'implementation 'com.google.android.material:material:1.2.1'implementation 'androidx.constraintlayout:constraintlayout:2.0.1'//roomdef room_version = "2.3.0"implementation "androidx.room:room-runtime:$room_version"annotationProcessor "androidx.room:room-compiler:$room_version"
}
ROM環(huán)境里的編譯依賴.bp 配置如下:
android_app {......static_libs: [ "androidx.appcompat_appcompat", "com.google.android.material_material", "androidx-constraintlayout_constraintlayout", "androidx.room_room-runtime", ],plugins: ["androidx.room_room-compiler-plugin"],......
}
導(dǎo)入關(guān)鍵字的差異
依賴文件里的導(dǎo)入關(guān)鍵字:
在AS和AOSP里面導(dǎo)入包的關(guān)鍵字有些差異,又分為兩種情況。
build.gradle | .bp | |
---|---|---|
代碼庫 | implementation | static_libs |
注解使用的庫 | annotationProcessor | plugins |
引入庫文件(libs):比較常見。引入的方式有多種。下文會講具體的幾種方式。
引入注解庫:比較流行,源碼中使用比較繁瑣,下文會重點(diǎn)講解。
庫文件的導(dǎo)入規(guī)則
眼尖的同學(xué)已經(jīng)看出規(guī)律了
如:implementation ‘a(chǎn)ndroidx.appcompat:appcompat:1.2.0’
bp 文件中:androidx.appcompat_appcompat,將“:” 改為 “”即可,不需要加版本號。其實(shí)就是group 與 name 中間用“”連接,基本上符合上述規(guī)則,當(dāng)然也有特殊
注解庫的導(dǎo)入規(guī)則
如今框架流行注解編程。
gradle 配置:annotationProcessor “androidx.room:room-compiler:$room_version”
bp 中就需要使用到plugins,對應(yīng)配置plugins: [“androidx.room_room-compiler-plugin”]
根據(jù)jar 包的規(guī)則,那plugin 命名應(yīng)該是“:” 改為 ”_" version+“-plugin” 。
SystemUI 使用Dagger2配置 plugins: [“dagger2-compiler-2.19”],所以命名規(guī)則并不是上文猜測的那樣。
那如何確定Jetpack框架的名稱呢?
確定Jetpack框架的名稱
源碼編譯,所有的內(nèi)容和都在源碼中,都需要在源碼環(huán)境中尋找。
以Room 為例
在prebuilts/sdk/current/androidx/Android.bp 配置了引入jar包 中有如下配置
android_library {name: "androidx.room_room-runtime",//名稱......manifest: "manifests/androidx.room_room-runtime/AndroidManifest.xml",//配置manifaststatic_libs: [//兩個room庫文件,三個依賴的庫文件"androidx.room_room-runtime-nodeps","androidx.room_room-common","androidx.sqlite_sqlite-framework","androidx.sqlite_sqlite","androidx.arch.core_core-runtime",],
}
插件配置在prebuilts/sdk/current/androidx/JavaPlugins.bp
java_plugin {name: "androidx.room_room-compiler-plugin",//名稱static_libs: [//1個room庫文件,1個依賴的庫文件"androidx.room_room-compiler","kotlin-reflect"],processor_class: "androidx.room.RoomProcessor",//需要指定處理的類
}
注意:AS 開發(fā) 并不需要配置 “processor_class”,我反編譯了room-compiler,找到了RoomProcessor.java.(AS 為什么不需要指定,我這里我就不研究了)
看下圖,META-INF/services/javax.annotation.processing.Processor 文件中配置了RoomProcessor.java(就按照這個文件配置就可以了)
如何確定源碼中哪些jetpack 庫可以使用呢?
在Android.bp 中搜索,或者看androidx目錄下包含了什么
prebuilts/sdk/current/androidx/m2repository/androidx$ ls
導(dǎo)入第三方的開源框架
以上講的是引入Jetpack相關(guān)jar包,其他常見的是否包含呢?如Glide,它是不屬于androidx 的
第三方庫,Android 源碼中整理就不算好了,使用比較亂。下面我梳理下
導(dǎo)入下載的jar包
大家最常用的,把 jar 包 放到 libs,就可以了(當(dāng)然,比較簡單,與其他庫關(guān)聯(lián)較少可以采用此種方式)
java_import {name: "disklrucache-jar",jars: ["disklrucache-4.12.0.jar"],sdk_version: "current",
}
android_library_import {name: "glide-4.12.0",aars: ["glide-4.12.0.aar"],sdk_version: "current",
}
android_library_import {name: "gifdecoder-4.12.0",aars: ["gifdecoder-4.12.0.aar",],sdk_version: "current",
}
android_library_import {name: "exifinterface-1.2.0",aars: ["exifinterface-1.2.0.aar",],sdk_version: "current",
}
android_app {......static_libs: ["disklrucache-jar","glide-4.12.0","gifdecoder-4.12.0","exifinterface-1.2.0"],
}
導(dǎo)入AOSP內(nèi)置的jar包
常用第三方放在了prebuilts/tools/common/m2/repository/下面包含了很多庫文件,如Glide,Okhttp,但比較尷尬的是,.bp文件并沒有寫好。應(yīng)用需要自己編寫,編寫方式可以參考上文。
以后google應(yīng)該會把 external 下 的整合到這個里面,可以關(guān)注下prebuilts/tools/common/m2/repository 中Android.bp文件的變化。
如:prebuilts/maven_repo/bumptech/Android.bp
java_import {name: "glide-prebuilt",jars: ["com/github/bumptech/glide/glide/4.8.0/glide-4.8.0.jar","com/github/bumptech/glide/disklrucache/4.8.0/disklrucache-4.8.0.jar","com/github/bumptech/glide/gifdecoder/4.8.0/gifdecoder-4.8.0.jar",],jetifier: true,notice: "LICENSE",
}
Android.bp 直接用"glide"了
static_libs: ["glide-prebuilt"],
導(dǎo)入jar包源碼
external 下面 很多第三方庫的源碼,如Glide的源碼,目錄為external/glide/
android_library {name: "glide",srcs: ["library/src/**/*.java","third_party/disklrucache/src/**/*.java","third_party/gif_decoder/src/**/*.java","third_party/gif_encoder/src/**/*.java",],manifest: "library/src/main/AndroidManifest.xml",libs: ["android-support-core-ui","android-support-compat","volley",],static_libs: ["android-support-fragment",],sdk_version: "current",
}復(fù)制代碼
App 的Android.bp 直接用"glide"了
static_libs: ["glide"],
以上三種方式都是引入 Android 中源碼存在的。不存在怎么辦,Android源碼 不像 AS,連上網(wǎng),配置下版本號就可以下載。
內(nèi)置新的Jetpack框架
引入第三方庫文件方式,方式一:aar包導(dǎo)入。就可以。但這里不討論,找些復(fù)雜的,包含annotationProcessor(bp 中的plugin) 。Hilt 是 Google 相對較新的框架。
Hilt基于Dagger2開發(fā),又針對Android進(jìn)行了專屬的DI優(yōu)化。
所以在導(dǎo)入Dagger2和它的依賴文件之外還需要導(dǎo)入Hilt專屬的一堆庫和依賴文件。
1. 獲取框架的庫文件
一般來說AS里導(dǎo)入完畢的目錄下即可獲取到對應(yīng)的庫文件,路徑一般在 :C:\Users\xxx.gradle\caches\modules-2\files-2.1\com.google.dagger\hilt-android
2. 確定額外的依賴文件
為什么需要額外的依賴文件?
完全依賴AS開發(fā)可能不知道,導(dǎo)入的包的同時可能引入其他的包。
如Hilt的是在dagger2基礎(chǔ)上開發(fā),當(dāng)然會引入Dagger2,
使用注解,需要javax.annotation包。
Dagger2,javax.annotation 在Gradle 自動下載好的,非項(xiàng)目中明確配置的,我們稱之為依賴包。
使用Gradle 自動下載,都會有pom 文件?!癲ependency”,表示需要依賴的jar 包,還包含了版本號等
如:hilt-android-2.28-alpha.pom
`<dependency>``<groupId>com.google.dagger</groupId>``<artifactId>dagger</artifactId>` //依賴的dagger2`<version>2.28</version>`//dagger2的版本
`</dependency>`
`<dependency>``<groupId>com.google.dagger</groupId>` `<artifactId>dagger-lint-aar</artifactId>``<version>2.28</version>`
`</dependency>`
`<dependency>``<groupId>com.google.code.findbugs</groupId>``<artifactId>jsr305</artifactId>``<version>3.0.1</version>`
`</dependency>`
......
3. 導(dǎo)入需要的依賴文件
比如SystemUI,已經(jīng)導(dǎo)入了一些文件,只要導(dǎo)入剩余的文件即可。
一般常用的 源碼中都是存在的,決定copy 之前,可以看下先源碼中是否存在,存在可以考慮使用。
當(dāng)然也有例外,如Hilt 我依賴的是源碼中dagger2是2.19 版本,編譯中報(bào)錯,沒有找到dagger2 中的class,反編譯jar確實(shí)不存在,使用2.28 的dagger 版本,問題就解決了。所以說可能存在庫文件版本較老的情況。
以下就是新增的文件夾,其中manifests 后文中有講。
manifests/ repository/com/google/dagger/dagger-compiler/2.28/repository/com/google/dagger/dagger-producers/2.28/repository/com/google/dagger/dagger-spi/2.28/repository/com/google/dagger/dagger/2.28/repository/com/google/dagger/hilt-android-compiler/repository/com/google/dagger/hilt-android/
4. 編寫最終的bp文件
這一步就是把依賴的包,關(guān)聯(lián)起來,根據(jù)上文的 pom 文件。
- 配置dagger2 2.28 的jar
java_import {name: "dagger2-2.28",jars: ["repository/com/google/dagger/dagger/2.28/dagger-2.28.jar"],host_supported: true,}
- 配置 dagger2-compiler 2.28 的jar (annotationProcessor 依賴的jar包)
java_import_host {name: "dagger2-compiler-2.28-import",jars: ["repository/com/google/dagger/dagger-compiler/2.28/dagger-compiler-2.28.jar","repository/com/google/dagger/dagger-producers/2.28/dagger-producers-2.28.jar","repository/com/google/dagger/dagger-spi/2.28/dagger-spi-2.28.jar","repository/com/google/dagger/dagger/2.28/dagger-2.28.jar","repository/com/google/guava/guava/25.1-jre/guava-25.1-jre.jar","repository/com/squareup/javapoet/1.11.1/javapoet-1.11.1.jar","repository/com/google/dagger/dagger-google-java-format/1.6/google-java-format-1.6-all-deps.jar",],
}
- 配置dagger2 的 plugin (annotationProcessor)
java_plugin {name: "dagger2-compiler-2.28",static_libs: ["dagger2-compiler-2.28-import","jsr330",],processor_class: "dagger.internal.codegen.ComponentProcessor",generates_api: true,
}
- 配置 hilt 依賴的aar包
android_library_import {name: "hilt-2.82-nodeps",aars: ["repository/com/google/dagger/hilt-android/2.28-alpha/hilt-android-2.28-alpha.aar"],sdk_version: "current",apex_available: ["//apex_available:platform","//apex_available:anyapex",],min_sdk_version: "14",static_libs: ["dagger2-2.28","jsr305","androidx.activity_activity","androidx.annotation_annotation","androidx.fragment_fragment",],}
-
配置hilt 的包
android_library 表示 aar 包,所以必須要配置manifests ,在上文中多出的manifasts文件夾中 放的就是這個文件,AndroidManifest.xml來自hilt-android-2.28-alpha.aar 中
android_library {name: "hilt-2.82",manifest: "manifests/dagger.hilt.android/AndroidManifest.xml",static_libs: ["hilt-2.82-nodeps","dagger2-2.28"],......
}
- 配置 hilt-compiler 2.82 jar包
java_import_host {name: "hilt-compiler-2.82-import",jars: ["repository/com/google/dagger/dagger-compiler/2.28/dagger-compiler-2.28.jar","repository/com/google/dagger/dagger-producers/2.28/dagger-producers-2.28.jar","repository/com/google/dagger/dagger-spi/2.28/dagger-spi-2.28.jar","repository/com/google/dagger/dagger/2.28/dagger-2.28.jar","repository/com/google/guava/guava/25.1-jre/guava-25.1-jre.jar","repository/com/squareup/javapoet/1.11.1/javapoet-1.11.1.jar","repository/com/google/dagger/dagger-google-java-format/1.6/google-java-format-1.6-all-deps.jar","repository/com/google/dagger/hilt-android-compiler/2.28-alpha/hilt-android-compiler-2.28-alpha.jar","repository/javax/inject/javax.inject/1/javax.inject-1.jar"],
}
-
配置hilt的 plugin (annotationProcessor)
反編譯查看需要配置的Processer
好吧,看到上圖我傻眼了,11個。下文代碼我只貼了一個,需要寫11個,其他省略。
java_plugin {name: "hilt-compiler-2.82",static_libs: ["hilt-compiler-2.82-import","jsr330",],processor_class: "dagger.hilt.processor.internal.root.RootProcessor",generates_api: true,
}
- 項(xiàng)目中引用
`static_libs: [``"androidx-constraintlayout_constraintlayout",``"androidx.appcompat_appcompat",``"com.google.android.material_material",``"androidx.room_room-runtime",``"androidx.lifecycle_lifecycle-viewmodel",``"androidx.lifecycle_lifecycle-livedata",``"hilt-2.82",``"jsr330"``],``plugins: ["androidx.room_room-compiler-plugin",``"hilt-compiler-2.82",``"hilt-compiler-2.82-UninstallModulesProcessor",``"hilt-compiler-2.82-TestRootProcessor",``"hilt-compiler-2.82-DefineComponentProcessor",``"hilt-compiler-2.82-BindValueProcessor",``"hilt-compiler-2.82-CustomTestApplicationProcessor",``"hilt-compiler-2.82-AndroidEntryPointProcessor",``"hilt-compiler-2.82-AggregatedDepsProcessor",``"hilt-compiler-2.82-OriginatingElementProcessor",``"hilt-compiler-2.82-AliasOfProcessor",``"hilt-compiler-2.82-GeneratesRootInputProcessor",``],`
-
編譯確認(rèn)
編譯失敗了!看到報(bào)錯,我的心也涼了。需要配置Gradle 插件。bp 可以配置Gradle插件?
看了下com/google/dagger/hilt-android-gradle-plugin/,但是并不清楚bp 怎么配置,在源碼里,只知道一處:prebuilts/gradle-plugin/Android.bp,但并沒有嘗試成功。有興趣的同學(xué),可以研究下。
而且hilt-android-gradle-plugin 的jar包,依賴包 至少十幾個。
public class MainActivity extends AppCompatActivity { ^ Expected @AndroidEntryPoint to have a value. Did you forget to apply the Gradle Plugin? [Hilt] Processing did not complete. See error above for details.
public class MainFragment extends BaseFragment { ^ Expected @AndroidEntryPoint to have a value. Did you forget to apply the Gradle Plugin? [Hilt] Processing did not complete. See error above for details.
public class AppApplication extends Application { ^ Expected @HiltAndroidApp to have a value. Did you forget to apply the Gradle Plugin? [Hilt] Processing did not complete. See error above for details.
雖然Hilt引入失敗,但是整個過程我覺得有必要分享一下,給大家一些導(dǎo)入新框架的參考。
源碼環(huán)境里集成開源框架的流程
常用開源框架的對照表
build.gradle | Android.bp | AOSP源碼位置 |
---|---|---|
androidx.appcompat:appcompat | androidx.appcompat_appcompat | /sdk/current/androidx/Android.bp |
androidx.core:core | androidx.core_core | prebuilts/sdk/current/androidx/Android.bp |
com.google.android.material:material | com.google.android.material_material | prebuilts/sdk/current/extras/material-design-x/Android.bp |
androidx.constraintlayout:constraintlayout | androidx-constraintlayout_constraintlayout | prebuilts/sdk/current/extras/constraint-layout-x/Android.bp |
androidx.lifecycle:lifecycle-livedata | androidx.lifecycle_lifecycle-livedata | prebuilts/sdk/current/androidx/Android.bp |
androidx.lifecycle:lifecycle-viewmodel | androidx.lifecycle_lifecycle-viewmodel | prebuilts/sdk/current/androidx/Android.bp |
androidx.recyclerview:recyclerview | androidx.recyclerview_recyclerview | prebuilts/sdk/current/androidx/Android.bp |
androidx.annotation:annotation | androidx.annotation_annotation | prebuilts/sdk/current/androidx/Android.bp |
androidx.viewpager2:viewpager2 | androidx.viewpager2_viewpager2 | prebuilts/sdk/current/androidx/Android.bp |
androidx.room:room-runtime | androidx.room_room-runtime | prebuilts/sdk/current/androidx/Android.bp |
glide | glide-prebuilt | prebuilts/maven_repo/bumptech/Android.bp |
gson | gson-prebuilt-jar | prebuilts/tools/common/m2/Android.bp |
Robolectric相關(guān) | Robolectric相關(guān) | prebuilts/tools/common/m2/robolectric.bp |
經(jīng)驗(yàn)總結(jié)
1、build.gradle 需要配置 額外插件的,如hilt、databinding viewbinding 不建議使用源碼編譯。
2、建議使用 AOSP 源碼 中 bp 已經(jīng)配置好的。這樣就可以直接使用了。
3、jetpack 包引入或者androidx 引入,建議先prebuilts/sdk/current/androidx 下尋找配置好的bp 文件
4、非androidx ,建議先在prebuilts/tools/common/m2下尋找尋找配置好的bp 文件
5、文章中的例子都是prebuilts目錄下配置,項(xiàng)目中使用,也可以配置在項(xiàng)目中,都是可以的。