mirror of
https://github.com/HighCapable/YukiHookAPI.git
synced 2025-09-04 09:45:19 +08:00
151 lines
45 KiB
JavaScript
151 lines
45 KiB
JavaScript
import{_ as e,r as o,o as p,c,b as s,d as n,e as t,a}from"./app-BpUB8-Q8.js";const i={},r=a(`<h1 id="宿主资源注入扩展" tabindex="-1"><a class="header-anchor" href="#宿主资源注入扩展" aria-hidden="true">#</a> 宿主资源注入扩展</h1><blockquote><p>这是一个将模块资源、<code>Activity</code> 组件以及 <code>Context</code> 主题注入到宿主的扩展功能。</p></blockquote><p>在使用以下功能之前,为防止资源 ID 互相冲突,你需要在当前 Xposed 模块项目的 <code>build.gradle</code> 中修改资源 ID。</p><blockquote><p>Kotlin DSL</p></blockquote><div class="language-kotlin line-numbers-mode" data-ext="kt"><pre class="shiki github-dark-dimmed" style="background-color:#22272e;" tabindex="0"><code><span class="line"><span style="color:#DCBDFB;">android</span><span style="color:#ADBAC7;"> {</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> androidResources.additionalParameters </span><span style="color:#F47067;">+=</span><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">listOf</span><span style="color:#ADBAC7;">(</span><span style="color:#96D0FF;">"--allow-reserved-package-id"</span><span style="color:#ADBAC7;">, </span><span style="color:#96D0FF;">"--package-id"</span><span style="color:#ADBAC7;">, </span><span style="color:#96D0FF;">"0x64"</span><span style="color:#ADBAC7;">)</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;">}</span></span>
|
||
<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote><p>Groovy DSL</p></blockquote><div class="language-groovy line-numbers-mode" data-ext="groovy"><pre class="shiki github-dark-dimmed" style="background-color:#22272e;" tabindex="0"><code><span class="line"><span style="color:#ADBAC7;">android {</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> androidResources</span><span style="color:#F47067;">.</span><span style="color:#ADBAC7;">additionalParameters </span><span style="color:#F47067;">+=</span><span style="color:#ADBAC7;"> [</span><span style="color:#96D0FF;">'--allow-reserved-package-id'</span><span style="color:#ADBAC7;">, </span><span style="color:#96D0FF;">'--package-id'</span><span style="color:#ADBAC7;">, </span><span style="color:#96D0FF;">'0x64'</span><span style="color:#ADBAC7;">]</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;">}</span></span>
|
||
<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><div class="custom-container warning"><p class="custom-container-title">注意</p><p>过往版本中的 <strong>aaptOptions.additionalParameters</strong> 已被作废,请参考上述写法并保持你的 <strong>Android Gradle Plugin</strong> 为最新版本。</p><p>提供的示例资源 ID 值仅供参考,不可使用 <strong>0x7f</strong>,默认为 <strong>0x64</strong>,为了防止当前宿主存在多个 Xposed 模块,建议自定义你自己的资源 ID。</p></div><h2 id="注入模块资源-resources" tabindex="-1"><a class="header-anchor" href="#注入模块资源-resources" aria-hidden="true">#</a> 注入模块资源 (Resources)</h2><p>在 Hook 宿主之后,我们可以直接在 Hooker 中得到的 <code>Context</code> 注入当前模块资源。</p><blockquote><p>示例如下</p></blockquote><div class="language-kotlin line-numbers-mode" data-ext="kt"><pre class="shiki github-dark-dimmed" style="background-color:#22272e;" tabindex="0"><code><span class="line"><span style="color:#DCBDFB;">resolve</span><span style="color:#ADBAC7;">().</span><span style="color:#DCBDFB;">firstMethod</span><span style="color:#ADBAC7;"> {</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> name </span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">"onCreate"</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">parameters</span><span style="color:#ADBAC7;">(Bundle::</span><span style="color:#DCBDFB;">class</span><span style="color:#ADBAC7;">)</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;">}.</span><span style="color:#DCBDFB;">hook</span><span style="color:#ADBAC7;"> {</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">after</span><span style="color:#ADBAC7;"> {</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">instance</span><span style="color:#ADBAC7;"><</span><span style="color:#F69D50;">Activity</span><span style="color:#ADBAC7;">>().</span><span style="color:#DCBDFB;">also</span><span style="color:#ADBAC7;"> {</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#768390;">// <方案1> 通过 Context 注入模块资源</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> it.</span><span style="color:#DCBDFB;">injectModuleAppResources</span><span style="color:#ADBAC7;">()</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#768390;">// <方案2> 直接得到宿主 Resources 注入模块资源</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> it.resources.</span><span style="color:#DCBDFB;">injectModuleAppResources</span><span style="color:#ADBAC7;">()</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#768390;">// 直接使用模块资源 ID</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> it.</span><span style="color:#DCBDFB;">getString</span><span style="color:#ADBAC7;">(R.id.app_name)</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> }</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> }</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;">}</span></span>
|
||
<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你还可以直接在 <code>AppLifecycle</code> 中注入当前模块资源。</p><blockquote><p>示例如下</p></blockquote><div class="language-kotlin line-numbers-mode" data-ext="kt"><pre class="shiki github-dark-dimmed" style="background-color:#22272e;" tabindex="0"><code><span class="line"><span style="color:#DCBDFB;">onAppLifecycle</span><span style="color:#ADBAC7;"> {</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">onCreate</span><span style="color:#ADBAC7;"> {</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#768390;">// 全局注入模块资源,但仅限于全局生命周期</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#768390;">// 类似 ImageView.setImageResource 这样的方法在 Activity 中需要单独注入</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#768390;">// <方案1> 通过 Context 注入模块资源</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">injectModuleAppResources</span><span style="color:#ADBAC7;">()</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#768390;">// <方案2> 直接得到宿主 Resources 注入模块资源</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> resources.</span><span style="color:#DCBDFB;">injectModuleAppResources</span><span style="color:#ADBAC7;">()</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#768390;">// 直接使用模块资源 ID</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">getString</span><span style="color:#ADBAC7;">(R.id.app_name)</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> }</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;">}</span></span>
|
||
<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><div class="custom-container tip"><p class="custom-container-title">小提示</p><p>更多功能请参考 <a href="../public/com/highcapable/yukihookapi/hook/factory/YukiHookFactory#context-resources-injectmoduleappresources-ext-method">Context+Resources.injectModuleAppResources</a> 方法。</p></div><h2 id="注册模块-activity" tabindex="-1"><a class="header-anchor" href="#注册模块-activity" aria-hidden="true">#</a> 注册模块 Activity</h2><p>在 Android 系统中所有应用的 <code>Activity</code> 启动时,都需要在 <code>AndroidManifest.xml</code> 中进行注册,在 Hook 过程中,如果我们想通过宿主来直接启动模块中未注册的 <code>Activity</code> 要怎么做呢?</p><p>在 Hook 宿主之后,我们可以直接在 Hooker 中得到的 <code>Context</code> 注册当前模块的 <code>Activity</code> 代理。</p><blockquote><p>示例如下</p></blockquote><div class="language-kotlin line-numbers-mode" data-ext="kt"><pre class="shiki github-dark-dimmed" style="background-color:#22272e;" tabindex="0"><code><span class="line"><span style="color:#DCBDFB;">resolve</span><span style="color:#ADBAC7;">().</span><span style="color:#DCBDFB;">firstMethod</span><span style="color:#ADBAC7;"> {</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> name </span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">"onCreate"</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">parameters</span><span style="color:#ADBAC7;">(Bundle::</span><span style="color:#DCBDFB;">class</span><span style="color:#ADBAC7;">)</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;">}.</span><span style="color:#DCBDFB;">hook</span><span style="color:#ADBAC7;"> {</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">after</span><span style="color:#ADBAC7;"> {</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">instance</span><span style="color:#ADBAC7;"><</span><span style="color:#F69D50;">Activity</span><span style="color:#ADBAC7;">>().</span><span style="color:#DCBDFB;">registerModuleAppActivities</span><span style="color:#ADBAC7;">()</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> }</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;">}</span></span>
|
||
<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你还可以直接在 <code>AppLifecycle</code> 中注册当前模块的 <code>Activity</code> 代理。</p><blockquote><p>示例如下</p></blockquote><div class="language-kotlin line-numbers-mode" data-ext="kt"><pre class="shiki github-dark-dimmed" style="background-color:#22272e;" tabindex="0"><code><span class="line"><span style="color:#DCBDFB;">onAppLifecycle</span><span style="color:#ADBAC7;"> {</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">onCreate</span><span style="color:#ADBAC7;"> {</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">registerModuleAppActivities</span><span style="color:#ADBAC7;">()</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> }</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;">}</span></span>
|
||
<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果没有填写 <code>proxy</code> 参数,API 将会根据当前 <code>Context</code> 自动获取当前宿主的启动入口 <code>Activity</code> 进行代理。</p><p>通常情况下,它是有效的,但是以上情况在一些 APP 中会失效,例如一些 <code>Activity</code> 会在注册清单上加入启动参数,那么我们就需要使用另一种解决方案。</p><p>若未注册的 <code>Activity</code> 不能被正确启动,我们可以手动拿到宿主的 <code>AndroidManifest.xml</code> 进行分析,来得到一个注册过的 <code>Activity</code> 标签,获取其中的 <code>name</code>。</p><p>你需要选择一个当前宿主可能用不到的、不需要的 <code>Activity</code> 作为一个“傀儡”将其进行代理,通常是有效的。</p><p>比如我们已经找到了能够被代理的合适 <code>Activity</code>。</p><blockquote><p>示例如下</p></blockquote><div class="language-xml line-numbers-mode" data-ext="xml"><pre class="shiki github-dark-dimmed" style="background-color:#22272e;" tabindex="0"><code><span class="line"><span style="color:#ADBAC7;"><</span><span style="color:#8DDB8C;">activity</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#6CB6FF;">android:name</span><span style="color:#ADBAC7;">=</span><span style="color:#96D0FF;">"com.demo.test.activity.TestActivity"</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> ...></span></span>
|
||
<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>根据其中的 <code>name</code>,我们只需要在方法中加入这个参数进行注册即可。</p><blockquote><p>示例如下</p></blockquote><div class="language-kotlin line-numbers-mode" data-ext="kt"><pre class="shiki github-dark-dimmed" style="background-color:#22272e;" tabindex="0"><code><span class="line"><span style="color:#DCBDFB;">registerModuleAppActivities</span><span style="color:#ADBAC7;">(proxy </span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">"com.demo.test.activity.TestActivity"</span><span style="color:#ADBAC7;">)</span></span>
|
||
<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>另一种情况,如果你对宿主的类编写了一个 <code>stub</code>,那么你可以直接通过 <code>Class</code> 对象来进行注册。</p><blockquote><p>示例如下</p></blockquote><div class="language-kotlin line-numbers-mode" data-ext="kt"><pre class="shiki github-dark-dimmed" style="background-color:#22272e;" tabindex="0"><code><span class="line"><span style="color:#DCBDFB;">registerModuleAppActivities</span><span style="color:#ADBAC7;">(TestActivity::</span><span style="color:#DCBDFB;">class</span><span style="color:#ADBAC7;">.java)</span></span>
|
||
<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>注册完成后,请将你需要使用宿主启动的模块中的 <code>Activity</code> 实现 <code>ModuleActivity</code> 接口。</p><p>这些 <code>Activity</code> 现在无需注册即可无缝存活于宿主中。</p><p>我们推荐你创建 <code>BaseActivity</code> 作为所有模块 <code>Activity</code> 的基类。</p><blockquote><p>示例如下</p></blockquote><div class="language-kotlin line-numbers-mode" data-ext="kt"><pre class="shiki github-dark-dimmed" style="background-color:#22272e;" tabindex="0"><code><span class="line"><span style="color:#F47067;">abstract</span><span style="color:#ADBAC7;"> </span><span style="color:#F47067;">class</span><span style="color:#ADBAC7;"> </span><span style="color:#F69D50;">BaseActivity</span><span style="color:#ADBAC7;"> : </span><span style="color:#F69D50;">AppCompatActivity</span><span style="color:#ADBAC7;">(), </span><span style="color:#DCBDFB;">ModuleActivity</span><span style="color:#ADBAC7;"> {</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#768390;">// 设置 AppCompat 主题 (如果当前是 [AppCompatActivity])</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#F47067;">override</span><span style="color:#ADBAC7;"> </span><span style="color:#F47067;">val</span><span style="color:#ADBAC7;"> moduleTheme </span><span style="color:#F47067;">get</span><span style="color:#ADBAC7;">() </span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;"> R.style.YourAppTheme</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#F47067;">override</span><span style="color:#ADBAC7;"> </span><span style="color:#F47067;">fun</span><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">getClassLoader</span><span style="color:#ADBAC7;">() </span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;"> delegate.</span><span style="color:#DCBDFB;">getClassLoader</span><span style="color:#ADBAC7;">()</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#F47067;">override</span><span style="color:#ADBAC7;"> </span><span style="color:#F47067;">fun</span><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">onCreate</span><span style="color:#ADBAC7;">(savedInstanceState: </span><span style="color:#F69D50;">Bundle</span><span style="color:#ADBAC7;">?) {</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> delegate.</span><span style="color:#DCBDFB;">onCreate</span><span style="color:#ADBAC7;">(savedInstanceState)</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#6CB6FF;">super</span><span style="color:#ADBAC7;">.</span><span style="color:#DCBDFB;">onCreate</span><span style="color:#ADBAC7;">(savedInstanceState)</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> }</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#F47067;">override</span><span style="color:#ADBAC7;"> </span><span style="color:#F47067;">fun</span><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">onConfigurationChanged</span><span style="color:#ADBAC7;">(newConfig: </span><span style="color:#F69D50;">Configuration</span><span style="color:#ADBAC7;">) {</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> delegate.</span><span style="color:#DCBDFB;">onConfigurationChanged</span><span style="color:#ADBAC7;">(newConfig)</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#6CB6FF;">super</span><span style="color:#ADBAC7;">.</span><span style="color:#DCBDFB;">onConfigurationChanged</span><span style="color:#ADBAC7;">(newConfig)</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> }</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#F47067;">override</span><span style="color:#ADBAC7;"> </span><span style="color:#F47067;">fun</span><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">onRestoreInstanceState</span><span style="color:#ADBAC7;">(savedInstanceState: </span><span style="color:#F69D50;">Bundle</span><span style="color:#ADBAC7;">) {</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> delegate.</span><span style="color:#DCBDFB;">onRestoreInstanceState</span><span style="color:#ADBAC7;">(savedInstanceState)</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#6CB6FF;">super</span><span style="color:#ADBAC7;">.</span><span style="color:#DCBDFB;">onRestoreInstanceState</span><span style="color:#ADBAC7;">(savedInstanceState)</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> }</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;">}</span></span>
|
||
<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>然后将需要实现的 <code>Activity</code> 继承于 <code>BaseActivity</code>。</p><blockquote><p>示例如下</p></blockquote><div class="language-kotlin line-numbers-mode" data-ext="kt"><pre class="shiki github-dark-dimmed" style="background-color:#22272e;" tabindex="0"><code><span class="line"><span style="color:#F47067;">class</span><span style="color:#ADBAC7;"> </span><span style="color:#F69D50;">HostTestActivity</span><span style="color:#ADBAC7;"> : </span><span style="color:#F69D50;">BaseActivity</span><span style="color:#ADBAC7;">() {</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#F47067;">override</span><span style="color:#ADBAC7;"> </span><span style="color:#F47067;">fun</span><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">onCreate</span><span style="color:#ADBAC7;">(savedInstanceState: </span><span style="color:#F69D50;">Bundle</span><span style="color:#ADBAC7;">?) {</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#6CB6FF;">super</span><span style="color:#ADBAC7;">.</span><span style="color:#DCBDFB;">onCreate</span><span style="color:#ADBAC7;">(savedInstanceState)</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#768390;">// 模块资源已被自动注入,可以直接使用 xml 装载布局</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">setContentView</span><span style="color:#ADBAC7;">(R.layout.activity_main)</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> }</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;">}</span></span>
|
||
<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>以上步骤全部完成后,你就可以在 (Xposed) 宿主环境任意存在 <code>Context</code> 的地方愉快地调用 <code>startActivity</code> 了。</p><blockquote><p>示例如下</p></blockquote><div class="language-kotlin line-numbers-mode" data-ext="kt"><pre class="shiki github-dark-dimmed" style="background-color:#22272e;" tabindex="0"><code><span class="line"><span style="color:#F47067;">val</span><span style="color:#ADBAC7;"> context: </span><span style="color:#F69D50;">Context</span><span style="color:#ADBAC7;"> </span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;"> </span><span style="color:#F47067;">..</span><span style="color:#ADBAC7;">. </span><span style="color:#768390;">// 假设这就是你的 Context</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;">context.</span><span style="color:#DCBDFB;">startActivity</span><span style="color:#ADBAC7;">(context, HostTestActivity::</span><span style="color:#DCBDFB;">class</span><span style="color:#ADBAC7;">.java)</span></span>
|
||
<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><p>上面我们在 <code>registerModuleAppActivities</code> 方法中设置的 <code>proxy</code> 参数为默认的全局代理 <code>Activity</code>。</p><p>如果你需要指定某个代理的 <code>Activity</code> 使用另外的宿主 <code>Activity</code> 进行代理,你可以参考如下方法。</p><blockquote><p>示例如下</p></blockquote><div class="language-kotlin line-numbers-mode" data-ext="kt"><pre class="shiki github-dark-dimmed" style="background-color:#22272e;" tabindex="0"><code><span class="line"><span style="color:#F47067;">class</span><span style="color:#ADBAC7;"> </span><span style="color:#F69D50;">HostTestActivity</span><span style="color:#ADBAC7;"> : </span><span style="color:#F69D50;">BaseActivity</span><span style="color:#ADBAC7;">() {</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#768390;">// 指定一个另外的代理 Activity 类名,其也必须存在于宿主的 AndroidManifest 中</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#F47067;">override</span><span style="color:#ADBAC7;"> </span><span style="color:#F47067;">val</span><span style="color:#ADBAC7;"> proxyClassName </span><span style="color:#F47067;">get</span><span style="color:#ADBAC7;">() </span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">"com.demo.test.activity.OtherActivity"</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#F47067;">override</span><span style="color:#ADBAC7;"> </span><span style="color:#F47067;">fun</span><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">onCreate</span><span style="color:#ADBAC7;">(savedInstanceState: </span><span style="color:#F69D50;">Bundle</span><span style="color:#ADBAC7;">?) {</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#6CB6FF;">super</span><span style="color:#ADBAC7;">.</span><span style="color:#DCBDFB;">onCreate</span><span style="color:#ADBAC7;">(savedInstanceState)</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#768390;">// 模块资源已被自动注入,可以直接使用 xml 装载布局</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">setContentView</span><span style="color:#ADBAC7;">(R.layout.activity_main)</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> }</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;">}</span></span>
|
||
<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><div class="custom-container tip"><p class="custom-container-title">小提示</p><p>更多功能请参考 <a href="../public/com/highcapable/yukihookapi/hook/factory/YukiHookFactory#context-registermoduleappactivities-ext-method">Context.registerModuleAppActivities</a> 方法。</p></div><h2 id="创建-contextthemewrapper-代理" tabindex="-1"><a class="header-anchor" href="#创建-contextthemewrapper-代理" aria-hidden="true">#</a> 创建 ContextThemeWrapper 代理</h2><p>有时候,我们需要使用 <code>MaterialAlertDialogBuilder</code> 来美化自己在宿主中的对话框,但是拿不到 AppCompat 主题就无法创建。</p><ul><li>会得到如下异常</li></ul><div class="language-text" data-ext="text"><pre class="shiki github-dark-dimmed" style="background-color:#22272e;" tabindex="0"><code><span class="line"><span style="color:#adbac7;">The style on this component requires your app theme to be Theme.AppCompat (or a descendant).</span></span>
|
||
<span class="line"><span style="color:#adbac7;"></span></span></code></pre></div><p>这时,我们想在宿主被 Hook 的当前 <code>Activity</code> 中使用 <code>MaterialAlertDialogBuilder</code> 来创建对话框,就可以有如下方法。</p><blockquote><p>示例如下</p></blockquote><div class="language-kotlin line-numbers-mode" data-ext="kt"><pre class="shiki github-dark-dimmed" style="background-color:#22272e;" tabindex="0"><code><span class="line"><span style="color:#DCBDFB;">resolve</span><span style="color:#ADBAC7;">().</span><span style="color:#DCBDFB;">firstMethod</span><span style="color:#ADBAC7;"> {</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> name </span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">"onCreate"</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">parameters</span><span style="color:#ADBAC7;">(Bundle::</span><span style="color:#DCBDFB;">class</span><span style="color:#ADBAC7;">)</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;">}.</span><span style="color:#DCBDFB;">hook</span><span style="color:#ADBAC7;"> {</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">after</span><span style="color:#ADBAC7;"> {</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#768390;">// 使用 applyModuleTheme 创建一个当前模块中的主题资源</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#F47067;">val</span><span style="color:#ADBAC7;"> appCompatContext </span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">instance</span><span style="color:#ADBAC7;"><</span><span style="color:#F69D50;">Activity</span><span style="color:#ADBAC7;">>().</span><span style="color:#DCBDFB;">applyModuleTheme</span><span style="color:#ADBAC7;">(R.style.Theme_AppCompat)</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#768390;">// 直接使用这个包装了模块主题后的 Context 创建对话框</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">MaterialAlertDialogBuilder</span><span style="color:#ADBAC7;">(appCompatContext)</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> .</span><span style="color:#DCBDFB;">setTitle</span><span style="color:#ADBAC7;">(</span><span style="color:#96D0FF;">"AppCompat 主题对话框"</span><span style="color:#ADBAC7;">)</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> .</span><span style="color:#DCBDFB;">setMessage</span><span style="color:#ADBAC7;">(</span><span style="color:#96D0FF;">"我是一个在宿主中显示的 AppCompat 主题对话框。"</span><span style="color:#ADBAC7;">)</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> .</span><span style="color:#DCBDFB;">setPositiveButton</span><span style="color:#ADBAC7;">(</span><span style="color:#96D0FF;">"确定"</span><span style="color:#ADBAC7;">, </span><span style="color:#6CB6FF;">null</span><span style="color:#ADBAC7;">)</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> .</span><span style="color:#DCBDFB;">show</span><span style="color:#ADBAC7;">()</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> }</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;">}</span></span>
|
||
<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你还可以对当前 <code>Context</code> 通过 <code>uiMode</code> 设置原生的夜间模式和日间模式,至少需要 Android 10 及以上系统版本支持且当前主题包含夜间模式相关元素。</p><blockquote><p>示例如下</p></blockquote><div class="language-kotlin line-numbers-mode" data-ext="kt"><pre class="shiki github-dark-dimmed" style="background-color:#22272e;" tabindex="0"><code><span class="line"><span style="color:#DCBDFB;">resolve</span><span style="color:#ADBAC7;">().</span><span style="color:#DCBDFB;">firstMethod</span><span style="color:#ADBAC7;"> {</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> name </span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">"onCreate"</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">parameters</span><span style="color:#ADBAC7;">(Bundle::</span><span style="color:#DCBDFB;">class</span><span style="color:#ADBAC7;">)</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;">}.</span><span style="color:#DCBDFB;">hook</span><span style="color:#ADBAC7;"> {</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">after</span><span style="color:#ADBAC7;"> {</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#768390;">// 定义当前模块中的主题资源</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#F47067;">var</span><span style="color:#ADBAC7;"> appCompatContext: </span><span style="color:#F69D50;">ModuleContextThemeWrapper</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#768390;">// <方案1> 直接得到 Configuration 对象进行设置</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> appCompatContext </span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">instance</span><span style="color:#ADBAC7;"><</span><span style="color:#F69D50;">Activity</span><span style="color:#ADBAC7;">>()</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> .</span><span style="color:#DCBDFB;">applyModuleTheme</span><span style="color:#ADBAC7;">(R.style.Theme_AppCompat)</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> .</span><span style="color:#DCBDFB;">applyConfiguration</span><span style="color:#ADBAC7;"> { uiMode </span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;"> Configuration.UI_MODE_NIGHT_YES }</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#768390;">// <方案2> 创建一个新的 Configuration 对象</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#768390;">// 此方案会破坏当前宿主中原有的字体缩放大小等设置,你需要手动重新传递 densityDpi 等参数</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> appCompatContext </span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">instance</span><span style="color:#ADBAC7;"><</span><span style="color:#F69D50;">Activity</span><span style="color:#ADBAC7;">>().</span><span style="color:#DCBDFB;">applyModuleTheme</span><span style="color:#ADBAC7;">(</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> theme </span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;"> R.style.Theme_AppCompat,</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> configuration </span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">Configuration</span><span style="color:#ADBAC7;">().</span><span style="color:#DCBDFB;">apply</span><span style="color:#ADBAC7;"> { uiMode </span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;"> Configuration.UI_MODE_NIGHT_YES }</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> )</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#768390;">// 直接使用这个包装了模块主题后的 Context 创建对话框</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">MaterialAlertDialogBuilder</span><span style="color:#ADBAC7;">(appCompatContext)</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> .</span><span style="color:#DCBDFB;">setTitle</span><span style="color:#ADBAC7;">(</span><span style="color:#96D0FF;">"AppCompat 主题对话框"</span><span style="color:#ADBAC7;">)</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> .</span><span style="color:#DCBDFB;">setMessage</span><span style="color:#ADBAC7;">(</span><span style="color:#96D0FF;">"我是一个在宿主中显示的 AppCompat 主题对话框。"</span><span style="color:#ADBAC7;">)</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> .</span><span style="color:#DCBDFB;">setPositiveButton</span><span style="color:#ADBAC7;">(</span><span style="color:#96D0FF;">"确定"</span><span style="color:#ADBAC7;">, </span><span style="color:#6CB6FF;">null</span><span style="color:#ADBAC7;">)</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> .</span><span style="color:#DCBDFB;">show</span><span style="color:#ADBAC7;">()</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> }</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;">}</span></span>
|
||
<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>这样,我们就可以在宿主中非常简单地使用 <code>MaterialAlertDialogBuilder</code> 创建对话框了。</p>`,64),d={class:"custom-container warning"},A=s("p",{class:"custom-container-title"},"可能存在的问题",-1),y=s("strong",null,"androidx",-1),D=s("strong",null,"MaterialAlertDialog",-1),B=s("strong",null,"模块 Demo",-1),C={href:"https://github.com/HighCapable/YukiHookAPI/tree/master/samples/demo-module/src/main/java/com/highcapable/yukihookapi/demo_module/hook/factory/ComponentCompatFactory.kt",target:"_blank",rel:"noopener noreferrer"},v=s("p",null,[n("某些 APP 在创建时可能会发生 "),s("strong",null,"ClassCastException"),n(" 异常,请手动指定新的 "),s("strong",null,"Configuration"),n(" 实例来进行修复。")],-1),u=a(`<div class="custom-container tip"><p class="custom-container-title">小提示</p><p>更多功能请参考 <a href="../public/com/highcapable/yukihookapi/hook/factory/YukiHookFactory#context-applymoduletheme-ext-method">Context.applyModuleTheme</a> 方法。</p></div><h2 id="classloader-冲突问题" tabindex="-1"><a class="header-anchor" href="#classloader-冲突问题" aria-hidden="true">#</a> ClassLoader 冲突问题</h2><p>本页面所介绍的内容都是直接将模块的资源注入到了宿主,由于模块与宿主不在同一个进程 (同一个 <strong>APK</strong>) 中,其可能存在 <code>ClassLoader</code> 冲突的问题。</p><p>若发生了 <code>ClassLoader</code> 冲突,你可能会遇到 <code>ClassCastException</code> 异常。</p><p><code>YukiHookAPI</code> 默认已解决了可能冲突的问题,其余情况需要你自行配置排除列表。</p><p>排除列表决定了这些 <code>Class</code> 需要被模块还是宿主的 <code>ClassLoader</code> 进行装载。</p><blockquote><p>示例如下</p></blockquote><div class="language-kotlin line-numbers-mode" data-ext="kt"><pre class="shiki github-dark-dimmed" style="background-color:#22272e;" tabindex="0"><code><span class="line"><span style="color:#768390;">// 排除属于宿主的 Class 类名</span></span>
|
||
<span class="line"><span style="color:#768390;">// 它们将会被宿主的 ClassLoader 装载</span></span>
|
||
<span class="line"><span style="color:#768390;">// 以下内容仅供演示,不要直接使用,请以你的实际情况为准</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;">ModuleClassLoader.</span><span style="color:#DCBDFB;">excludeHostClasses</span><span style="color:#ADBAC7;">(</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">"androidx.core.app.ActivityCompat"</span><span style="color:#ADBAC7;">,</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">"com.demo.Test"</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;">)</span></span>
|
||
<span class="line"><span style="color:#768390;">// 排除属于模块的 Class 类名</span></span>
|
||
<span class="line"><span style="color:#768390;">// 它们将会被模块 (当前 Hook 进程) 的 ClassLoader 装载</span></span>
|
||
<span class="line"><span style="color:#768390;">// 以下内容仅供演示,不要直接使用,请以你的实际情况为准</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;">ModuleClassLoader.</span><span style="color:#DCBDFB;">excludeModuleClasses</span><span style="color:#ADBAC7;">(</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">"com.demo.entry.HookEntry"</span><span style="color:#ADBAC7;">,</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">"com.demo.controller.ModuleController"</span></span>
|
||
<span class="line"><span style="color:#ADBAC7;">)</span></span>
|
||
<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你需要在向宿主注入模块资源的方法执行之前进行设置才能生效。</p><p>此功能仅为解决宿主与模块中可能存在<strong>同名的 <code>Class</code></strong> 情况,例如共用的 SDK 以及依赖,在大部分情况下你不会用到此功能。</p><div class="custom-container tip"><p class="custom-container-title">小提示</p><p>更多功能请参考 <a href="../public/com/highcapable/yukihookapi/hook/xposed/parasitic/reference/ModuleClassLoader">ModuleClassLoader</a>。</p></div>`,11);function m(b,F){const l=o("ExternalLinkIcon");return p(),c("div",null,[r,s("div",d,[A,s("p",null,[n("由于一些 APP 自身使用的 "),y,n(" 依赖库或自定义主题可能会对当前 "),D,n(" 实际样式造成干扰,例如对话框的按钮样式,这种情况你可以参考 "),B,n(" 中 "),s("a",C,[n("这里的示例代码"),t(l)]),n(" 来修复这个问题。")]),v]),u])}const k=e(i,[["render",m],["__file","host-inject.html.vue"]]);export{k as default};
|