Files
YukiHookAPI/assets/host-inject.html-BNOoOrx_.js
github-actions[bot] aac9e42e84 Deploy to GitHub pages
2025-08-02 18:17:09 +00:00

151 lines
45 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;">&quot;--allow-reserved-package-id&quot;</span><span style="color:#ADBAC7;">, </span><span style="color:#96D0FF;">&quot;--package-id&quot;</span><span style="color:#ADBAC7;">, </span><span style="color:#96D0FF;">&quot;0x64&quot;</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;">&#39;--allow-reserved-package-id&#39;</span><span style="color:#ADBAC7;">, </span><span style="color:#96D0FF;">&#39;--package-id&#39;</span><span style="color:#ADBAC7;">, </span><span style="color:#96D0FF;">&#39;0x64&#39;</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;">&quot;onCreate&quot;</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;">&lt;</span><span style="color:#F69D50;">Activity</span><span style="color:#ADBAC7;">&gt;().</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;">// &lt;方案1&gt; 通过 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;">// &lt;方案2&gt; 直接得到宿主 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;">// &lt;方案1&gt; 通过 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;">// &lt;方案2&gt; 直接得到宿主 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;">&quot;onCreate&quot;</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;">&lt;</span><span style="color:#F69D50;">Activity</span><span style="color:#ADBAC7;">&gt;().</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;">&lt;</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;">&quot;com.demo.test.activity.TestActivity&quot;</span></span>
<span class="line"><span style="color:#ADBAC7;"> ...&gt;</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;">&quot;com.demo.test.activity.TestActivity&quot;</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;">&quot;com.demo.test.activity.OtherActivity&quot;</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;">&quot;onCreate&quot;</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;">&lt;</span><span style="color:#F69D50;">Activity</span><span style="color:#ADBAC7;">&gt;().</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;">&quot;AppCompat 主题对话框&quot;</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;">&quot;我是一个在宿主中显示的 AppCompat 主题对话框。&quot;</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;">&quot;确定&quot;</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;">&quot;onCreate&quot;</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;">// &lt;方案1&gt; 直接得到 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;">&lt;</span><span style="color:#F69D50;">Activity</span><span style="color:#ADBAC7;">&gt;()</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;">// &lt;方案2&gt; 创建一个新的 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;">&lt;</span><span style="color:#F69D50;">Activity</span><span style="color:#ADBAC7;">&gt;().</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;">&quot;AppCompat 主题对话框&quot;</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;">&quot;我是一个在宿主中显示的 AppCompat 主题对话框。&quot;</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;">&quot;确定&quot;</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;">&quot;androidx.core.app.ActivityCompat&quot;</span><span style="color:#ADBAC7;">,</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">&quot;com.demo.Test&quot;</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;">&quot;com.demo.entry.HookEntry&quot;</span><span style="color:#ADBAC7;">,</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">&quot;com.demo.controller.ModuleController&quot;</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};