Comments (4)
大致浏览之后,我是比较相信这里是遇到bug了的。因为PreferenceFragmentCompat应该只是个androidx的fragment,怎么都不应该被实例化成Activity(ShadowActivity)的。所以问题可能出在ShadowAppComponentFactory上。
androidx不需要特别支持,所以我们应该找出它依赖的系统api有什么需要支持的。
如果你不能自己解决这个问题,最好fork项目后在sample或test工程里用最少代码复现一下这个问题。
androidx相关的例子可以在这个插件工程里添加代码:
https://github.com/Tencent/Shadow/tree/master/projects/test/plugin/androidx-cases/test-plugin-androidx-cases
from shadow.
Hi @shifujun
由于我们公司网络限制,无法 push code changes 到 github 上,请辛苦浏览复制以下复现问题的测试代码。
我在 Sample 里面加了一个 testcase,可复现此 Issue 所说的问题。
请看下面的 patch
- git patch, (打补丁)
1.1 请在您的 PC上创建 Issue#1194_Change.patch 文件,在 NotePad++ 打开 Issue#1194_Change.patch;
1.2 请将此 patch 内容复制到您的 Issue#1194_Change.patch 文件中,将 Issue#1194_Change.patch 文件拷贝到 Shadow 仓库的根目录;
1.3 在 Shadow 仓库中使用 git apply Issue#1194_Change.patch 打入补丁。
以下是补丁的内容:(请使用补丁内容)
diff --git a/projects/sample/source/sample-plugin/sample-app/build.gradle b/projects/sample/source/sample-plugin/sample-app/build.gradle
index 5bb93f01..85546e31 100644
--- a/projects/sample/source/sample-plugin/sample-app/build.gradle
+++ b/projects/sample/source/sample-plugin/sample-app/build.gradle
@@ -18,6 +18,7 @@ buildscript {
apply plugin: 'com.android.application'
apply plugin: 'com.tencent.shadow.plugin'
+apply plugin: 'kotlin-android'
android {
compileSdkVersion project.COMPILE_SDK_VERSION
@@ -68,6 +69,7 @@ dependencies {
//Shadow Transform后业务代码会有一部分实际引用runtime中的类
//如果不以compileOnly方式依赖,会导致其他Transform或者Proguard找不到这些类
pluginCompileOnly 'com.tencent.shadow.core:runtime'
+ implementation 'androidx.preference:preference:1.2.0'
}
preBuild.dependsOn(":sample-host-lib:jarDebugPackage")
diff --git a/projects/sample/source/sample-plugin/sample-app/src/main/AndroidManifest.xml b/projects/sample/source/sample-plugin/sample-app/src/main/AndroidManifest.xml
index abac57e8..83fbc3c7 100644
--- a/projects/sample/source/sample-plugin/sample-app/src/main/AndroidManifest.xml
+++ b/projects/sample/source/sample-plugin/sample-app/src/main/AndroidManifest.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
package="com.tencent.shadow.sample.plugin.app.lib">
<uses-feature android:glEsVersion="0x00020000" />
@@ -62,6 +63,8 @@
<activity android:name=".usecases.host_communication.PluginUseHostClassActivity" />
<activity android:name=".usecases.webview.WebViewActivity" />
<activity android:name=".usecases.fragment.TestDialogFragmentActivity" />
+ <activity android:name=".usecases.preferencefragmentcompatcase.RfFragment"
+ tools:ignore="Instantiatable" />
<provider
android:authorities="${applicationId}.provider.test"
diff --git a/projects/sample/source/sample-plugin/sample-app/src/main/java/com/tencent/shadow/sample/plugin/app/lib/UseCaseApplication.java b/projects/sample/source/sample-plugin/sample-app/src/main/java/com/tencent/shadow/sample/plugin/app/lib/UseCaseApplication.java
index 93c05284..3f43f005 100644
--- a/projects/sample/source/sample-plugin/sample-app/src/main/java/com/tencent/shadow/sample/plugin/app/lib/UseCaseApplication.java
+++ b/projects/sample/source/sample-plugin/sample-app/src/main/java/com/tencent/shadow/sample/plugin/app/lib/UseCaseApplication.java
@@ -22,6 +22,7 @@ import com.tencent.shadow.sample.plugin.app.lib.usecases.fragment.TestDynamicFra
import com.tencent.shadow.sample.plugin.app.lib.usecases.fragment.TestXmlFragmentActivity;
import com.tencent.shadow.sample.plugin.app.lib.usecases.host_communication.PluginUseHostClassActivity;
import com.tencent.shadow.sample.plugin.app.lib.usecases.packagemanager.TestPackageManagerActivity;
+import com.tencent.shadow.sample.plugin.app.lib.usecases.preferencefragmentcompatcase.RfFragment;
import com.tencent.shadow.sample.plugin.app.lib.usecases.provider.TestDBContentProviderActivity;
import com.tencent.shadow.sample.plugin.app.lib.usecases.provider.TestFileProviderActivity;
import com.tencent.shadow.sample.plugin.app.lib.usecases.receiver.TestDynamicReceiverActivity;
@@ -51,7 +52,8 @@ public class UseCaseApplication extends Application {
new TestActivityWindowSoftMode.Case(),
new TestActivitySetTheme.Case(),
new TestActivityOptionMenu.Case(),
- new WebViewActivity.Case()
+ new WebViewActivity.Case(),
+ new RfFragment.Case()
});
useCases.add(activityCategory);
@@ -97,5 +99,8 @@ public class UseCaseApplication extends Application {
new PluginUseHostClassActivity.Case(),
});
useCases.add(communicationCategory);
+ UseCaseCategory PreferenceFragmentCompatCategory = new UseCaseCategory("PreferenceFragmentCompat嵌套用例",
+ new UseCase[]{new RfFragment.Case(),});
+ useCases.add(PreferenceFragmentCompatCategory);
}
}
diff --git a/projects/sample/source/sample-plugin/sample-app/src/main/res/values/strings.xml b/projects/sample/source/sample-plugin/sample-app/src/main/res/values/strings.xml
index 8cb0af94..289eb0cb 100644
--- a/projects/sample/source/sample-plugin/sample-app/src/main/res/values/strings.xml
+++ b/projects/sample/source/sample-plugin/sample-app/src/main/res/values/strings.xml
@@ -20,5 +20,9 @@
<!-- Simple strings. -->
<string name="app_name">Shadow主测试用例集合</string>
<string name="host_add_plugin_view">这是插件中的string资源</string>
+ <string name="nv_backup_title">NV Backup</string>
+ <string name="rf_items">RF Module</string>
+ <string name="qti_nv">NV parameters</string>
+ <string name="qti_adjust">Calibration status</string>
</resources>
- 在 projects/sample/source/sample-plugin/sample-app/src/main/java/com/tencent/shadow/sample/plugin/app/lib/usecases 目录下新增一个 testcase,嵌套调用 PreferenceFragmentCompat
$ git status
On branch master
Your branch is up to date with 'origin/master'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: projects/sample/source/sample-plugin/sample-app/build.gradle
modified: projects/sample/source/sample-plugin/sample-app/src/main/AndroidManifest.xml
modified: projects/sample/source/sample-plugin/sample-app/src/main/java/com/tencent/shadow/sample/plugin/app/lib/UseCaseApplication.java
modified: projects/sample/source/sample-plugin/sample-app/src/main/res/values/strings.xml
Untracked files:
(use "git add <file>..." to include in what will be committed)
projects/sample/source/sample-plugin/sample-app/src/main/java/com/tencent/shadow/sample/plugin/app/lib/usecases/preferencefragmentcompatcase/
projects/sample/source/sample-plugin/sample-app/src/main/res/xml/
2.1 com/tencent/shadow/sample/plugin/app/lib/usecases/preferencefragmentcompatcase/RfFragment.kt
package com.tencent.shadow.sample.plugin.app.lib.usecases.preferencefragmentcompatcase
import android.os.Bundle
import com.tencent.shadow.sample.plugin.app.lib.R
import com.tencent.shadow.sample.plugin.app.lib.gallery.cases.entity.UseCase
class RfFragment : EngineerFragmentCompat() {
class Case : UseCase() {
override fun getName(): String {
return "PreferenceFragmentCompat 嵌套测试"
}
override fun getSummary(): String {
return "测试PreferenceFragmentCompat嵌套"
}
override fun getPageClass(): Class<*> {
return RfFragment::class.java
}
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.fragment_rf_container)
}
}
2.2 com/tencent/shadow/sample/plugin/app/lib/usecases/preferencefragmentcompatcase/NVBackupUI.kt
package com.tencent.shadow.sample.plugin.app.lib.usecases.preferencefragmentcompatcase
import android.os.Bundle
import android.util.Log
import androidx.preference.PreferenceFragmentCompat
import com.tencent.shadow.sample.plugin.app.lib.R
class NVBackupUI : PreferenceFragmentCompat() {
private val TAG = "NVBackupUI"
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
Log.d(TAG, "onCreatePreferences")
addPreferencesFromResource(R.xml.qti_nv_options)
}
}
2.3 com/tencent/shadow/sample/plugin/app/lib/usecases/preferencefragmentcompatcase/EngineerFragmentCompat.kt
package com.tencent.shadow.sample.plugin.app.lib.usecases.preferencefragmentcompatcase
import android.content.Context
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceScreen
import android.util.Log
import androidx.annotation.RequiresApi
import com.tencent.shadow.sample.plugin.app.lib.R
open class EngineerFragmentCompat : PreferenceFragmentCompat() {
private val TAG = "EngineerFragmentCompat"
private var mContext: Context? = null
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
Log.d(TAG, "onCreatePreferences")
}
override fun onAttach(p0: Context) {
super.onAttach(p0)
mContext = p0
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val preferenceScreen: PreferenceScreen = preferenceManager.preferenceScreen
for (i in 0 until preferenceScreen.preferenceCount) {
val preference = preferenceScreen.getPreference(i)
val intent = preference.intent
if (intent != null) {
preference.isEnabled = true
} else {
Log.w(TAG, "onViewCreated preference is not available for i: $i")
preference.isEnabled = false
}
}
}
/**
* 实例化 Fragment 来显示视图,这将在 onCreate 和 onViewCreated 之间调用。
* */
@RequiresApi(Build.VERSION_CODES.M)
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val view: View = super.onCreateView(inflater, container, savedInstanceState)
view.setBackgroundColor(
resources.getColor(R.color.material_grey_850, mContext?.theme)
)
return view
}
override fun getCallbackFragment(): Fragment {
return this
}
}
2.4 xml/fragment_rf_container.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:key="rf_container"
android:title="@string/rf_items">
<androidx.preference.Preference
android:key="nv_backup"
android:title="@string/nv_backup_title">
<intent
android:action="android.intent.action.MAIN"
android:targetClass="com.tencent.shadow.sample.plugin.app.lib.usecases.preferencefragmentcompatcase.NVBackupUI"
android:targetPackage="com.tencent.shadow.sample.host" />
</androidx.preference.Preference>
</PreferenceScreen>
2.5 xml/qti_nv_options.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<Preference
android:key="nv_function_new"
android:title="@string/qti_nv">
<intent
android:action="android.intent.action.MAIN"
android:targetClass="com.tencent.shadow.sample.plugin.app.lib.usecases.preferencefragmentcompatcase.NVBackupUIActivity"
android:targetPackage="com.tencent.shadow.sample.host" />
</Preference>
</PreferenceScreen>
-
测试方法:
基于本代码 commit chagnes
安装 sample-host:installDebug
进入 Shadow Dynamic测试宿主App
点击 启动插件
左边栏选择最后一项:PreferenceFragmentCompat嵌套用例,点击“启动” -
异常出现:
插件APP 闪退,UI界面回到宿主UI,com.tencent.shadow.sample.host:plugin Crashed
AndroidRuntime: Shutting down VM
--------- beginning of crash
AndroidRuntime: FATAL EXCEPTION: main
AndroidRuntime: Process: com.tencent.shadow.sample.host:plugin, PID: 27763
AndroidRuntime: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.tencent.shadow.sample.host/com.tencent.shadow.sample.plugin.runtime.PluginDefaultProxyActivity}: java.lang.RuntimeException: java.lang.ClassCastException: com.tencent.shadow.sample.plugin.app.lib.usecases.preferencefragmentcompatcase.RfFragment cannot be cast to com.tencent.shadow.core.runtime.ShadowActivity
AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3876)
AndroidRuntime: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4018)
AndroidRuntime: at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:111)
AndroidRuntime: at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
AndroidRuntime: at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2474)
AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:106)
AndroidRuntime: at android.os.Looper.loopOnce(Looper.java:240)
AndroidRuntime: at android.os.Looper.loop(Looper.java:351)
AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:8426)
AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:584)
AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1013)
AndroidRuntime: Caused by: java.lang.RuntimeException: java.lang.ClassCastException: com.tencent.shadow.sample.plugin.app.lib.usecases.preferencefragmentcompatcase.RfFragment cannot be cast to com.tencent.shadow.core.runtime.ShadowActivity
AndroidRuntime: at com.tencent.shadow.core.loader.delegates.ShadowActivityDelegate.onCreate(ShadowActivityDelegate.kt:159)
AndroidRuntime: at com.tencent.shadow.core.runtime.container.PluginContainerActivity.onCreate(PluginContainerActivity.java:84)
AndroidRuntime: at android.app.Activity.performCreate(Activity.java:8460)
AndroidRuntime: at android.app.Activity.performCreate(Activity.java:8433)
AndroidRuntime: at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1403)
AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3849)
AndroidRuntime: ... 12 more
AndroidRuntime: Caused by: java.lang.ClassCastException: com.tencent.shadow.sample.plugin.app.lib.usecases.preferencefragmentcompatcase.RfFragment cannot be cast to com.tencent.shadow.core.runtime.ShadowActivity
AndroidRuntime: at com.tencent.shadow.core.runtime.ShadowAppComponentFactory.instantiateActivity(ShadowAppComponentFactory.java:18)
AndroidRuntime: at androidx.core.app.CoreComponentFactory.instantiateActivity(CoreComponentFactory.java:45)
AndroidRuntime: at com.tencent.shadow.core.loader.delegates.ShadowActivityDelegate.onCreate(ShadowActivityDelegate.kt:120)
AndroidRuntime: ... 17 more
from shadow.
你前面这个patch我复制下来倒是能像你说的那样复现一个RfFragment cannot be cast to com.tencent.shadow.core.runtime.ShadowActivity
的crash。但这个看起来是非常正常的,因为你写了:
override fun getPageClass(): Class<*> {
return RfFragment::class.java
}
这是把一个车fragment填到intent里去startActivity了。(
如果这就是你说的原本的问题,那肯定是你的业务代码哪写错了,把fragment当activity去start了。
另外你代码中也没有NVBackupUIActivity
,看起来莫名其妙的。
特意指明让你在test-plugin-androidx-cases中复现问题就是避免sample-app中依赖的support包和你要添加的androidx冲突。否则你这个例子现在sample-app能单独运行吗?我这很正常的报Duplicate class found了。如果你能运行,我估计也会很正常的报类错误吧。改在test-plugin-androidx-cases中试试吧。test-plugin-androidx-cases和sample-app一样,test-dynamic-host和sample-host一样,只是这些test工程有自动化测试。
另外这样贴代码绝对不是正常的交流方式,你只是赶上我有空贴一下patch而已。你下次还是push上来吧。最不济也可以push到国内的其他公开git仓库上。
from shadow.
把fragment当activity去start了。
Hi @shifujun
确实,我是把 fragment 当作 activity 去start 了,导致了原来的问题。
感谢您的指导!
另外,回答您的 comment 中的问题:
1.
另外你代码中也没有NVBackupUIActivity,看起来莫名其妙的。
因为我贴代码时,认为只要调用到第二层嵌套的 PreferenceFragmentCompat UI 即可,不会再进到 NVBackupUIActivity,所以我没有把 NVBackupUIActivity 的代码贴出来。
谢谢!
from shadow.
Related Issues (20)
- 执行sample-app报错,要怎么解决? HOT 2
- 插件内可以调用qq分享吗?
- androidx.profileinstaller.ProfileVerifier安全校验失败? HOT 1
- 请问 normalImplementation 是只有Shadow才有的吗? HOT 2
- 宿主启动多插件 HOT 1
- Caused by: java.lang.ClassCastException: androidx.appcompat.widget.ContentFrameLayout cannot be cast to androidx.appcompat.widget.ContentFrameLayout HOT 2
- java.lang.VerifyError: Rejecting class com.demo.pluginmanager.UpPluginManager that attempts to sub-type erroneous class com.demo.pluginmanager.FastPluginManager (declaration of 'com.demo.pluginmanager.UpPluginManager' appears in /data/user/0/com.demo/files/upshadowmanager-release-1.3.4.2023070701.apk) HOT 3
- Caused by: java.lang.UnsupportedOperationException: Can't convert to color state list: type=0x1 at android.content.res.Resources.loadColorStateListForCookie(Resources.java:2718) at android.content.res.Resources.loadColorStateList(Resources.java:2699) at android.content.res.TypedArray.getColorStateList(TypedArray.java:485) at android.widget.TextView.<init>(TextView.java:746) at android.widget.TextView.<init>(TextView.java:671) at androidx.appcompat.widget.AppCompatTextView.<init>(AppCompatTextView.java:102) at androidx.appcompat.widget.AppCompatTextView.<init>(AppCompatTextView.java:97)
- shadow经过线上上亿用户的检验,想咨询下
- 希望添加 jni 调用的演示示例 HOT 2
- sample-host release模式多项测试失败 HOT 2
- 卸载插件时遇到无法删除文件的问题 HOT 2
- none-dynamic场景使用so HOT 4
- 启动插件时,会报上下文NullPointerException HOT 2
- 报错,找不到DelegateProvider
- 宿主更新插件,要重启宿主后插件才生效 HOT 1
- 怎么加载本地存储中的插件,而不是加载assets中的插件 HOT 1
- UnsatisfiedLinkError,so文件映射失败
- 关于插件和宿主通信的问题
- android 4.4.2 MultiDex 每次运行都要删除旧的dex
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from shadow.