android14-release版本DocumentsUI移植到Android Studio

本文主要是受了https://github.com/siren-ocean/DocumentsUI 的启发。由于DocumentsUI依赖较少,所有拿来入门练手。

运行环境:

Android Studio Jellyfish | 2023.3.1
Build #AI-233.14808.21.2331.11709847, built on April 13, 2024
Runtime version: 17.0.10+0-17.0.10b1087.21-11572160 amd64
gradle plugin version:8.4.1
gradle version:8.6
gradle JDK:17.0.10

最终完整版可运行代码会在整理好后上传github。
一开始我是想使用低版本gradle,但是由于framework.jar下的android/content/Context.class 使用的是JDK17编译的,会导致编译报错:类文件具有错误的版本 61.0, 应为 52.0。所以就使用的JDK17(后面发现其实还是可以使用低版本的gradle和android studio 去引用高版本JDK的framework.jar)。
以下为过程简单记录。
1.新建工程,package命名为com.android.documentsui。
2.删除默认activity和res,将aosp 中packages/apps/DocumentsUI/src中的源码,res和manifestcopy到此工程。
3.minSdk修改为26,解决编译报错问题
4.添加依赖库

diff --git a/app/build.gradle b/app/build.gradle
--- a/app/build.gradle  (revision 1524766154bf21ffcb0738b7901e8d21a299013d)
+++ b/app/build.gradle  (revision 60b5398ef261ade6a1160d542027d9c8c7317e7b)
@@ -27,8 +27,24 @@
         targetCompatibility JavaVersion.VERSION_1_8
     }
 }
-
+configurations.all {
+    resolutionStrategy.eachDependency { DependencyResolveDetails details ->
+        if (details.requested.group == 'com.google.guava' && details.requested.name == 'listenablefuture') {
+            details.useTarget 'com.google.guava:guava:31.0.1-jre'
+        }
+    }
+}
 dependencies {
+    compileOnly files('libs/framework.jar')
+
+    implementation libs.legacy.support.v4
+    implementation libs.commons.compress
+    // 添加 guava 依赖并排除 listenablefuture
+    implementation ('com.google.guava:guava:31.0.1-jre') {
+        exclude group: 'com.google.guava', module: 'listenablefuture'
+    }
+    implementation libs.recyclerview
+    implementation libs.recyclerview.selection
 
     implementation libs.appcompat
     implementation libs.material
@@ -37,4 +53,30 @@
     testImplementation libs.junit
     androidTestImplementation libs.ext.junit
     androidTestImplementation libs.espresso.core
-}
\ No newline at end of file
+}
+
+
+gradle.projectsEvaluated {
+    tasks.withType(JavaCompile) {
+        options.compilerArgs.add("-Xbootclasspath/p:$rootProject.rootDir/app/libs/framework.jar")
+    }
+}
+
+preBuild {
+    doLast {
+        // 注意:iml的路径要根据自己的实际情况来写
+        def imlFile = file("../.idea/modules/app/DocumentsUI.app.main.iml")
+        try {
+            def parsedXml = (new XmlParser()).parse(imlFile)
+            def jdkNode = parsedXml.component[1].orderEntry.find { it.'@type' == 'jdk' }
+            parsedXml.component[1].remove(jdkNode)
+            def sdkString = "Android API " + android.compileSdkVersion.substring("android-".length()) + " Platform"
+            new groovy.util.Node(parsedXml.component[1], 'orderEntry', ['type': 'jdk', 'jdkName': sdkString, 'jdkType': 'Android SDK'])
+            groovy.xml.XmlUtil.serialize(parsedXml, new FileOutputStream(imlFile))
+        } catch (FileNotFoundException e) {
+
+        }
+    }
+
+}
+
Index: gradle/libs.versions.toml
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
--- a/gradle/libs.versions.toml (revision 1524766154bf21ffcb0738b7901e8d21a299013d)
+++ b/gradle/libs.versions.toml (revision 60b5398ef261ade6a1160d542027d9c8c7317e7b)
@@ -7,6 +7,10 @@
 material = "1.12.0"
 activity = "1.9.0"
 constraintlayout = "2.1.4"
+recyclerview = "1.2.1"
+recyclerviewSelection = "1.1.0"
+legacySupportV4 = "1.0.0"
+commonsCompress = "1.26.2"
 
 [libraries]
 junit = { group = "junit", name = "junit", version.ref = "junit" }
@@ -16,6 +20,10 @@
 material = { group = "com.google.android.material", name = "material", version.ref = "material" }
 activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
 constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
+recyclerview = { group = "androidx.recyclerview", name = "recyclerview", version.ref = "recyclerview" }
+recyclerview-selection = { group = "androidx.recyclerview", name = "recyclerview-selection", version.ref = "recyclerviewSelection" }
+legacy-support-v4 = { group = "androidx.legacy", name = "legacy-support-v4", version.ref = "legacySupportV4" }
+commons-compress = { group = "org.apache.commons", name = "commons-compress", version.ref = "commonsCompress" }
 

5.解決编译报错:元素值必须为常量表达式

diff --git a/gradle.properties b/gradle.properties
--- a/gradle.properties (revision 60b5398ef261ade6a1160d542027d9c8c7317e7b)
+++ b/gradle.properties (revision bbea8c3f04c21ac89801d301f162f787a1002c91)
@@ -18,4 +18,6 @@
 # Enables namespacing of each library's R class so that its R class includes only the
 # resources declared in the library itself and none from the library's dependencies,
 # thereby reducing the size of the R class for that library
-android.nonTransitiveRClass=true
\ No newline at end of file
+android.nonTransitiveRClass=true
+
+android.nonFinalResIds=false

6.把缺少的java/com/android/modules/utils/build 下的SdkLevel和UnboundedSdkLevel放入android studio工程。
7.解决缺少id问题。
部分id存在于
out/soong/.intermediates/packages/apps/DocumentsUI/DocumentsUI/android_common/R.txt 这个文件中。可以在android studio中新建ids.xml 文件。

diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml
new file mode 100644
--- /dev/null   (revision e64969f8df18fe4f2a8200c70a1a7e5ab1ce153c)
+++ b/app/src/main/res/values/ids.xml   (revision e64969f8df18fe4f2a8200c70a1a7e5ab1ce153c)
@@ -0,0 +1,20 @@
+<resources>
+    <item type="id" name="search_src_text" />
+    <item type="id" name="search_close_btn" />
+    <item type="id" name="action_mode_bar" />
+    <item type="id" name="option_menu_show_hidden_files" />
+    <item type="id" name="sub_menu_grid" />
+    <item type="id" name="sub_menu_list" />
+    <item type="id" name="dir_menu_create_dir" />
+
+    <item type="id" name="option_menu_create_dir" />
+    <item type="id" name="option_menu_search" />
+    <item type="id" name="option_menu_select_all" />
+    <item type="id" name="option_menu_debug" />
+
+    <item type="id" name="option_menu_sort" />
+
+    <item type="id" name="action_mode_close_button" />
+
+
+</resources>
\ No newline at end of file

8.添加DocumentsStatsLog文件
DocumentsStatsLog位于out/soong/.intermediates/packages/apps/DocumentsUI/statslog-docsui-java-gen/gen/com/android/documentsui/DocumentsStatsLog.java,把此文件copy至app/src/main/java/com/android/documentsui/DocumentsStatsLog.java。
9.解决其他编译语法报错

diff --git a/app/src/main/java/com/android/documentsui/DirectoryLoader.java b/app/src/main/java/com/android/documentsui/DirectoryLoader.java
--- a/app/src/main/java/com/android/documentsui/DirectoryLoader.java    (revision 0e3dfb4862f2129032c0d387b3e089e3426e418d)
+++ b/app/src/main/java/com/android/documentsui/DirectoryLoader.java    (revision d3a6a73d79a22f891e1f9a263687a2296b29afad)
@@ -100,7 +100,7 @@
         mPhotoPicking = state.isPhotoPicking();
     }
 
-    @Override
+    //@Override
     protected Executor getExecutor() {
         return ProviderExecutor.forAuthority(mRoot.authority);
     }
Index: app/src/main/java/com/android/documentsui/archives/WriteableArchive.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/app/src/main/java/com/android/documentsui/archives/WriteableArchive.java b/app/src/main/java/com/android/documentsui/archives/WriteableArchive.java
--- a/app/src/main/java/com/android/documentsui/archives/WriteableArchive.java  (revision 0e3dfb4862f2129032c0d387b3e089e3426e418d)
+++ b/app/src/main/java/com/android/documentsui/archives/WriteableArchive.java  (revision d3a6a73d79a22f891e1f9a263687a2296b29afad)
@@ -298,7 +298,7 @@
         synchronized (mEntries) {
             for (final String path : mPendingEntries) {
                 try {
-                    mZipOutputStream.putArchiveEntry(mEntries.get(path));
+                    mZipOutputStream.putArchiveEntry((ZipArchiveEntry)mEntries.get(path));
                     mZipOutputStream.closeArchiveEntry();
                 } catch (IOException e) {
                     Log.e(TAG, "Failed to flush empty entries.", e);
Index: app/src/main/java/com/android/documentsui/inspector/KeyValueRow.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/app/src/main/java/com/android/documentsui/inspector/KeyValueRow.java b/app/src/main/java/com/android/documentsui/inspector/KeyValueRow.java
--- a/app/src/main/java/com/android/documentsui/inspector/KeyValueRow.java  (revision 0e3dfb4862f2129032c0d387b3e089e3426e418d)
+++ b/app/src/main/java/com/android/documentsui/inspector/KeyValueRow.java  (revision d3a6a73d79a22f891e1f9a263687a2296b29afad)
@@ -98,8 +98,8 @@
     public void setOnClickListener(OnClickListener callback) {
         TextView clickable = ((TextView) findViewById(R.id.table_row_value));
         mDefaultTextColor = clickable.getTextColors();
-        TypedArray ta = getContext().obtainStyledAttributes(R.styleable.TextAppearance);
-        int linkColor = ta.getColor(R.styleable.TextAppearance_android_textColorLink,
+        TypedArray ta = getContext().obtainStyledAttributes(android.R.styleable.TextAppearance);
+        int linkColor = ta.getColor(android.R.styleable.TextAppearance_textColorLink,
                 mDefaultTextColor.getDefaultColor());
         ta.recycle();
         clickable.setTextColor(linkColor);

10.使用系统签名
这里可以直接使用https://github.com/siren-ocean/DocumentsUI
这里的文件
11.修改versionCode,改成35.
12.解决运行时错误,注释部分代码

diff --git a/app/src/main/java/com/android/documentsui/roots/ProvidersCache.java b/app/src/main/java/com/android/documentsui/roots/ProvidersCache.java
--- a/app/src/main/java/com/android/documentsui/roots/ProvidersCache.java   (revision 900dbfa600a2c680e08016ba0371ba545c0d7e17)
+++ b/app/src/main/java/com/android/documentsui/roots/ProvidersCache.java   (revision a390c75512f2515fa2a7410efcef9ce80dfe36f6)
@@ -207,7 +207,7 @@
             assert (recentRoot.rootId == null);
             assert (recentRoot.derivedIcon == R.drawable.ic_root_recent);
             assert (recentRoot.derivedType == RootInfo.TYPE_RECENTS);
-            assert (recentRoot.flags == (Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_IS_CHILD));
+        //    assert (recentRoot.flags == (Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_IS_CHILD));
             assert (recentRoot.availableBytes == -1);
         }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容