From 31049bc046ddb43b79ede240dbeafdede7735959 Mon Sep 17 00:00:00 2001 From: yanglw Date: Sun, 14 Dec 2025 13:14:50 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=BD=93=E5=AE=B9?= =?UTF-8?q?=E5=99=A8=20Content=20Provider=20multiprocess=3D"true"=20?= =?UTF-8?q?=E6=97=B6=20hostContentProviderDelegate=20=E4=B8=BA=20null=20?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../runtime/container/PluginContainerContentProvider.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/projects/sdk/core/common/src/main/java/com/tencent/shadow/core/runtime/container/PluginContainerContentProvider.java b/projects/sdk/core/common/src/main/java/com/tencent/shadow/core/runtime/container/PluginContainerContentProvider.java index 61909b396..3ec602cfa 100644 --- a/projects/sdk/core/common/src/main/java/com/tencent/shadow/core/runtime/container/PluginContainerContentProvider.java +++ b/projects/sdk/core/common/src/main/java/com/tencent/shadow/core/runtime/container/PluginContainerContentProvider.java @@ -38,6 +38,10 @@ public class PluginContainerContentProvider extends ContentProvider { public PluginContainerContentProvider() { + ContentProviderDelegateProvider p = ContentProviderDelegateProviderHolder.contentProviderDelegateProvider; + if (p != null) { + hostContentProviderDelegate = p.getHostContentProviderDelegate(); + } ContentProviderDelegateProviderHolder.setDelegateProviderHolderPrepareListener(new ContentProviderDelegateProviderHolder.DelegateProviderHolderPrepareListener() { @Override public void onPrepare() { From 4e46068ea3b1135c02efa2f7914798fbeaa6f0bf Mon Sep 17 00:00:00 2001 From: yanglw Date: Sun, 14 Dec 2025 13:15:30 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AF=B9=E4=B8=80?= =?UTF-8?q?=E4=B8=AA=20Content=20Provider=20=E5=AD=98=E5=9C=A8=E5=A4=9A?= =?UTF-8?q?=E4=B8=AA=20authorities=20=E5=9C=BA=E6=99=AF=E7=9A=84=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/loader/managers/ComponentManager.kt | 19 ++++++++++++++----- .../managers/PluginContentProviderManager.kt | 16 ++++++++++------ 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/managers/ComponentManager.kt b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/managers/ComponentManager.kt index 0b8a1e78d..ac9dac36d 100644 --- a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/managers/ComponentManager.kt +++ b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/managers/ComponentManager.kt @@ -60,6 +60,10 @@ abstract class ComponentManager : PluginComponentLauncher { abstract fun onBindContainerContentProvider(pluginContentProvider: ComponentName): ContainerProviderInfo + open fun onBindContainerContentProvider(pluginContentProvider: ComponentName, pluginAuthority: String): ContainerProviderInfo { + return onBindContainerContentProvider(pluginContentProvider) + } + override fun startActivity( shadowContext: ShadowContext, pluginIntent: Intent, @@ -212,11 +216,16 @@ abstract class ComponentManager : PluginComponentLauncher { pluginManifest.providers?.forEach { val componentName = ComponentName(applicationPackageName, it.className) - mPluginContentProviderManager!!.addContentProviderInfo( - loadParameters.partKey, - it, - onBindContainerContentProvider(componentName) - ) + it.authorities.split(";") + .filter { authority -> authority.isNotBlank() } + .forEach { authority -> + mPluginContentProviderManager!!.addContentProviderInfo( + loadParameters.partKey, + it, + onBindContainerContentProvider(componentName, authority), + authority + ) + } } pluginManifest.receivers?.forEach { diff --git a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/managers/PluginContentProviderManager.kt b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/managers/PluginContentProviderManager.kt index 9d211df6c..135c77d72 100644 --- a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/managers/PluginContentProviderManager.kt +++ b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/managers/PluginContentProviderManager.kt @@ -71,21 +71,22 @@ class PluginContentProviderManager() : UriConverter.UriParseDelegate { fun addContentProviderInfo( partKey: String, pluginProviderInfo: PluginManifest.ProviderInfo, - containerProviderInfo: ContainerProviderInfo + containerProviderInfo: ContainerProviderInfo, + pluginAuthority: String ) { - if (providerMap.containsKey(pluginProviderInfo.authorities)) { + if (providerMap.containsKey(pluginAuthority)) { throw RuntimeException("重复添加 ContentProvider") } - providerAuthorityMap[pluginProviderInfo.authorities] = containerProviderInfo.authority - var pluginProviderInfos: HashSet? = null + providerAuthorityMap[pluginAuthority] = containerProviderInfo.authority + var pluginProviderInfos: HashSet? if (pluginProviderInfoMap.containsKey(partKey)) { pluginProviderInfos = pluginProviderInfoMap[partKey] } else { pluginProviderInfos = HashSet() + pluginProviderInfoMap[partKey] = pluginProviderInfos } pluginProviderInfos?.add(pluginProviderInfo) - pluginProviderInfoMap.put(partKey, pluginProviderInfos) } fun createContentProviderAndCallOnCreate( @@ -105,7 +106,10 @@ class PluginContentProviderManager() : UriConverter.UriParseDelegate { providerInfo.authority = it.authorities providerInfo.grantUriPermissions = it.grantUriPermissions contentProvider?.attachInfo(context, providerInfo) - providerMap[it.authorities] = contentProvider + it.authorities + .split(";") + .filter { authority -> authority.isNotBlank() } + .forEach { authority -> providerMap[authority] = contentProvider } } catch (e: Exception) { throw RuntimeException( "partKey==$partKey className==${it.className} authorities==${it.authorities}", From 8b5fee57027c5dff94d6f891bc49c14dde56e3af Mon Sep 17 00:00:00 2001 From: yanglw Date: Sun, 14 Dec 2025 13:15:59 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=AE=B9=E5=99=A8=20auth?= =?UTF-8?q?ority=20=E5=92=8C=E6=8F=92=E4=BB=B6=20authority=20=E4=B8=80?= =?UTF-8?q?=E8=87=B4=E6=97=B6=E8=BF=94=E5=9B=9E=E9=94=99=E8=AF=AF=20Uri=20?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../managers/PluginContentProviderManager.kt | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/managers/PluginContentProviderManager.kt b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/managers/PluginContentProviderManager.kt index 135c77d72..14908da28 100644 --- a/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/managers/PluginContentProviderManager.kt +++ b/projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/managers/PluginContentProviderManager.kt @@ -138,10 +138,29 @@ class PluginContentProviderManager() : UriConverter.UriParseDelegate { fun convert2PluginUri(uri: Uri): Uri { val containerAuthority: String? = uri.authority - if (!providerAuthorityMap.values.contains(containerAuthority)) { + val set = providerAuthorityMap.filter { it.value == containerAuthority } + if (set.isEmpty()) { throw IllegalArgumentException("不能识别的uri Authority:$containerAuthority") } val uriString = uri.toString() + for (entry in set) { + val pluginAuthority = entry.key + // 通过正则表达式去除 containerAuthority ,支持以下场景: + // 1. content://containerAuthority/pluginAuthority(插件内部调用 insert 、query 等方法) + // 2. content://containerAuthority/containerAuthority/pluginAuthority(插件内部调用 call 方法) + // 3. content://pluginAuthority (外部应用调用 content provider 方法) + // 正则表达式分为三个部分: + // 1. `^$CONTENT_PREFIX`: 匹配开头的 "content://"。 + // 2. `((?:$containerAuthority/)+)`: 第一个捕获组。它匹配并捕获零个或多个 "containerAuthority/" 组成的连续前缀。 + // - `(?:...)` 是一个非捕获组,仅用于组合。 + // 3. $pluginAuthority 是 pluginAuthority ,用于作为删除的锚点。 + val regex = Regex("^$CONTENT_PREFIX((?:$containerAuthority/)?)$pluginAuthority") + // 可能存在一个 containerAuthority 匹配多个 pluginAuthority 的场景,所以存在无法匹配的场景 + val matchResult = regex.find(uriString) ?: continue + // 如果找到了匹配的内容,则剔除匹配的 containerAuthority 内容 + val range = matchResult.groups[1]!!.range + return Uri.parse(uriString.substring(0, range.first) + uriString.substring(range.last + 1)) + } return Uri.parse(uriString.replace("$containerAuthority/", "")) }