主頁 > 移動端開發 > Gradle進階計劃(二)Gradle Plugin原理分析

Gradle進階計劃(二)Gradle Plugin原理分析

2021-02-01 12:56:23 移動端開發

通過 Gradle進階計劃(一)Gradle初探 的介紹,我們已經對Gradle有了初步的了解,這篇文章我們更深入研究一下 Gradle Plugin 的原理,

一、Gradle 和 Gradle Plugin

首先,我們需要先明確一個概念,就是 Gradle Gradle Plugin 是不同的,

(一)Gradle

結合上一篇文章,官方已經對Gradle已經有了很詳細的定義,這里在重點解釋一下,

Gradle 是一個構建專案的工具,將它用來編譯Android App能夠簡化你的編譯、打包、測驗程序,它其實不僅僅是用在Android Studio上,如何去理解構建工具呢?構建工具就是對你的專案進行編譯、運行、簽名、打包、依賴管理等一系列功能的合集,例如 Eclipse 最初是用來做 Java 開發的,Google 為了能在 Eclipse 上進行Android 開發,開發了ADT 插件(Android Developer Tools),正是因為有了 ADT ,我們才可以在 Eclipse 上進行編譯、運行、簽名、打包等一系列流程,而這背后的作業都是 ADT 的功勞,ADT 就是我們的構建工具,一般來說,構建工具除了以上提到的編譯、運行、簽名、打包等,還具備依賴管理的功能,什么是依賴管理呢?例如我們以前在 Eclipse 上開發 Android 參考第三方庫,一般都是先下載 jar 檔案,然后把 jar 檔案添加到 libs 目錄,依賴管理就是將這個程序自動化,

在 Gradle 之前也是 Android 也有其他構建工具的,這就是大名鼎鼎的 Maven,Java 世界中主要有三大構建工具:Ant、Maven 和 Gradle,經過幾年的發展,Ant 幾乎銷聲匿跡,所以在早期 Android 開發中,是使用 Maven 作為構建工具的,但是 Gradle 相較于 Maven 有著較大的優勢,所以 AS 時代,Google 用 Gradle 替代了 Maven 作為 Android 開發的構建工具,

  • Gradle 對于依賴的管理更加的簡潔,不需要像 Maven 定義 groupId、artifactId、version 等繁瑣的屬性值;
  • Gradle 支持動態的版本依賴,在版本號后面使用+號的方式可以實作動態的版本管理;
  • Gradle 在解決依賴沖突方面實作機制更加明確,使用 Maven 和 Gradle 進行依賴管理時都采用的是傳遞性依賴;而如果多個依賴項指向同一個依賴項的不同版本時就會引起依賴沖突,而 Maven 處理這種依賴關系往往是噩夢一般的存在;
  • Gradle 多模塊構建方面具有優勢,相較于 Maven 聚合 POM 的形式,Gradle allprojects 和 subprojects 的定義方法更加的方便和清晰;
  • Gradle 在插件機制的支持上做的更好,Maven 配置語法太受限于XML,Gradle中則一切變得非常簡單,

(二)Gradle Plugin

為了支持 Gradle 能在 AS 上使用,Google 開發了一個 AS 的插件叫 Android Gradle Plugin ,所以我們能在 AS 上使用 Gradle 完全是因為這個插件的原因,它一邊呼叫 Gradle 本身的代碼和批處理工具來構建專案,一邊呼叫 Android SDK 的編譯、打包功能,從而讓我們能夠順暢地在AS上進行開發,

Gradle Plugin 是獨立于Android Studio 運行的,它的更新也是與Android Studio分開的,Gradle Plugin 會有版本號,每個版本號又對應有一個或一些 Gradle發行版本(一般是限定一個最低版本),這也是為什么如果這兩個版本對應不上了,你的工程構建的時候會報錯,

插件版本Gradle版本
1.0.0 - 1.1.32.2.1 - 2.3
1.2.0 - 1.3.12.2.1 - 2.9
1.5.02.2.1 - 2.13
2.0.0 - 2.1.22.10 - 2.13
2.1.3 - 2.2.32.14.1+
2.3.0+3.3+
3.0.0+4.1+
3.1.0+4.4+

Android Studio 3.0 之后自動將插件版本升級到3.0.0,所以我們也需要對應地把Gradle升級到4.1才行,

其實前面我們還提到了Gradle Wrapper,這里再簡單說一下,

Gradle Wrapper:意為 Gradle 的包裝,它的作用是簡化Gradle本身的安裝、部署,不同版本的專案可能需要不同版本的Gradle,手工部署的話比較麻煩,而且可能產生沖突,所以需要Gradle Wrapper幫你搞定這些事情,Gradle Wrapper是Gradle專案的一部分,

假設我們本地有多個專案,一個是比較老的專案,還用著 Gradle 1.0 的版本,一個是比較新的專案用了 Gradle 2.0 的版本,但是你兩個專案肯定都想要同時運行的,如果你只裝了 Gradle 1.0 的話那肯定不行,所以為了解決這個問題,Google 推出了 Gradle Wrapper 的概念,它在你每個專案都配置了一個指定版本的 Gradle ,你可以理解為每個 Android 專案本地都有一個小型的 Gradle ,通過這個每個專案你可以支持用不同的 Gradle 版本來構建專案,

總結:

Gradle:是一個構建工具,版本定義在 gradle-wrapper.properties中的distributionUrl=https/://services.gradle.org/distributions/gradle-x.xx-all.zip
Gradle Plugin:是谷歌為使用Gradle而自行開發的工具,版本定義在 build.gradle中依賴的classpath 'com.android.tools.build:gradle:x.x.x'

二、Gradle Plugin 主要流程

對于原始碼的分析這里就不展開講了,詳情可參照 android gradle plugin 原始碼地址,我只介紹一下涉及到的主要流程,

Android gradle plugin 的入口類 com.android.build.gradle.AppPlugin,這個可以查看 properties 檔案,里面宣告了對應插件的入口類,

AppPlugin 繼承自 BasePlugin,AppPlugin 里沒有做太多的操作,主要是重寫了 createTaskManager 和 createExtension,剩下的大部分作業還是在 BasePlugin 里做的,

有幾點需要注意:

  • build.gradle 里見到的 android {} dsl 是在 BasePlugin.configureExtension() 里宣告的
  • 主要的 task 是在 BasePlugin.createAndroidTasks() 里生成的
  • 主要 task 的實作可以在 TaskManager 中找到
  • transform 會轉化成 TransformTask

三、主要 Task 分析

我們先看一下,生成一個 APK 所需的構建流程是怎樣的,官方流程圖如下:

下面是詳細的打包流程圖:

(1)打包資源檔案,使用aapt來打包res資源檔案,生成R.java、resources.arsc和res檔案,R.java檔案是所有res資源的id串列,resources.arsc里面會對所有的資源id進行組裝,在apk運行時獲取資源的時候會根據設備的情況獲得不同的資源,
(2)處理aidl檔案,生成相應java 檔案,這個階段aidl會處理.aidl檔案,生成對應的Java介面檔案,對于沒有使用到aidl的android工程,可以跳過此步驟,
(3)編譯工程源代碼,生成相應class 檔案,通過javac編譯R.java、Java介面檔案、Java源檔案,生成.class檔案,如果有配置混淆的話,會編譯成混淆的class檔案,
(4)轉換所有class檔案,生成classes.dex檔案,Android系統的Dalvik虛擬機的可執行檔案為DEX格式,程式運行所需的class.dex就是在這一步生成的,使用到的工具為dx,主要的作業是將java位元組碼轉換為Dalvik位元組碼、壓縮常量池、消除冗余資訊等,
(5)打包生成apk,apkbuilder將classes.dex、resources.arsc、res檔案夾(res/raw資源被原裝不動地打包進APK之外,其它的資源都會被編譯或者處理)、Other Resources(assets檔案夾)、AndroidManifest.xml打包成apk檔案,
(6)對apk檔案進行簽名,通過jarsigner對apk進行簽名,
(7)對簽名后的apk檔案進行對其處理,通過zipalign對簽名后的apk進行對齊處理,它能夠對打包后的app進行優化,

那么以 Task 的維度來看 apk 的打包,是什么流程呢?通過執行下面的命令,可以列印出打包一個 apk 需要哪些 task ,

./gradlew android-gradle-plugin-source:assembleDebug --console=plain

輸出結果如下:

:android-gradle-plugin-source:preBuild UP-TO-DATE
:android-gradle-plugin-source:preDebugBuild
:android-gradle-plugin-source:compileDebugAidl
:android-gradle-plugin-source:compileDebugRenderscript
:android-gradle-plugin-source:checkDebugManifest
:android-gradle-plugin-source:generateDebugBuildConfig
:android-gradle-plugin-source:prepareLintJar UP-TO-DATE
:android-gradle-plugin-source:generateDebugResValues
:android-gradle-plugin-source:generateDebugResources
:android-gradle-plugin-source:mergeDebugResources
:android-gradle-plugin-source:createDebugCompatibleScreenManifests
:android-gradle-plugin-source:processDebugManifest
:android-gradle-plugin-source:splitsDiscoveryTaskDebug
:android-gradle-plugin-source:processDebugResources
:android-gradle-plugin-source:generateDebugSources
:android-gradle-plugin-source:javaPreCompileDebug
:android-gradle-plugin-source:compileDebugJavaWithJavac
:android-gradle-plugin-source:compileDebugNdk NO-SOURCE
:android-gradle-plugin-source:compileDebugSources
:android-gradle-plugin-source:mergeDebugShaders
:android-gradle-plugin-source:compileDebugShaders
:android-gradle-plugin-source:generateDebugAssets
:android-gradle-plugin-source:mergeDebugAssets
:android-gradle-plugin-source:transformClassesWithDexBuilderForDebug
:android-gradle-plugin-source:transformDexArchiveWithExternalLibsDexMergerForDebug
:android-gradle-plugin-source:transformDexArchiveWithDexMergerForDebug
:android-gradle-plugin-source:mergeDebugJniLibFolders
:android-gradle-plugin-source:transformNativeLibsWithMergeJniLibsForDebug
:android-gradle-plugin-source:transformNativeLibsWithStripDebugSymbolForDebug
:android-gradle-plugin-source:processDebugJavaRes NO-SOURCE
:android-gradle-plugin-source:transformResourcesWithMergeJavaResForDebug
:android-gradle-plugin-source:validateSigningDebug
:android-gradle-plugin-source:packageDebug
:android-gradle-plugin-source:assembleDebug

下面列出了各個 task 的實作類及作用:

Task對應實作類作用
preBuild 空 task,只做錨點使用
preDebugBuild 空 task,只做錨點使用,與 preBuild 區別是這個 task 是 variant 的錨點
compileDebugAidlAidlCompile處理 aidl
compileDebugRenderscriptRenderscriptCompile處理 renderscript
checkDebugManifestCheckManifest檢測 manifest 是否存在
generateDebugBuildConfigGenerateBuildConfig生成 BuildConfig.java
prepareLintJarPrepareLintJar拷貝 lint jar 包到指定位置
generateDebugResValuesGenerateResValues生成 resvalues,generated.xml
generateDebugResources 空 task,錨點
mergeDebugResourcesMergeResources合并資源檔案
createDebugCompatibleScreenManifestsCompatibleScreensManifestmanifest 檔案中生成 compatible-screens,指定螢屏適配
processDebugManifestMergeManifests合并 manifest 檔案
splitsDiscoveryTaskDebugSplitsDiscovery生成 split-list.json,用于 apk 分包
processDebugResourcesProcessAndroidResourcesaapt 打包資源
generateDebugSources 空 task,錨點
javaPreCompileDebugJavaPreCompileTask生成 annotationProcessors.json 檔案
compileDebugJavaWithJavacAndroidJavaCompile編譯 java 檔案
compileDebugNdkNdkCompile編譯 ndk
compileDebugSources 空 task,錨點使用
mergeDebugShadersMergeSourceSetFolders合并 shader 檔案
compileDebugShadersShaderCompile編譯 shaders
generateDebugAssets 空 task,錨點
mergeDebugAssetsMergeSourceSetFolders合并 assets 檔案
transformClassesWithDexBuilderForDebugDexArchiveBuilderTransformclass 打包 dex
transformDexArchiveWithExternalLibsDexMergerForDebugExternalLibsMergerTransform打包三方庫的 dex,在 dex 增量的時候就不需要再 merge 了,節省時間
transformDexArchiveWithDexMergerForDebugDexMergerTransform打包最終的 dex
mergeDebugJniLibFoldersMergeSouceSetFolders合并 jni lib 檔案
transformNativeLibsWithMergeJniLibsForDebugMergeJavaResourcesTransform合并 jnilibs
transformNativeLibsWithStripDebugSymbolForDebugStripDebugSymbolTransform去掉 native lib 里的 debug 符號
processDebugJavaResProcessJavaResConfigAction處理 java res
transformResourcesWithMergeJavaResForDebugMergeJavaResourcesTransform合并 java res
validateSigningDebugValidateSigningTask驗證簽名
packageDebugPackageApplication打包 apk
assembleDebug 空 task,錨點

以上就是打包一個 APK 所需要的 Task,在分析主要Task之前,我們先了解一下 Task 的分類,

在 Gradle Plugin 中的 Task 主要有三種:

(1)普通 Task

  • 一般繼承 DefaultTask;
  • 看 @TaskAction 注解的方法,此方法就是這個 Task 做的事情

(2)增量 Task:相對于全量來說的,全量我們可以理解為呼叫 clean 以后第一次編譯的程序,這個就是全量編譯,之后修改了代碼或者資源檔案,再次編譯,就是增量編譯,

  • 首先這個 Task 要繼承 IncrementalTask;
  • 其次看 isIncremental 方法,如果回傳 true,說明支持增量,回傳 false 則不支持;
  • 然后看 doFullTaskAction 方法,是全量的時候執行的操作;
  • 最后看 doIncrementalTaskAction 方法,這里是增量的時候執行的操作,

(3)Transform:這個后面我會專門出一篇文章來講,

  • 繼承自 Transform;
  • 重點關注 transform 方法實作,

1. generateDebugBuildConfig

(1)實作類:GenerateBuildConfig

(2)整體實作:

(3)代碼呼叫:

GenerateBuildConfig.generate -> BuildConfigGenerator.generate -> JavaWriter

(4)分析實作:

在 GenerateBuildConfig 中,主要生成代碼的步驟如下:

  • 生成 BuildConfigGenerator
  • 添加默認的屬性,包括 DEBUG,APPLICATION_ID,FLAVOR,VERSION_CODE,VERSION_NAME
  • 添加自定義屬性
  • 呼叫 JavaWriter 生成 BuildConfig.java 檔案

2. mergeDebugResources

(1)實作類:MergeResources

(2)整體實作:

(3)代碼呼叫:

MergeResources.doFullTaskAction -> ResourceMerger.mergeData -> MergedResourceWriter.end 
-> QueueableAapt2.compile -> Aapt2QueuedResourceProcessor.compile -> AaptProcess.compile 
-> AaptV2CommandBuilder.makeCompile

(4)分析實作:

MergeResources 這個類,繼承自 IncrementalTask,我們重點關注 doFullTaskAction 這個全量方法,

  • 通過 getConfiguredResourceSets() 獲取 resourceSets,包括了自己的 res/ 和 依賴庫的 res/ 以及 build/generated/res/rs
  • 創建 ResourceMerger
  • 創建 QueueableResourceCompiler,因為 gradle3.x 以后支持了 aapt2,所以這里有兩種選擇 aapt 和 aapt2,其中 aapt2 有三種模式,OutOfProcessAaptV2,AaptV2Jni,QueueableAapt2,這里默認創建了 QueueableAapt2,resourceCompiler = QueueableAapt2
  • 將第一步獲取的 resourceSet 加入 ResourceMerger 中
  • 創建 MergedResourceWriter
  • 呼叫 ResourceMerger.mergeData 合并資源
  • 呼叫 MergedResourceWriter 的 start(),addItem(),end() 方法
  • 呼叫 QueueableAapt2 -> Aapt2QueuedResourceProcessor -> AaptProcess 處理資源,這一步呼叫 aapt2 命令去處理資源,處理完以后 xxx.xml.flat 格式

3. processDebugResources

(1)實作類:ProcessAndroidResources

(2)整體實作:

(3)代碼呼叫:

ProcessAndroidResources.doFullTaskAction -> ProcessAndroidResources.invokeAaptForSplit 
-> AndroidBuilder.processResources -> QueueAapt2.link -> Aapt2QueuedResourceProcessor.link 
-> AaptProcess.link -> AaptV2CommandBuilder.makeLink

(4)分析實作:

  • 獲取 split 資料,回傳的是一個 ApkData 串列,ApkData 有三個子類,分別是 Main,Universal,FullSplit,這里的 ApkData 會回傳一個 Universal 和多個 FullSplit,Universal 代表的是主 apk,FullSplit 就是根據螢屏密度拆分的 apk,如果我們沒有配置 splits apk,那么這里只會回傳一個 Main 的實體,標識完整的 apk,
  • 處理 main 和 不依賴 density 的 ApkData 資源
  • 呼叫 invokeAaptForSplit 處理資源
  • 呼叫 AndroidBuilder.processResources -> QueueAapt2.link -> Aapt2QueuedResourceProcessor.link -> AaptProcess.link -> AaptV2CommandBuilder.makeLink 處理資源,生成資源包以及 R.java 檔案
  • 處理其他 ApkData 資源,這里只會生成資源包而不會生成 R.java 檔案

4. processDebugManifest

(1)實作類:MergeManifests

(2)整體實作:

(3)代碼呼叫:

MergeManifests.dofFullTaskAction -> AndroidBuilder.mergeManifestsForApplication 
-> Invoker.merge -> ManifestMerge2.merge

(4)分析實作:

這個 task 功能主要是合并 mainfest,包括 module 和 flavor 里的,整個程序通過 MergingReport,ManifestMerger2 和 XmlDocument 進行,
這里直接看 ManifestMerger2.merge() 的 merge 程序 , 主要有幾個步驟:

  • 獲取依賴庫的 manifest 資訊,用 LoadedManifestInfo 標識
  • 獲取主 module 的 manifest 資訊
  • 替換主 module 的 Manifest 中定義的某些屬性,替換成 gradle 中定義的屬性 例如: package, version_code, version_name, min_sdk_versin 等
  • 合并 flavor,buildType 中的 manifest
  • 合并依賴庫的 manifest
  • 處理 manifest 的 placeholders
  • 之后對最終合并后的 manifest 中的一些屬性重新進行一次替換,類似步驟 4
  • 保存 manifest 到 build/intermediates/manifest/fullxxx/AndroidManifest.xml 這就生成了最終的 Manifest 檔案

5. transformClassesWithDexBuilderForDebug

(1)實作類:DexArchiveBuilderTransform

(2)整體實作:

(3)代碼呼叫:

DexArchiveBuilderTransform.transform -> DexArchiveBuilderTransform.convertJarToDexArchive 
-> DexArchiveBuilderTransform.convertToDexArchive -> DexArchiveBuilderTransform.launchProcessing 
-> DxDexArchiveBuilder.convert

(4)分析實作:

在 DexArchiveBuilderTransform 中,對 class 的處理分為兩種方式,一種是對 目錄下的 class 進行處理,一種是對 .jar 里的 class 進行處理,
為什么要分為這兩種方式呢?.jar 中的 class 一般來說都是依賴庫,基本上不會改變,gradle 在這里做了一個快取,但是兩種方式最終都會呼叫到 convertToDexArchive,

  • convertJarToDexArchive 處理 jar,處理 .jar 時,會對 jar 包中的每一個 class 都單獨打成一個 .dex 檔案,之后還是放在 .jar 包中
  • convertToDexArchive 處理 dir 以及 jar 的后續處理, 對 dir 處理使用 convertToDexArchive,其中會呼叫 launchProcessing,在 launchProcessing 中,有下面幾個步驟:a)判斷目錄下的 class 是否新增或者修改過 b)呼叫 DexArchiveBuilder.build 去處理修改過的 class c)DexArchiveBuilder 有兩個子類,D8DexArchiveBuilder 和 DxDexArchiveBuilder,分別是呼叫 d8 和 dx 去打 dex

6. transformDexArchiveWithExternalLibsDexMergerForDebug / transformDexArchiveWithDexMergerForDebug

(1)實作類:ExternalLibsMergerTransform / DexMergerTransform

(2)整體實作:

(3)代碼呼叫:

// dx 
ExternalLibsMergerTransform / DexMergerTransform.transform -> DexMergerTransformCallable.call 
-> DxDexArchiveMerger.mergeDexArchives -> DxDexArchiveMerger.mergeMonoDex 
-> DexArchiveMergerCallable.call -> DexMerger.merge

// d8
ExternalLibsMergerTransform / DexMergerTransform.transform -> DexMergerTransformCallable.call 
-> D8DexArchiveMerger.mergeDexArchives -> 呼叫 D8 命令

(4)分析實作:

主要是處理依賴庫的 dex,把上一步生成的依賴庫的 dex merge 成一個 dex,

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/255249.html

標籤:其他

上一篇:Android學習記錄(二十一)

下一篇:android博客導航總結,以及個人常用android免費學習干貨(文章,視頻,矢量圖,字體等)資源分享?

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more