From aac9e42e846551c74411acf2c3395fd56d893ce7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 2 Aug 2025 18:17:09 +0000 Subject: [PATCH] Deploy to GitHub pages --- .nojekyll | 0 404.html | 34 + assets/404.html-5sy5zeZP.js | 1 + assets/404.html-BkgNjMhp.js | 1 + assets/BaseFinder.html-C6lfjJ7s.js | 1 + assets/BaseFinder.html-CAOGJdjR.js | 9 + assets/BaseFinder.html-CAvlkbqd.js | 1 + assets/BaseFinder.html-DvwHVrKn.js | 9 + assets/ChannelData.html-BX_rAvQg.js | 1 + assets/ChannelData.html-Bp3A6ogd.js | 23 + assets/ChannelData.html-C7ktasrE.js | 1 + assets/ChannelData.html-CFQv84Ul.js | 23 + assets/ChannelPriority.html-BGoRh-pu.js | 1 + assets/ChannelPriority.html-BHp-ErCM.js | 1 + assets/ChannelPriority.html-CEzIYSdp.js | 2 + assets/ChannelPriority.html-DFUm-PWb.js | 2 + assets/ComponentTypeFactory.html-357LuQ82.js | 1 + assets/ComponentTypeFactory.html-B-t1GVQa.js | 1 + assets/ComponentTypeFactory.html-DptIpBn2.js | 1 + assets/ComponentTypeFactory.html-VD1JaHTz.js | 1 + assets/ConstructorFinder.html-CVpWcXzr.js | 88 ++ assets/ConstructorFinder.html-CmDHOksx.js | 1 + assets/ConstructorFinder.html-DrSYr7fy.js | 88 ++ assets/ConstructorFinder.html-DuJIkaTM.js | 1 + assets/ConstructorRules.html-BuW8PcLh.js | 1 + assets/ConstructorRules.html-Bxffddpr.js | 9 + assets/ConstructorRules.html-CjPJ9499.js | 9 + assets/ConstructorRules.html-phFNNXJ8.js | 1 + assets/CountRules.html-BiTeupWL.js | 1 + assets/CountRules.html-CAljrhzL.js | 6 + assets/CountRules.html-cCBf7VmB.js | 6 + assets/CountRules.html-lW3FW-Bi.js | 1 + assets/CurrentClass.html-BT6y6bjW.js | 1 + assets/CurrentClass.html-CF1c04UQ.js | 16 + assets/CurrentClass.html-Drrw8tv5.js | 1 + assets/CurrentClass.html-Dwxk2yiw.js | 16 + assets/DefinedTypeFactory.html-B0M9p-6D.js | 2 + assets/DefinedTypeFactory.html-C97GePUm.js | 1 + assets/DefinedTypeFactory.html-DI2zOcK2.js | 1 + assets/DefinedTypeFactory.html-DyzA4S0r.js | 2 + assets/DexClassFinder.html-BAaqClmM.js | 1 + assets/DexClassFinder.html-BbI_zWlb.js | 45 + assets/DexClassFinder.html-CGIuabI3.js | 1 + assets/DexClassFinder.html-DDicCU5w.js | 45 + assets/ExecutorType.html-Crao5k7G.js | 1 + assets/ExecutorType.html-DyWI3DE3.js | 8 + assets/ExecutorType.html-lxG6aiIx.js | 8 + assets/ExecutorType.html-tZrR-ZDE.js | 1 + assets/FieldFinder.html-C9KHPG3N.js | 1 + assets/FieldFinder.html-Cj74NK2V.js | 84 ++ assets/FieldFinder.html-CoQdzzYH.js | 1 + assets/FieldFinder.html-Di6mgVKf.js | 84 ++ assets/FieldRules.html-D50kuywF.js | 7 + assets/FieldRules.html-DePoZYvp.js | 1 + assets/FieldRules.html-DnAEAxmC.js | 1 + assets/FieldRules.html-DzJvDeKO.js | 7 + assets/GenericClass.html-8gR9C4nD.js | 4 + assets/GenericClass.html-CsB6lKmB.js | 1 + assets/GenericClass.html-DO13T8ug.js | 1 + assets/GenericClass.html-DQHoN7CN.js | 4 + assets/GraphicsTypeFactory.html-B1x8cclg.js | 1 + assets/GraphicsTypeFactory.html-CnqF4An8.js | 1 + assets/GraphicsTypeFactory.html-Dq_zQQPa.js | 1 + assets/GraphicsTypeFactory.html-pywoj7PR.js | 1 + assets/HookClass.html-CIc4FkOC.js | 2 + assets/HookClass.html-CJV3GEVs.js | 2 + assets/HookClass.html-CW_9kHEG.js | 1 + assets/HookClass.html-CszRm9Er.js | 1 + assets/HookParam.html-ArPvy40F.js | 88 ++ assets/HookParam.html-BjAineUd.js | 88 ++ assets/HookParam.html-CQJSudBe.js | 1 + assets/HookParam.html-SbRyLaGf.js | 1 + assets/HookResources.html-B9Np_jgF.js | 1 + assets/HookResources.html-DA2dINvc.js | 1 + assets/HookResources.html-_3fh2QXJ.js | 2 + assets/HookResources.html-zBrjRa5p.js | 2 + assets/IYukiHookXposedInit.html-CjNI4nFN.js | 5 + assets/IYukiHookXposedInit.html-DEGewXhq.js | 1 + assets/IYukiHookXposedInit.html-DTEi8nM4.js | 5 + assets/IYukiHookXposedInit.html-Dr7_YjoO.js | 1 + .../InjectYukiHookWithXposed.html-4oxD2_xz.js | 8 + .../InjectYukiHookWithXposed.html-B4v_FVid.js | 8 + .../InjectYukiHookWithXposed.html-BGS_DJ2i.js | 1 + .../InjectYukiHookWithXposed.html-C_GfVAhD.js | 1 + assets/MemberRules.html-CzY4xHkS.js | 1 + assets/MemberRules.html-DBoFuxYs.js | 3 + assets/MemberRules.html-WT4l8b-Y.js | 3 + assets/MemberRules.html-r3ZOm1rb.js | 1 + assets/MemberRulesResult.html-4uRTQRQi.js | 1 + assets/MemberRulesResult.html-C2cLl89Y.js | 6 + assets/MemberRulesResult.html-CPcOEYiz.js | 6 + assets/MemberRulesResult.html-DVBlYWR7.js | 1 + assets/MethodFinder.html-BepwXG9K.js | 1 + assets/MethodFinder.html-CtgDtD9U.js | 104 +++ assets/MethodFinder.html-DLZMTsEY.js | 104 +++ assets/MethodFinder.html-DxYxJsjj.js | 1 + assets/MethodRules.html-B2dSoNBv.js | 13 + assets/MethodRules.html-BCtTTlLz.js | 1 + assets/MethodRules.html-CW03U_a6.js | 13 + assets/MethodRules.html-DETSSGJ6.js | 1 + assets/ModifierRules.html-B1V1DMvv.js | 14 + assets/ModifierRules.html-B9KoNMo6.js | 1 + assets/ModifierRules.html-DD38DB4t.js | 14 + assets/ModifierRules.html-DZnBFn8R.js | 1 + assets/ModuleAppActivity.html-BffipQvV.js | 3 + assets/ModuleAppActivity.html-BwDznH0J.js | 1 + assets/ModuleAppActivity.html-CrhmOsh-.js | 1 + assets/ModuleAppActivity.html-e7GuQiJo.js | 3 + .../ModuleAppCompatActivity.html-BCax3oQU.js | 1 + .../ModuleAppCompatActivity.html-C5B-6ZTc.js | 4 + .../ModuleAppCompatActivity.html-Csob9Ceu.js | 4 + .../ModuleAppCompatActivity.html-JFvN5vF4.js | 1 + assets/ModuleApplication.html--_5n76BL.js | 17 + assets/ModuleApplication.html-BkkBbb-2.js | 1 + assets/ModuleApplication.html-C4NqW1gZ.js | 1 + assets/ModuleApplication.html-DYtHym0q.js | 17 + assets/ModuleClassLoader.html-BFtfl5mt.js | 1 + assets/ModuleClassLoader.html-BbehDNqJ.js | 4 + assets/ModuleClassLoader.html-BwGRnYn5.js | 1 + assets/ModuleClassLoader.html-a6gisn52.js | 4 + ...ModuleContextThemeWrapper.html-BylfEIpg.js | 3 + ...ModuleContextThemeWrapper.html-D3JVFalR.js | 1 + ...ModuleContextThemeWrapper.html-DNoARGj7.js | 1 + ...ModuleContextThemeWrapper.html-UouAIg96.js | 3 + .../ModulePreferenceFragment.html-BozNh-bQ.js | 22 + .../ModulePreferenceFragment.html-CXpIHn7Z.js | 1 + .../ModulePreferenceFragment.html-DSUkMTGs.js | 1 + .../ModulePreferenceFragment.html-XrU_e4rC.js | 22 + assets/NameRules.html-BWk6zL2M.js | 1 + assets/NameRules.html-DOue2ksg.js | 9 + assets/NameRules.html-DopiK4pt.js | 1 + assets/NameRules.html-zuU55Nke.js | 9 + assets/ObjectRules.html-1b_D9aS8.js | 2 + assets/ObjectRules.html-DA4rLBnV.js | 2 + assets/ObjectRules.html-DjhVlNAH.js | 1 + assets/ObjectRules.html-Dxosvxi0.js | 1 + assets/PackageParam.html-356ELE7K.js | 1 + assets/PackageParam.html-B3y0YF_m.js | 1 + assets/PackageParam.html-Bti7eWUt.js | 129 +++ assets/PackageParam.html-vqkHjjmt.js | 129 +++ assets/PrefsData.html-B72hWN1s.js | 1 + assets/PrefsData.html-BInEpoWz.js | 18 + assets/PrefsData.html-BbIfbfIq.js | 1 + assets/PrefsData.html-BbtXNnuS.js | 18 + assets/ReflectionFactory.html-BTXWRqP4.js | 1 + assets/ReflectionFactory.html-BVjwrqby.js | 120 +++ assets/ReflectionFactory.html-BiQJ-KKx.js | 1 + assets/ReflectionFactory.html-Z7mH28Qd.js | 120 +++ assets/VariableTypeFactory.html-BUNfn5Dn.js | 1 + assets/VariableTypeFactory.html-Cel7GBhi.js | 1 + assets/VariableTypeFactory.html-DDYYL3th.js | 1 + assets/VariableTypeFactory.html-DqSR6Ejd.js | 1 + assets/VariousClass.html-3D_jbtJ_.js | 1 + assets/VariousClass.html-BdAcgrdg.js | 4 + assets/VariousClass.html-CKljcU2t.js | 1 + assets/VariousClass.html-DXVXaoSY.js | 4 + assets/ViewTypeFactory.html-2ZSLUHiw.js | 1 + assets/ViewTypeFactory.html-CIPHyInd.js | 1 + assets/ViewTypeFactory.html-DPcuUPhN.js | 1 + assets/ViewTypeFactory.html-pGgKQdI9.js | 1 + assets/YLog.html-COO68ekD.js | 1 + assets/YLog.html-DvNg4c8I.js | 29 + assets/YLog.html-KE-5aK_7.js | 1 + assets/YLog.html-g2dfXKDH.js | 29 + assets/YLogData.html-4aWpXHE7.js | 11 + assets/YLogData.html-Bjac08gN.js | 1 + assets/YLogData.html-DIaUDgTt.js | 11 + assets/YLogData.html-XHmF_gos.js | 1 + assets/YukiBaseHooker.html-CWm_43km.js | 1 + assets/YukiBaseHooker.html-D01KVdut.js | 3 + assets/YukiBaseHooker.html-Dg91Mdnk.js | 3 + assets/YukiBaseHooker.html-E78OJRmm.js | 1 + assets/YukiHookAPI.html-BRFLeDZT.js | 93 ++ assets/YukiHookAPI.html-CtkZ6zEO.js | 1 + assets/YukiHookAPI.html-DqgBnIkU.js | 1 + assets/YukiHookAPI.html-DwLoSNWF.js | 93 ++ assets/YukiHookDataChannel.html-0wHuRMGr.js | 16 + assets/YukiHookDataChannel.html-Citru5C3.js | 1 + assets/YukiHookDataChannel.html-DgdZw6CE.js | 1 + assets/YukiHookDataChannel.html-iKhC7MJd.js | 16 + assets/YukiHookFactory.html-B7vz7jla.js | 11 + assets/YukiHookFactory.html-BKpat8zr.js | 1 + assets/YukiHookFactory.html-CoBstbjt.js | 1 + assets/YukiHookFactory.html-Dp3ev0qR.js | 11 + assets/YukiHookPrefsBridge.html-BG7-Nq7V.js | 1 + assets/YukiHookPrefsBridge.html-DVZoJTsa.js | 34 + assets/YukiHookPrefsBridge.html-Dprm2-90.js | 34 + assets/YukiHookPrefsBridge.html-XzXYFQ1s.js | 1 + assets/YukiHookPriority.html-AgDP0CYh.js | 1 + assets/YukiHookPriority.html-BzBXrjfk.js | 5 + assets/YukiHookPriority.html-CUgcejgE.js | 5 + assets/YukiHookPriority.html-smxFpy5Q.js | 1 + assets/YukiMemberHookCreator.html-C0fIOtqI.js | 1 + assets/YukiMemberHookCreator.html-C1zPXD2D.js | 1 + assets/YukiMemberHookCreator.html-De9-pEl1.js | 36 + assets/YukiMemberHookCreator.html-WvIyCwTr.js | 36 + assets/YukiModuleResources.html-CAc6ozP1.js | 3 + assets/YukiModuleResources.html-DZnAa6JN.js | 1 + assets/YukiModuleResources.html-DyrSatFK.js | 3 + assets/YukiModuleResources.html-jRWj4Ooi.js | 1 + assets/YukiResForwarder.html-CtCGVu9N.js | 1 + assets/YukiResForwarder.html-DHpOwzIq.js | 4 + assets/YukiResForwarder.html-DMGGwbMr.js | 1 + assets/YukiResForwarder.html-PPhoLmXZ.js | 4 + assets/YukiResources.html--5kriWCV.js | 1 + assets/YukiResources.html-CwrMMidY.js | 7 + assets/YukiResources.html-DZg6eRc4.js | 7 + assets/YukiResources.html-DzFxHHne.js | 1 + .../YukiResourcesHookCreator.html-CKh6FwjE.js | 97 ++ .../YukiResourcesHookCreator.html-CuPFBHZF.js | 97 ++ .../YukiResourcesHookCreator.html-DW5yilOs.js | 1 + .../YukiResourcesHookCreator.html-RF6ZJecD.js | 1 + assets/YukiXposedEvent.html-BFs-WRvy.js | 1 + assets/YukiXposedEvent.html-BIvOGBiv.js | 6 + assets/YukiXposedEvent.html-C9AS9omI.js | 1 + assets/YukiXposedEvent.html-DtehWaX2.js | 6 + assets/about.html-B_eiWEVD.js | 16 + assets/about.html-C7A_QXrx.js | 16 + assets/about.html-D2yzzIyM.js | 1 + assets/about.html-DDk-q1tu.js | 1 + assets/api-example.html-CKw7e9Ka.js | 1 + assets/api-example.html-DtfHDuEM.js | 237 +++++ assets/api-example.html-pCpzRhE2.js | 1 + assets/api-example.html-t4M0wmt4.js | 235 +++++ assets/api-exception.html-9Je71x4B.js | 336 +++++++ assets/api-exception.html-Dw1mqBwg.js | 1 + assets/api-exception.html-Pu6YF45s.js | 1 + assets/api-exception.html-vCoW3MFk.js | 340 +++++++ assets/api-using.html-CsMd954C.js | 1 + assets/api-using.html-DtbSeeEs.js | 50 + assets/api-using.html-P_EkKVX5.js | 50 + assets/api-using.html-zXrI7_0R.js | 1 + assets/app-BpUB8-Q8.js | 16 + assets/changelog.html-B8UfyBpi.js | 1 + assets/changelog.html-BQ5AB5_x.js | 1 + assets/changelog.html-Bti1NzlA.js | 1 + assets/changelog.html-D0nYCScY.js | 1 + assets/contacts.html-BSRuPKMe.js | 1 + assets/contacts.html-BfIGgEZ9.js | 1 + assets/contacts.html-CGQemCaU.js | 1 + assets/contacts.html-Co35EHVH.js | 1 + assets/example.html-CnT6OQuI.js | 1 + assets/example.html-Cp22GGCP.js | 300 ++++++ assets/example.html-DBLcpd3T.js | 1 + assets/example.html-l_t2vpgR.js | 300 ++++++ assets/future.html-BJR2WZUb.js | 1 + assets/future.html-BS9bLph2.js | 1 + assets/future.html-L0gip76T.js | 1 + assets/future.html-aS7aVBMr.js | 1 + assets/home.html-BWNdBIZw.js | 1 + assets/home.html-Bhz1Th03.js | 1 + assets/home.html-CSP-y2Sx.js | 1 + assets/home.html-Cg57uIpM.js | 1 + assets/home.html-DAJQxBy-.js | 1 + assets/home.html-DVG1oAZg.js | 71 ++ assets/home.html-DwzlpDun.js | 1 + assets/home.html-Hj1hpUN3.js | 71 ++ assets/host-inject.html-BNOoOrx_.js | 150 +++ assets/host-inject.html-BRZka0o7.js | 1 + assets/host-inject.html-COD96F06.js | 1 + assets/host-inject.html-DyCVxqXv.js | 156 ++++ assets/host-lifecycle.html-BgnOErBM.js | 1 + assets/host-lifecycle.html-BqYisHbJ.js | 51 + assets/host-lifecycle.html-BsjcaKw0.js | 47 + assets/host-lifecycle.html-C7PzYAZN.js | 1 + assets/index.html-5uusgM1u.js | 1 + assets/index.html-Bo0olcew.js | 1 + assets/index.html-CB7-jiwu.js | 14 + assets/index.html-CHgP8geU.js | 1 + assets/index.html-D6YZKtoe.js | 1 + assets/index.html-NYRlXN7n.js | 14 + assets/knowledge.html-BJFcZiJH.js | 1 + assets/knowledge.html-BvjZCte4.js | 13 + assets/knowledge.html-CFMQgPep.js | 1 + assets/knowledge.html-CabyS3rt.js | 13 + assets/logger.html-B-OHJyal.js | 47 + assets/logger.html-BW4Gjfc-.js | 1 + assets/logger.html-C9kwF_yM.js | 51 + assets/logger.html-Dfs7bQRS.js | 1 + assets/move-to-api-1-2-x.html-CCb8Xv2u.js | 1 + assets/move-to-api-1-2-x.html-D8SebGDZ.js | 1 + assets/move-to-api-1-2-x.html-IonwGaOH.js | 67 ++ assets/move-to-api-1-2-x.html-etgyp2HF.js | 67 ++ assets/move-to-api-1-3-x.html-C6uNfo-e.js | 18 + assets/move-to-api-1-3-x.html-CPnNzAVm.js | 1 + assets/move-to-api-1-3-x.html-DBMmjUYq.js | 18 + assets/move-to-api-1-3-x.html-f3TZzPCU.js | 1 + assets/move-to-new-api.html-Bd10LyS9.js | 1 + assets/move-to-new-api.html-CtQJCJWD.js | 208 +++++ assets/move-to-new-api.html-DwX5LqED.js | 208 +++++ assets/move-to-new-api.html-kyRByfpu.js | 1 + assets/quick-start.html-CnOHbn2J.js | 170 ++++ assets/quick-start.html-Dq2QHQuy.js | 1 + assets/quick-start.html-pUciT6Ob.js | 160 ++++ assets/quick-start.html-teZCSUoB.js | 1 + assets/r8-proguard.html-BruKL-ec.js | 2 + assets/r8-proguard.html-C9EyjikD.js | 2 + assets/r8-proguard.html-DnD4WWCL.js | 1 + assets/r8-proguard.html-Y47fgLwe.js | 1 + assets/reflection.html-BZdJSVZS.js | 822 ++++++++++++++++ assets/reflection.html-BohdUWGg.js | 1 + assets/reflection.html-D65pVYER.js | 849 +++++++++++++++++ assets/reflection.html-DXPuhLBz.js | 1 + assets/style-DJZs_E_O.css | 1 + assets/supportive.html-CTTW-ar9.js | 1 + assets/supportive.html-Cd4sY_Jm.js | 1 + assets/supportive.html-DFnCbU7r.js | 1 + assets/supportive.html-bOj3zBC_.js | 1 + assets/xposed-channel.html-B7eDf6ix.js | 1 + assets/xposed-channel.html-BeC6v_Qb.js | 118 +++ assets/xposed-channel.html-DWoHNeKf.js | 1 + assets/xposed-channel.html-DZ4m7tlI.js | 120 +++ assets/xposed-storage.html-ByKfNh6r.js | 1 + assets/xposed-storage.html-CFhC-RoM.js | 38 + assets/xposed-storage.html-CZy1SL3y.js | 1 + assets/xposed-storage.html-DYzzLHun.js | 38 + assets/xposed-using.html-7rTJRpMs.js | 88 ++ assets/xposed-using.html-B9LNrU2W.js | 88 ++ assets/xposed-using.html-CgLVQrdV.js | 1 + assets/xposed-using.html-sNzVArkO.js | 1 + ...ukihookapi-projectbuilder.html-0qjforhM.js | 1 + ...ukihookapi-projectbuilder.html-Bq3KEpgx.js | 1 + ...ukihookapi-projectbuilder.html-DnghHaiT.js | 1 + ...ukihookapi-projectbuilder.html-xbo0Krpt.js | 1 + en/about/about.html | 49 + en/about/changelog.html | 34 + en/about/contacts.html | 34 + en/about/future.html | 34 + en/api/home.html | 34 + .../highcapable/yukihookapi/YukiHookAPI.html | 126 +++ .../xposed/InjectYukiHookWithXposed.html | 41 + .../yukihookapi/hook/bean/CurrentClass.html | 49 + .../yukihookapi/hook/bean/GenericClass.html | 37 + .../yukihookapi/hook/bean/HookClass.html | 35 + .../yukihookapi/hook/bean/HookResources.html | 35 + .../yukihookapi/hook/bean/VariousClass.html | 37 + .../hook/core/YukiMemberHookCreator.html | 69 ++ .../hook/core/YukiResourcesHookCreator.html | 130 +++ .../core/api/compat/type/ExecutorType.html | 41 + .../core/api/priority/YukiHookPriority.html | 38 + .../hook/core/finder/base/BaseFinder.html | 42 + .../core/finder/base/rules/CountRules.html | 39 + .../core/finder/base/rules/ModifierRules.html | 47 + .../core/finder/base/rules/NameRules.html | 42 + .../core/finder/base/rules/ObjectRules.html | 35 + .../core/finder/classes/DexClassFinder.html | 78 ++ .../classes/rules/ConstructorRules.html | 42 + .../core/finder/classes/rules/FieldRules.html | 40 + .../finder/classes/rules/MemberRules.html | 36 + .../finder/classes/rules/MethodRules.html | 46 + .../rules/result/MemberRulesResult.html | 39 + .../finder/members/ConstructorFinder.html | 121 +++ .../hook/core/finder/members/FieldFinder.html | 117 +++ .../core/finder/members/MethodFinder.html | 137 +++ .../hook/entity/YukiBaseHooker.html | 36 + .../hook/factory/ReflectionFactory.html | 153 +++ .../hook/factory/YukiHookFactory.html | 44 + .../yukihookapi/hook/log/YLog.html | 62 ++ .../yukihookapi/hook/log/data/YLogData.html | 44 + .../yukihookapi/hook/param/HookParam.html | 121 +++ .../yukihookapi/hook/param/PackageParam.html | 162 ++++ .../type/android/ComponentTypeFactory.html | 34 + .../type/android/GraphicsTypeFactory.html | 34 + .../hook/type/android/ViewTypeFactory.html | 34 + .../hook/type/defined/DefinedTypeFactory.html | 35 + .../hook/type/java/VariableTypeFactory.html | 34 + .../xposed/application/ModuleApplication.html | 50 + .../xposed/bridge/event/YukiXposedEvent.html | 39 + .../bridge/resources/YukiModuleResources.html | 36 + .../bridge/resources/YukiResForwarder.html | 37 + .../bridge/resources/YukiResources.html | 40 + .../xposed/channel/YukiHookDataChannel.html | 49 + .../hook/xposed/channel/data/ChannelData.html | 56 ++ .../channel/priority/ChannelPriority.html | 35 + .../activity/base/ModuleAppActivity.html | 36 + .../base/ModuleAppCompatActivity.html | 37 + .../wrapper/ModuleContextThemeWrapper.html | 36 + .../reference/ModuleClassLoader.html | 37 + .../xposed/prefs/YukiHookPrefsBridge.html | 67 ++ .../hook/xposed/prefs/data/PrefsData.html | 51 + .../prefs/ui/ModulePreferenceFragment.html | 55 ++ .../xposed/proxy/IYukiHookXposedInit.html | 38 + en/api/special-features/host-inject.html | 189 ++++ en/api/special-features/host-lifecycle.html | 84 ++ en/api/special-features/logger.html | 84 ++ en/api/special-features/reflection.html | 882 ++++++++++++++++++ en/api/special-features/xposed-channel.html | 153 +++ en/api/special-features/xposed-storage.html | 71 ++ en/config/api-example.html | 270 ++++++ en/config/api-exception.html | 373 ++++++++ en/config/api-using.html | 83 ++ en/config/move-to-api-1-2-x.html | 100 ++ en/config/move-to-api-1-3-x.html | 51 + en/config/r8-proguard.html | 35 + en/config/xposed-using.html | 121 +++ en/guide/example.html | 333 +++++++ en/guide/home.html | 104 +++ en/guide/knowledge.html | 46 + en/guide/move-to-new-api.html | 241 +++++ en/guide/quick-start.html | 203 ++++ en/guide/supportive.html | 34 + en/index.html | 47 + en/tools/yukihookapi-projectbuilder.html | 34 + images/logo.png | Bin 0 -> 24264 bytes images/yukihookapi-projectbuilder-en.png | Bin 0 -> 364753 bytes images/yukihookapi-projectbuilder-zh-cn.png | Bin 0 -> 684305 bytes index.html | 34 + zh-cn/about/about.html | 49 + zh-cn/about/changelog.html | 34 + zh-cn/about/contacts.html | 34 + zh-cn/about/future.html | 34 + zh-cn/api/home.html | 34 + .../highcapable/yukihookapi/YukiHookAPI.html | 126 +++ .../xposed/InjectYukiHookWithXposed.html | 41 + .../yukihookapi/hook/bean/CurrentClass.html | 49 + .../yukihookapi/hook/bean/GenericClass.html | 37 + .../yukihookapi/hook/bean/HookClass.html | 35 + .../yukihookapi/hook/bean/HookResources.html | 35 + .../yukihookapi/hook/bean/VariousClass.html | 37 + .../hook/core/YukiMemberHookCreator.html | 69 ++ .../hook/core/YukiResourcesHookCreator.html | 130 +++ .../core/api/compat/type/ExecutorType.html | 41 + .../core/api/priority/YukiHookPriority.html | 38 + .../hook/core/finder/base/BaseFinder.html | 42 + .../core/finder/base/rules/CountRules.html | 39 + .../core/finder/base/rules/ModifierRules.html | 47 + .../core/finder/base/rules/NameRules.html | 42 + .../core/finder/base/rules/ObjectRules.html | 35 + .../core/finder/classes/DexClassFinder.html | 78 ++ .../classes/rules/ConstructorRules.html | 42 + .../core/finder/classes/rules/FieldRules.html | 40 + .../finder/classes/rules/MemberRules.html | 36 + .../finder/classes/rules/MethodRules.html | 46 + .../rules/result/MemberRulesResult.html | 39 + .../finder/members/ConstructorFinder.html | 121 +++ .../hook/core/finder/members/FieldFinder.html | 117 +++ .../core/finder/members/MethodFinder.html | 137 +++ .../hook/entity/YukiBaseHooker.html | 36 + .../hook/factory/ReflectionFactory.html | 153 +++ .../hook/factory/YukiHookFactory.html | 44 + .../yukihookapi/hook/log/YLog.html | 62 ++ .../yukihookapi/hook/log/data/YLogData.html | 44 + .../yukihookapi/hook/param/HookParam.html | 121 +++ .../yukihookapi/hook/param/PackageParam.html | 162 ++++ .../type/android/ComponentTypeFactory.html | 34 + .../type/android/GraphicsTypeFactory.html | 34 + .../hook/type/android/ViewTypeFactory.html | 34 + .../hook/type/defined/DefinedTypeFactory.html | 35 + .../hook/type/java/VariableTypeFactory.html | 34 + .../xposed/application/ModuleApplication.html | 50 + .../xposed/bridge/event/YukiXposedEvent.html | 39 + .../bridge/resources/YukiModuleResources.html | 36 + .../bridge/resources/YukiResForwarder.html | 37 + .../bridge/resources/YukiResources.html | 40 + .../xposed/channel/YukiHookDataChannel.html | 49 + .../hook/xposed/channel/data/ChannelData.html | 56 ++ .../channel/priority/ChannelPriority.html | 35 + .../activity/base/ModuleAppActivity.html | 36 + .../base/ModuleAppCompatActivity.html | 37 + .../wrapper/ModuleContextThemeWrapper.html | 36 + .../reference/ModuleClassLoader.html | 37 + .../xposed/prefs/YukiHookPrefsBridge.html | 67 ++ .../hook/xposed/prefs/data/PrefsData.html | 51 + .../prefs/ui/ModulePreferenceFragment.html | 55 ++ .../xposed/proxy/IYukiHookXposedInit.html | 38 + zh-cn/api/special-features/host-inject.html | 183 ++++ .../api/special-features/host-lifecycle.html | 80 ++ zh-cn/api/special-features/logger.html | 80 ++ zh-cn/api/special-features/reflection.html | 855 +++++++++++++++++ .../api/special-features/xposed-channel.html | 151 +++ .../api/special-features/xposed-storage.html | 71 ++ zh-cn/config/api-example.html | 268 ++++++ zh-cn/config/api-exception.html | 369 ++++++++ zh-cn/config/api-using.html | 83 ++ zh-cn/config/move-to-api-1-2-x.html | 100 ++ zh-cn/config/move-to-api-1-3-x.html | 51 + zh-cn/config/r8-proguard.html | 35 + zh-cn/config/xposed-using.html | 121 +++ zh-cn/guide/example.html | 333 +++++++ zh-cn/guide/home.html | 104 +++ zh-cn/guide/knowledge.html | 46 + zh-cn/guide/move-to-new-api.html | 241 +++++ zh-cn/guide/quick-start.html | 193 ++++ zh-cn/guide/supportive.html | 34 + zh-cn/index.html | 47 + zh-cn/tools/yukihookapi-projectbuilder.html | 34 + 486 files changed, 21771 insertions(+) create mode 100644 .nojekyll create mode 100644 404.html create mode 100644 assets/404.html-5sy5zeZP.js create mode 100644 assets/404.html-BkgNjMhp.js create mode 100644 assets/BaseFinder.html-C6lfjJ7s.js create mode 100644 assets/BaseFinder.html-CAOGJdjR.js create mode 100644 assets/BaseFinder.html-CAvlkbqd.js create mode 100644 assets/BaseFinder.html-DvwHVrKn.js create mode 100644 assets/ChannelData.html-BX_rAvQg.js create mode 100644 assets/ChannelData.html-Bp3A6ogd.js create mode 100644 assets/ChannelData.html-C7ktasrE.js create mode 100644 assets/ChannelData.html-CFQv84Ul.js create mode 100644 assets/ChannelPriority.html-BGoRh-pu.js create mode 100644 assets/ChannelPriority.html-BHp-ErCM.js create mode 100644 assets/ChannelPriority.html-CEzIYSdp.js create mode 100644 assets/ChannelPriority.html-DFUm-PWb.js create mode 100644 assets/ComponentTypeFactory.html-357LuQ82.js create mode 100644 assets/ComponentTypeFactory.html-B-t1GVQa.js create mode 100644 assets/ComponentTypeFactory.html-DptIpBn2.js create mode 100644 assets/ComponentTypeFactory.html-VD1JaHTz.js create mode 100644 assets/ConstructorFinder.html-CVpWcXzr.js create mode 100644 assets/ConstructorFinder.html-CmDHOksx.js create mode 100644 assets/ConstructorFinder.html-DrSYr7fy.js create mode 100644 assets/ConstructorFinder.html-DuJIkaTM.js create mode 100644 assets/ConstructorRules.html-BuW8PcLh.js create mode 100644 assets/ConstructorRules.html-Bxffddpr.js create mode 100644 assets/ConstructorRules.html-CjPJ9499.js create mode 100644 assets/ConstructorRules.html-phFNNXJ8.js create mode 100644 assets/CountRules.html-BiTeupWL.js create mode 100644 assets/CountRules.html-CAljrhzL.js create mode 100644 assets/CountRules.html-cCBf7VmB.js create mode 100644 assets/CountRules.html-lW3FW-Bi.js create mode 100644 assets/CurrentClass.html-BT6y6bjW.js create mode 100644 assets/CurrentClass.html-CF1c04UQ.js create mode 100644 assets/CurrentClass.html-Drrw8tv5.js create mode 100644 assets/CurrentClass.html-Dwxk2yiw.js create mode 100644 assets/DefinedTypeFactory.html-B0M9p-6D.js create mode 100644 assets/DefinedTypeFactory.html-C97GePUm.js create mode 100644 assets/DefinedTypeFactory.html-DI2zOcK2.js create mode 100644 assets/DefinedTypeFactory.html-DyzA4S0r.js create mode 100644 assets/DexClassFinder.html-BAaqClmM.js create mode 100644 assets/DexClassFinder.html-BbI_zWlb.js create mode 100644 assets/DexClassFinder.html-CGIuabI3.js create mode 100644 assets/DexClassFinder.html-DDicCU5w.js create mode 100644 assets/ExecutorType.html-Crao5k7G.js create mode 100644 assets/ExecutorType.html-DyWI3DE3.js create mode 100644 assets/ExecutorType.html-lxG6aiIx.js create mode 100644 assets/ExecutorType.html-tZrR-ZDE.js create mode 100644 assets/FieldFinder.html-C9KHPG3N.js create mode 100644 assets/FieldFinder.html-Cj74NK2V.js create mode 100644 assets/FieldFinder.html-CoQdzzYH.js create mode 100644 assets/FieldFinder.html-Di6mgVKf.js create mode 100644 assets/FieldRules.html-D50kuywF.js create mode 100644 assets/FieldRules.html-DePoZYvp.js create mode 100644 assets/FieldRules.html-DnAEAxmC.js create mode 100644 assets/FieldRules.html-DzJvDeKO.js create mode 100644 assets/GenericClass.html-8gR9C4nD.js create mode 100644 assets/GenericClass.html-CsB6lKmB.js create mode 100644 assets/GenericClass.html-DO13T8ug.js create mode 100644 assets/GenericClass.html-DQHoN7CN.js create mode 100644 assets/GraphicsTypeFactory.html-B1x8cclg.js create mode 100644 assets/GraphicsTypeFactory.html-CnqF4An8.js create mode 100644 assets/GraphicsTypeFactory.html-Dq_zQQPa.js create mode 100644 assets/GraphicsTypeFactory.html-pywoj7PR.js create mode 100644 assets/HookClass.html-CIc4FkOC.js create mode 100644 assets/HookClass.html-CJV3GEVs.js create mode 100644 assets/HookClass.html-CW_9kHEG.js create mode 100644 assets/HookClass.html-CszRm9Er.js create mode 100644 assets/HookParam.html-ArPvy40F.js create mode 100644 assets/HookParam.html-BjAineUd.js create mode 100644 assets/HookParam.html-CQJSudBe.js create mode 100644 assets/HookParam.html-SbRyLaGf.js create mode 100644 assets/HookResources.html-B9Np_jgF.js create mode 100644 assets/HookResources.html-DA2dINvc.js create mode 100644 assets/HookResources.html-_3fh2QXJ.js create mode 100644 assets/HookResources.html-zBrjRa5p.js create mode 100644 assets/IYukiHookXposedInit.html-CjNI4nFN.js create mode 100644 assets/IYukiHookXposedInit.html-DEGewXhq.js create mode 100644 assets/IYukiHookXposedInit.html-DTEi8nM4.js create mode 100644 assets/IYukiHookXposedInit.html-Dr7_YjoO.js create mode 100644 assets/InjectYukiHookWithXposed.html-4oxD2_xz.js create mode 100644 assets/InjectYukiHookWithXposed.html-B4v_FVid.js create mode 100644 assets/InjectYukiHookWithXposed.html-BGS_DJ2i.js create mode 100644 assets/InjectYukiHookWithXposed.html-C_GfVAhD.js create mode 100644 assets/MemberRules.html-CzY4xHkS.js create mode 100644 assets/MemberRules.html-DBoFuxYs.js create mode 100644 assets/MemberRules.html-WT4l8b-Y.js create mode 100644 assets/MemberRules.html-r3ZOm1rb.js create mode 100644 assets/MemberRulesResult.html-4uRTQRQi.js create mode 100644 assets/MemberRulesResult.html-C2cLl89Y.js create mode 100644 assets/MemberRulesResult.html-CPcOEYiz.js create mode 100644 assets/MemberRulesResult.html-DVBlYWR7.js create mode 100644 assets/MethodFinder.html-BepwXG9K.js create mode 100644 assets/MethodFinder.html-CtgDtD9U.js create mode 100644 assets/MethodFinder.html-DLZMTsEY.js create mode 100644 assets/MethodFinder.html-DxYxJsjj.js create mode 100644 assets/MethodRules.html-B2dSoNBv.js create mode 100644 assets/MethodRules.html-BCtTTlLz.js create mode 100644 assets/MethodRules.html-CW03U_a6.js create mode 100644 assets/MethodRules.html-DETSSGJ6.js create mode 100644 assets/ModifierRules.html-B1V1DMvv.js create mode 100644 assets/ModifierRules.html-B9KoNMo6.js create mode 100644 assets/ModifierRules.html-DD38DB4t.js create mode 100644 assets/ModifierRules.html-DZnBFn8R.js create mode 100644 assets/ModuleAppActivity.html-BffipQvV.js create mode 100644 assets/ModuleAppActivity.html-BwDznH0J.js create mode 100644 assets/ModuleAppActivity.html-CrhmOsh-.js create mode 100644 assets/ModuleAppActivity.html-e7GuQiJo.js create mode 100644 assets/ModuleAppCompatActivity.html-BCax3oQU.js create mode 100644 assets/ModuleAppCompatActivity.html-C5B-6ZTc.js create mode 100644 assets/ModuleAppCompatActivity.html-Csob9Ceu.js create mode 100644 assets/ModuleAppCompatActivity.html-JFvN5vF4.js create mode 100644 assets/ModuleApplication.html--_5n76BL.js create mode 100644 assets/ModuleApplication.html-BkkBbb-2.js create mode 100644 assets/ModuleApplication.html-C4NqW1gZ.js create mode 100644 assets/ModuleApplication.html-DYtHym0q.js create mode 100644 assets/ModuleClassLoader.html-BFtfl5mt.js create mode 100644 assets/ModuleClassLoader.html-BbehDNqJ.js create mode 100644 assets/ModuleClassLoader.html-BwGRnYn5.js create mode 100644 assets/ModuleClassLoader.html-a6gisn52.js create mode 100644 assets/ModuleContextThemeWrapper.html-BylfEIpg.js create mode 100644 assets/ModuleContextThemeWrapper.html-D3JVFalR.js create mode 100644 assets/ModuleContextThemeWrapper.html-DNoARGj7.js create mode 100644 assets/ModuleContextThemeWrapper.html-UouAIg96.js create mode 100644 assets/ModulePreferenceFragment.html-BozNh-bQ.js create mode 100644 assets/ModulePreferenceFragment.html-CXpIHn7Z.js create mode 100644 assets/ModulePreferenceFragment.html-DSUkMTGs.js create mode 100644 assets/ModulePreferenceFragment.html-XrU_e4rC.js create mode 100644 assets/NameRules.html-BWk6zL2M.js create mode 100644 assets/NameRules.html-DOue2ksg.js create mode 100644 assets/NameRules.html-DopiK4pt.js create mode 100644 assets/NameRules.html-zuU55Nke.js create mode 100644 assets/ObjectRules.html-1b_D9aS8.js create mode 100644 assets/ObjectRules.html-DA4rLBnV.js create mode 100644 assets/ObjectRules.html-DjhVlNAH.js create mode 100644 assets/ObjectRules.html-Dxosvxi0.js create mode 100644 assets/PackageParam.html-356ELE7K.js create mode 100644 assets/PackageParam.html-B3y0YF_m.js create mode 100644 assets/PackageParam.html-Bti7eWUt.js create mode 100644 assets/PackageParam.html-vqkHjjmt.js create mode 100644 assets/PrefsData.html-B72hWN1s.js create mode 100644 assets/PrefsData.html-BInEpoWz.js create mode 100644 assets/PrefsData.html-BbIfbfIq.js create mode 100644 assets/PrefsData.html-BbtXNnuS.js create mode 100644 assets/ReflectionFactory.html-BTXWRqP4.js create mode 100644 assets/ReflectionFactory.html-BVjwrqby.js create mode 100644 assets/ReflectionFactory.html-BiQJ-KKx.js create mode 100644 assets/ReflectionFactory.html-Z7mH28Qd.js create mode 100644 assets/VariableTypeFactory.html-BUNfn5Dn.js create mode 100644 assets/VariableTypeFactory.html-Cel7GBhi.js create mode 100644 assets/VariableTypeFactory.html-DDYYL3th.js create mode 100644 assets/VariableTypeFactory.html-DqSR6Ejd.js create mode 100644 assets/VariousClass.html-3D_jbtJ_.js create mode 100644 assets/VariousClass.html-BdAcgrdg.js create mode 100644 assets/VariousClass.html-CKljcU2t.js create mode 100644 assets/VariousClass.html-DXVXaoSY.js create mode 100644 assets/ViewTypeFactory.html-2ZSLUHiw.js create mode 100644 assets/ViewTypeFactory.html-CIPHyInd.js create mode 100644 assets/ViewTypeFactory.html-DPcuUPhN.js create mode 100644 assets/ViewTypeFactory.html-pGgKQdI9.js create mode 100644 assets/YLog.html-COO68ekD.js create mode 100644 assets/YLog.html-DvNg4c8I.js create mode 100644 assets/YLog.html-KE-5aK_7.js create mode 100644 assets/YLog.html-g2dfXKDH.js create mode 100644 assets/YLogData.html-4aWpXHE7.js create mode 100644 assets/YLogData.html-Bjac08gN.js create mode 100644 assets/YLogData.html-DIaUDgTt.js create mode 100644 assets/YLogData.html-XHmF_gos.js create mode 100644 assets/YukiBaseHooker.html-CWm_43km.js create mode 100644 assets/YukiBaseHooker.html-D01KVdut.js create mode 100644 assets/YukiBaseHooker.html-Dg91Mdnk.js create mode 100644 assets/YukiBaseHooker.html-E78OJRmm.js create mode 100644 assets/YukiHookAPI.html-BRFLeDZT.js create mode 100644 assets/YukiHookAPI.html-CtkZ6zEO.js create mode 100644 assets/YukiHookAPI.html-DqgBnIkU.js create mode 100644 assets/YukiHookAPI.html-DwLoSNWF.js create mode 100644 assets/YukiHookDataChannel.html-0wHuRMGr.js create mode 100644 assets/YukiHookDataChannel.html-Citru5C3.js create mode 100644 assets/YukiHookDataChannel.html-DgdZw6CE.js create mode 100644 assets/YukiHookDataChannel.html-iKhC7MJd.js create mode 100644 assets/YukiHookFactory.html-B7vz7jla.js create mode 100644 assets/YukiHookFactory.html-BKpat8zr.js create mode 100644 assets/YukiHookFactory.html-CoBstbjt.js create mode 100644 assets/YukiHookFactory.html-Dp3ev0qR.js create mode 100644 assets/YukiHookPrefsBridge.html-BG7-Nq7V.js create mode 100644 assets/YukiHookPrefsBridge.html-DVZoJTsa.js create mode 100644 assets/YukiHookPrefsBridge.html-Dprm2-90.js create mode 100644 assets/YukiHookPrefsBridge.html-XzXYFQ1s.js create mode 100644 assets/YukiHookPriority.html-AgDP0CYh.js create mode 100644 assets/YukiHookPriority.html-BzBXrjfk.js create mode 100644 assets/YukiHookPriority.html-CUgcejgE.js create mode 100644 assets/YukiHookPriority.html-smxFpy5Q.js create mode 100644 assets/YukiMemberHookCreator.html-C0fIOtqI.js create mode 100644 assets/YukiMemberHookCreator.html-C1zPXD2D.js create mode 100644 assets/YukiMemberHookCreator.html-De9-pEl1.js create mode 100644 assets/YukiMemberHookCreator.html-WvIyCwTr.js create mode 100644 assets/YukiModuleResources.html-CAc6ozP1.js create mode 100644 assets/YukiModuleResources.html-DZnAa6JN.js create mode 100644 assets/YukiModuleResources.html-DyrSatFK.js create mode 100644 assets/YukiModuleResources.html-jRWj4Ooi.js create mode 100644 assets/YukiResForwarder.html-CtCGVu9N.js create mode 100644 assets/YukiResForwarder.html-DHpOwzIq.js create mode 100644 assets/YukiResForwarder.html-DMGGwbMr.js create mode 100644 assets/YukiResForwarder.html-PPhoLmXZ.js create mode 100644 assets/YukiResources.html--5kriWCV.js create mode 100644 assets/YukiResources.html-CwrMMidY.js create mode 100644 assets/YukiResources.html-DZg6eRc4.js create mode 100644 assets/YukiResources.html-DzFxHHne.js create mode 100644 assets/YukiResourcesHookCreator.html-CKh6FwjE.js create mode 100644 assets/YukiResourcesHookCreator.html-CuPFBHZF.js create mode 100644 assets/YukiResourcesHookCreator.html-DW5yilOs.js create mode 100644 assets/YukiResourcesHookCreator.html-RF6ZJecD.js create mode 100644 assets/YukiXposedEvent.html-BFs-WRvy.js create mode 100644 assets/YukiXposedEvent.html-BIvOGBiv.js create mode 100644 assets/YukiXposedEvent.html-C9AS9omI.js create mode 100644 assets/YukiXposedEvent.html-DtehWaX2.js create mode 100644 assets/about.html-B_eiWEVD.js create mode 100644 assets/about.html-C7A_QXrx.js create mode 100644 assets/about.html-D2yzzIyM.js create mode 100644 assets/about.html-DDk-q1tu.js create mode 100644 assets/api-example.html-CKw7e9Ka.js create mode 100644 assets/api-example.html-DtfHDuEM.js create mode 100644 assets/api-example.html-pCpzRhE2.js create mode 100644 assets/api-example.html-t4M0wmt4.js create mode 100644 assets/api-exception.html-9Je71x4B.js create mode 100644 assets/api-exception.html-Dw1mqBwg.js create mode 100644 assets/api-exception.html-Pu6YF45s.js create mode 100644 assets/api-exception.html-vCoW3MFk.js create mode 100644 assets/api-using.html-CsMd954C.js create mode 100644 assets/api-using.html-DtbSeeEs.js create mode 100644 assets/api-using.html-P_EkKVX5.js create mode 100644 assets/api-using.html-zXrI7_0R.js create mode 100644 assets/app-BpUB8-Q8.js create mode 100644 assets/changelog.html-B8UfyBpi.js create mode 100644 assets/changelog.html-BQ5AB5_x.js create mode 100644 assets/changelog.html-Bti1NzlA.js create mode 100644 assets/changelog.html-D0nYCScY.js create mode 100644 assets/contacts.html-BSRuPKMe.js create mode 100644 assets/contacts.html-BfIGgEZ9.js create mode 100644 assets/contacts.html-CGQemCaU.js create mode 100644 assets/contacts.html-Co35EHVH.js create mode 100644 assets/example.html-CnT6OQuI.js create mode 100644 assets/example.html-Cp22GGCP.js create mode 100644 assets/example.html-DBLcpd3T.js create mode 100644 assets/example.html-l_t2vpgR.js create mode 100644 assets/future.html-BJR2WZUb.js create mode 100644 assets/future.html-BS9bLph2.js create mode 100644 assets/future.html-L0gip76T.js create mode 100644 assets/future.html-aS7aVBMr.js create mode 100644 assets/home.html-BWNdBIZw.js create mode 100644 assets/home.html-Bhz1Th03.js create mode 100644 assets/home.html-CSP-y2Sx.js create mode 100644 assets/home.html-Cg57uIpM.js create mode 100644 assets/home.html-DAJQxBy-.js create mode 100644 assets/home.html-DVG1oAZg.js create mode 100644 assets/home.html-DwzlpDun.js create mode 100644 assets/home.html-Hj1hpUN3.js create mode 100644 assets/host-inject.html-BNOoOrx_.js create mode 100644 assets/host-inject.html-BRZka0o7.js create mode 100644 assets/host-inject.html-COD96F06.js create mode 100644 assets/host-inject.html-DyCVxqXv.js create mode 100644 assets/host-lifecycle.html-BgnOErBM.js create mode 100644 assets/host-lifecycle.html-BqYisHbJ.js create mode 100644 assets/host-lifecycle.html-BsjcaKw0.js create mode 100644 assets/host-lifecycle.html-C7PzYAZN.js create mode 100644 assets/index.html-5uusgM1u.js create mode 100644 assets/index.html-Bo0olcew.js create mode 100644 assets/index.html-CB7-jiwu.js create mode 100644 assets/index.html-CHgP8geU.js create mode 100644 assets/index.html-D6YZKtoe.js create mode 100644 assets/index.html-NYRlXN7n.js create mode 100644 assets/knowledge.html-BJFcZiJH.js create mode 100644 assets/knowledge.html-BvjZCte4.js create mode 100644 assets/knowledge.html-CFMQgPep.js create mode 100644 assets/knowledge.html-CabyS3rt.js create mode 100644 assets/logger.html-B-OHJyal.js create mode 100644 assets/logger.html-BW4Gjfc-.js create mode 100644 assets/logger.html-C9kwF_yM.js create mode 100644 assets/logger.html-Dfs7bQRS.js create mode 100644 assets/move-to-api-1-2-x.html-CCb8Xv2u.js create mode 100644 assets/move-to-api-1-2-x.html-D8SebGDZ.js create mode 100644 assets/move-to-api-1-2-x.html-IonwGaOH.js create mode 100644 assets/move-to-api-1-2-x.html-etgyp2HF.js create mode 100644 assets/move-to-api-1-3-x.html-C6uNfo-e.js create mode 100644 assets/move-to-api-1-3-x.html-CPnNzAVm.js create mode 100644 assets/move-to-api-1-3-x.html-DBMmjUYq.js create mode 100644 assets/move-to-api-1-3-x.html-f3TZzPCU.js create mode 100644 assets/move-to-new-api.html-Bd10LyS9.js create mode 100644 assets/move-to-new-api.html-CtQJCJWD.js create mode 100644 assets/move-to-new-api.html-DwX5LqED.js create mode 100644 assets/move-to-new-api.html-kyRByfpu.js create mode 100644 assets/quick-start.html-CnOHbn2J.js create mode 100644 assets/quick-start.html-Dq2QHQuy.js create mode 100644 assets/quick-start.html-pUciT6Ob.js create mode 100644 assets/quick-start.html-teZCSUoB.js create mode 100644 assets/r8-proguard.html-BruKL-ec.js create mode 100644 assets/r8-proguard.html-C9EyjikD.js create mode 100644 assets/r8-proguard.html-DnD4WWCL.js create mode 100644 assets/r8-proguard.html-Y47fgLwe.js create mode 100644 assets/reflection.html-BZdJSVZS.js create mode 100644 assets/reflection.html-BohdUWGg.js create mode 100644 assets/reflection.html-D65pVYER.js create mode 100644 assets/reflection.html-DXPuhLBz.js create mode 100644 assets/style-DJZs_E_O.css create mode 100644 assets/supportive.html-CTTW-ar9.js create mode 100644 assets/supportive.html-Cd4sY_Jm.js create mode 100644 assets/supportive.html-DFnCbU7r.js create mode 100644 assets/supportive.html-bOj3zBC_.js create mode 100644 assets/xposed-channel.html-B7eDf6ix.js create mode 100644 assets/xposed-channel.html-BeC6v_Qb.js create mode 100644 assets/xposed-channel.html-DWoHNeKf.js create mode 100644 assets/xposed-channel.html-DZ4m7tlI.js create mode 100644 assets/xposed-storage.html-ByKfNh6r.js create mode 100644 assets/xposed-storage.html-CFhC-RoM.js create mode 100644 assets/xposed-storage.html-CZy1SL3y.js create mode 100644 assets/xposed-storage.html-DYzzLHun.js create mode 100644 assets/xposed-using.html-7rTJRpMs.js create mode 100644 assets/xposed-using.html-B9LNrU2W.js create mode 100644 assets/xposed-using.html-CgLVQrdV.js create mode 100644 assets/xposed-using.html-sNzVArkO.js create mode 100644 assets/yukihookapi-projectbuilder.html-0qjforhM.js create mode 100644 assets/yukihookapi-projectbuilder.html-Bq3KEpgx.js create mode 100644 assets/yukihookapi-projectbuilder.html-DnghHaiT.js create mode 100644 assets/yukihookapi-projectbuilder.html-xbo0Krpt.js create mode 100644 en/about/about.html create mode 100644 en/about/changelog.html create mode 100644 en/about/contacts.html create mode 100644 en/about/future.html create mode 100644 en/api/home.html create mode 100644 en/api/public/com/highcapable/yukihookapi/YukiHookAPI.html create mode 100644 en/api/public/com/highcapable/yukihookapi/annotation/xposed/InjectYukiHookWithXposed.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/bean/CurrentClass.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/bean/GenericClass.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/bean/HookClass.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/bean/HookResources.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/bean/VariousClass.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/core/YukiMemberHookCreator.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/core/YukiResourcesHookCreator.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/core/api/compat/type/ExecutorType.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/core/api/priority/YukiHookPriority.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/BaseFinder.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/CountRules.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/ModifierRules.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/NameRules.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/ObjectRules.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/DexClassFinder.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/ConstructorRules.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/FieldRules.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/MemberRules.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/MethodRules.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/result/MemberRulesResult.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/core/finder/members/ConstructorFinder.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/core/finder/members/FieldFinder.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/core/finder/members/MethodFinder.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/entity/YukiBaseHooker.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/factory/YukiHookFactory.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/log/YLog.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/log/data/YLogData.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/param/HookParam.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/param/PackageParam.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/type/android/ComponentTypeFactory.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/type/android/GraphicsTypeFactory.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/type/android/ViewTypeFactory.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/type/defined/DefinedTypeFactory.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/type/java/VariableTypeFactory.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/xposed/application/ModuleApplication.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/event/YukiXposedEvent.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiModuleResources.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResForwarder.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResources.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/xposed/channel/YukiHookDataChannel.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/xposed/channel/data/ChannelData.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/xposed/channel/priority/ChannelPriority.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/base/ModuleAppActivity.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/base/ModuleAppCompatActivity.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/context/wrapper/ModuleContextThemeWrapper.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/reference/ModuleClassLoader.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookPrefsBridge.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/ui/ModulePreferenceFragment.html create mode 100644 en/api/public/com/highcapable/yukihookapi/hook/xposed/proxy/IYukiHookXposedInit.html create mode 100644 en/api/special-features/host-inject.html create mode 100644 en/api/special-features/host-lifecycle.html create mode 100644 en/api/special-features/logger.html create mode 100644 en/api/special-features/reflection.html create mode 100644 en/api/special-features/xposed-channel.html create mode 100644 en/api/special-features/xposed-storage.html create mode 100644 en/config/api-example.html create mode 100644 en/config/api-exception.html create mode 100644 en/config/api-using.html create mode 100644 en/config/move-to-api-1-2-x.html create mode 100644 en/config/move-to-api-1-3-x.html create mode 100644 en/config/r8-proguard.html create mode 100644 en/config/xposed-using.html create mode 100644 en/guide/example.html create mode 100644 en/guide/home.html create mode 100644 en/guide/knowledge.html create mode 100644 en/guide/move-to-new-api.html create mode 100644 en/guide/quick-start.html create mode 100644 en/guide/supportive.html create mode 100644 en/index.html create mode 100644 en/tools/yukihookapi-projectbuilder.html create mode 100644 images/logo.png create mode 100644 images/yukihookapi-projectbuilder-en.png create mode 100644 images/yukihookapi-projectbuilder-zh-cn.png create mode 100644 index.html create mode 100644 zh-cn/about/about.html create mode 100644 zh-cn/about/changelog.html create mode 100644 zh-cn/about/contacts.html create mode 100644 zh-cn/about/future.html create mode 100644 zh-cn/api/home.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/YukiHookAPI.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/annotation/xposed/InjectYukiHookWithXposed.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/bean/CurrentClass.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/bean/GenericClass.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/bean/HookClass.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/bean/HookResources.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/bean/VariousClass.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/core/YukiMemberHookCreator.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/core/YukiResourcesHookCreator.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/core/api/compat/type/ExecutorType.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/core/api/priority/YukiHookPriority.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/base/BaseFinder.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/CountRules.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/ModifierRules.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/NameRules.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/ObjectRules.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/DexClassFinder.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/ConstructorRules.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/FieldRules.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/MemberRules.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/MethodRules.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/result/MemberRulesResult.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/members/ConstructorFinder.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/members/FieldFinder.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/members/MethodFinder.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/entity/YukiBaseHooker.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/factory/YukiHookFactory.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/log/YLog.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/log/data/YLogData.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/param/HookParam.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/param/PackageParam.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/type/android/ComponentTypeFactory.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/type/android/GraphicsTypeFactory.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/type/android/ViewTypeFactory.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/type/defined/DefinedTypeFactory.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/type/java/VariableTypeFactory.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/application/ModuleApplication.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/event/YukiXposedEvent.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiModuleResources.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResForwarder.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResources.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/channel/YukiHookDataChannel.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/channel/data/ChannelData.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/channel/priority/ChannelPriority.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/base/ModuleAppActivity.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/base/ModuleAppCompatActivity.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/context/wrapper/ModuleContextThemeWrapper.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/reference/ModuleClassLoader.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookPrefsBridge.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/ui/ModulePreferenceFragment.html create mode 100644 zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/proxy/IYukiHookXposedInit.html create mode 100644 zh-cn/api/special-features/host-inject.html create mode 100644 zh-cn/api/special-features/host-lifecycle.html create mode 100644 zh-cn/api/special-features/logger.html create mode 100644 zh-cn/api/special-features/reflection.html create mode 100644 zh-cn/api/special-features/xposed-channel.html create mode 100644 zh-cn/api/special-features/xposed-storage.html create mode 100644 zh-cn/config/api-example.html create mode 100644 zh-cn/config/api-exception.html create mode 100644 zh-cn/config/api-using.html create mode 100644 zh-cn/config/move-to-api-1-2-x.html create mode 100644 zh-cn/config/move-to-api-1-3-x.html create mode 100644 zh-cn/config/r8-proguard.html create mode 100644 zh-cn/config/xposed-using.html create mode 100644 zh-cn/guide/example.html create mode 100644 zh-cn/guide/home.html create mode 100644 zh-cn/guide/knowledge.html create mode 100644 zh-cn/guide/move-to-new-api.html create mode 100644 zh-cn/guide/quick-start.html create mode 100644 zh-cn/guide/supportive.html create mode 100644 zh-cn/index.html create mode 100644 zh-cn/tools/yukihookapi-projectbuilder.html diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/404.html b/404.html new file mode 100644 index 00000000..2548b4d1 --- /dev/null +++ b/404.html @@ -0,0 +1,34 @@ + + +
+ + + + + +注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
abstract class BaseFinder
+
变更记录
v1.0.70
新增
v1.1.0
修改
分离原始命名 BaseFinder
中的部分方法与参数到 MemberBaseFinder
功能描述
这是
Class
与Member
查找类功能的基本类实现。
inner class IndexTypeCondition internal constructor(private val type: IndexConfigType)
+
变更记录
v1.0.70
新增
功能描述
字节码下标筛选实现类。
fun index(num: Int)
+
变更记录
v1.0.70
新增
功能描述
设置下标。
若 index
小于零则为倒序,此时可以使用 IndexTypeConditionSort.reverse
方法实现。
可使用 IndexTypeConditionSort.first
和 IndexTypeConditionSort.last
设置首位和末位筛选条件。
fun index(): IndexTypeConditionSort
+
变更记录
v1.0.70
新增
功能描述
得到下标。
inner class IndexTypeConditionSort internal constructor()
+
变更记录
v1.0.70
新增
功能描述
字节码下标排序实现类。
fun first()
+
变更记录
v1.0.70
新增
功能描述
设置满足条件的第一个。
fun last()
+
变更记录
v1.0.70
新增
功能描述
设置满足条件的最后一个。
fun reverse(num: Int)
+
变更记录
v1.0.70
新增
功能描述
`,53),l=[p];function t(c,d){return e(),a("div",null,l)}const i=s(n,[["render",t],["__file","BaseFinder.html.vue"]]);export{i as default}; diff --git a/assets/BaseFinder.html-CAvlkbqd.js b/assets/BaseFinder.html-CAvlkbqd.js new file mode 100644 index 00000000..401171bc --- /dev/null +++ b/assets/BaseFinder.html-CAvlkbqd.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-0f719471","path":"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/base/BaseFinder.html","title":"BaseFinder - class","lang":"zh-CN","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"BaseFinder.IndexTypeCondition - class","slug":"basefinder-indextypecondition-class","link":"#basefinder-indextypecondition-class","children":[{"level":3,"title":"index - method","slug":"index-method","link":"#index-method","children":[]},{"level":3,"title":"index - method","slug":"index-method-1","link":"#index-method-1","children":[]},{"level":3,"title":"IndexTypeConditionSort - class","slug":"indextypeconditionsort-class","link":"#indextypeconditionsort-class","children":[]}]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":2}]},"filePathRelative":"zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/base/BaseFinder.md"}');export{e as data}; diff --git a/assets/BaseFinder.html-DvwHVrKn.js b/assets/BaseFinder.html-DvwHVrKn.js new file mode 100644 index 00000000..88b0269e --- /dev/null +++ b/assets/BaseFinder.html-DvwHVrKn.js @@ -0,0 +1,9 @@ +import{_ as s,o as e,c as n,a as o}from"./app-BpUB8-Q8.js";const a={},t=o(`设置倒序下标。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
abstract class BaseFinder
+
Change Records
v1.0.70
added
v1.1.0
modified
分离原始命名 BaseFinder
中的部分方法与参数到 MemberBaseFinder
Function Illustrate
这是
Class
与Member
查找类功能的基本类实现。
inner class IndexTypeCondition internal constructor(private val type: IndexConfigType)
+
Change Records
v1.0.70
added
Function Illustrate
字节码下标筛选实现类。
fun index(num: Int)
+
Change Records
v1.0.70
added
Function Illustrate
设置下标。
若 index
小于零则为倒序,此时可以使用 IndexTypeConditionSort.reverse
方法实现。
可使用 IndexTypeConditionSort.first
和 IndexTypeConditionSort.last
设置首位和末位筛选条件。
fun index(): IndexTypeConditionSort
+
Change Records
v1.0.70
added
Function Illustrate
得到下标。
inner class IndexTypeConditionSort internal constructor()
+
Change Records
v1.0.70
added
Function Illustrate
字节码下标排序实现类。
fun first()
+
Change Records
v1.0.70
added
Function Illustrate
设置满足条件的第一个。
fun last()
+
Change Records
v1.0.70
added
Function Illustrate
设置满足条件的最后一个。
fun reverse(num: Int)
+
Change Records
v1.0.70
added
Function Illustrate
`,54),l=[t];function c(d,p){return e(),n("div",null,l)}const i=s(a,[["render",c],["__file","BaseFinder.html.vue"]]);export{i as default}; diff --git a/assets/ChannelData.html-BX_rAvQg.js b/assets/ChannelData.html-BX_rAvQg.js new file mode 100644 index 00000000..cd70d4e4 --- /dev/null +++ b/assets/ChannelData.html-BX_rAvQg.js @@ -0,0 +1 @@ +const a=JSON.parse('{"key":"v-2f64a2d4","path":"/en/api/public/com/highcapable/yukihookapi/hook/xposed/channel/data/ChannelData.html","title":"ChannelData - class","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":3}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/xposed/channel/data/ChannelData.md"}');export{a as data}; diff --git a/assets/ChannelData.html-Bp3A6ogd.js b/assets/ChannelData.html-Bp3A6ogd.js new file mode 100644 index 00000000..f9a96ac6 --- /dev/null +++ b/assets/ChannelData.html-Bp3A6ogd.js @@ -0,0 +1,23 @@ +import{_ as s,o as a,c as n,a as l}from"./app-BpUB8-Q8.js";const e={},o=l(`设置倒序下标。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
data class ChannelData<T>(var key: String, var value: T?) : Serializable
+
变更记录
v1.0.88
新增
v1.1.5
修改
实现了 Serializable
接口
功能描述
数据通讯桥键值构造类。
这个类是对 YukiHookDataChannel
的一个扩展用法。
功能示例
建立一个模板类定义模块与宿主需要发送的键值数据。
示例如下
object DataConst {
+
+ val TEST_KV_DATA_1 = ChannelData("test_data_1", "defalut value")
+ val TEST_KV_DATA_2 = ChannelData("test_data_2", 0)
+}
+
键值数据定义后,你就可以方便地在模块和宿主中调用所需要发送的数据。
模块示例如下
// 从指定包名的宿主获取
+dataChannel(packageName = "com.example.demo").wait(DataConst.TEST_KV_DATA_1) { value ->
+ // Your code here.
+}
+// 发送给指定包名的宿主 - 未填写 value 时将使用模板提供的默认值
+dataChannel(packageName = "com.example.demo").put(DataConst.TEST_KV_DATA_1, value = "sending value")
+
宿主示例如下
// 从模块获取
+dataChannel.wait(DataConst.TEST_KV_DATA_1) { value ->
+ // Your code here.
+}
+// 发送给模块 - 未填写 value 时将使用模板提供的默认值
+dataChannel.put(DataConst.TEST_KV_DATA_1, value = "sending value")
+
你依然可以不使用模板定义的默认值,随时修改你的默认值。
示例如下
// 获取 - 此时 value 取到的默认值将会是 2 - 并不是模板提供的 0
+dataChannel.wait(DataConst.TEST_KV_DATA_2, value = 2) { value ->
+ // Your code here.
+}
+
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
data class ChannelData<T>(var key: String, var value: T?) : Serializable
+
Change Records
v1.0.88
added
v1.1.5
modified
实现了 Serializable
接口
Function Illustrate
数据通讯桥键值构造类。
这个类是对 YukiHookDataChannel
的一个扩展用法。
Function Example
建立一个模板类定义模块与宿主需要发送的键值数据。
The following example
object DataConst {
+
+ val TEST_KV_DATA_1 = ChannelData("test_data_1", "defalut value")
+ val TEST_KV_DATA_2 = ChannelData("test_data_2", 0)
+}
+
键值数据定义后,你就可以方便地在模块和宿主中调用所需要发送的数据。
模块示例如下
// 从指定包名的宿主获取
+dataChannel(packageName = "com.example.demo").wait(DataConst.TEST_KV_DATA_1) { value ->
+ // Your code here.
+}
+// 发送给指定包名的宿主 - 未填写 value 时将使用模板提供的默认值
+dataChannel(packageName = "com.example.demo").put(DataConst.TEST_KV_DATA_1, value = "sending value")
+
宿主示例如下
// 从模块获取
+dataChannel.wait(DataConst.TEST_KV_DATA_1) { value ->
+ // Your code here.
+}
+// 发送给模块 - 未填写 value 时将使用模板提供的默认值
+dataChannel.put(DataConst.TEST_KV_DATA_1, value = "sending value")
+
你依然可以不使用模板定义的默认值,随时修改你的默认值。
The following example
// 获取 - 此时 value 取到的默认值将会是 2 - 并不是模板提供的 0
+dataChannel.wait(DataConst.TEST_KV_DATA_2, value = 2) { value ->
+ // Your code here.
+}
+
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
class ChannelPriority(private val conditions: () -> Boolean)
+
变更记录
v1.1.5
新增
功能描述
数据通讯桥响应优先级构造类。
这个类是对 YukiHookDataChannel
的一个扩展用法。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
class ChannelPriority(private val conditions: () -> Boolean)
+
Change Records
v1.1.5
added
Function Illustrate
数据通讯桥响应优先级构造类。
这个类是对 YukiHookDataChannel
的一个扩展用法。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
变更记录
v1.0
添加
功能描述
',6),l={href:"https://github.com/HighCapable/YukiHookAPI/blob/master/yukihookapi-core/src/main/java/com/highcapable/yukihookapi/hook/type/android/ComponentTypeFactory.kt",target:"_blank",rel:"noopener noreferrer"};function k(m,h){const t=a("ExternalLinkIcon");return n(),r("div",null,[i,e("p",null,[o("详情可 "),e("a",l,[o("点击这里"),s(t)]),o(" 进行查看。")])])}const u=c(d,[["render",k],["__file","ComponentTypeFactory.html.vue"]]);export{u as default}; diff --git a/assets/ComponentTypeFactory.html-B-t1GVQa.js b/assets/ComponentTypeFactory.html-B-t1GVQa.js new file mode 100644 index 00000000..8a88bc9f --- /dev/null +++ b/assets/ComponentTypeFactory.html-B-t1GVQa.js @@ -0,0 +1 @@ +import{_ as n,r as a,o as c,c as r,b as o,d as e,e as s,a as i}from"./app-BpUB8-Q8.js";const p={},l=i('这是一个预置反射类型的常量类,主要为
Android
相关组件的Class
内容,跟随版本更新会逐一进行增加。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
Change Records
v1.0
first
Function Illustrate
',7),d={href:"https://github.com/HighCapable/YukiHookAPI/blob/master/yukihookapi-core/src/main/java/com/highcapable/yukihookapi/hook/type/android/ComponentTypeFactory.kt",target:"_blank",rel:"noopener noreferrer"};function h(u,m){const t=a("ExternalLinkIcon");return c(),r("div",null,[l,o("p",null,[e("详情可 "),o("a",d,[e("点击这里"),s(t)]),e(" 进行查看。")])])}const g=n(p,[["render",h],["__file","ComponentTypeFactory.html.vue"]]);export{g as default}; diff --git a/assets/ComponentTypeFactory.html-DptIpBn2.js b/assets/ComponentTypeFactory.html-DptIpBn2.js new file mode 100644 index 00000000..c01018c5 --- /dev/null +++ b/assets/ComponentTypeFactory.html-DptIpBn2.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-8293d958","path":"/en/api/public/com/highcapable/yukihookapi/hook/type/android/ComponentTypeFactory.html","title":"ComponentTypeFactory - kt","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":6}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/type/android/ComponentTypeFactory.md"}');export{e as data}; diff --git a/assets/ComponentTypeFactory.html-VD1JaHTz.js b/assets/ComponentTypeFactory.html-VD1JaHTz.js new file mode 100644 index 00000000..13796a81 --- /dev/null +++ b/assets/ComponentTypeFactory.html-VD1JaHTz.js @@ -0,0 +1 @@ +const o=JSON.parse('{"key":"v-5e874c45","path":"/zh-cn/api/public/com/highcapable/yukihookapi/hook/type/android/ComponentTypeFactory.html","title":"ComponentTypeFactory - kt","lang":"zh-CN","frontmatter":{"pageClass":"code-page"},"headers":[],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":6}]},"filePathRelative":"zh-cn/api/public/com/highcapable/yukihookapi/hook/type/android/ComponentTypeFactory.md"}');export{o as data}; diff --git a/assets/ConstructorFinder.html-CVpWcXzr.js b/assets/ConstructorFinder.html-CVpWcXzr.js new file mode 100644 index 00000000..98689824 --- /dev/null +++ b/assets/ConstructorFinder.html-CVpWcXzr.js @@ -0,0 +1,88 @@ +import{_ as s,o as n,c as o,a as e}from"./app-BpUB8-Q8.js";const a={},l=e(`这是一个预置反射类型的常量类,主要为
Android
相关组件的Class
内容,跟随版本更新会逐一进行增加。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
class ConstructorFinder internal constructor(override val classSet: Class<*>) : MemberBaseFinder
+
Change Records
v1.0
first
v1.0.2
modified
合并到 BaseFinder
v1.1.0
modified
合并到 MemberBaseFinder
v1.1.8
modified
移动 hookInstance
参数到 MemberBaseFinder.MemberHookerManager
Function Illustrate
Constructor
查找类。
可通过指定类型查找指定 Constructor
或一组 Constructor
。
var paramCount: Int
+
Change Records
v1.0.67
added
Function Illustrate
设置
Constructor
参数个数。
你可以不使用 param
指定参数类型而是仅使用此变量指定参数个数。
若参数个数小于零则忽略并使用 param
。
fun modifiers(conditions: ModifierConditions): IndexTypeCondition
+
Change Records
v1.0.67
added
v1.0.80
modified
将方法体进行 inline
v1.1.0
modified
合并到 ModifierConditions
Function Illustrate
设置
Constructor
标识符筛选条件。
可不设置筛选条件,默认模糊查找并取第一个匹配的 Constructor
。
Pay Attention
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun emptyParam(): IndexTypeCondition
+
Change Records
v1.0.75
added
Function Illustrate
设置
Constructor
空参数、无参数。
fun param(vararg paramType: Any): IndexTypeCondition
+
Change Records
v1.0
first
Function Illustrate
设置
Constructor
参数。
如果同时使用了 paramCount
则 paramType
的数量必须与 paramCount
完全匹配。
如果 Constructor
中存在一些无意义又很长的类型,你可以使用 VagueType 来替代它。
Pay Attention
无参 Constructor 请使用 emptyParam 设置查找条件。
有参 Constructor 必须使用此方法设定参数或使用 paramCount 指定个数。
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun param(conditions: ObjectsConditions): IndexTypeCondition
+
Change Records
v1.1.5
added
Function Illustrate
设置
Constructor
参数条件。
Pay Attention
无参 Constructor 请使用 emptyParam 设置查找条件。
有参 Constructor 必须使用此方法设定参数或使用 paramCount 指定个数。
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun paramCount(num: Int): IndexTypeCondition
+
Change Records
v1.0.70
added
Function Illustrate
设置
Constructor
参数个数。
你可以不使用 param
指定参数类型而是仅使用此方法指定参数个数。
若参数个数小于零则忽略并使用 param
。
Pay Attention
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun paramCount(numRange: IntRange): IndexTypeCondition
+
Change Records
v1.1.0
added
Function Illustrate
设置
Constructor
参数个数范围。
你可以不使用 param
指定参数类型而是仅使用此方法指定参数个数范围。
Pay Attention
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun paramCount(conditions: CountConditions): IndexTypeCondition
+
Change Records
v1.1.0
added
Function Illustrate
设置
Constructor
参数个数条件。
你可以不使用 param
指定参数类型而是仅使用此方法指定参数个数条件。
Pay Attention
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun superClass(isOnlySuperClass: Boolean)
+
Change Records
v1.0.80
added
Function Illustrate
设置在
classSet
的所有父类中查找当前Constructor
。
Notice
若当前 classSet 的父类较多可能会耗时,API 会自动循环到父类继承是 Any 前的最后一个类。
inner class RemedyPlan internal constructor()
+
Change Records
v1.0
first
Function Illustrate
Constructor
重查找实现类,可累计失败次数直到查找成功。
inline fun constructor(initiate: ConstructorConditions)
+
Change Records
v1.0
first
v1.0.80
modified
将方法体进行 inline
Function Illustrate
创建需要重新查找的
Constructor
。
你可以添加多个备选 Constructor
,直到成功为止,若最后依然失败,将停止查找并输出错误日志。
inner class Result internal constructor()
+
Change Records
v1.0.1
added
Function Illustrate
RemedyPlan
结果实现类。
fun onFind(initiate: MutableList<Constructor<*>>.() -> Unit)
+
Change Records
v1.0.1
added
v1.1.0
modified
initiate
参数 Constructor
变为 HashSet<Constructor>
v1.2.0
modified
initiate
类型由 HashSet
修改为 MutableList
Function Illustrate
当在
RemedyPlan
中找到结果时。
Function Example
你可以方便地对重查找的 Constructor
实现 onFind
方法。
The following example
constructor {
+ // Your code here.
+}.onFind {
+ // Your code here.
+}
+
inner class Process internal constructor(internal val isNoSuch: Boolean, internal val throwable: Throwable?) : BaseResult
+
Change Records
v1.1.0
added
Function Illustrate
Constructor
查找结果处理类,为hookManager
提供。
inline fun result(initiate: Process.() -> Unit): Process
+
Change Records
v1.1.0
added
Function Illustrate
创建监听结果事件方法体。
Function Example
你可以使用 lambda 形式创建 Result
类。
The following example
constructor {
+ // Your code here.
+}.result {
+ all()
+ remedys {}
+ onNoSuchConstructor {}
+}
+
fun all(): Process
+
Change Records
v1.1.0
added
Function Illustrate
设置全部查找条件匹配的多个
Constructor
实例结果到hookManager
。
inline fun remedys(initiate: RemedyPlan.() -> Unit): Result
+
Change Records
v1.1.0
added
Function Illustrate
创建
Constructor
重查找功能。
Function Example
当你遇到一种 Constructor
可能存在不同形式的存在时,可以使用 RemedyPlan
重新查找它,而没有必要使用 onNoSuchConstructor
捕获异常二次查找 Constructor
。
若第一次查找失败了,你还可以在这里继续添加此方法体直到成功为止。
The following example
constructor {
+ // Your code here.
+}.remedys {
+ constructor {
+ // Your code here.
+ }
+ constructor {
+ // Your code here.
+ }
+}
+
inline fun onNoSuchConstructor(result: (Throwable) -> Unit): Result
+
Change Records
v1.1.0
added
Function Illustrate
监听找不到
Constructor
时。
只会返回第一次的错误信息,不会返回 RemedyPlan
的错误信息。
inner class Result internal constructor(internal val isNoSuch: Boolean, internal val throwable: Throwable?) : BaseResult
+
Change Records
v1.0
first
v1.1.0
modified
继承到接口 BaseResult
Function Illustrate
Constructor
查找结果实现类。
inline fun result(initiate: Result.() -> Unit): Result
+
Change Records
v1.0
first
v1.0.80
modified
将方法体进行 inline
Function Illustrate
创建监听结果事件方法体。
Function Example
你可以使用 lambda 形式创建 Result
类。
The following example
constructor {
+ // Your code here.
+}.result {
+ get().call()
+ all()
+ remedys {}
+ onNoSuchConstructor {}
+}
+
fun get(): Instance
+
Change Records
v1.0.2
added
Function Illustrate
获得
Constructor
实例处理类。
若有多个 Constructor
结果只会返回第一个。
Pay Attention
若你设置了 remedys 请使用 wait 回调结果方法。
Function Example
你可以通过获得方法所在实例来执行构造方法创建新的实例对象。
The following example
constructor {
+ // Your code here.
+}.get().call()
+
你可以 cast
构造方法为指定类型的实例对象。
The following example
constructor {
+ // Your code here.
+}.get().newInstance<TestClass>()
+
Pay Attention
若构造方法含有参数则后方参数必填。
The following example
constructor {
+ // Your code here.
+}.get().newInstance<TestClass>("param1", "param2")
+
fun all(): MutableList<Instance>
+
Change Records
v1.1.0
added
v1.2.0
modified
返回值类型由 ArrayList
修改为 MutableList
Function Illustrate
获得
Constructor
实例处理类数组。
返回全部查找条件匹配的多个 Constructor
实例结果。
Function Example
你可以通过此方法来获得当前条件结果中匹配的全部 Constructor
。
The following example
constructor {
+ // Your code here.
+}.all().forEach { instance ->
+ instance.call(...)
+}
+
fun give(): Constructor<*>?
+
Change Records
v1.0.67
added
Function Illustrate
得到
Constructor
本身。
若有多个 Constructor
结果只会返回第一个。
在查找条件找不到任何结果的时候将返回 null
。
fun giveAll(): MutableList<Constructor<*>>
+
Change Records
v1.1.0
added
v1.2.0
modified
返回值类型由 HashSet
修改为 MutableList
Function Illustrate
得到
Constructor
本身数组。
返回全部查找条件匹配的多个 Constructor
实例。
在查找条件找不到任何结果的时候将返回空的 MutableList
。
fun wait(initiate: Instance.() -> Unit)
+
Change Records
v1.0.2
added
Function Illustrate
获得
Constructor
实例处理类,配合RemedyPlan
使用。
若有多个 Constructor
结果只会返回第一个。
Pay Attention
若你设置了 remedys 必须使用此方法才能获得结果。
若你没有设置 remedys 此方法将不会被回调。
fun waitAll(initiate: MutableList<Instance>.() -> Unit)
+
Change Records
v1.1.0
added
v1.2.0
modified
initiate
类型由 ArrayList
修改为 MutableList
Function Illustrate
获得
Constructor
实例处理类数组,配合RemedyPlan
使用。
返回全部查找条件匹配的多个 Constructor
实例结果。
Pay Attention
若你设置了 remedys 必须使用此方法才能获得结果。
若你没有设置 remedys 此方法将不会被回调。
inline fun remedys(initiate: RemedyPlan.() -> Unit): Result
+
Change Records
v1.0
first
v1.0.80
modified
将方法体进行 inline
Function Illustrate
创建
Constructor
重查找功能。
Function Example
当你遇到一种 Constructor
可能存在不同形式的存在时,可以使用 RemedyPlan
重新查找它,而没有必要使用 onNoSuchConstructor
捕获异常二次查找 Constructor
。
若第一次查找失败了,你还可以在这里继续添加此方法体直到成功为止。
The following example
constructor {
+ // Your code here.
+}.remedys {
+ constructor {
+ // Your code here.
+ }
+ constructor {
+ // Your code here.
+ }
+}
+
inline fun onNoSuchConstructor(result: (Throwable) -> Unit): Result
+
Change Records
v1.0
first
v1.0.80
modified
将方法体进行 inline
Function Illustrate
监听找不到
Constructor
时。
只会返回第一次的错误信息,不会返回 RemedyPlan
的错误信息。
fun ignored(): Result
+
Change Records
v1.1.0
added
Function Illustrate
忽略异常并停止打印任何错误日志。
若 MemberBaseFinder.MemberHookerManager.isNotIgnoredNoSuchMemberFailure
为 false
则自动忽略。
Notice
此时若要监听异常结果,你需要手动实现 onNoSuchConstructor 方法。
Change Records
v1.0.3
added
v1.1.0
deprecated
请迁移到新方法 ignored()
inner class Instance internal constructor(private val constructor: Constructor<*>?)
+
Change Records
v1.0.2
added
v1.1.0
modified
新增 constructor
参数
Function Illustrate
Constructor
实例处理类。
fun call(vararg args: Any?): Any?
+
Change Records
v1.0.2
added
v1.1.6
modified
修改参数命名 param
为 args
Function Illustrate
执行
Constructor
创建目标实例,不指定目标实例类型。
fun <T> newInstance(vararg args: Any?): T?
+
Change Records
v1.0.2
added
v1.1.6
modified
修改参数命名 param
为 args
Function Illustrate
`,310),p=[l];function c(t,r){return n(),o("div",null,p)}const i=s(a,[["render",c],["__file","ConstructorFinder.html.vue"]]);export{i as default}; diff --git a/assets/ConstructorFinder.html-CmDHOksx.js b/assets/ConstructorFinder.html-CmDHOksx.js new file mode 100644 index 00000000..3c1fddfd --- /dev/null +++ b/assets/ConstructorFinder.html-CmDHOksx.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-1e2cbc9c","path":"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/members/ConstructorFinder.html","title":"ConstructorFinder - class","lang":"zh-CN","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"paramCount - field","slug":"paramcount-field","link":"#paramcount-field","children":[]},{"level":2,"title":"modifiers - method","slug":"modifiers-method","link":"#modifiers-method","children":[]},{"level":2,"title":"emptyParam - method","slug":"emptyparam-method","link":"#emptyparam-method","children":[]},{"level":2,"title":"param - method","slug":"param-method","link":"#param-method","children":[]},{"level":2,"title":"param - method","slug":"param-method-1","link":"#param-method-1","children":[]},{"level":2,"title":"paramCount - method","slug":"paramcount-method","link":"#paramcount-method","children":[]},{"level":2,"title":"paramCount - method","slug":"paramcount-method-1","link":"#paramcount-method-1","children":[]},{"level":2,"title":"paramCount - method","slug":"paramcount-method-2","link":"#paramcount-method-2","children":[]},{"level":2,"title":"superClass - method","slug":"superclass-method","link":"#superclass-method","children":[]},{"level":2,"title":"RemedyPlan - class","slug":"remedyplan-class","link":"#remedyplan-class","children":[{"level":3,"title":"constructor - method","slug":"constructor-method","link":"#constructor-method","children":[]},{"level":3,"title":"Result - class","slug":"result-class","link":"#result-class","children":[]}]},{"level":2,"title":"Process - class","slug":"process-class","link":"#process-class","children":[{"level":3,"title":"result - method","slug":"result-method","link":"#result-method","children":[]},{"level":3,"title":"all - method","slug":"all-method","link":"#all-method","children":[]},{"level":3,"title":"remedys - method","slug":"remedys-method","link":"#remedys-method","children":[]},{"level":3,"title":"onNoSuchConstructor - method","slug":"onnosuchconstructor-method","link":"#onnosuchconstructor-method","children":[]}]},{"level":2,"title":"Result - class","slug":"result-class-1","link":"#result-class-1","children":[{"level":3,"title":"result - method","slug":"result-method-1","link":"#result-method-1","children":[]},{"level":3,"title":"get - method","slug":"get-method","link":"#get-method","children":[]},{"level":3,"title":"all - method","slug":"all-method-1","link":"#all-method-1","children":[]},{"level":3,"title":"give - method","slug":"give-method","link":"#give-method","children":[]},{"level":3,"title":"giveAll - method","slug":"giveall-method","link":"#giveall-method","children":[]},{"level":3,"title":"wait - method","slug":"wait-method","link":"#wait-method","children":[]},{"level":3,"title":"waitAll - method","slug":"waitall-method","link":"#waitall-method","children":[]},{"level":3,"title":"remedys - method","slug":"remedys-method-1","link":"#remedys-method-1","children":[]},{"level":3,"title":"onNoSuchConstructor - method","slug":"onnosuchconstructor-method-1","link":"#onnosuchconstructor-method-1","children":[]},{"level":3,"title":"ignored - method","slug":"ignored-method","link":"#ignored-method","children":[]},{"level":3,"title":"Instance - class","slug":"instance-class","link":"#instance-class","children":[]}]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":10}]},"filePathRelative":"zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/members/ConstructorFinder.md"}');export{e as data}; diff --git a/assets/ConstructorFinder.html-DrSYr7fy.js b/assets/ConstructorFinder.html-DrSYr7fy.js new file mode 100644 index 00000000..0a10b82e --- /dev/null +++ b/assets/ConstructorFinder.html-DrSYr7fy.js @@ -0,0 +1,88 @@ +import{_ as s,o,c as n,a}from"./app-BpUB8-Q8.js";const e={},l=a(`执行
Constructor
创建目标实例 ,指定T
目标实例类型。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
class ConstructorFinder internal constructor(override val classSet: Class<*>) : MemberBaseFinder
+
变更记录
v1.0
添加
v1.0.2
修改
合并到 BaseFinder
v1.1.0
修改
合并到 MemberBaseFinder
v1.1.8
修改
移动 hookInstance
参数到 MemberBaseFinder.MemberHookerManager
功能描述
Constructor
查找类。
可通过指定类型查找指定 Constructor
或一组 Constructor
。
var paramCount: Int
+
变更记录
v1.0.67
新增
功能描述
设置
Constructor
参数个数。
你可以不使用 param
指定参数类型而是仅使用此变量指定参数个数。
若参数个数小于零则忽略并使用 param
。
fun modifiers(conditions: ModifierConditions): IndexTypeCondition
+
变更记录
v1.0.67
新增
v1.0.80
修改
将方法体进行 inline
v1.1.0
修改
合并到 ModifierConditions
功能描述
设置
Constructor
标识符筛选条件。
可不设置筛选条件,默认模糊查找并取第一个匹配的 Constructor
。
特别注意
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun emptyParam(): IndexTypeCondition
+
变更记录
v1.0.75
新增
功能描述
设置
Constructor
空参数、无参数。
fun param(vararg paramType: Any): IndexTypeCondition
+
变更记录
v1.0
添加
功能描述
设置
Constructor
参数。
如果同时使用了 paramCount
则 paramType
的数量必须与 paramCount
完全匹配。
如果 Constructor
中存在一些无意义又很长的类型,你可以使用 VagueType 来替代它。
特别注意
无参 Constructor 请使用 emptyParam 设置查找条件。
有参 Constructor 必须使用此方法设定参数或使用 paramCount 指定个数。
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun param(conditions: ObjectsConditions): IndexTypeCondition
+
变更记录
v1.1.5
新增
功能描述
设置
Constructor
参数条件。
特别注意
无参 Constructor 请使用 emptyParam 设置查找条件。
有参 Constructor 必须使用此方法设定参数或使用 paramCount 指定个数。
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun paramCount(num: Int): IndexTypeCondition
+
变更记录
v1.0.70
新增
功能描述
设置
Constructor
参数个数。
你可以不使用 param
指定参数类型而是仅使用此方法指定参数个数。
若参数个数小于零则忽略并使用 param
。
特别注意
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun paramCount(numRange: IntRange): IndexTypeCondition
+
变更记录
v1.1.0
新增
功能描述
设置
Constructor
参数个数范围。
你可以不使用 param
指定参数类型而是仅使用此方法指定参数个数范围。
特别注意
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun paramCount(conditions: CountConditions): IndexTypeCondition
+
变更记录
v1.1.0
新增
功能描述
设置
Constructor
参数个数条件。
你可以不使用 param
指定参数类型而是仅使用此方法指定参数个数条件。
特别注意
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun superClass(isOnlySuperClass: Boolean)
+
变更记录
v1.0.80
新增
功能描述
设置在
classSet
的所有父类中查找当前Constructor
。
注意
若当前 classSet 的父类较多可能会耗时,API 会自动循环到父类继承是 Any 前的最后一个类。
inner class RemedyPlan internal constructor()
+
变更记录
v1.0
添加
功能描述
Constructor
重查找实现类,可累计失败次数直到查找成功。
inline fun constructor(initiate: ConstructorConditions)
+
变更记录
v1.0
添加
v1.0.80
修改
将方法体进行 inline
功能描述
创建需要重新查找的
Constructor
。
你可以添加多个备选 Constructor
,直到成功为止,若最后依然失败,将停止查找并输出错误日志。
inner class Result internal constructor()
+
变更记录
v1.0.1
新增
功能描述
RemedyPlan
结果实现类。
fun onFind(initiate: MutableList<Constructor<*>>.() -> Unit)
+
变更记录
v1.0.1
新增
v1.1.0
修改
initiate
参数 Constructor
变为 HashSet<Constructor>
v1.2.0
修改
initiate
类型由 HashSet
修改为 MutableList
功能描述
当在
RemedyPlan
中找到结果时。
功能示例
你可以方便地对重查找的 Constructor
实现 onFind
方法。
示例如下
constructor {
+ // Your code here.
+}.onFind {
+ // Your code here.
+}
+
inner class Process internal constructor(internal val isNoSuch: Boolean, internal val throwable: Throwable?) : BaseResult
+
变更记录
v1.1.0
新增
功能描述
Constructor
查找结果处理类,为hookManager
提供。
inline fun result(initiate: Process.() -> Unit): Process
+
变更记录
v1.1.0
新增
功能描述
创建监听结果事件方法体。
功能示例
你可以使用 lambda 形式创建 Result
类。
示例如下
constructor {
+ // Your code here.
+}.result {
+ all()
+ remedys {}
+ onNoSuchConstructor {}
+}
+
fun all(): Process
+
变更记录
v1.1.0
新增
功能描述
设置全部查找条件匹配的多个
Constructor
实例结果到hookManager
。
inline fun remedys(initiate: RemedyPlan.() -> Unit): Result
+
变更记录
v1.1.0
新增
功能描述
创建
Constructor
重查找功能。
功能示例
当你遇到一种 Constructor
可能存在不同形式的存在时,可以使用 RemedyPlan
重新查找它,而没有必要使用 onNoSuchConstructor
捕获异常二次查找 Constructor
。
若第一次查找失败了,你还可以在这里继续添加此方法体直到成功为止。
示例如下
constructor {
+ // Your code here.
+}.remedys {
+ constructor {
+ // Your code here.
+ }
+ constructor {
+ // Your code here.
+ }
+}
+
inline fun onNoSuchConstructor(result: (Throwable) -> Unit): Result
+
变更记录
v1.1.0
新增
功能描述
监听找不到
Constructor
时。
只会返回第一次的错误信息,不会返回 RemedyPlan
的错误信息。
inner class Result internal constructor(internal val isNoSuch: Boolean, internal val throwable: Throwable?) : BaseResult
+
变更记录
v1.0
添加
v1.1.0
修改
继承到接口 BaseResult
功能描述
Constructor
查找结果实现类。
inline fun result(initiate: Result.() -> Unit): Result
+
变更记录
v1.0
添加
v1.0.80
修改
将方法体进行 inline
功能描述
创建监听结果事件方法体。
功能示例
你可以使用 lambda 形式创建 Result
类。
示例如下
constructor {
+ // Your code here.
+}.result {
+ get().call()
+ all()
+ remedys {}
+ onNoSuchConstructor {}
+}
+
fun get(): Instance
+
变更记录
v1.0.2
新增
功能描述
获得
Constructor
实例处理类。
若有多个 Constructor
结果只会返回第一个。
特别注意
若你设置了 remedys 请使用 wait 回调结果方法。
功能示例
你可以通过获得方法所在实例来执行构造方法创建新的实例对象。
示例如下
constructor {
+ // Your code here.
+}.get().call()
+
你可以 cast
构造方法为指定类型的实例对象。
示例如下
constructor {
+ // Your code here.
+}.get().newInstance<TestClass>()
+
特别注意
若构造方法含有参数则后方参数必填。
示例如下
constructor {
+ // Your code here.
+}.get().newInstance<TestClass>("param1", "param2")
+
fun all(): MutableList<Instance>
+
变更记录
v1.1.0
新增
v1.2.0
修改
返回值类型由 ArrayList
修改为 MutableList
功能描述
获得
Constructor
实例处理类数组。
返回全部查找条件匹配的多个 Constructor
实例结果。
功能示例
你可以通过此方法来获得当前条件结果中匹配的全部 Constructor
。
示例如下
constructor {
+ // Your code here.
+}.all().forEach { instance ->
+ instance.call(...)
+}
+
fun give(): Constructor<*>?
+
变更记录
v1.0.67
新增
功能描述
得到
Constructor
本身。
若有多个 Constructor
结果只会返回第一个。
在查找条件找不到任何结果的时候将返回 null
。
fun giveAll(): MutableList<Constructor<*>>
+
变更记录
v1.1.0
新增
v1.2.0
修改
返回值类型由 HashSet
修改为 MutableList
功能描述
得到
Constructor
本身数组。
返回全部查找条件匹配的多个 Constructor
实例。
在查找条件找不到任何结果的时候将返回空的 MutableList
。
fun wait(initiate: Instance.() -> Unit)
+
变更记录
v1.0.2
新增
功能描述
获得
Constructor
实例处理类,配合RemedyPlan
使用。
若有多个 Constructor
结果只会返回第一个。
特别注意
若你设置了 remedys 必须使用此方法才能获得结果。
若你没有设置 remedys 此方法将不会被回调。
fun waitAll(initiate: MutableList<Instance>.() -> Unit)
+
变更记录
v1.1.0
新增
v1.2.0
修改
initiate
类型由 ArrayList
修改为 MutableList
功能描述
获得
Constructor
实例处理类数组,配合RemedyPlan
使用。
返回全部查找条件匹配的多个 Constructor
实例结果。
特别注意
若你设置了 remedys 必须使用此方法才能获得结果。
若你没有设置 remedys 此方法将不会被回调。
inline fun remedys(initiate: RemedyPlan.() -> Unit): Result
+
变更记录
v1.0
添加
v1.0.80
修改
将方法体进行 inline
功能描述
创建
Constructor
重查找功能。
功能示例
当你遇到一种 Constructor
可能存在不同形式的存在时,可以使用 RemedyPlan
重新查找它,而没有必要使用 onNoSuchConstructor
捕获异常二次查找 Constructor
。
若第一次查找失败了,你还可以在这里继续添加此方法体直到成功为止。
示例如下
constructor {
+ // Your code here.
+}.remedys {
+ constructor {
+ // Your code here.
+ }
+ constructor {
+ // Your code here.
+ }
+}
+
inline fun onNoSuchConstructor(result: (Throwable) -> Unit): Result
+
变更记录
v1.0
添加
v1.0.80
修改
将方法体进行 inline
功能描述
监听找不到
Constructor
时。
只会返回第一次的错误信息,不会返回 RemedyPlan
的错误信息。
fun ignored(): Result
+
变更记录
v1.1.0
新增
功能描述
忽略异常并停止打印任何错误日志。
若 MemberBaseFinder.MemberHookerManager.isNotIgnoredNoSuchMemberFailure
为 false
则自动忽略。
注意
此时若要监听异常结果,你需要手动实现 onNoSuchConstructor 方法。
变更记录
v1.0.3
新增
v1.1.0
作废
请迁移到新方法 ignored()
inner class Instance internal constructor(private val constructor: Constructor<*>?)
+
变更记录
v1.0.2
新增
v1.1.0
修改
新增 constructor
参数
功能描述
Constructor
实例处理类。
fun call(vararg args: Any?): Any?
+
变更记录
v1.0.2
新增
v1.1.6
修改
修改参数命名 param
为 args
功能描述
执行
Constructor
创建目标实例,不指定目标实例类型。
fun <T> newInstance(vararg args: Any?): T?
+
变更记录
v1.0.2
新增
v1.1.6
修改
修改参数命名 param
为 args
功能描述
`,309),p=[l];function c(t,r){return o(),n("div",null,p)}const i=s(e,[["render",c],["__file","ConstructorFinder.html.vue"]]);export{i as default}; diff --git a/assets/ConstructorFinder.html-DuJIkaTM.js b/assets/ConstructorFinder.html-DuJIkaTM.js new file mode 100644 index 00000000..b1da5268 --- /dev/null +++ b/assets/ConstructorFinder.html-DuJIkaTM.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-a71937aa","path":"/en/api/public/com/highcapable/yukihookapi/hook/core/finder/members/ConstructorFinder.html","title":"ConstructorFinder - class","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"paramCount - field","slug":"paramcount-field","link":"#paramcount-field","children":[]},{"level":2,"title":"modifiers - method","slug":"modifiers-method","link":"#modifiers-method","children":[]},{"level":2,"title":"emptyParam - method","slug":"emptyparam-method","link":"#emptyparam-method","children":[]},{"level":2,"title":"param - method","slug":"param-method","link":"#param-method","children":[]},{"level":2,"title":"param - method","slug":"param-method-1","link":"#param-method-1","children":[]},{"level":2,"title":"paramCount - method","slug":"paramcount-method","link":"#paramcount-method","children":[]},{"level":2,"title":"paramCount - method","slug":"paramcount-method-1","link":"#paramcount-method-1","children":[]},{"level":2,"title":"paramCount - method","slug":"paramcount-method-2","link":"#paramcount-method-2","children":[]},{"level":2,"title":"superClass - method","slug":"superclass-method","link":"#superclass-method","children":[]},{"level":2,"title":"RemedyPlan - class","slug":"remedyplan-class","link":"#remedyplan-class","children":[{"level":3,"title":"constructor - method","slug":"constructor-method","link":"#constructor-method","children":[]},{"level":3,"title":"Result - class","slug":"result-class","link":"#result-class","children":[]}]},{"level":2,"title":"Process - class","slug":"process-class","link":"#process-class","children":[{"level":3,"title":"result - method","slug":"result-method","link":"#result-method","children":[]},{"level":3,"title":"all - method","slug":"all-method","link":"#all-method","children":[]},{"level":3,"title":"remedys - method","slug":"remedys-method","link":"#remedys-method","children":[]},{"level":3,"title":"onNoSuchConstructor - method","slug":"onnosuchconstructor-method","link":"#onnosuchconstructor-method","children":[]}]},{"level":2,"title":"Result - class","slug":"result-class-1","link":"#result-class-1","children":[{"level":3,"title":"result - method","slug":"result-method-1","link":"#result-method-1","children":[]},{"level":3,"title":"get - method","slug":"get-method","link":"#get-method","children":[]},{"level":3,"title":"all - method","slug":"all-method-1","link":"#all-method-1","children":[]},{"level":3,"title":"give - method","slug":"give-method","link":"#give-method","children":[]},{"level":3,"title":"giveAll - method","slug":"giveall-method","link":"#giveall-method","children":[]},{"level":3,"title":"wait - method","slug":"wait-method","link":"#wait-method","children":[]},{"level":3,"title":"waitAll - method","slug":"waitall-method","link":"#waitall-method","children":[]},{"level":3,"title":"remedys - method","slug":"remedys-method-1","link":"#remedys-method-1","children":[]},{"level":3,"title":"onNoSuchConstructor - method","slug":"onnosuchconstructor-method-1","link":"#onnosuchconstructor-method-1","children":[]},{"level":3,"title":"ignored - method","slug":"ignored-method","link":"#ignored-method","children":[]},{"level":3,"title":"Instance - class","slug":"instance-class","link":"#instance-class","children":[]}]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":9}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/core/finder/members/ConstructorFinder.md"}');export{e as data}; diff --git a/assets/ConstructorRules.html-BuW8PcLh.js b/assets/ConstructorRules.html-BuW8PcLh.js new file mode 100644 index 00000000..8cc216fe --- /dev/null +++ b/assets/ConstructorRules.html-BuW8PcLh.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-08b70f7f","path":"/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/ConstructorRules.html","title":"ConstructorRules - class","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"paramCount - field","slug":"paramcount-field","link":"#paramcount-field","children":[]},{"level":2,"title":"modifiers - method","slug":"modifiers-method","link":"#modifiers-method","children":[]},{"level":2,"title":"emptyParam - method","slug":"emptyparam-method","link":"#emptyparam-method","children":[]},{"level":2,"title":"param - method","slug":"param-method","link":"#param-method","children":[]},{"level":2,"title":"param - method","slug":"param-method-1","link":"#param-method-1","children":[]},{"level":2,"title":"paramCount - method","slug":"paramcount-method","link":"#paramcount-method","children":[]},{"level":2,"title":"paramCount - method","slug":"paramcount-method-1","link":"#paramcount-method-1","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":4}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/ConstructorRules.md"}');export{e as data}; diff --git a/assets/ConstructorRules.html-Bxffddpr.js b/assets/ConstructorRules.html-Bxffddpr.js new file mode 100644 index 00000000..63b2b552 --- /dev/null +++ b/assets/ConstructorRules.html-Bxffddpr.js @@ -0,0 +1,9 @@ +import{_ as o,o as s,c as a,a as e}from"./app-BpUB8-Q8.js";const n={},t=e(`执行
Constructor
创建目标实例 ,指定T
目标实例类型。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
class ConstructorRules internal constructor(private val rulesData: ConstructorRulesData) : BaseRules
+
Change Records
v1.1.0
added
Function Illustrate
Constructor
查找条件实现类。
var paramCount: Int
+
Change Records
v1.1.0
added
Function Illustrate
设置
Constructor
参数个数。
你可以不使用 param
指定参数类型而是仅使用此变量指定参数个数。
若参数个数小于零则忽略并使用 param
。
fun modifiers(conditions: ModifierConditions)
+
Change Records
v1.1.0
added
Function Illustrate
设置
Constructor
标识符筛选条件。
可不设置筛选条件。
fun emptyParam()
+
Change Records
v1.1.0
added
Function Illustrate
设置
Constructor
空参数、无参数。
fun param(vararg paramType: Any)
+
Change Records
v1.1.0
added
Function Illustrate
设置
Constructor
参数。
如果同时使用了 paramCount
则 paramType
的数量必须与 paramCount
完全匹配。
如果 Constructor
中存在一些无意义又很长的类型,你可以使用 VagueType
来替代它。
Pay Attention
无参 Constructor 请使用 emptyParam 设置查找条件。
有参 Constructor 必须使用此方法设定参数或使用 paramCount 指定个数。
fun param(conditions: ObjectsConditions)
+
Change Records
v1.1.5
added
Function Illustrate
设置
Constructor
参数条件。
Pay Attention
无参 Constructor 请使用 emptyParam 设置查找条件。
有参 Constructor 必须使用此方法设定参数或使用 paramCount 指定个数。
fun paramCount(numRange: IntRange)
+
Change Records
v1.1.0
added
Function Illustrate
设置
Constructor
参数个数范围。
你可以不使用 param
指定参数类型而是仅使用此方法指定参数个数范围。
fun paramCount(conditions: CountConditions)
+
Change Records
v1.1.0
added
Function Illustrate
设置
Constructor
参数个数条件。
你可以不使用 param
指定参数类型而是仅使用此方法指定参数个数条件。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
class ConstructorRules internal constructor(private val rulesData: ConstructorRulesData) : BaseRules
+
变更记录
v1.1.0
新增
功能描述
Constructor
查找条件实现类。
var paramCount: Int
+
变更记录
v1.1.0
新增
功能描述
设置
Constructor
参数个数。
你可以不使用 param
指定参数类型而是仅使用此变量指定参数个数。
若参数个数小于零则忽略并使用 param
。
fun modifiers(conditions: ModifierConditions)
+
变更记录
v1.1.0
新增
功能描述
设置
Constructor
标识符筛选条件。
可不设置筛选条件。
fun emptyParam()
+
变更记录
v1.1.0
新增
功能描述
设置
Constructor
空参数、无参数。
fun param(vararg paramType: Any)
+
变更记录
v1.1.0
新增
功能描述
设置
Constructor
参数。
如果同时使用了 paramCount
则 paramType
的数量必须与 paramCount
完全匹配。
如果 Constructor
中存在一些无意义又很长的类型,你可以使用 VagueType
来替代它。
特别注意
无参 Constructor 请使用 emptyParam 设置查找条件。
有参 Constructor 必须使用此方法设定参数或使用 paramCount 指定个数。
fun param(conditions: ObjectsConditions)
+
变更记录
v1.1.5
新增
功能描述
设置
Constructor
参数条件。
特别注意
无参 Constructor 请使用 emptyParam 设置查找条件。
有参 Constructor 必须使用此方法设定参数或使用 paramCount 指定个数。
fun paramCount(numRange: IntRange)
+
变更记录
v1.1.0
新增
功能描述
设置
Constructor
参数个数范围。
你可以不使用 param
指定参数类型而是仅使用此方法指定参数个数范围。
fun paramCount(conditions: CountConditions)
+
变更记录
v1.1.0
新增
功能描述
设置
Constructor
参数个数条件。
你可以不使用 param
指定参数类型而是仅使用此方法指定参数个数条件。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
class CountRules private constructor()
+
Change Records
v1.1.0
added
Function Illustrate
这是一个模糊
Class
、Member
数组 (下标) 个数条件实现类。
可对 R8 混淆后的 Class
、Member
进行更加详细的定位。
fun Int.isZero(): Boolean
+
Change Records
v1.1.0
added
Function Illustrate
是否为 0。
fun Int.moreThan(count: Int): Boolean
+
Change Records
v1.1.0
added
Function Illustrate
大于
count
。
fun Int.lessThan(count: Int): Boolean
+
Change Records
v1.1.0
added
Function Illustrate
小于
count
。
fun Int.inInterval(countRange: IntRange): Boolean
+
Change Records
v1.1.0
added
Function Illustrate
`,33),l=[t];function c(p,r){return e(),n("div",null,l)}const i=s(a,[["render",c],["__file","CountRules.html.vue"]]);export{i as default}; diff --git a/assets/CountRules.html-cCBf7VmB.js b/assets/CountRules.html-cCBf7VmB.js new file mode 100644 index 00000000..9665f6ff --- /dev/null +++ b/assets/CountRules.html-cCBf7VmB.js @@ -0,0 +1,6 @@ +import{_ as s,o,c as e,a as n}from"./app-BpUB8-Q8.js";const a={},t=n(`在
countRange
区间 A ≤ this ≤ B。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
class CountRules private constructor()
+
变更记录
v1.1.0
新增
功能描述
这是一个模糊
Class
、Member
数组 (下标) 个数条件实现类。
可对 R8 混淆后的 Class
、Member
进行更加详细的定位。
fun Int.isZero(): Boolean
+
变更记录
v1.1.0
新增
功能描述
是否为 0。
fun Int.moreThan(count: Int): Boolean
+
变更记录
v1.1.0
新增
功能描述
大于
count
。
fun Int.lessThan(count: Int): Boolean
+
变更记录
v1.1.0
新增
功能描述
小于
count
。
fun Int.inInterval(countRange: IntRange): Boolean
+
变更记录
v1.1.0
新增
功能描述
`,32),l=[t];function c(p,r){return o(),e("div",null,l)}const i=s(a,[["render",c],["__file","CountRules.html.vue"]]);export{i as default}; diff --git a/assets/CountRules.html-lW3FW-Bi.js b/assets/CountRules.html-lW3FW-Bi.js new file mode 100644 index 00000000..e57a3043 --- /dev/null +++ b/assets/CountRules.html-lW3FW-Bi.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-52995ef7","path":"/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/CountRules.html","title":"CountRules - class","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"Int.isZero - i-ext-method","slug":"int-iszero-i-ext-method","link":"#int-iszero-i-ext-method","children":[]},{"level":2,"title":"Int.moreThan - i-ext-method","slug":"int-morethan-i-ext-method","link":"#int-morethan-i-ext-method","children":[]},{"level":2,"title":"Int.lessThan - i-ext-method","slug":"int-lessthan-i-ext-method","link":"#int-lessthan-i-ext-method","children":[]},{"level":2,"title":"Int.inInterval - i-ext-method","slug":"int-ininterval-i-ext-method","link":"#int-ininterval-i-ext-method","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":2}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/CountRules.md"}');export{e as data}; diff --git a/assets/CurrentClass.html-BT6y6bjW.js b/assets/CurrentClass.html-BT6y6bjW.js new file mode 100644 index 00000000..197cd5ca --- /dev/null +++ b/assets/CurrentClass.html-BT6y6bjW.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-b6a815c4","path":"/en/api/public/com/highcapable/yukihookapi/hook/bean/CurrentClass.html","title":"CurrentClass - class","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"name - field","slug":"name-field","link":"#name-field","children":[]},{"level":2,"title":"simpleName - field","slug":"simplename-field","link":"#simplename-field","children":[]},{"level":2,"title":"generic - method","slug":"generic-method","link":"#generic-method","children":[]},{"level":2,"title":"generic - method","slug":"generic-method-1","link":"#generic-method-1","children":[]},{"level":2,"title":"superClass - method","slug":"superclass-method","link":"#superclass-method","children":[]},{"level":2,"title":"field - method","slug":"field-method","link":"#field-method","children":[]},{"level":2,"title":"method - method","slug":"method-method","link":"#method-method","children":[]},{"level":2,"title":"SuperClass - class","slug":"superclass-class","link":"#superclass-class","children":[{"level":3,"title":"name - field","slug":"name-field-1","link":"#name-field-1","children":[]},{"level":3,"title":"simpleName - field","slug":"simplename-field-1","link":"#simplename-field-1","children":[]},{"level":3,"title":"generic - method","slug":"generic-method-2","link":"#generic-method-2","children":[]},{"level":3,"title":"generic - method","slug":"generic-method-3","link":"#generic-method-3","children":[]},{"level":3,"title":"field - method","slug":"field-method-1","link":"#field-method-1","children":[]},{"level":3,"title":"method - method","slug":"method-method-1","link":"#method-method-1","children":[]}]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":3}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/bean/CurrentClass.md"}');export{e as data}; diff --git a/assets/CurrentClass.html-CF1c04UQ.js b/assets/CurrentClass.html-CF1c04UQ.js new file mode 100644 index 00000000..36b98efa --- /dev/null +++ b/assets/CurrentClass.html-CF1c04UQ.js @@ -0,0 +1,16 @@ +import{_ as s,o as e,c as a,a as n}from"./app-BpUB8-Q8.js";const o={},l=n(`在
countRange
区间 A ≤ this ≤ B。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
class CurrentClass internal constructor(private val classSet: Class<*>, internal val instance: Any)
+
Change Records
v1.0.70
added
v1.1.0
modified
调整了构造方法的参数名称
Function Illustrate
当前实例的类操作对象。
val name: String
+
Change Records
v1.1.0
added
Function Illustrate
获得当前
classSet
的Class.getName
。
val simpleName: String
+
Change Records
v1.1.0
added
Function Illustrate
获得当前
classSet
的Class.getSimpleName
。
fun generic(): GenericClass?
+
Change Records
v1.1.0
added
Function Illustrate
获得当前实例中的泛型父类。
如果当前实例不存在泛型将返回 null
。
inline fun generic(initiate: GenericClass.() -> Unit): GenericClass?
+
Change Records
v1.1.0
added
Function Illustrate
获得当前实例中的泛型父类。
如果当前实例不存在泛型将返回 null
。
fun superClass(): SuperClass
+
Change Records
v1.0.80
added
Function Illustrate
调用父类实例。
inline fun field(initiate: FieldConditions): FieldFinder.Result.Instance
+
Change Records
v1.0.70
added
Function Illustrate
调用当前实例中的变量。
inline fun method(initiate: MethodConditions): MethodFinder.Result.Instance
+
Change Records
v1.0.70
added
Function Illustrate
调用当前实例中的方法。
inner class SuperClass internal constructor(private val superClassSet: Class<*>)
+
Change Records
v1.0.80
added
v1.1.0
modified
新增 superClassSet
参数
Function Illustrate
当前类的父类实例的类操作对象。
val name: String
+
Change Records
v1.1.0
added
Function Illustrate
获得当前
classSet
中父类的Class.getName
。
val simpleName: String
+
Change Records
v1.1.0
added
Function Illustrate
获得当前
classSet
中父类的Class.getSimpleName
。
fun generic(): GenericClass?
+
Change Records
v1.1.0
added
Function Illustrate
获得当前实例父类中的泛型父类。
如果当前实例不存在泛型将返回 null
。
inline fun generic(initiate: GenericClass.() -> Unit): GenericClass?
+
Change Records
v1.1.0
added
Function Illustrate
获得当前实例父类中的泛型父类。
如果当前实例不存在泛型将返回 null
。
inline fun field(initiate: FieldConditions): FieldFinder.Result.Instance
+
Change Records
v1.0.80
added
Function Illustrate
调用父类实例中的变量。
inline fun method(initiate: MethodConditions): MethodFinder.Result.Instance
+
Change Records
v1.0.80
added
Function Illustrate
`,100),t=[l];function p(c,d){return e(),a("div",null,t)}const i=s(o,[["render",p],["__file","CurrentClass.html.vue"]]);export{i as default}; diff --git a/assets/CurrentClass.html-Drrw8tv5.js b/assets/CurrentClass.html-Drrw8tv5.js new file mode 100644 index 00000000..b0fdefd6 --- /dev/null +++ b/assets/CurrentClass.html-Drrw8tv5.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-6e47300f","path":"/zh-cn/api/public/com/highcapable/yukihookapi/hook/bean/CurrentClass.html","title":"CurrentClass - class","lang":"zh-CN","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"name - field","slug":"name-field","link":"#name-field","children":[]},{"level":2,"title":"simpleName - field","slug":"simplename-field","link":"#simplename-field","children":[]},{"level":2,"title":"generic - method","slug":"generic-method","link":"#generic-method","children":[]},{"level":2,"title":"generic - method","slug":"generic-method-1","link":"#generic-method-1","children":[]},{"level":2,"title":"superClass - method","slug":"superclass-method","link":"#superclass-method","children":[]},{"level":2,"title":"field - method","slug":"field-method","link":"#field-method","children":[]},{"level":2,"title":"method - method","slug":"method-method","link":"#method-method","children":[]},{"level":2,"title":"SuperClass - class","slug":"superclass-class","link":"#superclass-class","children":[{"level":3,"title":"name - field","slug":"name-field-1","link":"#name-field-1","children":[]},{"level":3,"title":"simpleName - field","slug":"simplename-field-1","link":"#simplename-field-1","children":[]},{"level":3,"title":"generic - method","slug":"generic-method-2","link":"#generic-method-2","children":[]},{"level":3,"title":"generic - method","slug":"generic-method-3","link":"#generic-method-3","children":[]},{"level":3,"title":"field - method","slug":"field-method-1","link":"#field-method-1","children":[]},{"level":3,"title":"method - method","slug":"method-method-1","link":"#method-method-1","children":[]}]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":5}]},"filePathRelative":"zh-cn/api/public/com/highcapable/yukihookapi/hook/bean/CurrentClass.md"}');export{e as data}; diff --git a/assets/CurrentClass.html-Dwxk2yiw.js b/assets/CurrentClass.html-Dwxk2yiw.js new file mode 100644 index 00000000..c0cb9874 --- /dev/null +++ b/assets/CurrentClass.html-Dwxk2yiw.js @@ -0,0 +1,16 @@ +import{_ as s,o as a,c as e,a as n}from"./app-BpUB8-Q8.js";const o={},l=n(`调用父类实例中的方法。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
class CurrentClass internal constructor(private val classSet: Class<*>, internal val instance: Any)
+
变更记录
v1.0.70
新增
v1.1.0
修改
调整了构造方法的参数名称
功能描述
当前实例的类操作对象。
val name: String
+
变更记录
v1.1.0
新增
功能描述
获得当前
classSet
的Class.getName
。
val simpleName: String
+
变更记录
v1.1.0
新增
功能描述
获得当前
classSet
的Class.getSimpleName
。
fun generic(): GenericClass?
+
变更记录
v1.1.0
新增
功能描述
获得当前实例中的泛型父类。
如果当前实例不存在泛型将返回 null
。
inline fun generic(initiate: GenericClass.() -> Unit): GenericClass?
+
变更记录
v1.1.0
新增
功能描述
获得当前实例中的泛型父类。
如果当前实例不存在泛型将返回 null
。
fun superClass(): SuperClass
+
变更记录
v1.0.80
新增
功能描述
调用父类实例。
inline fun field(initiate: FieldConditions): FieldFinder.Result.Instance
+
变更记录
v1.0.70
新增
功能描述
调用当前实例中的变量。
inline fun method(initiate: MethodConditions): MethodFinder.Result.Instance
+
变更记录
v1.0.70
新增
功能描述
调用当前实例中的方法。
inner class SuperClass internal constructor(private val superClassSet: Class<*>)
+
变更记录
v1.0.80
新增
v1.1.0
修改
新增 superClassSet
参数
功能描述
当前类的父类实例的类操作对象。
val name: String
+
变更记录
v1.1.0
新增
功能描述
获得当前
classSet
中父类的Class.getName
。
val simpleName: String
+
变更记录
v1.1.0
新增
功能描述
获得当前
classSet
中父类的Class.getSimpleName
。
fun generic(): GenericClass?
+
变更记录
v1.1.0
新增
功能描述
获得当前实例父类中的泛型父类。
如果当前实例不存在泛型将返回 null
。
inline fun generic(initiate: GenericClass.() -> Unit): GenericClass?
+
变更记录
v1.1.0
新增
功能描述
获得当前实例父类中的泛型父类。
如果当前实例不存在泛型将返回 null
。
inline fun field(initiate: FieldConditions): FieldFinder.Result.Instance
+
变更记录
v1.0.80
新增
功能描述
调用父类实例中的变量。
inline fun method(initiate: MethodConditions): MethodFinder.Result.Instance
+
变更记录
v1.0.80
新增
功能描述
`,99),p=[l];function c(t,r){return a(),e("div",null,p)}const i=s(o,[["render",c],["__file","CurrentClass.html.vue"]]);export{i as default}; diff --git a/assets/DefinedTypeFactory.html-B0M9p-6D.js b/assets/DefinedTypeFactory.html-B0M9p-6D.js new file mode 100644 index 00000000..3fd52f56 --- /dev/null +++ b/assets/DefinedTypeFactory.html-B0M9p-6D.js @@ -0,0 +1,2 @@ +import{_ as e,o,c as a,a as s}from"./app-BpUB8-Q8.js";const t={},c=s(`调用父类实例中的方法。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
变更记录
v1.1.0
新增
功能描述
这是一个内部类型的定义常量类,主要用于反射 API 相关用法的延伸。
val VagueType: Class<*>
+
变更记录
v1.1.0
新增
功能描述
`,12),n=[c];function d(p,r){return o(),a("div",null,n)}const i=e(t,[["render",d],["__file","DefinedTypeFactory.html.vue"]]);export{i as default}; diff --git a/assets/DefinedTypeFactory.html-C97GePUm.js b/assets/DefinedTypeFactory.html-C97GePUm.js new file mode 100644 index 00000000..4bc9a96b --- /dev/null +++ b/assets/DefinedTypeFactory.html-C97GePUm.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-5acc12ab","path":"/zh-cn/api/public/com/highcapable/yukihookapi/hook/type/defined/DefinedTypeFactory.html","title":"DefinedTypeFactory - kt","lang":"zh-CN","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"VagueType - field","slug":"vaguetype-field","link":"#vaguetype-field","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":3}]},"filePathRelative":"zh-cn/api/public/com/highcapable/yukihookapi/hook/type/defined/DefinedTypeFactory.md"}');export{e as data}; diff --git a/assets/DefinedTypeFactory.html-DI2zOcK2.js b/assets/DefinedTypeFactory.html-DI2zOcK2.js new file mode 100644 index 00000000..5bdde328 --- /dev/null +++ b/assets/DefinedTypeFactory.html-DI2zOcK2.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-a2615d0c","path":"/en/api/public/com/highcapable/yukihookapi/hook/type/defined/DefinedTypeFactory.html","title":"DefinedTypeFactory - kt","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"VagueType - field","slug":"vaguetype-field","link":"#vaguetype-field","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":2}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/type/defined/DefinedTypeFactory.md"}');export{e as data}; diff --git a/assets/DefinedTypeFactory.html-DyzA4S0r.js b/assets/DefinedTypeFactory.html-DyzA4S0r.js new file mode 100644 index 00000000..4f556c3f --- /dev/null +++ b/assets/DefinedTypeFactory.html-DyzA4S0r.js @@ -0,0 +1,2 @@ +import{_ as e,o as t,c as o,a}from"./app-BpUB8-Q8.js";const n={},s=a(`得到模糊类型。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
Change Records
v1.1.0
added
Function Illustrate
这是一个内部类型的定义常量类,主要用于反射 API 相关用法的延伸。
val VagueType: Class<*>
+
Change Records
v1.1.0
added
Function Illustrate
`,13),c=[s];function r(d,i){return t(),o("div",null,c)}const p=e(n,[["render",r],["__file","DefinedTypeFactory.html.vue"]]);export{p as default}; diff --git a/assets/DexClassFinder.html-BAaqClmM.js b/assets/DexClassFinder.html-BAaqClmM.js new file mode 100644 index 00000000..5cb56fab --- /dev/null +++ b/assets/DexClassFinder.html-BAaqClmM.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-2a898c66","path":"/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/DexClassFinder.html","title":"DexClassFinder - class","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"companion object - object","slug":"companion-object-object","link":"#companion-object-object","children":[{"level":3,"title":"clearCache - method","slug":"clearcache-method","link":"#clearcache-method","children":[]}]},{"level":2,"title":"fullName - field","slug":"fullname-field","link":"#fullname-field","children":[]},{"level":2,"title":"simpleName - field","slug":"simplename-field","link":"#simplename-field","children":[]},{"level":2,"title":"singleName - field","slug":"singlename-field","link":"#singlename-field","children":[]},{"level":2,"title":"from - method","slug":"from-method","link":"#from-method","children":[]},{"level":2,"title":"modifiers - method","slug":"modifiers-method","link":"#modifiers-method","children":[]},{"level":2,"title":"fullName - method","slug":"fullname-method","link":"#fullname-method","children":[]},{"level":2,"title":"simpleName - method","slug":"simplename-method","link":"#simplename-method","children":[]},{"level":2,"title":"singleName - method","slug":"singlename-method","link":"#singlename-method","children":[]},{"level":2,"title":"fullName - method","slug":"fullname-method-1","link":"#fullname-method-1","children":[]},{"level":2,"title":"simpleName - method","slug":"simplename-method-1","link":"#simplename-method-1","children":[]},{"level":2,"title":"singleName - method","slug":"singlename-method-1","link":"#singlename-method-1","children":[]},{"level":2,"title":"extends - method","slug":"extends-method","link":"#extends-method","children":[]},{"level":2,"title":"extends - method","slug":"extends-method-1","link":"#extends-method-1","children":[]},{"level":2,"title":"implements - method","slug":"implements-method","link":"#implements-method","children":[]},{"level":2,"title":"implements - method","slug":"implements-method-1","link":"#implements-method-1","children":[]},{"level":2,"title":"anonymous - method","slug":"anonymous-method","link":"#anonymous-method","children":[]},{"level":2,"title":"noExtends - method","slug":"noextends-method","link":"#noextends-method","children":[]},{"level":2,"title":"noImplements - method","slug":"noimplements-method","link":"#noimplements-method","children":[]},{"level":2,"title":"noSuper - method","slug":"nosuper-method","link":"#nosuper-method","children":[]},{"level":2,"title":"enclosing - method","slug":"enclosing-method","link":"#enclosing-method","children":[]},{"level":2,"title":"enclosing - method","slug":"enclosing-method-1","link":"#enclosing-method-1","children":[]},{"level":2,"title":"FromPackageRules - class","slug":"frompackagerules-class","link":"#frompackagerules-class","children":[{"level":3,"title":"absolute - method","slug":"absolute-method","link":"#absolute-method","children":[]}]},{"level":2,"title":"ClassNameRules - class","slug":"classnamerules-class","link":"#classnamerules-class","children":[{"level":3,"title":"optional - method","slug":"optional-method","link":"#optional-method","children":[]}]},{"level":2,"title":"member - method","slug":"member-method","link":"#member-method","children":[]},{"level":2,"title":"field - method","slug":"field-method","link":"#field-method","children":[]},{"level":2,"title":"method - method","slug":"method-method","link":"#method-method","children":[]},{"level":2,"title":"constructor - method","slug":"constructor-method","link":"#constructor-method","children":[]},{"level":2,"title":"Result - class","slug":"result-class","link":"#result-class","children":[{"level":3,"title":"result - method","slug":"result-method","link":"#result-method","children":[]},{"level":3,"title":"get - method","slug":"get-method","link":"#get-method","children":[]},{"level":3,"title":"all - method","slug":"all-method","link":"#all-method","children":[]},{"level":3,"title":"all - method","slug":"all-method-1","link":"#all-method-1","children":[]},{"level":3,"title":"wait - method","slug":"wait-method","link":"#wait-method","children":[]},{"level":3,"title":"waitAll - method","slug":"waitall-method","link":"#waitall-method","children":[]},{"level":3,"title":"onNoClassDefFoundError - method","slug":"onnoclassdeffounderror-method","link":"#onnoclassdeffounderror-method","children":[]},{"level":3,"title":"ignored - method","slug":"ignored-method","link":"#ignored-method","children":[]}]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":5}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/DexClassFinder.md"}');export{e as data}; diff --git a/assets/DexClassFinder.html-BbI_zWlb.js b/assets/DexClassFinder.html-BbI_zWlb.js new file mode 100644 index 00000000..2acc1056 --- /dev/null +++ b/assets/DexClassFinder.html-BbI_zWlb.js @@ -0,0 +1,45 @@ +import{_ as s,o as e,c as a,a as o}from"./app-BpUB8-Q8.js";const n={},l=o(`得到模糊类型。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
class DexClassFinder internal constructor(
+ internal var name: String,
+ internal var async: Boolean,
+ override val loaderSet: ClassLoader?
+) : ClassBaseFinder
+
变更记录
v1.1.0
新增
功能描述
Class
查找类。
可使用 BaseDexClassLoader
通过指定条件查找指定 Class
或一组 Class
。
注意
此功能尚实验阶段,性能与稳定性可能仍然存在问题,使用过程遇到问题请向我们报告并帮助我们改进。
变更记录
v1.1.0
新增
fun clearCache(context: Context?, versionName: String?, versionCode: Long?)
+
变更记录
v1.1.0
新增
功能描述
清除当前
DexClassFinder
的Class
缓存。
适用于全部通过 ClassLoader.searchClass 或 PackageParam.searchClass 获取的 DexClassFinder
。
var fullName: String
+
变更记录
v1.1.0
新增
功能描述
设置
Class
完整名称。
只会查找匹配到的 Class.getName
。
例如 com.demo.Test
需要填写 com.demo.Test
。
var simpleName: String
+
变更记录
v1.1.0
新增
功能描述
设置
Class
简单名称。
只会查找匹配到的 Class.getSimpleName
。
例如 com.demo.Test
只需要填写 Test
。
对于匿名类例如 com.demo.Test$InnerTest
会为空,此时你可以使用 singleName。
var singleName: String
+
变更记录
v1.1.0
新增
功能描述
设置
Class
独立名称。
设置后将首先使用 Class.getSimpleName
,若为空则会使用 Class.getName
进行处理。
例如 com.demo.Test
只需要填写 Test
。
对于匿名类例如 com.demo.Test$InnerTest
只需要填写 Test$InnerTest
。
fun from(vararg name: String): FromPackageRules
+
变更记录
v1.1.0
新增
功能描述
设置在指定包名范围查找当前
Class
。
设置后仅会在当前 name
开头匹配的包名路径下进行查找,可提升查找速度。
例如 ↓
com.demo.test
com.demo.test.demo
注意
建议设置此参数指定查找范围,否则 Class 过多时将会非常慢。
fun modifiers(conditions: ModifierConditions)
+
变更记录
v1.1.0
新增
功能描述
设置
Class
标识符筛选条件。
可不设置筛选条件。
fun fullName(value: String): ClassNameRules
+
变更记录
v1.1.0
新增
功能描述
设置
Class
完整名称。
只会查找匹配到的 Class.getName
。
例如 com.demo.Test
需要填写 com.demo.Test
。
fun simpleName(value: String): ClassNameRules
+
变更记录
v1.1.0
新增
功能描述
设置
Class
简单名称。
只会查找匹配到的 Class.getSimpleName
。
例如 com.demo.Test
只需要填写 Test
。
对于匿名类例如 com.demo.Test$InnerTest 会为空
,此时你可以使用 singleName。
fun singleName(value: String): ClassNameRules
+
变更记录
v1.1.0
新增
功能描述
设置
Class
独立名称。
设置后将首先使用 Class.getSimpleName
,若为空则会使用 Class.getName
进行处理。
例如 com.demo.Test
只需要填写 Test
。
对于匿名类例如 com.demo.Test$InnerTest
只需要填写 Test$InnerTest
。
fun fullName(conditions: NameConditions)
+
变更记录
v1.1.0
新增
功能描述
设置
Class
完整名称条件。
只会查找匹配到的 Class.getName
。
fun simpleName(conditions: NameConditions)
+
变更记录
v1.1.0
新增
功能描述
设置
Class
简单名称条件。
只会查找匹配到的 Class.getSimpleName
。
fun singleName(conditions: NameConditions)
+
变更记录
v1.1.0
新增
功能描述
设置
Class
独立名称条件。
设置后将首先使用 Class.getSimpleName
,若为空则会使用 Class.getName
进行处理。
inline fun <reified T> extends()
+
变更记录
v1.1.0
新增
功能描述
设置
Class
继承的父类。
fun extends(vararg name: String)
+
变更记录
v1.1.0
新增
功能描述
设置
Class
继承的父类。
会同时查找 name
中所有匹配的父类。
inline fun <reified T> implements()
+
变更记录
v1.1.0
新增
功能描述
设置
Class
实现的接口类。
fun implements(vararg name: String)
+
变更记录
v1.1.0
新增
功能描述
设置
Class
实现的接口类。
会同时查找 name
中所有匹配的接口类。
fun anonymous()
+
变更记录
v1.1.0
新增
功能描述
标识
Class
为匿名类。
例如 com.demo.Test$1
或 com.demo.Test$InnerTest
。
标识后你可以使用 enclosing 来进一步指定匿名类的 (封闭类) 主类。
fun noExtends()
+
变更记录
v1.1.0
新增
功能描述
设置
Class
没有任何继承。
此时 Class
只应该继承于 Any
。
注意
设置此条件后 extends 将失效。
fun noImplements()
+
变更记录
v1.1.0
新增
功能描述
设置
Class
没有任何接口。
注意
设置此条件后 implements 将失效。
fun noSuper()
+
变更记录
v1.1.0
新增
功能描述
设置
Class
没有任何继承与接口。
此时 Class
只应该继承于 Any
。
注意
设置此条件后 extends 与 implements 将失效。
inline fun <reified T> enclosing()
+
变更记录
v1.1.0
新增
功能描述
设置
Class
匿名类的 (封闭类) 主类。
fun enclosing(vararg name: String)
+
变更记录
v1.1.0
新增
功能描述
设置
Class
匿名类的 (封闭类) 主类。
会同时查找 name
中所有匹配的 (封闭类) 主类。
inner class FromPackageRules internal constructor(private val packages: MutableList<ClassRulesData.PackageRulesData>)
+
变更记录
v1.1.0
新增
功能描述
包名范围名称过滤匹配条件实现类。
fun absolute()
+
变更记录
v1.1.0
新增
功能描述
设置包名绝对匹配。
例如有如下包名 ↓
com.demo.test.a
com.demo.test.a.b
com.demo.test.active
若包名条件为 com.demo.test.a
则绝对匹配仅能匹配到第一个。
相反地,不设置以上示例会全部匹配。
inner class ClassNameRules internal constructor(private val name: ClassRulesData.NameRulesData)
+
变更记录
v1.1.0
新增
功能描述
类名匹配条件实现类。
fun optional()
+
变更记录
v1.1.0
新增
功能描述
设置类名可选。
例如有如下类名 ↓
com.demo.Test
fullName / Test
simpleName
defpackage.a
fullName / a
simpleName
这两个类名都是同一个类,但是在有些版本中被混淆有些版本没有。
此时可设置类名为 com.demo.Test
fullName / Test
simpleName。
这样就可在完全匹配类名情况下使用类名而忽略其它查找条件,否则忽略此条件继续使用其它查找条件。
inline fun member(initiate: MemberRules.() -> Unit): MemberRulesResult
+
变更记录
v1.1.0
新增
功能描述
设置
Class
满足的Member
条件。
inline fun field(initiate: FieldRules.() -> Unit): MemberRulesResult
+
变更记录
v1.1.0
新增
功能描述
设置
Class
满足的Field
条件。
inline fun method(initiate: MethodRules.() -> Unit): MemberRulesResult
+
变更记录
v1.1.0
新增
功能描述
设置
Class
满足的Method
条件。
inline fun constructor(initiate: ConstructorRules.() -> Unit): MemberRulesResult
+
变更记录
v1.1.0
新增
功能描述
设置
Class
满足的Constructor
条件。
inner class Result internal constructor(internal var isNotFound: Boolean, internal var throwable: Throwable?) : BaseResult
+
变更记录
v1.1.0
新增
功能描述
Class
查找结果实现类。
inline fun result(initiate: Result.() -> Unit): Result
+
变更记录
v1.1.0
新增
功能描述
创建监听结果事件方法体。
fun get(): Class<*>?
+
变更记录
v1.1.0
新增
功能描述
得到
Class
本身。
若有多个 Class
结果只会返回第一个。
在查找条件找不到任何结果的时候将返回 null
。
若你设置了 async
请使用 wait 方法。
fun all(): MutableList<Class<*>>
+
变更记录
v1.1.0
新增
v1.2.0
修改
返回值类型由 HashSet
修改为 MutableList
功能描述
得到
Class
本身数组。
返回全部查找条件匹配的多个 Class
实例。
在查找条件找不到任何结果的时候将返回空的 MutableList
。
若你设置了 async
请使用 waitAll 方法。
fun all(result: (Class<*>) -> Unit): Result
+
变更记录
v1.1.0
新增
功能描述
得到
Class
本身数组 (依次遍历)。
回调全部查找条件匹配的多个 Class
实例。
在查找条件找不到任何结果的时候将不会执行。
若你设置了 async
请使用 waitAll 方法。
fun wait(result: (Class<*>?) -> Unit): Result
+
变更记录
v1.1.0
新增
功能描述
得到
Class
本身 (异步)。
若有多个 Class
结果只会回调第一个。
在查找条件找不到任何结果的时候将回调 null。
你需要设置 async
后此方法才会被回调,否则请使用 get 方法。
fun waitAll(result: (MutableList<Class<*>>) -> Unit): Result
+
变更记录
v1.1.0
新增
v1.2.0
修改
result
类型由 HashSet
修改为 MutableList
功能描述
得到
Class
本身数组 (异步)。
回调全部查找条件匹配的多个 Class
实例。
在查找条件找不到任何结果的时候将回调空的 MutableList
。
你需要设置 async
后此方法才会被回调,否则请使用 all 方法。
fun onNoClassDefFoundError(result: (Throwable) -> Unit): Result
+
变更记录
v1.1.0
新增
功能描述
监听找不到
Class
时。
fun ignored(): Result
+
变更记录
v1.1.0
新增
功能描述
忽略异常并停止打印任何错误日志。
此时若要监听异常结果,你需要手动实现 onNoClassDefFoundError 方法。
`,314),p=[l];function c(t,d){return e(),a("div",null,p)}const i=s(n,[["render",c],["__file","DexClassFinder.html.vue"]]);export{i as default}; diff --git a/assets/DexClassFinder.html-CGIuabI3.js b/assets/DexClassFinder.html-CGIuabI3.js new file mode 100644 index 00000000..93ddb0bc --- /dev/null +++ b/assets/DexClassFinder.html-CGIuabI3.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-45111efc","path":"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/DexClassFinder.html","title":"DexClassFinder - class","lang":"zh-CN","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"companion object - object","slug":"companion-object-object","link":"#companion-object-object","children":[{"level":3,"title":"clearCache - method","slug":"clearcache-method","link":"#clearcache-method","children":[]}]},{"level":2,"title":"fullName - field","slug":"fullname-field","link":"#fullname-field","children":[]},{"level":2,"title":"simpleName - field","slug":"simplename-field","link":"#simplename-field","children":[]},{"level":2,"title":"singleName - field","slug":"singlename-field","link":"#singlename-field","children":[]},{"level":2,"title":"from - method","slug":"from-method","link":"#from-method","children":[]},{"level":2,"title":"modifiers - method","slug":"modifiers-method","link":"#modifiers-method","children":[]},{"level":2,"title":"fullName - method","slug":"fullname-method","link":"#fullname-method","children":[]},{"level":2,"title":"simpleName - method","slug":"simplename-method","link":"#simplename-method","children":[]},{"level":2,"title":"singleName - method","slug":"singlename-method","link":"#singlename-method","children":[]},{"level":2,"title":"fullName - method","slug":"fullname-method-1","link":"#fullname-method-1","children":[]},{"level":2,"title":"simpleName - method","slug":"simplename-method-1","link":"#simplename-method-1","children":[]},{"level":2,"title":"singleName - method","slug":"singlename-method-1","link":"#singlename-method-1","children":[]},{"level":2,"title":"extends - method","slug":"extends-method","link":"#extends-method","children":[]},{"level":2,"title":"extends - method","slug":"extends-method-1","link":"#extends-method-1","children":[]},{"level":2,"title":"implements - method","slug":"implements-method","link":"#implements-method","children":[]},{"level":2,"title":"implements - method","slug":"implements-method-1","link":"#implements-method-1","children":[]},{"level":2,"title":"anonymous - method","slug":"anonymous-method","link":"#anonymous-method","children":[]},{"level":2,"title":"noExtends - method","slug":"noextends-method","link":"#noextends-method","children":[]},{"level":2,"title":"noImplements - method","slug":"noimplements-method","link":"#noimplements-method","children":[]},{"level":2,"title":"noSuper - method","slug":"nosuper-method","link":"#nosuper-method","children":[]},{"level":2,"title":"enclosing - method","slug":"enclosing-method","link":"#enclosing-method","children":[]},{"level":2,"title":"enclosing - method","slug":"enclosing-method-1","link":"#enclosing-method-1","children":[]},{"level":2,"title":"FromPackageRules - class","slug":"frompackagerules-class","link":"#frompackagerules-class","children":[{"level":3,"title":"absolute - method","slug":"absolute-method","link":"#absolute-method","children":[]}]},{"level":2,"title":"ClassNameRules - class","slug":"classnamerules-class","link":"#classnamerules-class","children":[{"level":3,"title":"optional - method","slug":"optional-method","link":"#optional-method","children":[]}]},{"level":2,"title":"member - method","slug":"member-method","link":"#member-method","children":[]},{"level":2,"title":"field - method","slug":"field-method","link":"#field-method","children":[]},{"level":2,"title":"method - method","slug":"method-method","link":"#method-method","children":[]},{"level":2,"title":"constructor - method","slug":"constructor-method","link":"#constructor-method","children":[]},{"level":2,"title":"Result - class","slug":"result-class","link":"#result-class","children":[{"level":3,"title":"result - method","slug":"result-method","link":"#result-method","children":[]},{"level":3,"title":"get - method","slug":"get-method","link":"#get-method","children":[]},{"level":3,"title":"all - method","slug":"all-method","link":"#all-method","children":[]},{"level":3,"title":"all - method","slug":"all-method-1","link":"#all-method-1","children":[]},{"level":3,"title":"wait - method","slug":"wait-method","link":"#wait-method","children":[]},{"level":3,"title":"waitAll - method","slug":"waitall-method","link":"#waitall-method","children":[]},{"level":3,"title":"onNoClassDefFoundError - method","slug":"onnoclassdeffounderror-method","link":"#onnoclassdeffounderror-method","children":[]},{"level":3,"title":"ignored - method","slug":"ignored-method","link":"#ignored-method","children":[]}]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":6}]},"filePathRelative":"zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/DexClassFinder.md"}');export{e as data}; diff --git a/assets/DexClassFinder.html-DDicCU5w.js b/assets/DexClassFinder.html-DDicCU5w.js new file mode 100644 index 00000000..d00ca0d7 --- /dev/null +++ b/assets/DexClassFinder.html-DDicCU5w.js @@ -0,0 +1,45 @@ +import{_ as s,o as e,c as a,a as o}from"./app-BpUB8-Q8.js";const n={},l=o(`Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
class DexClassFinder internal constructor(
+ internal var name: String,
+ internal var async: Boolean,
+ override val loaderSet: ClassLoader?
+) : ClassBaseFinder
+
Change Records
v1.1.0
added
Function Illustrate
Class
查找类。
可使用 BaseDexClassLoader
通过指定条件查找指定 Class
或一组 Class
。
Notice
此功能尚在实验阶段,性能与稳定性可能仍然存在问题,使用过程遇到问题请向我们报告并帮助我们改进。
Change Records
v1.1.0
added
fun clearCache(context: Context?, versionName: String?, versionCode: Long?)
+
Change Records
v1.1.0
added
Function Illustrate
清除当前
DexClassFinder
的Class
缓存。
适用于全部通过 ClassLoader.searchClass 或 PackageParam.searchClass 获取的 DexClassFinder
。
var fullName: String
+
Change Records
v1.1.0
added
Function Illustrate
设置
Class
完整名称。
只会查找匹配到的 Class.getName
。
例如 com.demo.Test
需要填写 com.demo.Test
。
var simpleName: String
+
Change Records
v1.1.0
added
Function Illustrate
设置
Class
简单名称。
只会查找匹配到的 Class.getSimpleName
。
例如 com.demo.Test
只需要填写 Test
。
对于匿名类例如 com.demo.Test$InnerTest
会为空,此时你可以使用 singleName。
var singleName: String
+
Change Records
v1.1.0
added
Function Illustrate
设置
Class
独立名称。
设置后将首先使用 Class.getSimpleName
,若为空则会使用 Class.getName
进行处理。
例如 com.demo.Test
只需要填写 Test
。
对于匿名类例如 com.demo.Test$InnerTest
只需要填写 Test$InnerTest
。
fun from(vararg name: String): FromPackageRules
+
Change Records
v1.1.0
added
Function Illustrate
设置在指定包名范围查找当前
Class
。
设置后仅会在当前 name
开头匹配的包名路径下进行查找,可提升查找速度。
例如 ↓
com.demo.test
com.demo.test.demo
Notice
建议设置此参数指定查找范围,否则 Class 过多时将会非常慢。
fun modifiers(conditions: ModifierConditions)
+
Change Records
v1.1.0
added
Function Illustrate
设置
Class
标识符筛选条件。
可不设置筛选条件。
fun fullName(value: String): ClassNameRules
+
Change Records
v1.1.0
added
Function Illustrate
设置
Class
完整名称。
只会查找匹配到的 Class.getName
。
例如 com.demo.Test
需要填写 com.demo.Test
。
fun simpleName(value: String): ClassNameRules
+
Change Records
v1.1.0
added
Function Illustrate
设置
Class
简单名称。
只会查找匹配到的 Class.getSimpleName
。
例如 com.demo.Test
只需要填写 Test
。
对于匿名类例如 com.demo.Test$InnerTest 会为空
,此时你可以使用 singleName。
fun singleName(value: String): ClassNameRules
+
Change Records
v1.1.0
added
Function Illustrate
设置
Class
独立名称。
设置后将首先使用 Class.getSimpleName
,若为空则会使用 Class.getName
进行处理。
例如 com.demo.Test
只需要填写 Test
。
对于匿名类例如 com.demo.Test$InnerTest
只需要填写 Test$InnerTest
。
fun fullName(conditions: NameConditions)
+
Change Records
v1.1.0
added
Function Illustrate
设置
Class
完整名称条件。
只会查找匹配到的 Class.getName
。
fun simpleName(conditions: NameConditions)
+
Change Records
v1.1.0
added
Function Illustrate
设置
Class
简单名称条件。
只会查找匹配到的 Class.getSimpleName
。
fun singleName(conditions: NameConditions)
+
Change Records
v1.1.0
added
Function Illustrate
设置
Class
独立名称条件。
设置后将首先使用 Class.getSimpleName
,若为空则会使用 Class.getName
进行处理。
inline fun <reified T> extends()
+
Change Records
v1.1.0
added
Function Illustrate
设置
Class
继承的父类。
fun extends(vararg name: String)
+
Change Records
v1.1.0
added
Function Illustrate
设置
Class
继承的父类。
会同时查找 name
中所有匹配的父类。
inline fun <reified T> implements()
+
Change Records
v1.1.0
added
Function Illustrate
设置
Class
实现的接口类。
fun implements(vararg name: String)
+
Change Records
v1.1.0
added
Function Illustrate
设置
Class
实现的接口类。
会同时查找 name
中所有匹配的接口类。
fun anonymous()
+
Change Records
v1.1.0
added
Function Illustrate
标识
Class
为匿名类。
例如 com.demo.Test$1
或 com.demo.Test$InnerTest
。
标识后你可以使用 enclosing 来进一步指定匿名类的 (封闭类) 主类。
fun noExtends()
+
Change Records
v1.1.0
added
Function Illustrate
设置
Class
没有任何继承。
此时 Class
只应该继承于 Any
。
Notice
设置此条件后 extends 将失效。
fun noImplements()
+
Change Records
v1.1.0
added
Function Illustrate
设置
Class
没有任何接口。
Notice
设置此条件后 implements 将失效。
fun noSuper()
+
Change Records
v1.1.0
added
Function Illustrate
设置
Class
没有任何继承与接口。
此时 Class
只应该继承于 Any
。
Notice
设置此条件后 extends 与 implements 将失效。
inline fun <reified T> enclosing()
+
Change Records
v1.1.0
added
Function Illustrate
设置
Class
匿名类的 (封闭类) 主类。
fun enclosing(vararg name: String)
+
Change Records
v1.1.0
added
Function Illustrate
设置
Class
匿名类的 (封闭类) 主类。
会同时查找 name
中所有匹配的 (封闭类) 主类。
inner class FromPackageRules internal constructor(private val packages: MutableList<ClassRulesData.PackageRulesData>)
+
Change Records
v1.1.0
added
Function Illustrate
包名范围名称过滤匹配条件实现类。
fun absolute()
+
Change Records
v1.1.0
added
Function Illustrate
设置包名绝对匹配。
例如有如下包名 ↓
com.demo.test.a
com.demo.test.a.b
com.demo.test.active
若包名条件为 com.demo.test.a
则绝对匹配仅能匹配到第一个。
相反地,不设置以上示例会全部匹配。
inner class ClassNameRules internal constructor(private val name: ClassRulesData.NameRulesData)
+
Change Records
v1.1.0
added
Function Illustrate
类名匹配条件实现类。
fun optional()
+
Change Records
v1.1.0
added
Function Illustrate
设置类名可选。
例如有如下类名 ↓
com.demo.Test
fullName / Test
simpleName
defpackage.a
fullName / a
simpleName
这两个类名都是同一个类,但是在有些版本中被混淆有些版本没有。
此时可设置类名为 com.demo.Test
fullName / Test
simpleName。
这样就可在完全匹配类名情况下使用类名而忽略其它查找条件,否则忽略此条件继续使用其它查找条件。
inline fun member(initiate: MemberRules.() -> Unit): MemberRulesResult
+
Change Records
v1.1.0
added
Function Illustrate
设置
Class
满足的Member
条件。
inline fun field(initiate: FieldRules.() -> Unit): MemberRulesResult
+
Change Records
v1.1.0
added
Function Illustrate
设置
Class
满足的Field
条件。
inline fun method(initiate: MethodRules.() -> Unit): MemberRulesResult
+
Change Records
v1.1.0
added
Function Illustrate
设置
Class
满足的Method
条件。
inline fun constructor(initiate: ConstructorRules.() -> Unit): MemberRulesResult
+
Change Records
v1.1.0
added
Function Illustrate
设置
Class
满足的Constructor
条件。
inner class Result internal constructor(internal var isNotFound: Boolean, internal var throwable: Throwable?) : BaseResult
+
Change Records
v1.1.0
added
Function Illustrate
Class
查找结果实现类。
inline fun result(initiate: Result.() -> Unit): Result
+
Change Records
v1.1.0
added
Function Illustrate
创建监听结果事件方法体。
fun get(): Class<*>?
+
Change Records
v1.1.0
added
Function Illustrate
得到
Class
本身。
若有多个 Class
结果只会返回第一个。
在查找条件找不到任何结果的时候将返回 null
。
若你设置了 async
请使用 wait 方法。
fun all(): MutableList<Class<*>>
+
Change Records
v1.1.0
added
v1.2.0
modified
返回值类型由 HashSet
修改为 MutableList
Function Illustrate
得到
Class
本身数组。
返回全部查找条件匹配的多个 Class
实例。
在查找条件找不到任何结果的时候将返回空的 MutableList
。
若你设置了 async
请使用 waitAll 方法。
fun all(result: (Class<*>) -> Unit): Result
+
Change Records
v1.1.0
added
Function Illustrate
得到
Class
本身数组 (依次遍历)。
回调全部查找条件匹配的多个 Class
实例。
在查找条件找不到任何结果的时候将不会执行。
若你设置了 async
请使用 waitAll 方法。
fun wait(result: (Class<*>?) -> Unit): Result
+
Change Records
v1.1.0
added
Function Illustrate
得到
Class
本身 (异步)。
若有多个 Class
结果只会回调第一个。
在查找条件找不到任何结果的时候将回调 null。
你需要设置 async
后此方法才会被回调,否则请使用 get 方法。
fun waitAll(result: (MutableList<Class<*>>) -> Unit): Result
+
Change Records
v1.1.0
added
v1.2.0
modified
result
类型由 HashSet
修改为 MutableList
Function Illustrate
得到
Class
本身数组 (异步)。
回调全部查找条件匹配的多个 Class
实例。
在查找条件找不到任何结果的时候将回调空的 MutableList
。
你需要设置 async
后此方法才会被回调,否则请使用 all 方法。
fun onNoClassDefFoundError(result: (Throwable) -> Unit): Result
+
Change Records
v1.1.0
added
Function Illustrate
监听找不到
Class
时。
fun ignored(): Result
+
Change Records
v1.1.0
added
Function Illustrate
忽略异常并停止打印任何错误日志。
此时若要监听异常结果,你需要手动实现 onNoClassDefFoundError 方法。
`,315),t=[l];function p(c,d){return e(),a("div",null,t)}const i=s(n,[["render",p],["__file","DexClassFinder.html.vue"]]);export{i as default}; diff --git a/assets/ExecutorType.html-Crao5k7G.js b/assets/ExecutorType.html-Crao5k7G.js new file mode 100644 index 00000000..9a1f1e7d --- /dev/null +++ b/assets/ExecutorType.html-Crao5k7G.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-f150b17c","path":"/en/api/public/com/highcapable/yukihookapi/hook/core/api/compat/type/ExecutorType.html","title":"ExecutorType - class","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"UNKNOWN - enum","slug":"unknown-enum","link":"#unknown-enum","children":[]},{"level":2,"title":"XPOSED - enum","slug":"xposed-enum","link":"#xposed-enum","children":[]},{"level":2,"title":"LSPOSED_LSPATCH - enum","slug":"lsposed-lspatch-enum","link":"#lsposed-lspatch-enum","children":[]},{"level":2,"title":"ED_XPOSED - enum","slug":"ed-xposed-enum","link":"#ed-xposed-enum","children":[]},{"level":2,"title":"TAICHI_XPOSED - enum","slug":"taichi-xposed-enum","link":"#taichi-xposed-enum","children":[]},{"level":2,"title":"BUG_XPOSED - enum","slug":"bug-xposed-enum","link":"#bug-xposed-enum","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":2}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/core/api/compat/type/ExecutorType.md"}');export{e as data}; diff --git a/assets/ExecutorType.html-DyWI3DE3.js b/assets/ExecutorType.html-DyWI3DE3.js new file mode 100644 index 00000000..8cd8515e --- /dev/null +++ b/assets/ExecutorType.html-DyWI3DE3.js @@ -0,0 +1,8 @@ +import{_ as e,o as s,c as a,a as o}from"./app-BpUB8-Q8.js";const n={},c=o(`注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
enum class ExecutorType
+
变更记录
v1.1.9
新增
功能描述
Hook Framework 类型定义。
定义了目前已知使用频率较高的 Hook Framework。
后期根据 Hook Framework 特征和使用情况将会继续添加新的类型。
无法识别的 Hook Framework 将被定义为 UNKNOWN
。
UNKNOWN
+
变更记录
v1.1.9
新增
功能描述
未知类型。
XPOSED
+
变更记录
v1.1.9
新增
功能描述
原版、第三方 Xposed。
LSPOSED_LSPATCH
+
变更记录
v1.1.9
新增
功能描述
LSPosed、LSPatch。
ED_XPOSED
+
变更记录
v1.1.9
新增
功能描述
EdXposed。
TAICHI_XPOSED
+
变更记录
v1.1.9
新增
功能描述
TaiChi (太极)。
BUG_XPOSED
+
变更记录
v1.1.9
新增
功能描述
`,46),p=[c];function d(t,l){return s(),a("div",null,p)}const i=e(n,[["render",d],["__file","ExecutorType.html.vue"]]);export{i as default}; diff --git a/assets/ExecutorType.html-lxG6aiIx.js b/assets/ExecutorType.html-lxG6aiIx.js new file mode 100644 index 00000000..1f2f3c7c --- /dev/null +++ b/assets/ExecutorType.html-lxG6aiIx.js @@ -0,0 +1,8 @@ +import{_ as e,o as s,c as a,a as o}from"./app-BpUB8-Q8.js";const n={},t=o(`BugXposed (应用转生)。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
enum class ExecutorType
+
Change Records
v1.1.9
added
Function Illustrate
Hook Framework 类型定义。
定义了目前已知使用频率较高的 Hook Framework。
后期根据 Hook Framework 特征和使用情况将会继续添加新的类型。
无法识别的 Hook Framework 将被定义为 UNKNOWN
。
UNKNOWN
+
Change Records
v1.1.9
added
Function Illustrate
未知类型。
XPOSED
+
Change Records
v1.1.9
added
Function Illustrate
原版、第三方 Xposed。
LSPOSED_LSPATCH
+
Change Records
v1.1.9
added
Function Illustrate
LSPosed、LSPatch。
ED_XPOSED
+
Change Records
v1.1.9
added
Function Illustrate
EdXposed。
TAICHI_XPOSED
+
Change Records
v1.1.9
added
Function Illustrate
TaiChi (太极)。
BUG_XPOSED
+
Change Records
v1.1.9
added
Function Illustrate
`,47),c=[t];function d(p,l){return s(),a("div",null,c)}const i=e(n,[["render",d],["__file","ExecutorType.html.vue"]]);export{i as default}; diff --git a/assets/ExecutorType.html-tZrR-ZDE.js b/assets/ExecutorType.html-tZrR-ZDE.js new file mode 100644 index 00000000..9115c8bf --- /dev/null +++ b/assets/ExecutorType.html-tZrR-ZDE.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-2728e033","path":"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/api/compat/type/ExecutorType.html","title":"ExecutorType - class","lang":"zh-CN","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"UNKNOWN - enum","slug":"unknown-enum","link":"#unknown-enum","children":[]},{"level":2,"title":"XPOSED - enum","slug":"xposed-enum","link":"#xposed-enum","children":[]},{"level":2,"title":"LSPOSED_LSPATCH - enum","slug":"lsposed-lspatch-enum","link":"#lsposed-lspatch-enum","children":[]},{"level":2,"title":"ED_XPOSED - enum","slug":"ed-xposed-enum","link":"#ed-xposed-enum","children":[]},{"level":2,"title":"TAICHI_XPOSED - enum","slug":"taichi-xposed-enum","link":"#taichi-xposed-enum","children":[]},{"level":2,"title":"BUG_XPOSED - enum","slug":"bug-xposed-enum","link":"#bug-xposed-enum","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":2}]},"filePathRelative":"zh-cn/api/public/com/highcapable/yukihookapi/hook/core/api/compat/type/ExecutorType.md"}');export{e as data}; diff --git a/assets/FieldFinder.html-C9KHPG3N.js b/assets/FieldFinder.html-C9KHPG3N.js new file mode 100644 index 00000000..14cf72e9 --- /dev/null +++ b/assets/FieldFinder.html-C9KHPG3N.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-22449c48","path":"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/members/FieldFinder.html","title":"FieldFinder - class","lang":"zh-CN","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"name - field","slug":"name-field","link":"#name-field","children":[]},{"level":2,"title":"type - field","slug":"type-field","link":"#type-field","children":[]},{"level":2,"title":"modifiers - method","slug":"modifiers-method","link":"#modifiers-method","children":[]},{"level":2,"title":"order - method","slug":"order-method","link":"#order-method","children":[]},{"level":2,"title":"name - method","slug":"name-method","link":"#name-method","children":[]},{"level":2,"title":"name - method","slug":"name-method-1","link":"#name-method-1","children":[]},{"level":2,"title":"type - method","slug":"type-method","link":"#type-method","children":[]},{"level":2,"title":"type - method","slug":"type-method-1","link":"#type-method-1","children":[]},{"level":2,"title":"superClass - method","slug":"superclass-method","link":"#superclass-method","children":[]},{"level":2,"title":"RemedyPlan - class","slug":"remedyplan-class","link":"#remedyplan-class","children":[{"level":3,"title":"field - method","slug":"field-method","link":"#field-method","children":[]},{"level":3,"title":"Result - class","slug":"result-class","link":"#result-class","children":[]}]},{"level":2,"title":"Result - class","slug":"result-class-1","link":"#result-class-1","children":[{"level":3,"title":"result - method","slug":"result-method","link":"#result-method","children":[]},{"level":3,"title":"get - method","slug":"get-method","link":"#get-method","children":[]},{"level":3,"title":"all - method","slug":"all-method","link":"#all-method","children":[]},{"level":3,"title":"give - method","slug":"give-method","link":"#give-method","children":[]},{"level":3,"title":"giveAll - method","slug":"giveall-method","link":"#giveall-method","children":[]},{"level":3,"title":"wait - method","slug":"wait-method","link":"#wait-method","children":[]},{"level":3,"title":"waitAll - method","slug":"waitall-method","link":"#waitall-method","children":[]},{"level":3,"title":"remedys - method","slug":"remedys-method","link":"#remedys-method","children":[]},{"level":3,"title":"onNoSuchField - method","slug":"onnosuchfield-method","link":"#onnosuchfield-method","children":[]},{"level":3,"title":"ignored - method","slug":"ignored-method","link":"#ignored-method","children":[]},{"level":3,"title":"Instance - class","slug":"instance-class","link":"#instance-class","children":[]}]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":10}]},"filePathRelative":"zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/members/FieldFinder.md"}');export{e as data}; diff --git a/assets/FieldFinder.html-Cj74NK2V.js b/assets/FieldFinder.html-Cj74NK2V.js new file mode 100644 index 00000000..e4409fcc --- /dev/null +++ b/assets/FieldFinder.html-Cj74NK2V.js @@ -0,0 +1,84 @@ +import{_ as s,o as e,c as o,a as n}from"./app-BpUB8-Q8.js";const a={},l=n(`BugXposed (应用转生)。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
class FieldFinder internal constructor(override val classSet: Class<*>?) : MemberBaseFinder
+
Change Records
v1.0
first
v1.0.2
modified
合并到 BaseFinder
v1.1.0
modified
合并到 MemberBaseFinder
v1.1.8
modified
移动 hookInstance
参数到 MemberBaseFinder.MemberHookerManager
Function Illustrate
Field
查找类。
可通过指定类型查找指定 Field
或一组 Field
。
Change Records
v1.0
first
v1.0.2
移除
var name: String
+
Change Records
v1.0
first
v1.0.70
modified
允许不填写名称
Function Illustrate
设置
Field
名称。
Pay Attention
若不填写名称则必须存在一个其它条件。
var type: Any?
+
Change Records
v1.0
first
Function Illustrate
设置
Field
类型。
可不填写类型。
fun modifiers(conditions: ModifierConditions): IndexTypeCondition
+
Change Records
v1.0.67
added
v1.0.80
modified
将方法体进行 inline
v1.1.0
modified
合并到 ModifierConditions
Function Illustrate
设置
Field
标识符筛选条件。
可不设置筛选条件。
Pay Attention
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun order(): IndexTypeCondition
+
Change Records
v1.0.70
added
Function Illustrate
顺序筛选字节码的下标。
fun name(value: String): IndexTypeCondition
+
Change Records
v1.0.70
added
Function Illustrate
设置
Field
名称。
Pay Attention
若不填写名称则必须存在一个其它条件。
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun name(conditions: NameConditions): IndexTypeCondition
+
Change Records
v1.0.88
added
v1.1.0
modified
合并到 NameConditions
Function Illustrate
设置
Field
名称条件。
Pay Attention
若不填写名称则必须存在一个其它条件。
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun type(value: Any): IndexTypeCondition
+
Change Records
v1.0.70
added
Function Illustrate
设置
Field
类型。
可不填写类型。
Pay Attention
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun type(conditions: ObjectConditions): IndexTypeCondition
+
Change Records
v1.1.5
added
Function Illustrate
设置
Field
类型条件。
可不填写类型。
Pay Attention
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun superClass(isOnlySuperClass: Boolean)
+
Change Records
v1.0.80
added
Function Illustrate
设置在
classSet
的所有父类中查找当前Field
。
Notice
若当前 classSet 的父类较多可能会耗时,API 会自动循环到父类继承是 Any 前的最后一个类。
inner class RemedyPlan internal constructor()
+
Change Records
v1.1.0
added
Function Illustrate
Field
重查找实现类,可累计失败次数直到查找成功。
inline fun field(initiate: FieldConditions): Result
+
Change Records
v1.1.0
added
Function Illustrate
创建需要重新查找的
Field
。
你可以添加多个备选 Field
,直到成功为止,若最后依然失败,将停止查找并输出错误日志。
inner class Result internal constructor()
+
Change Records
v1.1.0
added
Function Illustrate
RemedyPlan
结果实现类。
fun onFind(initiate: MutableList<Field>.() -> Unit)
+
Change Records
v1.1.0
added
v1.2.0
modified
initiate
类型由 HashSet
修改为 MutableList
Function Illustrate
当在
RemedyPlan
中找到结果时。
功能示例
你可以方便地对重查找的 Field
实现 onFind
方法。
示例如下
field {
+ // Your code here.
+}.onFind {
+ // Your code here.
+}
+
inner class Result internal constructor(internal val isNoSuch: Boolean, internal val throwable: Throwable?) : BaseResult
+
Change Records
v1.0
first
v1.1.0
modified
继承到接口 BaseResult
Function Illustrate
Field
查找结果实现类。
inline fun result(initiate: Result.() -> Unit): Result
+
Change Records
v1.0
first
v1.0.80
modified
将方法体进行 inline
Function Illustrate
创建监听结果事件方法体。
功能示例
你可以使用 lambda 形式创建 Result
类。
示例如下
field {
+ // Your code here.
+}.result {
+ get(instance).set("something")
+ get(instance).string()
+ get(instance).cast<CustomClass>()
+ get().boolean()
+ all(instance)
+ give()
+ giveAll()
+ onNoSuchField {}
+}
+
fun get(instance: Any?): Instance
+
Change Records
v1.0
first
Function Illustrate
获得
Field
实例处理类。
若有多个 Field
结果只会返回第一个。
功能示例
你可以轻松地得到 Field
的实例以及使用它进行设置实例。
示例如下
field {
+ // Your code here.
+}.get(instance).set("something")
+
如果你取到的是静态 Field
,可以不需要设置实例。
示例如下
field {
+ // Your code here.
+}.get().set("something")
+
fun all(instance: Any?): MutableList<Instance>
+
Change Records
v1.1.0
added
v1.2.0
modified
返回值类型由 ArrayList
修改为 MutableList
Function Illustrate
获得
Field
实例处理类数组。
返回全部查找条件匹配的多个 Field
实例结果。
功能示例
你可以通过此方法来获得当前条件结果中匹配的全部 Field
,其 Field
所在实例用法与 get
相同。
示例如下
field {
+ // Your code here.
+}.all(instance).forEach { instance ->
+ instance.self
+}
+
fun give(): Field?
+
Change Records
v1.0
first
Function Illustrate
得到
Field
本身。
若有多个 Field 结果只会返回第一个。
在查找条件找不到任何结果的时候将返回 null
。
fun giveAll(): MutableList<Field>
+
Change Records
v1.1.0
added
v1.2.0
modified
返回值类型由 HashSet
修改为 MutableList
Function Illustrate
得到
Field
本身数组。
返回全部查找条件匹配的多个 Field
实例。
在查找条件找不到任何结果的时候将返回空的 MutableList
。
fun wait(instance: Any?, initiate: Instance.() -> Unit)
+
Change Records
v1.1.0
added
Function Illustrate
获得
Field
实例处理类,配合RemedyPlan
使用。
若有多个 Field
结果只会返回第一个。
Pay Attention
若你设置了 remedys 必须使用此方法才能获得结果。
若你没有设置 remedys 此方法将不会被回调。
fun waitAll(instance: Any?, initiate: MutableList<Instance>.() -> Unit)
+
Change Records
v1.1.0
added
v1.2.0
modified
initiate
类型由 ArrayList
修改为 MutableList
Function Illustrate
获得
Field
实例处理类数组,配合RemedyPlan
使用。
返回全部查找条件匹配的多个 Field
实例结果。
Pay Attention
若你设置了 remedys 必须使用此方法才能获得结果。
若你没有设置 remedys 此方法将不会被回调。
inline fun remedys(initiate: RemedyPlan.() -> Unit): Result
+
Change Records
v1.1.0
added
Function Illustrate
创建
Field
重查找功能。
功能示例
当你遇到一种 Field
可能存在不同形式的存在时,可以使用 RemedyPlan
重新查找它,而没有必要使用 onNoSuchField
捕获异常二次查找 Field
。
若第一次查找失败了,你还可以在这里继续添加此方法体直到成功为止。
示例如下
field {
+ // Your code here.
+}.remedys {
+ field {
+ // Your code here.
+ }
+ field {
+ // Your code here.
+ }
+}
+
fun onNoSuchField(result: (Throwable) -> Unit): Result
+
Change Records
v1.0
first
Function Illustrate
监听找不到
Field
时。
fun ignored(): Result
+
Change Records
v1.1.0
added
Function Illustrate
忽略异常并停止打印任何错误日志。
若 MemberBaseFinder.MemberHookerManager.isNotIgnoredNoSuchMemberFailure
为 false
则自动忽略。
Notice
此时若要监听异常结果,你需要手动实现 onNoSuchField 方法。
Change Records
v1.0.3
added
v1.1.0
deprecated
请迁移到新方法 ignored()
inner class Instance internal constructor(private val instance: Any?, private val field: Field?)
+
Change Records
v1.0
first
v1.1.0
modified
新增 field
参数
不再对外公开 self
参数
Function Illustrate
Field
实例变量处理类。
Change Records
v1.0
first
v1.1.0
移除
请直接使用 any
方法得到 Field
自身的实例化对象
fun current(ignored: Boolean): CurrentClass?
+
inline fun current(ignored: Boolean, initiate: CurrentClass.() -> Unit): Any?
+
Change Records
v1.1.0
added
Function Illustrate
获得当前
Field
自身self
实例的类操作对象CurrentClass
。
fun <T> cast(): T?
+
Change Records
v1.0
first
v1.0.68
modified
修改 为 of
cast
移动方法到 Instance
Function Illustrate
得到当前
Field
实例。
fun byte(): Byte?
+
Change Records
v1.0.68
added
Function Illustrate
得到当前
Field
Byte 实例。
fun int(): Int
+
Change Records
v1.0.65
added
v1.0.68
modified
修改 为 ofInt
int
移动方法到 Instance
Function Illustrate
得到当前
Field
Int 实例。
fun long(): Long
+
Change Records
v1.0.65
added
v1.0.68
modified
修改 为 ofLong
long
移动方法到 Instance
Function Illustrate
得到当前
Field
Long 实例。
fun short(): Short
+
Change Records
v1.0.65
added
v1.0.68
modified
修改 为 ofShort
short
移动方法到 Instance
Function Illustrate
得到当前
Field
Short 实例。
fun double(): Double
+
Change Records
v1.0.65
added
v1.0.68
modified
修改 为 ofDouble
double
移动方法到 Instance
Function Illustrate
得到当前
Field
Double 实例。
fun float(): Float
+
Change Records
v1.0.65
added
v1.0.68
modified
修改 为 ofFloat
float
移动方法到 Instance
Function Illustrate
得到当前
Field
Float 实例。
fun string(): String
+
Change Records
v1.0.65
added
v1.0.68
modified
修改 为 ofString
string
移动方法到 Instance
Function Illustrate
得到当前
Field
String 实例。
fun char(): Char
+
Change Records
v1.0.68
added
Function Illustrate
得到当前
Field
Char 实例。
fun boolean(): Boolean
+
Change Records
v1.0.65
added
v1.0.68
modified
修改 为 ofBoolean
boolean
移动方法到 Instance
Function Illustrate
得到当前
Field
Boolean 实例。
fun any(): Any?
+
Change Records
v1.0.65
added
v1.0.68
modified
修改 为 ofAny
any
移动方法到 Instance
Function Illustrate
得到当前
Field
Any 实例。
inline fun <reified T> array(): Array<T>
+
Change Records
v1.0.68
added
Function Illustrate
得到当前
Field
Array 实例。
inline fun <reified T> list(): List<T>
+
Change Records
v1.0.68
added
Function Illustrate
得到当前
Field
List 实例。
fun set(any: Any?)
+
Change Records
v1.0
first
Function Illustrate
设置当前
Field
实例。
fun setTrue()
+
Change Records
v1.0
first
Function Illustrate
设置当前
Field
实例为true
。
Pay Attention
请确保实例对象类型为 Boolean。
fun setFalse()
+
Change Records
v1.0
first
Function Illustrate
设置当前
Field
实例为false
。
Pay Attention
请确保实例对象类型为 Boolean。
fun setNull()
+
Change Records
v1.0
first
Function Illustrate
`,388),p=[l];function c(t,d){return e(),o("div",null,p)}const i=s(a,[["render",c],["__file","FieldFinder.html.vue"]]);export{i as default}; diff --git a/assets/FieldFinder.html-CoQdzzYH.js b/assets/FieldFinder.html-CoQdzzYH.js new file mode 100644 index 00000000..9e824e0d --- /dev/null +++ b/assets/FieldFinder.html-CoQdzzYH.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-42e0f0ab","path":"/en/api/public/com/highcapable/yukihookapi/hook/core/finder/members/FieldFinder.html","title":"FieldFinder - class","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"name - field","slug":"name-field","link":"#name-field","children":[]},{"level":2,"title":"type - field","slug":"type-field","link":"#type-field","children":[]},{"level":2,"title":"modifiers - method","slug":"modifiers-method","link":"#modifiers-method","children":[]},{"level":2,"title":"order - method","slug":"order-method","link":"#order-method","children":[]},{"level":2,"title":"name - method","slug":"name-method","link":"#name-method","children":[]},{"level":2,"title":"name - method","slug":"name-method-1","link":"#name-method-1","children":[]},{"level":2,"title":"type - method","slug":"type-method","link":"#type-method","children":[]},{"level":2,"title":"type - method","slug":"type-method-1","link":"#type-method-1","children":[]},{"level":2,"title":"superClass - method","slug":"superclass-method","link":"#superclass-method","children":[]},{"level":2,"title":"RemedyPlan - class","slug":"remedyplan-class","link":"#remedyplan-class","children":[{"level":3,"title":"field - method","slug":"field-method","link":"#field-method","children":[]},{"level":3,"title":"Result - class","slug":"result-class","link":"#result-class","children":[]}]},{"level":2,"title":"Result - class","slug":"result-class-1","link":"#result-class-1","children":[{"level":3,"title":"result - method","slug":"result-method","link":"#result-method","children":[]},{"level":3,"title":"get - method","slug":"get-method","link":"#get-method","children":[]},{"level":3,"title":"all - method","slug":"all-method","link":"#all-method","children":[]},{"level":3,"title":"give - method","slug":"give-method","link":"#give-method","children":[]},{"level":3,"title":"giveAll - method","slug":"giveall-method","link":"#giveall-method","children":[]},{"level":3,"title":"wait - method","slug":"wait-method","link":"#wait-method","children":[]},{"level":3,"title":"waitAll - method","slug":"waitall-method","link":"#waitall-method","children":[]},{"level":3,"title":"remedys - method","slug":"remedys-method","link":"#remedys-method","children":[]},{"level":3,"title":"onNoSuchField - method","slug":"onnosuchfield-method","link":"#onnosuchfield-method","children":[]},{"level":3,"title":"ignored - method","slug":"ignored-method","link":"#ignored-method","children":[]},{"level":3,"title":"Instance - class","slug":"instance-class","link":"#instance-class","children":[]}]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":9}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/core/finder/members/FieldFinder.md"}');export{e as data}; diff --git a/assets/FieldFinder.html-Di6mgVKf.js b/assets/FieldFinder.html-Di6mgVKf.js new file mode 100644 index 00000000..0da67c99 --- /dev/null +++ b/assets/FieldFinder.html-Di6mgVKf.js @@ -0,0 +1,84 @@ +import{_ as s,o as e,c as o,a}from"./app-BpUB8-Q8.js";const n={},l=a(`设置当前
Field
实例为null
。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
class FieldFinder internal constructor(override val classSet: Class<*>?) : MemberBaseFinder
+
变更记录
v1.0
添加
v1.0.2
修改
合并到 BaseFinder
v1.1.0
修改
合并到 MemberBaseFinder
v1.1.8
修改
移动 hookInstance
参数到 MemberBaseFinder.MemberHookerManager
功能描述
Field
查找类。
可通过指定类型查找指定 Field
或一组 Field
。
变更记录
v1.0
添加
v1.0.2
移除
var name: String
+
变更记录
v1.0
添加
v1.0.70
修改
允许不填写名称
功能描述
设置
Field
名称。
特别注意
若不填写名称则必须存在一个其它条件。
var type: Any?
+
变更记录
v1.0
添加
功能描述
设置
Field
类型。
可不填写类型。
fun modifiers(conditions: ModifierConditions): IndexTypeCondition
+
变更记录
v1.0.67
新增
v1.0.80
修改
将方法体进行 inline
v1.1.0
修改
合并到 ModifierConditions
功能描述
设置
Field
标识符筛选条件。
可不设置筛选条件。
特别注意
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun order(): IndexTypeCondition
+
变更记录
v1.0.70
新增
功能描述
顺序筛选字节码的下标。
fun name(value: String): IndexTypeCondition
+
变更记录
v1.0.70
新增
功能描述
设置
Field
名称。
特别注意
若不填写名称则必须存在一个其它条件。
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun name(conditions: NameConditions): IndexTypeCondition
+
变更记录
v1.0.88
新增
v1.1.0
修改
合并到 NameConditions
功能描述
设置
Field
名称条件。
特别注意
若不填写名称则必须存在一个其它条件。
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun type(value: Any): IndexTypeCondition
+
变更记录
v1.0.70
新增
功能描述
设置
Field
类型。
可不填写类型。
特别注意
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun type(conditions: ObjectConditions): IndexTypeCondition
+
变更记录
v1.1.5
新增
功能描述
设置
Field
类型条件。
可不填写类型。
特别注意
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun superClass(isOnlySuperClass: Boolean)
+
变更记录
v1.0.80
新增
功能描述
设置在
classSet
的所有父类中查找当前Field
。
注意
若当前 classSet 的父类较多可能会耗时,API 会自动循环到父类继承是 Any 前的最后一个类。
inner class RemedyPlan internal constructor()
+
变更记录
v1.1.0
新增
功能描述
Field
重查找实现类,可累计失败次数直到查找成功。
inline fun field(initiate: FieldConditions): Result
+
变更记录
v1.1.0
新增
功能描述
创建需要重新查找的
Field
。
你可以添加多个备选 Field
,直到成功为止,若最后依然失败,将停止查找并输出错误日志。
inner class Result internal constructor()
+
变更记录
v1.1.0
新增
功能描述
RemedyPlan
结果实现类。
fun onFind(initiate: MutableList<Field>.() -> Unit)
+
变更记录
v1.1.0
新增
v1.2.0
修改
initiate
类型由 HashSet
修改为 MutableList
功能描述
当在
RemedyPlan
中找到结果时。
功能示例
你可以方便地对重查找的 Field
实现 onFind
方法。
示例如下
field {
+ // Your code here.
+}.onFind {
+ // Your code here.
+}
+
inner class Result internal constructor(internal val isNoSuch: Boolean, internal val throwable: Throwable?) : BaseResult
+
变更记录
v1.0
添加
v1.1.0
修改
继承到接口 BaseResult
功能描述
Field
查找结果实现类。
inline fun result(initiate: Result.() -> Unit): Result
+
变更记录
v1.0
添加
v1.0.80
修改
将方法体进行 inline
功能描述
创建监听结果事件方法体。
功能示例
你可以使用 lambda 形式创建 Result
类。
示例如下
field {
+ // Your code here.
+}.result {
+ get(instance).set("something")
+ get(instance).string()
+ get(instance).cast<CustomClass>()
+ get().boolean()
+ all(instance)
+ give()
+ giveAll()
+ onNoSuchField {}
+}
+
fun get(instance: Any?): Instance
+
变更记录
v1.0
添加
功能描述
获得
Field
实例处理类。
若有多个 Field
结果只会返回第一个。
功能示例
你可以轻松地得到 Field
的实例以及使用它进行设置实例。
示例如下
field {
+ // Your code here.
+}.get(instance).set("something")
+
如果你取到的是静态 Field
,可以不需要设置实例。
示例如下
field {
+ // Your code here.
+}.get().set("something")
+
fun all(instance: Any?): MutableList<Instance>
+
变更记录
v1.1.0
新增
v1.2.0
修改
返回值类型由 ArrayList
修改为 MutableList
功能描述
获得
Field
实例处理类数组。
返回全部查找条件匹配的多个 Field
实例结果。
功能示例
你可以通过此方法来获得当前条件结果中匹配的全部 Field
,其 Field
所在实例用法与 get
相同。
示例如下
field {
+ // Your code here.
+}.all(instance).forEach { instance ->
+ instance.self
+}
+
fun give(): Field?
+
变更记录
v1.0
添加
功能描述
得到
Field
本身。
若有多个 Field 结果只会返回第一个。
在查找条件找不到任何结果的时候将返回 null
。
fun giveAll(): MutableList<Field>
+
变更记录
v1.1.0
新增
v1.2.0
修改
返回值类型由 HashSet
修改为 MutableList
功能描述
得到
Field
本身数组。
返回全部查找条件匹配的多个 Field
实例。
在查找条件找不到任何结果的时候将返回空的 MutableList
。
fun wait(instance: Any?, initiate: Instance.() -> Unit)
+
变更记录
v1.1.0
新增
功能描述
获得
Field
实例处理类,配合RemedyPlan
使用。
若有多个 Field
结果只会返回第一个。
特别注意
若你设置了 remedys 必须使用此方法才能获得结果。
若你没有设置 remedys 此方法将不会被回调。
fun waitAll(instance: Any?, initiate: MutableList<Instance>.() -> Unit)
+
变更记录
v1.1.0
新增
v1.2.0
修改
initiate
类型由 ArrayList
修改为 MutableList
功能描述
获得
Field
实例处理类数组,配合RemedyPlan
使用。
返回全部查找条件匹配的多个 Field
实例结果。
特别注意
若你设置了 remedys 必须使用此方法才能获得结果。
若你没有设置 remedys 此方法将不会被回调。
inline fun remedys(initiate: RemedyPlan.() -> Unit): Result
+
变更记录
v1.1.0
新增
功能描述
创建
Field
重查找功能。
功能示例
当你遇到一种 Field
可能存在不同形式的存在时,可以使用 RemedyPlan
重新查找它,而没有必要使用 onNoSuchField
捕获异常二次查找 Field
。
若第一次查找失败了,你还可以在这里继续添加此方法体直到成功为止。
示例如下
field {
+ // Your code here.
+}.remedys {
+ field {
+ // Your code here.
+ }
+ field {
+ // Your code here.
+ }
+}
+
fun onNoSuchField(result: (Throwable) -> Unit): Result
+
变更记录
v1.0
添加
功能描述
监听找不到
Field
时。
fun ignored(): Result
+
变更记录
v1.1.0
新增
功能描述
忽略异常并停止打印任何错误日志。
若 MemberBaseFinder.MemberHookerManager.isNotIgnoredNoSuchMemberFailure
为 false
则自动忽略。
注意
此时若要监听异常结果,你需要手动实现 onNoSuchField 方法。
变更记录
v1.0.3
新增
v1.1.0
作废
请迁移到新方法 ignored()
inner class Instance internal constructor(private val instance: Any?, private val field: Field?)
+
变更记录
v1.0
添加
v1.1.0
修改
新增 field
参数
不再对外公开 self
参数
功能描述
Field
实例变量处理类。
变更记录
v1.0
添加
v1.1.0
移除
请直接使用 any
方法得到 Field
自身的实例化对象
fun current(ignored: Boolean): CurrentClass?
+
inline fun current(ignored: Boolean, initiate: CurrentClass.() -> Unit): Any?
+
变更记录
v1.1.0
新增
功能描述
获得当前
Field
自身self
实例的类操作对象CurrentClass
。
fun <T> cast(): T?
+
变更记录
v1.0
添加
v1.0.68
修改
修改 为 of
cast
移动方法到 Instance
功能描述
得到当前
Field
实例。
fun byte(): Byte?
+
变更记录
v1.0.68
新增
功能描述
得到当前
Field
Byte 实例。
fun int(): Int
+
变更记录
v1.0.65
新增
v1.0.68
修改
修改 为 ofInt
int
移动方法到 Instance
功能描述
得到当前
Field
Int 实例。
fun long(): Long
+
变更记录
v1.0.65
新增
v1.0.68
修改
修改 为 ofLong
long
移动方法到 Instance
功能描述
得到当前
Field
Long 实例。
fun short(): Short
+
变更记录
v1.0.65
新增
v1.0.68
修改
修改 为 ofShort
short
移动方法到 Instance
功能描述
得到当前
Field
Short 实例。
fun double(): Double
+
变更记录
v1.0.65
新增
v1.0.68
修改
修改 为 ofDouble
double
移动方法到 Instance
功能描述
得到当前
Field
Double 实例。
fun float(): Float
+
变更记录
v1.0.65
新增
v1.0.68
修改
修改 为 ofFloat
float
移动方法到 Instance
功能描述
得到当前
Field
Float 实例。
fun string(): String
+
变更记录
v1.0.65
新增
v1.0.68
修改
修改 为 ofString
string
移动方法到 Instance
功能描述
得到当前
Field
String 实例。
fun char(): Char
+
变更记录
v1.0.68
新增
功能描述
得到当前
Field
Char 实例。
fun boolean(): Boolean
+
变更记录
v1.0.65
新增
v1.0.68
修改
修改 为 ofBoolean
boolean
移动方法到 Instance
功能描述
得到当前
Field
Boolean 实例。
fun any(): Any?
+
变更记录
v1.0.65
新增
v1.0.68
修改
修改 为 ofAny
any
移动方法到 Instance
功能描述
得到当前
Field
Any 实例。
inline fun <reified T> array(): Array<T>
+
变更记录
v1.0.68
新增
功能描述
得到当前
Field
Array 实例。
inline fun <reified T> list(): List<T>
+
变更记录
v1.0.68
新增
功能描述
得到当前
Field
List 实例。
fun set(any: Any?)
+
变更记录
v1.0
添加
功能描述
设置当前
Field
实例。
fun setTrue()
+
变更记录
v1.0
添加
功能描述
设置当前
Field
实例为true
。
特别注意
请确保实例对象类型为 Boolean。
fun setFalse()
+
变更记录
v1.0
添加
功能描述
设置当前
Field
实例为false
。
特别注意
请确保实例对象类型为 Boolean。
fun setNull()
+
变更记录
v1.0
添加
功能描述
`,387),p=[l];function c(t,d){return e(),o("div",null,p)}const i=s(n,[["render",c],["__file","FieldFinder.html.vue"]]);export{i as default}; diff --git a/assets/FieldRules.html-D50kuywF.js b/assets/FieldRules.html-D50kuywF.js new file mode 100644 index 00000000..84502a68 --- /dev/null +++ b/assets/FieldRules.html-D50kuywF.js @@ -0,0 +1,7 @@ +import{_ as s,o as e,c as a,a as o}from"./app-BpUB8-Q8.js";const n={},l=o(`设置当前
Field
实例为null
。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
class FieldRules internal constructor(private val rulesData: FieldRulesData) : BaseRules
+
变更记录
v1.1.0
新增
功能描述
Field
查找条件实现类。
var name: String
+
变更记录
v1.1.0
新增
功能描述
设置
Field
名称。
var type: Any?
+
变更记录
v1.1.0
新增
功能描述
设置
Field
类型。
可不填写类型。
fun modifiers(conditions: ModifierConditions)
+
变更记录
v1.1.0
新增
功能描述
设置
Field
标识符筛选条件。
可不设置筛选条件。
fun name(conditions: NameConditions)
+
变更记录
v1.1.0
新增
功能描述
设置
Field
名称条件。
fun type(conditions: ObjectConditions)
+
变更记录
v1.1.5
新增
功能描述
设置
Field
类型条件。
可不填写类型。
`,40),p=[l];function c(t,d){return e(),a("div",null,p)}const i=s(n,[["render",c],["__file","FieldRules.html.vue"]]);export{i as default}; diff --git a/assets/FieldRules.html-DePoZYvp.js b/assets/FieldRules.html-DePoZYvp.js new file mode 100644 index 00000000..3a02dbe0 --- /dev/null +++ b/assets/FieldRules.html-DePoZYvp.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-3e67a42e","path":"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/FieldRules.html","title":"FieldRules - class","lang":"zh-CN","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"name - field","slug":"name-field","link":"#name-field","children":[]},{"level":2,"title":"type - field","slug":"type-field","link":"#type-field","children":[]},{"level":2,"title":"modifiers - method","slug":"modifiers-method","link":"#modifiers-method","children":[]},{"level":2,"title":"name - method","slug":"name-method","link":"#name-method","children":[]},{"level":2,"title":"type - method","slug":"type-method","link":"#type-method","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":5}]},"filePathRelative":"zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/FieldRules.md"}');export{e as data}; diff --git a/assets/FieldRules.html-DnAEAxmC.js b/assets/FieldRules.html-DnAEAxmC.js new file mode 100644 index 00000000..898b149b --- /dev/null +++ b/assets/FieldRules.html-DnAEAxmC.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-21f64ebf","path":"/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/FieldRules.html","title":"FieldRules - class","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"name - field","slug":"name-field","link":"#name-field","children":[]},{"level":2,"title":"type - field","slug":"type-field","link":"#type-field","children":[]},{"level":2,"title":"modifiers - method","slug":"modifiers-method","link":"#modifiers-method","children":[]},{"level":2,"title":"name - method","slug":"name-method","link":"#name-method","children":[]},{"level":2,"title":"type - method","slug":"type-method","link":"#type-method","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":4}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/FieldRules.md"}');export{e as data}; diff --git a/assets/FieldRules.html-DzJvDeKO.js b/assets/FieldRules.html-DzJvDeKO.js new file mode 100644 index 00000000..174cd694 --- /dev/null +++ b/assets/FieldRules.html-DzJvDeKO.js @@ -0,0 +1,7 @@ +import{_ as s,o as e,c as a,a as o}from"./app-BpUB8-Q8.js";const n={},t=o(`Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
class FieldRules internal constructor(private val rulesData: FieldRulesData) : BaseRules
+
Change Records
v1.1.0
added
Function Illustrate
Field
查找条件实现类。
var name: String
+
Change Records
v1.1.0
added
Function Illustrate
设置
Field
名称。
var type: Any?
+
Change Records
v1.1.0
added
Function Illustrate
设置
Field
类型。
可不填写类型。
fun modifiers(conditions: ModifierConditions)
+
Change Records
v1.1.0
added
Function Illustrate
设置
Field
标识符筛选条件。
可不设置筛选条件。
fun name(conditions: NameConditions)
+
Change Records
v1.1.0
added
Function Illustrate
设置
Field
名称条件。
fun type(conditions: ObjectConditions)
+
Change Records
v1.1.5
added
Function Illustrate
设置
Field
类型条件。
可不填写类型。
`,41),l=[t];function c(d,p){return e(),a("div",null,l)}const i=s(n,[["render",c],["__file","FieldRules.html.vue"]]);export{i as default}; diff --git a/assets/GenericClass.html-8gR9C4nD.js b/assets/GenericClass.html-8gR9C4nD.js new file mode 100644 index 00000000..9f36ea62 --- /dev/null +++ b/assets/GenericClass.html-8gR9C4nD.js @@ -0,0 +1,4 @@ +import{_ as s,o as e,c as a,a as n}from"./app-BpUB8-Q8.js";const o={},t=n(`Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
class GenericClass internal constructor(private val type: ParameterizedType)
+
Change Records
v1.1.0
added
Function Illustrate
当前
Class
的泛型父类操作对象。
fun argument(index: Int): Class<*>?
+
inline fun <reified T> argument(index: Int): Class<T>?
+
Change Records
v1.1.0
added
v1.1.5
modified
新增泛型返回值 Class<T>
方法
v1.2.0
modified
方法的返回值可为 null
Function Illustrate
获得泛型参数数组下标的
Class
实例。
Notice
在运行时局部变量的泛型会被擦除,获取不到时将会返回 null。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
class GenericClass internal constructor(private val type: ParameterizedType)
+
变更记录
v1.1.0
新增
功能描述
当前
Class
的泛型父类操作对象。
fun argument(index: Int): Class<*>?
+
inline fun <reified T> argument(index: Int): Class<T>?
+
变更记录
v1.1.0
新增
v1.1.5
修改
新增泛型返回值 Class<T>
方法
v1.2.0
修改
方法的返回值可为 null
功能描述
获得泛型参数数组下标的
Class
实例。
注意
在运行时局部变量的泛型会被擦除,获取不到时将会返回 null。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
Change Records
v1.0
first
Function Illustrate
',7),l={href:"https://github.com/HighCapable/YukiHookAPI/blob/master/yukihookapi-core/src/main/java/com/highcapable/yukihookapi/hook/type/android/GraphicsTypeFactory.kt",target:"_blank",rel:"noopener noreferrer"};function h(u,m){const t=c("ExternalLinkIcon");return n(),r("div",null,[d,o("p",null,[e("详情可 "),o("a",l,[e("点击这里"),s(t)]),e(" 进行查看。")])])}const k=a(p,[["render",h],["__file","GraphicsTypeFactory.html.vue"]]);export{k as default}; diff --git a/assets/GraphicsTypeFactory.html-CnqF4An8.js b/assets/GraphicsTypeFactory.html-CnqF4An8.js new file mode 100644 index 00000000..a02b0d77 --- /dev/null +++ b/assets/GraphicsTypeFactory.html-CnqF4An8.js @@ -0,0 +1 @@ +const a=JSON.parse('{"key":"v-7b0abf86","path":"/en/api/public/com/highcapable/yukihookapi/hook/type/android/GraphicsTypeFactory.html","title":"GraphicsTypeFactory - kt","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":6}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/type/android/GraphicsTypeFactory.md"}');export{a as data}; diff --git a/assets/GraphicsTypeFactory.html-Dq_zQQPa.js b/assets/GraphicsTypeFactory.html-Dq_zQQPa.js new file mode 100644 index 00000000..19a44573 --- /dev/null +++ b/assets/GraphicsTypeFactory.html-Dq_zQQPa.js @@ -0,0 +1 @@ +const a=JSON.parse('{"key":"v-4ea62475","path":"/zh-cn/api/public/com/highcapable/yukihookapi/hook/type/android/GraphicsTypeFactory.html","title":"GraphicsTypeFactory - kt","lang":"zh-CN","frontmatter":{"pageClass":"code-page"},"headers":[],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":6}]},"filePathRelative":"zh-cn/api/public/com/highcapable/yukihookapi/hook/type/android/GraphicsTypeFactory.md"}');export{a as data}; diff --git a/assets/GraphicsTypeFactory.html-pywoj7PR.js b/assets/GraphicsTypeFactory.html-pywoj7PR.js new file mode 100644 index 00000000..40356a1f --- /dev/null +++ b/assets/GraphicsTypeFactory.html-pywoj7PR.js @@ -0,0 +1 @@ +import{_ as a,r as t,o as r,c as s,b as o,d as e,e as n,a as p}from"./app-BpUB8-Q8.js";const i={},d=p('这是一个预置反射类型的常量类,主要为
Android
相关Graphics
的Class
内容,跟随版本更新会逐一进行增加。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
变更记录
v1.0
添加
功能描述
',6),l={href:"https://github.com/HighCapable/YukiHookAPI/blob/master/yukihookapi-core/src/main/java/com/highcapable/yukihookapi/hook/type/android/GraphicsTypeFactory.kt",target:"_blank",rel:"noopener noreferrer"};function h(k,_){const c=t("ExternalLinkIcon");return r(),s("div",null,[d,o("p",null,[e("详情可 "),o("a",l,[e("点击这里"),n(c)]),e(" 进行查看。")])])}const y=a(i,[["render",h],["__file","GraphicsTypeFactory.html.vue"]]);export{y as default}; diff --git a/assets/HookClass.html-CIc4FkOC.js b/assets/HookClass.html-CIc4FkOC.js new file mode 100644 index 00000000..97bf22fd --- /dev/null +++ b/assets/HookClass.html-CIc4FkOC.js @@ -0,0 +1,2 @@ +import{_ as s,o,c as a,a as e}from"./app-BpUB8-Q8.js";const n={},t=e(`这是一个预置反射类型的常量类,主要为
Android
相关Graphics
的Class
内容,跟随版本更新会逐一进行增加。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
class HookClass internal constructor(internal var instance: Class<*>?, internal var name: String, internal var throwable: Throwable?)
+
Change Records
v1.0
first
v1.1.0
modified
HookClass
相关功能不再对外开放
Function Illustrate
创建一个当前 Hook 的
Class
接管类。
instance
为实例,name
为实例完整包名,throwable
为找不到实例的时候抛出的异常。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
class HookClass internal constructor(internal var instance: Class<*>?, internal var name: String, internal var throwable: Throwable?)
+
变更记录
v1.0
添加
v1.1.0
修改
HookClass
相关功能不再对外开放
功能描述
创建一个当前 Hook 的
Class
接管类。
instance
为实例,name
为实例完整包名,throwable
为找不到实例的时候抛出的异常。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
class HookParam private constructor(
+ private val creatorInstance: YukiMemberHookCreator,
+ private var paramId: String,
+ private var param: YukiHookCallback.Param?
+)
+
变更记录
v1.0
添加
v1.1.0
修改
移动 HookParamWrapper
到 YukiHookCallback.Param
修正拼写错误的 creater 命名到 creator
v1.1.5
修改
新增 paramId
参数
v1.2.0
修改
不再开放构造方法
功能描述
Hook 方法、构造方法的目标对象实现类。
val args: Array<Any?>
+
变更记录
在 v1.0
添加
功能描述
获取当前 Hook 对象
member
或constructor
的参数对象数组。
这里的数组每项类型默认为 Any
,你可以使用 args
方法来实现 ArgsModifyer.cast
功能。
变更记录
v1.0
添加
v1.0.75
移除
请使用 args(index = 0)
或 args().first()
变更记录
v1.0
添加
v1.0.75
移除
请使用 args().last()
val instance: Any
+
变更记录
v1.0
添加
功能描述
获取当前 Hook 实例的对象。
特别注意
如果你当前 Hook 的对象是一个静态,那么它将不存在实例的对象。
如果你不确定当前实例的对象是否为 null
,你可以使用 instanceOrNull
。
val instanceOrNull: Any?
+
变更记录
v1.1.8
新增
功能描述
获取当前 Hook 实例的对象。
特别注意
如果你当前 Hook 的对象是一个静态,那么它将不存在实例的对象。
val instanceClass: Class<*>?
+
变更记录
v1.0
添加
v1.2.0
修改
加入可空类型 (空安全)
功能描述
获取当前 Hook 实例的类对象。
特别注意
如果你当前 Hook 的对象是一个静态,那么它将不存在实例的对象。
val member: Member
+
变更记录
v1.1.0
新增
功能描述
获取当前 Hook 对象的
Member
。
在不确定 Member
类型为 Method
或 Constructor
时可以使用此方法。
val method: Method
+
变更记录
v1.0
添加
功能描述
获取当前 Hook 对象的方法。
val constructor: Constructor
+
变更记录
v1.0
添加
功能描述
获取当前 Hook 对象的构造方法。
var result: Any?
+
变更记录
v1.0
添加
功能描述
获取、设置当前 Hook 对象的
method
或constructor
的返回值。
val dataExtra: Bundle
+
变更记录
v1.1.5
新增
功能描述
获取当前回调方法体范围内的数据存储实例。
val hasThrowable: Boolean
+
变更记录
v1.1.0
新增
功能描述
判断是否存在设置过的方法调用抛出异常。
val throwable: Throwable?
+
变更记录
v1.1.0
新增
功能描述
获取设置的方法调用抛出异常。
fun Throwable.throwToApp()
+
变更记录
v1.1.0
新增
功能描述
向 Hook APP 抛出异常。
使用 hasThrowable
判断当前是否存在被抛出的异常。
使用 throwable
获取当前设置的方法调用抛出异常。
仅会在回调方法的 MemberHookCreator.before
或 MemberHookCreator.after
中生效。
特别注意
设置后会同时执行 resultNull 方法并将异常抛出给当前 Hook APP。
功能示例
Hook 过程中的异常仅会作用于 (Xposed) 宿主环境,目标 Hook APP 不会受到影响。
若想将异常抛给 Hook APP,可以直接使用如下方法。
示例如下
hook {
+ before {
+ RuntimeException("Test Exception").throwToApp()
+ }
+}
+
特别注意
向 Hook APP 抛出异常会对其暴露被 Hook 的事实,是不安全的,容易被检测,请按实际场景合理使用。
inline fun <reified T> result(): T?
+
变更记录
v1.0.75
新增
功能描述
获取当前 Hook 对象的
method
或constructor
的返回值T
。
变更记录
v1.0.66
新增
v1.0.75
移除
变更记录
v1.0.66
新增
v1.0.75
移除
inline fun <reified T> instance(): T
+
变更记录
v1.0
添加
功能描述
获取当前 Hook 实例的对象
T
。
功能示例
你可以通过 instance
方法轻松使用泛型 cast
为目标对象的类型。
示例如下
instance<Activity>().finish()
+
inline fun <reified T> instanceOrNull(): T?
+
变更记录
v1.1.8
新增
功能描述
获取当前 Hook 实例的对象
T
。
功能示例
用法请参考 instance 方法。
fun args(): ArgsIndexCondition
+
变更记录
v1.0.75
新增
功能描述
获取当前 Hook 对象的
method
或constructor
的参数数组下标实例化类。
fun args(index: Int): ArgsModifyer
+
变更记录
v1.0
添加
v1.0.75
修改
默认值 index = 0
移动到新的使用方法 args().first()
功能描述
获取当前 Hook 对象的
method
或constructor
的参数实例化对象类。
功能示例
你可以通过 args
方法修改当前 Hook 实例的方法、构造方法的参数内容。
你可以直接使用 set
方法设置 param
为你的目标实例,接受 Any
类型。
特别注意
请确保 param 类型为你的目标实例类型。
示例如下
args(index = 0).set("modify the value")
+
你可以这样直接设置第一位 param
的值。
示例如下
args().first().set("modify the value")
+
你还可以直接设置最后一位 param
的值。
示例如下
args().last().set("modify the value")
+
你还可以使用 setNull
方法设置 param
为空。
示例如下
args(index = 1).setNull()
+
你还可以使用 setTrue
方法设置 param
为 true
。
特别注意
请确保 param 类型为 Boolean。
示例如下
args(index = 1).setTrue()
+
你还可以使用 setFalse
方法设置 param
为 false
。
特别注意
请确保 param 类型为 Boolean。
示例如下
args(index = 1).setFalse()
+
fun callOriginal(): Any?
+
fun <T> callOriginal(): T?
+
变更记录
v1.1.0
新增
功能描述
执行原始
Member
。
调用自身未进行 Hook 的原始 Member
并调用原始参数执行。
功能实例
此方法可以 invoke
原始未经 Hook 的 Member
对象,取决于原始 Member
的参数。
调用自身原始的方法不会再经过当前 before
、after
以及 replaceUnit
、replaceAny
。
比如我们 Hook 的这个方法被这样调用 test("test value")
,使用此方法会调用其中的 "test value"
作为参数。
示例如下
method {
+ name = "test"
+ param(StringClass)
+ returnType = StringClass
+}.hook {
+ after {
+ // <方案1> 不使用泛型,不获取方法执行结果,调用将使用原方法传入的 args 自动传参
+ callOriginal()
+ // <方案2> 使用泛型,已知方法执行结果参数类型进行 cast
+ // 假设返回值为 String,失败会返回 null,调用将使用原方法传入的 args 自动传参
+ val value = callOriginal<String>()
+ }
+}
+
fun invokeOriginal(vararg args: Any?): Any?
+
fun <T> invokeOriginal(vararg args: Any?): T?
+
变更记录
v1.0
添加
v1.1.0
修改
不再需要使用 member.invokeOriginal
进行调用
功能描述
执行原始
Member
。
调用自身未进行 Hook 的原始 Member
并自定义 args
执行。
功能实例
此方法可以 invoke
原始未经 Hook 的 Member
对象,可自定义需要调用的参数内容。
调用自身原始的方法不会再经过当前 before
、after
以及 replaceUnit
、replaceAny
。
比如我们 Hook 的这个方法被这样调用 test("test value")
,使用此方法可自定义其中的 args
作为参数。
示例如下
method {
+ name = "test"
+ param(StringClass)
+ returnType = StringClass
+}.hook {
+ after {
+ // <方案1> 不使用泛型,不获取方法执行结果
+ invokeOriginal("test value")
+ // <方案2> 使用泛型,已知方法执行结果参数类型进行 cast,假设返回值为 String,失败会返回 null
+ val value = invokeOriginal<String>("test value")
+ }
+}
+
fun resultTrue()
+
变更记录
v1.0
添加
功能描述
设置当前 Hook 对象方法的
result
返回值为true
。
特别注意
请确保 result 类型为 Boolean。
fun resultFalse()
+
变更记录
v1.0
添加
功能描述
设置当前 Hook 对象方法的
result
返回值为false
。
特别注意
请确保 result 类型为 Boolean。
fun resultNull()
+
变更记录
v1.0
添加
功能描述
注意
此方法将强制设置 Hook 对象方法的 result 为 null。
inner class ArgsIndexCondition internal constructor()
+
变更记录
v1.0.75
新增
功能描述
对方法参数的数组下标进行实例化类。
fun first(): ArgsModifyer
+
变更记录
v1.0.75
新增
功能描述
获取当前 Hook 对象的
method
或constructor
的参数数组第一位。
fun last(): ArgsModifyer
+
变更记录
v1.0.75
新增
功能描述
获取当前 Hook 对象的
method
或constructor
的参数数组最后一位。
inner class ArgsModifyer internal constructor(private val index: Int)
+
变更记录
v1.0
添加
功能描述
对方法参数的修改进行实例化类。
fun <T> cast(): T?
+
变更记录
v1.0.66
新增
v1.0.68
修改
修改 为 of
cast
功能描述
得到方法参数的实例对象
T
。
fun byte(): Byte?
+
变更记录
v1.0.68
新增
功能描述
得到方法参数的实例对象 Byte。
fun int(): Int
+
变更记录
v1.0.66
新增
v1.0.68
修改
修改 为 ofInt
int
功能描述
得到方法参数的实例对象 Int。
fun long(): Long
+
变更记录
v1.0.66
新增
v1.0.68
修改
修改 为 ofLong
long
功能描述
得到方法参数的实例对象 Long。
fun short(): Short
+
变更记录
v1.0.66
新增
v1.0.68
修改
修改 为 ofShort
short
功能描述
得到方法参数的实例对象 Short。
fun double(): Double
+
变更记录
v1.0.66
新增
v1.0.68
修改
修改 为 ofDouble
double
功能描述
得到方法参数的实例对象 Double。
fun float(): Float
+
变更记录
v1.0.66
新增
v1.0.68
修改
修改 为 ofFloat
float
功能描述
得到方法参数的实例对象 Float。
fun string(): String
+
变更记录
v1.0.66
新增
v1.0.68
修改
修改 为 ofString
string
功能描述
得到方法参数的实例对象 String。
fun char(): Char
+
变更记录
v1.0.68
新增
功能描述
得到方法参数的实例对象 Char。
fun boolean(): Boolean
+
变更记录
v1.0.66
新增
v1.0.68
修改
修改 为 ofBoolean
boolean
功能描述
得到方法参数的实例对象 Boolean。
fun any(): Any?
+
变更记录
v1.0.77
新增
功能描述
得到方法参数的实例对象 Any。
inline fun <reified T> array(): Array<T>
+
变更记录
v1.0.68
新增
功能描述
得到方法参数的实例对象 Array。
inline fun <reified T> list(): List<T>
+
变更记录
v1.0.68
新增
功能描述
得到方法参数的实例对象 List。
fun <T> set(any: T?)
+
变更记录
v1.0
添加
功能描述
设置方法参数的实例对象。
fun setNull()
+
变更记录
v1.0
添加
功能描述
设置方法参数的实例对象为
null
。
fun setTrue()
+
变更记录
v1.0
添加
功能描述
设置方法参数的实例对象为
true
。
特别注意
请确保目标对象的类型是 Boolean。
fun setFalse()
+
变更记录
v1.0
添加
功能描述
设置方法参数的实例对象为
false
。
特别注意
请确保目标对象的类型是 Boolean。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
class HookParam private constructor(
+ private val creatorInstance: YukiMemberHookCreator,
+ private var paramId: String,
+ private var param: YukiHookCallback.Param?
+)
+
Change Records
v1.0
first
v1.1.0
modified
移动 HookParamWrapper
到 YukiHookCallback.Param
修正拼写错误的 creater 命名到 creator
v1.1.5
modified
新增 paramId
参数
v1.2.0
modified
不再开放构造方法
Function Illustrate
Hook 方法、构造方法的目标对象实现类。
val args: Array<Any?>
+
Change Records
在 v1.0
添加
Function Illustrate
获取当前 Hook 对象
member
或constructor
的参数对象数组。
这里的数组每项类型默认为 Any
,你可以使用 args
方法来实现 ArgsModifyer.cast
功能。
Change Records
v1.0
first
v1.0.75
removed
请使用 args(index = 0)
或 args().first()
Change Records
v1.0
first
v1.0.75
removed
请使用 args().last()
val instance: Any
+
Change Records
v1.0
first
Function Illustrate
获取当前 Hook 实例的对象。
Pay Attention
如果你当前 Hook 的对象是一个静态,那么它将不存在实例的对象。
如果你不确定当前实例的对象是否为 null
,你可以使用 instanceOrNull
。
val instanceOrNull: Any?
+
Change Records
v1.1.8
added
Function Illustrate
获取当前 Hook 实例的对象。
Pay Attention
如果你当前 Hook 的对象是一个静态,那么它将不存在实例的对象。
val instanceClass: Class<*>?
+
Change Records
v1.0
first
v1.2.0
modified
加入可空类型 (空安全)
Function Illustrate
获取当前 Hook 实例的类对象。
Pay Attention
如果你当前 Hook 的对象是一个静态,那么它将不存在实例的对象。
val member: Member
+
Change Records
v1.1.0
added
Function Illustrate
获取当前 Hook 对象的
Member
。
在不确定 Member
类型为 Method
或 Constructor
时可以使用此方法。
val method: Method
+
Change Records
v1.0
first
Function Illustrate
获取当前 Hook 对象的方法。
val constructor: Constructor
+
Change Records
v1.0
first
Function Illustrate
获取当前 Hook 对象的构造方法。
var result: Any?
+
Change Records
v1.0
first
Function Illustrate
获取、设置当前 Hook 对象的
method
或constructor
的返回值。
val dataExtra: Bundle
+
Change Records
v1.1.5
added
Function Illustrate
获取当前回调方法体范围内的数据存储实例。
val hasThrowable: Boolean
+
Change Records
v1.1.0
added
Function Illustrate
判断是否存在设置过的方法调用抛出异常。
val throwable: Throwable?
+
Change Records
v1.1.0
added
Function Illustrate
获取设置的方法调用抛出异常。
fun Throwable.throwToApp()
+
Change Records
v1.1.0
added
Function Illustrate
向 Hook APP 抛出异常。
使用 hasThrowable
判断当前是否存在被抛出的异常。
使用 throwable
获取当前设置的方法调用抛出异常。
仅会在回调方法的 MemberHookCreator.before
或 MemberHookCreator.after
中生效。
Pay Attention
设置后会同时执行 resultNull 方法并将异常抛出给当前 Hook APP。
Function Example
Hook 过程中的异常仅会作用于 (Xposed) 宿主环境,目标 Hook APP 不会受到影响。
若想将异常抛给 Hook APP,可以直接使用如下方法。
The following example
hook {
+ before {
+ RuntimeException("Test Exception").throwToApp()
+ }
+}
+
Pay Attention
向 Hook APP 抛出异常会对其暴露被 Hook 的事实,是不安全的,容易被检测,请按实际场景合理使用。
inline fun <reified T> result(): T?
+
Change Records
v1.0.75
added
Function Illustrate
获取当前 Hook 对象的
method
或constructor
的返回值T
。
Change Records
v1.0.66
added
v1.0.75
removed
Change Records
v1.0.66
added
v1.0.75
removed
inline fun <reified T> instance(): T
+
Change Records
v1.0
first
Function Illustrate
获取当前 Hook 实例的对象
T
。
Function Example
你可以通过 instance
方法轻松使用泛型 cast
为目标对象的类型。
The following example
instance<Activity>().finish()
+
inline fun <reified T> instanceOrNull(): T?
+
Function Illustrate
v1.1.8
added
Function Illustrate
获取当前 Hook 实例的对象
T
。
Function Example
用法请参考 instance 方法。
fun args(): ArgsIndexCondition
+
Change Records
v1.0.75
added
Function Illustrate
获取当前 Hook 对象的
method
或constructor
的参数数组下标实例化类。
fun args(index: Int): ArgsModifyer
+
Change Records
v1.0
first
v1.0.75
modified
默认值 index = 0
移动到新的使用方法 args().first()
Function Illustrate
获取当前 Hook 对象的
method
或constructor
的参数实例化对象类。
Function Example
你可以通过 args
方法修改当前 Hook 实例的方法、构造方法的参数内容。
你可以直接使用 set
方法设置 param
为你的目标实例,接受 Any
类型。
Pay Attention
请确保 param 类型为你的目标实例类型。
The following example
args(index = 0).set("modify the value")
+
你可以这样直接设置第一位 param
的值。
The following example
args().first().set("modify the value")
+
你还可以直接设置最后一位 param
的值。
The following example
args().last().set("modify the value")
+
你还可以使用 setNull
方法设置 param
为空。
The following example
args(index = 1).setNull()
+
你还可以使用 setTrue
方法设置 param
为 true
。
Pay Attention
请确保 param 类型为 Boolean。
The following example
args(index = 1).setTrue()
+
你还可以使用 setFalse
方法设置 param
为 false
。
Pay Attention
请确保 param 类型为 Boolean。
The following example
args(index = 1).setFalse()
+
fun callOriginal(): Any?
+
fun <T> callOriginal(): T?
+
Change Records
v1.1.0
added
Function Illustrate
执行原始
Member
。
调用自身未进行 Hook 的原始 Member
并调用原始参数执行。
功能实例
此方法可以 invoke
原始未经 Hook 的 Member
对象,取决于原始 Member
的参数。
调用自身原始的方法不会再经过当前 before
、after
以及 replaceUnit
、replaceAny
。
比如我们 Hook 的这个方法被这样调用 test("test value")
,使用此方法会调用其中的 "test value"
作为参数。
The following example
method {
+ name = "test"
+ param(StringClass)
+ returnType = StringClass
+}.hook {
+ after {
+ // <方案1> 不使用泛型,不获取方法执行结果,调用将使用原方法传入的 args 自动传参
+ callOriginal()
+ // <方案2> 使用泛型,已知方法执行结果参数类型进行 cast
+ // 假设返回值为 String,失败会返回 null,调用将使用原方法传入的 args 自动传参
+ val value = callOriginal<String>()
+ }
+}
+
fun invokeOriginal(vararg args: Any?): Any?
+
fun <T> invokeOriginal(vararg args: Any?): T?
+
Change Records
v1.0
first
v1.1.0
modified
不再需要使用 member.invokeOriginal
进行调用
Function Illustrate
执行原始
Member
。
调用自身未进行 Hook 的原始 Member
并自定义 args
执行。
功能实例
此方法可以 invoke
原始未经 Hook 的 Member
对象,可自定义需要调用的参数内容。
调用自身原始的方法不会再经过当前 before
、after
以及 replaceUnit
、replaceAny
。
比如我们 Hook 的这个方法被这样调用 test("test value")
,使用此方法可自定义其中的 args
作为参数。
The following example
method {
+ name = "test"
+ param(StringClass)
+ returnType = StringClass
+}.hook {
+ after {
+ // <方案1> 不使用泛型,不获取方法执行结果
+ invokeOriginal("test value")
+ // <方案2> 使用泛型,已知方法执行结果参数类型进行 cast,假设返回值为 String,失败会返回 null
+ val value = invokeOriginal<String>("test value")
+ }
+}
+
fun resultTrue()
+
Change Records
v1.0
first
Function Illustrate
设置当前 Hook 对象方法的
result
返回值为true
。
Pay Attention
请确保 result 类型为 Boolean。
fun resultFalse()
+
Change Records
v1.0
first
Function Illustrate
设置当前 Hook 对象方法的
result
返回值为false
。
Pay Attention
请确保 result 类型为 Boolean。
fun resultNull()
+
Change Records
v1.0
first
Function Illustrate
Notice
此方法将强制设置 Hook 对象方法的 result 为 null。
inner class ArgsIndexCondition internal constructor()
+
Change Records
v1.0.75
added
Function Illustrate
对方法参数的数组下标进行实例化类。
fun first(): ArgsModifyer
+
Change Records
v1.0.75
added
Function Illustrate
获取当前 Hook 对象的
method
或constructor
的参数数组第一位。
fun last(): ArgsModifyer
+
Change Records
v1.0.75
added
Function Illustrate
获取当前 Hook 对象的
method
或constructor
的参数数组最后一位。
inner class ArgsModifyer internal constructor(private val index: Int)
+
Change Records
v1.0
first
Function Illustrate
对方法参数的修改进行实例化类。
fun <T> cast(): T?
+
Change Records
v1.0.66
added
v1.0.68
modified
修改 为 of
cast
Function Illustrate
得到方法参数的实例对象
T
。
fun byte(): Byte?
+
Change Records
v1.0.68
added
Function Illustrate
得到方法参数的实例对象 Byte。
fun int(): Int
+
Change Records
v1.0.66
added
v1.0.68
modified
修改 为 ofInt
int
Function Illustrate
得到方法参数的实例对象 Int。
fun long(): Long
+
Change Records
v1.0.66
added
v1.0.68
modified
修改 为 ofLong
long
Function Illustrate
得到方法参数的实例对象 Long。
fun short(): Short
+
Change Records
v1.0.66
added
v1.0.68
modified
修改 为 ofShort
short
Function Illustrate
得到方法参数的实例对象 Short。
fun double(): Double
+
Change Records
v1.0.66
added
v1.0.68
modified
修改 为 ofDouble
double
Function Illustrate
得到方法参数的实例对象 Double。
fun float(): Float
+
Change Records
v1.0.66
added
v1.0.68
modified
修改 为 ofFloat
float
Function Illustrate
得到方法参数的实例对象 Float。
fun string(): String
+
Change Records
v1.0.66
added
v1.0.68
modified
修改 为 ofString
string
Function Illustrate
得到方法参数的实例对象 String。
fun char(): Char
+
Change Records
v1.0.68
added
Function Illustrate
得到方法参数的实例对象 Char。
fun boolean(): Boolean
+
Change Records
v1.0.66
added
v1.0.68
modified
修改 为 ofBoolean
boolean
Function Illustrate
得到方法参数的实例对象 Boolean。
fun any(): Any?
+
Change Records
v1.0.77
added
Function Illustrate
得到方法参数的实例对象 Any。
inline fun <reified T> array(): Array<T>
+
Change Records
v1.0.68
added
Function Illustrate
得到方法参数的实例对象 Array。
inline fun <reified T> list(): List<T>
+
Change Records
v1.0.68
added
Function Illustrate
得到方法参数的实例对象 List。
fun <T> set(any: T?)
+
Change Records
v1.0
first
Function Illustrate
设置方法参数的实例对象。
fun setNull()
+
Change Records
v1.0
first
Function Illustrate
设置方法参数的实例对象为
null
。
fun setTrue()
+
Change Records
v1.0
first
Function Illustrate
设置方法参数的实例对象为
true
。
Pay Attention
请确保目标对象的类型是 Boolean。
fun setFalse()
+
Change Records
v1.0
first
Function Illustrate
设置方法参数的实例对象为
false
。
Pay Attention
请确保目标对象的类型是 Boolean。
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
class HookResources internal constructor(var instance: YukiResources?)
+
Change Records
v1.0.80
added
Function Illustrate
`,7),c=[t];function r(l,p){return o(),e("div",null,c)}const d=s(n,[["render",r],["__file","HookResources.html.vue"]]);export{d as default}; diff --git a/assets/HookResources.html-zBrjRa5p.js b/assets/HookResources.html-zBrjRa5p.js new file mode 100644 index 00000000..3f7462ae --- /dev/null +++ b/assets/HookResources.html-zBrjRa5p.js @@ -0,0 +1,2 @@ +import{_ as s,o,c as e,a}from"./app-BpUB8-Q8.js";const c={},n=a(`创建一个当前 Hook 的
YukiResources
接管类。
class HookResources internal constructor(var instance: YukiResources?)
+
变更记录
v1.0.80
新增
功能描述
`,6),l=[n];function r(t,p){return o(),e("div",null,l)}const i=s(c,[["render",r],["__file","HookResources.html.vue"]]);export{i as default}; diff --git a/assets/IYukiHookXposedInit.html-CjNI4nFN.js b/assets/IYukiHookXposedInit.html-CjNI4nFN.js new file mode 100644 index 00000000..a0f02124 --- /dev/null +++ b/assets/IYukiHookXposedInit.html-CjNI4nFN.js @@ -0,0 +1,5 @@ +import{_ as o,o as e,c as s,a as n}from"./app-BpUB8-Q8.js";const a={},c=n(`创建一个当前 Hook 的
YukiResources
接管类。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
interface IYukiHookXposedInit
+
变更记录
v1.0
添加
v1.0.80
修改
作废
作废了 名称但保留接口YukiHookXposedInitProxy
迁移到 IYukiHookXposedInit
新名称
功能描述
YukiHookAPI 的 Xposed 装载 API 调用接口。
fun onInit()
+
变更记录
v1.0.5
新增
功能描述
配置
YukiHookAPI.Configs
的初始化方法。
特别注意
在这里只能进行初始化配置,不能进行 Hook 操作。
此方法可选,你也可以选择不对 YukiHookAPI.Configs 进行配置。
fun onHook()
+
变更记录
v1.0
添加
功能描述
Xposed API 的模块装载调用入口方法。
fun onXposedEvent()
+
变更记录
v1.0.80
新增
功能描述
监听 Xposed 原生装载事件。
若你的 Hook 事件中存在需要兼容的原生 Xposed 功能,可在这里实现。
请在这里使用 YukiXposedEvent 创建回调事件监听。
可监听的事件如下:
YukiXposedEvent.onInitZygote
YukiXposedEvent.onHandleLoadPackage
YukiXposedEvent.onHandleInitPackageResources
特别注意
此接口仅供监听和实现原生 Xposed API 的功能,请不要在这里操作 YukiHookAPI。
变更记录
v1.0
添加
v1.0.80
作废
请迁移到 IYukiHookXposedInit
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
interface IYukiHookXposedInit
+
Change Records
v1.0
first
v1.0.80
modified
deprecated
作废了 名称但保留接口YukiHookXposedInitProxy
迁移到 IYukiHookXposedInit
新名称
Function Illustrate
YukiHookAPI 的 Xposed 装载 API 调用接口。
fun onInit()
+
Change Records
v1.0.5
added
Function Illustrate
配置
YukiHookAPI.Configs
的初始化方法。
Pay Attention
在这里只能进行初始化配置,不能进行 Hook 操作。
此方法可选,你也可以选择不对 YukiHookAPI.Configs 进行配置。
fun onHook()
+
Change Records
v1.0
first
Function Illustrate
Xposed API 的模块装载调用入口方法。
fun onXposedEvent()
+
Change Records
v1.0.80
added
Function Illustrate
监听 Xposed 原生装载事件。
若你的 Hook 事件中存在需要兼容的原生 Xposed 功能,可在这里实现。
请在这里使用 YukiXposedEvent 创建回调事件监听。
可监听的事件如下:
YukiXposedEvent.onInitZygote
YukiXposedEvent.onHandleLoadPackage
YukiXposedEvent.onHandleInitPackageResources
Pay Attention
此接口仅供监听和实现原生 Xposed API 的功能,请不要在这里操作 YukiHookAPI。
Change Records
v1.0
first
v1.0.80
deprecated
请迁移到 IYukiHookXposedInit
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
annotation class InjectYukiHookWithXposed(
+ val sourcePath: String,
+ val modulePackageName: String,
+ val entryClassName: String,
+ val isUsingXposedModuleStatus: Boolean,
+ val isUsingResourcesHook: Boolean
+)
+
变更记录
v1.0
添加
v1.0.80
修改
新增 entryClassName
参数
v1.0.92
修改
新增 isUsingResourcesHook
参数
v1.2.0
修改
新增 isUsingXposedModuleStatus
参数
功能描述
标识
YukiHookAPI
注入 Xposed 入口的类注解。
功能示例
详情请参考 InjectYukiHookWithXposed 注解。
`,15),c=[p];function l(t,i){return o(),n("div",null,c)}const d=s(e,[["render",l],["__file","InjectYukiHookWithXposed.html.vue"]]);export{d as default}; diff --git a/assets/InjectYukiHookWithXposed.html-B4v_FVid.js b/assets/InjectYukiHookWithXposed.html-B4v_FVid.js new file mode 100644 index 00000000..27320327 --- /dev/null +++ b/assets/InjectYukiHookWithXposed.html-B4v_FVid.js @@ -0,0 +1,8 @@ +import{_ as o,o as s,c as n,a as e}from"./app-BpUB8-Q8.js";const a={},t=e(`Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
annotation class InjectYukiHookWithXposed(
+ val sourcePath: String,
+ val modulePackageName: String,
+ val entryClassName: String,
+ val isUsingXposedModuleStatus: Boolean,
+ val isUsingResourcesHook: Boolean
+)
+
Change Records
v1.0
first
v1.0.80
modified
新增 entryClassName
参数
v1.0.92
modified
新增 isUsingResourcesHook
参数
v1.2.0
modified
新增 isUsingXposedModuleStatus
参数
Function Illustrate
标识
YukiHookAPI
注入 Xposed 入口的类注解。
Function Example
详情请参考 InjectYukiHookWithXposed Annotation。
`,16),c=[t];function p(l,i){return s(),n("div",null,c)}const d=o(a,[["render",p],["__file","InjectYukiHookWithXposed.html.vue"]]);export{d as default}; diff --git a/assets/InjectYukiHookWithXposed.html-BGS_DJ2i.js b/assets/InjectYukiHookWithXposed.html-BGS_DJ2i.js new file mode 100644 index 00000000..5d62a1ff --- /dev/null +++ b/assets/InjectYukiHookWithXposed.html-BGS_DJ2i.js @@ -0,0 +1 @@ +const o=JSON.parse('{"key":"v-818b3ca6","path":"/en/api/public/com/highcapable/yukihookapi/annotation/xposed/InjectYukiHookWithXposed.html","title":"InjectYukiHookWithXposed - annotation","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":3}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/annotation/xposed/InjectYukiHookWithXposed.md"}');export{o as data}; diff --git a/assets/InjectYukiHookWithXposed.html-C_GfVAhD.js b/assets/InjectYukiHookWithXposed.html-C_GfVAhD.js new file mode 100644 index 00000000..1f3895bc --- /dev/null +++ b/assets/InjectYukiHookWithXposed.html-C_GfVAhD.js @@ -0,0 +1 @@ +const o=JSON.parse('{"key":"v-30f3ba1e","path":"/zh-cn/api/public/com/highcapable/yukihookapi/annotation/xposed/InjectYukiHookWithXposed.html","title":"InjectYukiHookWithXposed - annotation","lang":"zh-CN","frontmatter":{"pageClass":"code-page"},"headers":[],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":4}]},"filePathRelative":"zh-cn/api/public/com/highcapable/yukihookapi/annotation/xposed/InjectYukiHookWithXposed.md"}');export{o as data}; diff --git a/assets/MemberRules.html-CzY4xHkS.js b/assets/MemberRules.html-CzY4xHkS.js new file mode 100644 index 00000000..eea10d08 --- /dev/null +++ b/assets/MemberRules.html-CzY4xHkS.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-77f11cf9","path":"/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/MemberRules.html","title":"MemberRules - class","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"modifiers - method","slug":"modifiers-method","link":"#modifiers-method","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":3}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/MemberRules.md"}');export{e as data}; diff --git a/assets/MemberRules.html-DBoFuxYs.js b/assets/MemberRules.html-DBoFuxYs.js new file mode 100644 index 00000000..7042623f --- /dev/null +++ b/assets/MemberRules.html-DBoFuxYs.js @@ -0,0 +1,3 @@ +import{_ as e,o as s,c as o,a}from"./app-BpUB8-Q8.js";const n={},t=a(`Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
class MemberRules internal constructor(private val rulesData: MemberRulesData) : BaseRules
+
Change Records
v1.1.0
added
Function Illustrate
Member
查找条件实现类。
fun modifiers(conditions: ModifierConditions)
+
Change Records
v1.1.0
added
Function Illustrate
设置
Member
标识符筛选条件。
可不设置筛选条件。
`,15),l=[t];function c(r,p){return s(),o("div",null,l)}const d=e(n,[["render",c],["__file","MemberRules.html.vue"]]);export{d as default}; diff --git a/assets/MemberRules.html-WT4l8b-Y.js b/assets/MemberRules.html-WT4l8b-Y.js new file mode 100644 index 00000000..f6b1f034 --- /dev/null +++ b/assets/MemberRules.html-WT4l8b-Y.js @@ -0,0 +1,3 @@ +import{_ as s,o as e,c as o,a}from"./app-BpUB8-Q8.js";const n={},l=a(`注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
class MemberRules internal constructor(private val rulesData: MemberRulesData) : BaseRules
+
变更记录
v1.1.0
新增
功能描述
Member
查找条件实现类。
fun modifiers(conditions: ModifierConditions)
+
变更记录
v1.1.0
新增
功能描述
设置
Member
标识符筛选条件。
可不设置筛选条件。
`,14),c=[l];function t(p,r){return e(),o("div",null,c)}const i=s(n,[["render",t],["__file","MemberRules.html.vue"]]);export{i as default}; diff --git a/assets/MemberRules.html-r3ZOm1rb.js b/assets/MemberRules.html-r3ZOm1rb.js new file mode 100644 index 00000000..22324e69 --- /dev/null +++ b/assets/MemberRules.html-r3ZOm1rb.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-2cab152c","path":"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/MemberRules.html","title":"MemberRules - class","lang":"zh-CN","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"modifiers - method","slug":"modifiers-method","link":"#modifiers-method","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":4}]},"filePathRelative":"zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/MemberRules.md"}');export{e as data}; diff --git a/assets/MemberRulesResult.html-4uRTQRQi.js b/assets/MemberRulesResult.html-4uRTQRQi.js new file mode 100644 index 00000000..dbe7adc6 --- /dev/null +++ b/assets/MemberRulesResult.html-4uRTQRQi.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-b8000f3a","path":"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/result/MemberRulesResult.html","title":"MemberRulesResult - class","lang":"zh-CN","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"none - method","slug":"none-method","link":"#none-method","children":[]},{"level":2,"title":"count - method","slug":"count-method","link":"#count-method","children":[]},{"level":2,"title":"count - method","slug":"count-method-1","link":"#count-method-1","children":[]},{"level":2,"title":"count - method","slug":"count-method-2","link":"#count-method-2","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":3}]},"filePathRelative":"zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/result/MemberRulesResult.md"}');export{e as data}; diff --git a/assets/MemberRulesResult.html-C2cLl89Y.js b/assets/MemberRulesResult.html-C2cLl89Y.js new file mode 100644 index 00000000..3fba4cf9 --- /dev/null +++ b/assets/MemberRulesResult.html-C2cLl89Y.js @@ -0,0 +1,6 @@ +import{_ as s,o as e,c as o,a}from"./app-BpUB8-Q8.js";const n={},l=a(`注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
class MemberRulesResult internal constructor(private val rulesData: MemberRulesData)
+
变更记录
v1.1.0
新增
功能描述
当前
Member
查找条件结果实现类。
fun none(): MemberRulesResult
+
变更记录
v1.1.0
新增
功能描述
设置当前
Member
在查找条件中个数为0
。
fun count(num: Int): MemberRulesResult
+
变更记录
v1.1.0
新增
功能描述
设置当前
Member
在查找条件中需要全部匹配的个数。
fun count(numRange: IntRange): MemberRulesResult
+
变更记录
v1.1.0
新增
功能描述
设置当前
Member
在查找条件中需要全部匹配的个数范围。
fun count(conditions: CountConditions): MemberRulesResult
+
变更记录
v1.1.0
新增
功能描述
`,31),t=[l];function c(p,r){return e(),o("div",null,t)}const i=s(n,[["render",c],["__file","MemberRulesResult.html.vue"]]);export{i as default}; diff --git a/assets/MemberRulesResult.html-CPcOEYiz.js b/assets/MemberRulesResult.html-CPcOEYiz.js new file mode 100644 index 00000000..6b3d7883 --- /dev/null +++ b/assets/MemberRulesResult.html-CPcOEYiz.js @@ -0,0 +1,6 @@ +import{_ as e,o as s,c as o,a as n}from"./app-BpUB8-Q8.js";const a={},t=n(`设置当前
Member
在查找条件中需要全部匹配的个数条件。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
class MemberRulesResult internal constructor(private val rulesData: MemberRulesData)
+
Change Records
v1.1.0
added
Function Illustrate
当前
Member
查找条件结果实现类。
fun none(): MemberRulesResult
+
Change Records
v1.1.0
added
Function Illustrate
设置当前
Member
在查找条件中个数为0
。
fun count(num: Int): MemberRulesResult
+
Change Records
v1.1.0
added
Function Illustrate
设置当前
Member
在查找条件中需要全部匹配的个数。
fun count(numRange: IntRange): MemberRulesResult
+
Change Records
v1.1.0
added
Function Illustrate
设置当前
Member
在查找条件中需要全部匹配的个数范围。
fun count(conditions: CountConditions): MemberRulesResult
+
Change Records
v1.1.0
added
Function Illustrate
`,32),l=[t];function c(r,p){return s(),o("div",null,l)}const i=e(a,[["render",c],["__file","MemberRulesResult.html.vue"]]);export{i as default}; diff --git a/assets/MemberRulesResult.html-DVBlYWR7.js b/assets/MemberRulesResult.html-DVBlYWR7.js new file mode 100644 index 00000000..4fc22e37 --- /dev/null +++ b/assets/MemberRulesResult.html-DVBlYWR7.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-5e375d98","path":"/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/result/MemberRulesResult.html","title":"MemberRulesResult - class","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"none - method","slug":"none-method","link":"#none-method","children":[]},{"level":2,"title":"count - method","slug":"count-method","link":"#count-method","children":[]},{"level":2,"title":"count - method","slug":"count-method-1","link":"#count-method-1","children":[]},{"level":2,"title":"count - method","slug":"count-method-2","link":"#count-method-2","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":2}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/result/MemberRulesResult.md"}');export{e as data}; diff --git a/assets/MethodFinder.html-BepwXG9K.js b/assets/MethodFinder.html-BepwXG9K.js new file mode 100644 index 00000000..d37e79dd --- /dev/null +++ b/assets/MethodFinder.html-BepwXG9K.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-fd738322","path":"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/members/MethodFinder.html","title":"MethodFinder - class","lang":"zh-CN","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"name - field","slug":"name-field","link":"#name-field","children":[]},{"level":2,"title":"paramCount - field","slug":"paramcount-field","link":"#paramcount-field","children":[]},{"level":2,"title":"returnType - field","slug":"returntype-field","link":"#returntype-field","children":[]},{"level":2,"title":"modifiers - method","slug":"modifiers-method","link":"#modifiers-method","children":[]},{"level":2,"title":"emptyParam - method","slug":"emptyparam-method","link":"#emptyparam-method","children":[]},{"level":2,"title":"param - method","slug":"param-method","link":"#param-method","children":[]},{"level":2,"title":"param - method","slug":"param-method-1","link":"#param-method-1","children":[]},{"level":2,"title":"order - method","slug":"order-method","link":"#order-method","children":[]},{"level":2,"title":"name - method","slug":"name-method","link":"#name-method","children":[]},{"level":2,"title":"name - method","slug":"name-method-1","link":"#name-method-1","children":[]},{"level":2,"title":"paramCount - method","slug":"paramcount-method","link":"#paramcount-method","children":[]},{"level":2,"title":"paramCount - method","slug":"paramcount-method-1","link":"#paramcount-method-1","children":[]},{"level":2,"title":"paramCount - method","slug":"paramcount-method-2","link":"#paramcount-method-2","children":[]},{"level":2,"title":"returnType - method","slug":"returntype-method","link":"#returntype-method","children":[]},{"level":2,"title":"returnType - method","slug":"returntype-method-1","link":"#returntype-method-1","children":[]},{"level":2,"title":"superClass - method","slug":"superclass-method","link":"#superclass-method","children":[]},{"level":2,"title":"RemedyPlan - class","slug":"remedyplan-class","link":"#remedyplan-class","children":[{"level":3,"title":"method - method","slug":"method-method","link":"#method-method","children":[]},{"level":3,"title":"Result - class","slug":"result-class","link":"#result-class","children":[]}]},{"level":2,"title":"Process - class","slug":"process-class","link":"#process-class","children":[{"level":3,"title":"result - method","slug":"result-method","link":"#result-method","children":[]},{"level":3,"title":"all - method","slug":"all-method","link":"#all-method","children":[]},{"level":3,"title":"remedys - method","slug":"remedys-method","link":"#remedys-method","children":[]},{"level":3,"title":"onNoSuchMethod - method","slug":"onnosuchmethod-method","link":"#onnosuchmethod-method","children":[]}]},{"level":2,"title":"Result - class","slug":"result-class-1","link":"#result-class-1","children":[{"level":3,"title":"result - method","slug":"result-method-1","link":"#result-method-1","children":[]},{"level":3,"title":"get - method","slug":"get-method","link":"#get-method","children":[]},{"level":3,"title":"all - method","slug":"all-method-1","link":"#all-method-1","children":[]},{"level":3,"title":"give - method","slug":"give-method","link":"#give-method","children":[]},{"level":3,"title":"giveAll - method","slug":"giveall-method","link":"#giveall-method","children":[]},{"level":3,"title":"wait - method","slug":"wait-method","link":"#wait-method","children":[]},{"level":3,"title":"waitAll - method","slug":"waitall-method","link":"#waitall-method","children":[]},{"level":3,"title":"remedys - method","slug":"remedys-method-1","link":"#remedys-method-1","children":[]},{"level":3,"title":"onNoSuchMethod - method","slug":"onnosuchmethod-method-1","link":"#onnosuchmethod-method-1","children":[]},{"level":3,"title":"ignored - method","slug":"ignored-method","link":"#ignored-method","children":[]},{"level":3,"title":"Instance - class","slug":"instance-class","link":"#instance-class","children":[]},{"level":3,"title":"array - method","slug":"array-method","link":"#array-method","children":[]},{"level":3,"title":"list - method","slug":"list-method","link":"#list-method","children":[]}]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":10}]},"filePathRelative":"zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/members/MethodFinder.md"}');export{e as data}; diff --git a/assets/MethodFinder.html-CtgDtD9U.js b/assets/MethodFinder.html-CtgDtD9U.js new file mode 100644 index 00000000..62eae6ba --- /dev/null +++ b/assets/MethodFinder.html-CtgDtD9U.js @@ -0,0 +1,104 @@ +import{_ as s,o as e,c as o,a}from"./app-BpUB8-Q8.js";const n={},l=a(`设置当前
Member
在查找条件中需要全部匹配的个数条件。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
class MethodFinder internal constructor(override val classSet: Class<*>) : MemberBaseFinder
+
Change Records
v1.0
first
v1.0.2
modified
合并到 BaseFinder
v1.1.0
modified
合并到 MemberBaseFinder
v1.1.8
modified
移动 hookInstance
参数到 MemberBaseFinder.MemberHookerManager
Function Illustrate
Method
查找类。
可通过指定类型查找指定 Method
或一组 Method
。
var name: String
+
Change Records
v1.0
first
v1.0.70
modified
允许不填写名称
Function Illustrate
设置
Method
名称。
Pay Attention
若不填写名称则必须存在一个其它条件。
var paramCount: Int
+
Change Records
v1.0.67
added
Function Illustrate
设置
Method
参数个数。
你可以不使用 param
指定参数类型而是仅使用此变量指定参数个数。
若参数个数小于零则忽略并使用 param
。
var returnType: Any?
+
Change Records
v1.0
first
Function Illustrate
设置
Method
返回值,可不填写返回值。
fun modifiers(conditions: ModifierConditions): IndexTypeCondition
+
Change Records
v1.0.67
added
v1.0.80
modified
将方法体进行 inline
v1.1.0
modified
合并到 ModifierConditions
Function Illustrate
设置
Method
标识符筛选条件。
可不设置筛选条件。
Pay Attention
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun emptyParam(): IndexTypeCondition
+
Change Records
v1.0.75
added
Function Illustrate
设置
Method
空参数、无参数。
fun param(vararg paramType: Any): IndexTypeCondition
+
Change Records
v1.0
first
Function Illustrate
设置
Method
参数。
如果同时使用了 paramCount
则 paramType
的数量必须与 paramCount
完全匹配。
如果 Method
中存在一些无意义又很长的类型,你可以使用 VagueType 来替代它。
Pay Attention
无参 Method 请使用 emptyParam 设置查找条件。
有参 Method 必须使用此方法设定参数或使用 paramCount 指定个数。
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun param(conditions: ObjectsConditions): IndexTypeCondition
+
Change Records
v1.1.5
added
Function Illustrate
设置
Method
参数条件。
Pay Attention
无参 Method 请使用 emptyParam 设置查找条件。
有参 Method 必须使用此方法设定参数或使用 paramCount 指定个数。
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun order(): IndexTypeCondition
+
Change Records
v1.0.70
added
Function Illustrate
顺序筛选字节码的下标。
fun name(value: String): IndexTypeCondition
+
Change Records
v1.0.70
added
Function Illustrate
设置
Method
名称。
Pay Attention
若不填写名称则必须存在一个其它条件。
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun name(conditions: NameConditions): IndexTypeCondition
+
Change Records
v1.0.88
added
v1.1.0
modified
合并到 NameConditions
Function Illustrate
设置
Method
名称条件。
Pay Attention
若不填写名称则必须存在一个其它条件。
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun paramCount(num: Int): IndexTypeCondition
+
Change Records
v1.0.70
added
Function Illustrate
设置
Method
参数个数。
你可以不使用 param
指定参数类型而是仅使用此方法指定参数个数。
若参数个数小于零则忽略并使用 param
。
Pay Attention
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun paramCount(numRange: IntRange): IndexTypeCondition
+
Change Records
v1.1.0
added
Function Illustrate
设置
Method
参数个数范围。
你可以不使用 param
指定参数类型而是仅使用此方法指定参数个数范围。
Pay Attention
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun paramCount(conditions: CountConditions): IndexTypeCondition
+
Change Records
v1.1.0
added
Function Illustrate
设置
Method
参数个数条件。
你可以不使用 param
指定参数类型而是仅使用此方法指定参数个数条件。
Pay Attention
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun returnType(value: Any): IndexTypeCondition
+
Change Records
v1.0.70
added
Function Illustrate
设置
Method
返回值。
可不填写返回值。
Pay Attention
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun returnType(conditions: ObjectConditions): IndexTypeCondition
+
Change Records
v1.1.5
added
Function Illustrate
设置
Method
返回值条件。
可不填写返回值。
Pay Attention
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun superClass(isOnlySuperClass: Boolean)
+
Change Records
v1.0.80
added
Function Illustrate
设置在
classSet
的所有父类中查找当前Method
。
Notice
若当前 classSet 的父类较多可能会耗时,API 会自动循环到父类继承是 Any 前的最后一个类。
inner class RemedyPlan internal constructor()
+
Change Records
v1.0
first
Function Illustrate
Method
重查找实现类,可累计失败次数直到查找成功。
inline fun method(initiate: MethodConditions): Result
+
Change Records
v1.0
first
v1.0.80
modified
将方法体进行 inline
Function Illustrate
创建需要重新查找的
Method
。
你可以添加多个备选 Method
,直到成功为止,若最后依然失败,将停止查找并输出错误日志。
inner class Result internal constructor()
+
Change Records
v1.0.1
added
Function Illustrate
RemedyPlan
结果实现类。
fun onFind(initiate: MutableList<Method>.() -> Unit)
+
Change Records
v1.0.1
added
v1.1.0
modified
initiate
参数 Method
变为 HashSet<Method>
v1.2.0
modified
initiate
类型由 HashSet
修改为 MutableList
Function Illustrate
当在
RemedyPlan
中找到结果时。
Function Example
你可以方便地对重查找的 Method
实现 onFind
方法。
The following example
method {
+ // Your code here.
+}.onFind {
+ // Your code here.
+}
+
inner class Process internal constructor(internal val isNoSuch: Boolean, internal val throwable: Throwable?) : BaseResult
+
Change Records
v1.1.0
added
Function Illustrate
Method
查找结果处理类,为hookManager
提供。
inline fun result(initiate: Process.() -> Unit): Process
+
Change Records
v1.1.0
added
Function Illustrate
创建监听结果事件方法体。
Function Example
你可以使用 lambda 形式创建 Result
类。
The following example
method {
+ // Your code here.
+}.result {
+ all()
+ remedys {}
+ onNoSuchMethod {}
+}
+
fun all(): Process
+
Change Records
v1.1.0
added
Function Illustrate
设置全部查找条件匹配的多个
Method
实例结果到hookManager
。
inline fun remedys(initiate: RemedyPlan.() -> Unit): Result
+
Change Records
v1.1.0
added
Function Illustrate
创建
Method
重查找功能。
Function Example
当你遇到一种 Method
可能存在不同形式的存在时,可以使用 RemedyPlan
重新查找它,而没有必要使用 onNoSuchMethod
捕获异常二次查找 Method
。
若第一次查找失败了,你还可以在这里继续添加此方法体直到成功为止。
The following example
method {
+ // Your code here.
+}.remedys {
+ method {
+ // Your code here.
+ }
+ method {
+ // Your code here.
+ }
+}
+
inline fun onNoSuchMethod(result: (Throwable) -> Unit): Result
+
Change Records
v1.1.0
added
Function Illustrate
监听找不到
Method
时。
只会返回第一次的错误信息,不会返回 RemedyPlan
的错误信息。
inner class Result internal constructor(internal val isNoSuch: Boolean, private val throwable: Throwable?) : BaseResult
+
Change Records
v1.0
first
v1.1.0
modified
继承到接口 BaseResult
Function Illustrate
Method
查找结果实现类。
inline fun result(initiate: Result.() -> Unit): Result
+
Change Records
v1.0
first
v1.0.80
modified
将方法体进行 inline
Function Illustrate
创建监听结果事件方法体。
Function Example
你可以使用 lambda 形式创建 Result
类。
The following example
method {
+ // Your code here.
+}.result {
+ get(instance).call()
+ all(instance)
+ remedys {}
+ onNoSuchMethod {}
+}
+
fun get(instance: Any?): Instance
+
Change Records
v1.0.2
added
Function Illustrate
获得
Method
实例处理类。
若有多个 Method
结果只会返回第一个。
Pay Attention
若你设置了 remedys 请使用 wait 回调结果方法。
Function Example
你可以通过获得方法所在实例来执行 Method
。
The following example
method {
+ // Your code here.
+}.get(instance).call()
+
若当前为静态方法,你可以不设置实例。
The following example
method {
+ // Your code here.
+}.get().call()
+
fun all(instance: Any?): MutableList<Instance>
+
Change Records
v1.1.0
added
v1.2.0
modified
返回值类型由 ArrayList
修改为 MutableList
Function Illustrate
获得
Method
实例处理类数组。
返回全部查找条件匹配的多个 Method
实例结果。
Function Example
你可以通过此方法来获得当前条件结果中匹配的全部 Method
,其方法所在实例用法与 get
相同。
The following example
method {
+ // Your code here.
+}.all(instance).forEach { instance ->
+ instance.call(...)
+}
+
fun give(): Method?
+
Change Records
v1.0.67
added
Function Illustrate
得到
Method
本身。
若有多个 Method
结果只会返回第一个。
在查找条件找不到任何结果的时候将返回 null
。
fun giveAll(): MutableList<Method>
+
Change Records
v1.1.0
added
v1.2.0
modified
返回值类型由 HashSet
修改为 MutableList
Function Illustrate
得到
Method
本身数组。
返回全部查找条件匹配的多个 Method
实例。
在查找条件找不到任何结果的时候将返回空的 MutableList
。
fun wait(instance: Any?, initiate: Instance.() -> Unit)
+
Change Records
v1.0.2
added
Function Illustrate
获得
Method
实例处理类,配合RemedyPlan
使用。
若有多个 Method
结果只会返回第一个。
Pay Attention
若你设置了 remedys 必须使用此方法才能获得结果。
若你没有设置 remedys 此方法将不会被回调。
fun waitAll(instance: Any?, initiate: MutableList<Instance>.() -> Unit)
+
Change Records
v1.1.0
added
v1.2.0
modified
initiate
类型由 ArrayList
修改为 MutableList
Function Illustrate
获得
Method
实例处理类数组,配合RemedyPlan
使用。
返回全部查找条件匹配的多个 Method
实例结果。
Pay Attention
若你设置了 remedys 必须使用此方法才能获得结果。
若你没有设置 remedys 此方法将不会被回调。
inline fun remedys(initiate: RemedyPlan.() -> Unit): Result
+
Change Records
v1.0
first
v1.0.80
modified
将方法体进行 inline
Function Illustrate
创建
Method
重查找功能。
Function Example
当你遇到一种 Method
可能存在不同形式的存在时,可以使用 RemedyPlan
重新查找它,而没有必要使用 onNoSuchMethod
捕获异常二次查找 Method
。
若第一次查找失败了,你还可以在这里继续添加此方法体直到成功为止。
The following example
method {
+ // Your code here.
+}.remedys {
+ method {
+ // Your code here.
+ }
+ method {
+ // Your code here.
+ }
+}
+
inline fun onNoSuchMethod(result: (Throwable) -> Unit): Result
+
Change Records
v1.0
first
v1.0.80
modified
将方法体进行 inline
Function Illustrate
监听找不到
Method
时。
只会返回第一次的错误信息,不会返回 RemedyPlan
的错误信息。
fun ignored(): Result
+
Change Records
v1.1.0
added
Function Illustrate
忽略异常并停止打印任何错误日志。
若 MemberBaseFinder.MemberHookerManager.isNotIgnoredNoSuchMemberFailure
为 false
则自动忽略。
Notice
此时若要监听异常结果,你需要手动实现 onNoSuchMethod 方法。
Change Records
v1.0.3
added
v1.1.0
deprecated
请迁移到新方法 ignored()
inner class Instance internal constructor(private val instance: Any?, private val method: Method?)
+
Change Records
v1.0.2
added
v1.1.0
modified
新增 method
参数
Function Illustrate
Method
实例处理类。
fun original(): Instance
+
Change Records
v1.1.0
added
Function Illustrate
标识需要调用当前
Method
未经 Hook 的原始方法。
若当前 Method
并未 Hook 则会使用原始的 Method.invoke
方法调用。
Pay Attention
你只能在 (Xposed) 宿主环境中使用此功能。
fun call(vararg args: Any?): Any?
+
Change Records
v1.0.2
added
v1.1.6
modified
修改参数命名 param
为 args
Function Illustrate
执行
Method
,不指定返回值类型。
fun <T> invoke(vararg args: Any?): T?
+
Change Records
v1.0.2
added
v1.1.6
modified
修改参数命名 param
为 args
Function Illustrate
执行
Method
,指定T
返回值类型。
fun byte(vararg args: Any?): Byte?
+
Change Records
v1.0.68
added
v1.1.6
modified
修改参数命名 param
为 args
Function Illustrate
执行
Method
,指定 Byte 返回值类型。
fun int(vararg args: Any?): Int
+
Change Records
v1.0.65
added
v1.0.68
modified
修改 为 callInt
int
v1.1.6
modified
修改参数命名 param
为 args
Function Illustrate
执行
Method
,指定 Int 返回值类型。
fun long(vararg args: Any?): Long
+
Change Records
v1.0.65
added
v1.0.68
modified
修改 为 callLong
long
v1.1.6
modified
修改参数命名 param
为 args
Function Illustrate
执行
Method
,指定 Long 返回值类型。
fun short(vararg args: Any?): Short
+
Change Records
v1.0.65
added
v1.0.68
modified
修改 为 callShort
short
v1.1.6
modified
修改参数命名 param
为 args
Function Illustrate
执行
Method
,指定 Short 返回值类型。
fun double(vararg args: Any?): Double
+
Change Records
v1.0.65
added
v1.0.68
modified
修改 为 callDouble
double
v1.1.6
modified
修改参数命名 param
为 args
Function Illustrate
执行
Method
,指定 Double 返回值类型。
fun float(vararg args: Any?): Float
+
Change Records
v1.0.65
added
v1.0.68
modified
修改 为 callFloat
float
v1.1.6
modified
修改参数命名 param
为 args
Function Illustrate
执行
Method
,指定 Float 返回值类型。
fun string(vararg args: Any?): String
+
Change Records
v1.0.65
added
v1.0.68
modified
修改 为 callString
string
v1.1.6
modified
修改参数命名 param
为 args
Function Illustrate
执行
Method
,指定 String 返回值类型。
fun char(vararg args: Any?): Char
+
Change Records
v1.0.68
added
v1.1.6
modified
修改参数命名 param
为 args
Function Illustrate
执行
Method
,指定 Char 返回值类型。
fun boolean(vararg args: Any?): Boolean
+
Change Records
v1.0.65
added
v1.0.68
modified
修改 为 callBoolean
boolean
v1.1.6
modified
修改参数命名 param
为 args
Function Illustrate
执行
Method
,指定 Boolean 返回值类型。
inline fun <reified T> array(vararg args: Any?): Array<T>
+
Change Records
v1.0.68
added
v1.1.6
modified
修改参数命名 param
为 args
Function Illustrate
执行
Method
,指定 Array 返回值类型。
inline fun <reified T> list(vararg args: Any?): List<T>
+
Change Records
v1.0.68
added
v1.1.6
modified
修改参数命名 param
为 args
Function Illustrate
`,470),p=[l];function c(t,d){return e(),o("div",null,p)}const i=s(n,[["render",c],["__file","MethodFinder.html.vue"]]);export{i as default}; diff --git a/assets/MethodFinder.html-DLZMTsEY.js b/assets/MethodFinder.html-DLZMTsEY.js new file mode 100644 index 00000000..f2987b55 --- /dev/null +++ b/assets/MethodFinder.html-DLZMTsEY.js @@ -0,0 +1,104 @@ +import{_ as s,o,c as e,a}from"./app-BpUB8-Q8.js";const n={},p=a(`执行
Method
,指定 List 返回值类型。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
class MethodFinder internal constructor(override val classSet: Class<*>) : MemberBaseFinder
+
变更记录
v1.0
添加
v1.0.2
修改
合并到 BaseFinder
v1.1.0
修改
合并到 MemberBaseFinder
v1.1.8
修改
移动 hookInstance
参数到 MemberBaseFinder.MemberHookerManager
功能描述
Method
查找类。
可通过指定类型查找指定 Method
或一组 Method
。
var name: String
+
变更记录
v1.0
添加
v1.0.70
修改
允许不填写名称
功能描述
设置
Method
名称。
特别注意
若不填写名称则必须存在一个其它条件。
var paramCount: Int
+
变更记录
v1.0.67
新增
功能描述
设置
Method
参数个数。
你可以不使用 param
指定参数类型而是仅使用此变量指定参数个数。
若参数个数小于零则忽略并使用 param
。
var returnType: Any?
+
变更记录
v1.0
添加
功能描述
设置
Method
返回值,可不填写返回值。
fun modifiers(conditions: ModifierConditions): IndexTypeCondition
+
变更记录
v1.0.67
新增
v1.0.80
修改
将方法体进行 inline
v1.1.0
修改
合并到 ModifierConditions
功能描述
设置
Method
标识符筛选条件。
可不设置筛选条件。
特别注意
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun emptyParam(): IndexTypeCondition
+
变更记录
v1.0.75
新增
功能描述
设置
Method
空参数、无参数。
fun param(vararg paramType: Any): IndexTypeCondition
+
变更记录
v1.0
添加
功能描述
设置
Method
参数。
如果同时使用了 paramCount
则 paramType
的数量必须与 paramCount
完全匹配。
如果 Method
中存在一些无意义又很长的类型,你可以使用 VagueType 来替代它。
特别注意
无参 Method 请使用 emptyParam 设置查找条件。
有参 Method 必须使用此方法设定参数或使用 paramCount 指定个数。
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun param(conditions: ObjectsConditions): IndexTypeCondition
+
变更记录
v1.1.5
新增
功能描述
设置
Method
参数条件。
特别注意
无参 Method 请使用 emptyParam 设置查找条件。
有参 Method 必须使用此方法设定参数或使用 paramCount 指定个数。
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun order(): IndexTypeCondition
+
变更记录
v1.0.70
新增
功能描述
顺序筛选字节码的下标。
fun name(value: String): IndexTypeCondition
+
变更记录
v1.0.70
新增
功能描述
设置
Method
名称。
特别注意
若不填写名称则必须存在一个其它条件。
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun name(conditions: NameConditions): IndexTypeCondition
+
变更记录
v1.0.88
新增
v1.1.0
修改
合并到 NameConditions
功能描述
设置
Method
名称条件。
特别注意
若不填写名称则必须存在一个其它条件。
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun paramCount(num: Int): IndexTypeCondition
+
变更记录
v1.0.70
新增
功能描述
设置
Method
参数个数。
你可以不使用 param
指定参数类型而是仅使用此方法指定参数个数。
若参数个数小于零则忽略并使用 param
。
特别注意
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun paramCount(numRange: IntRange): IndexTypeCondition
+
变更记录
v1.1.0
新增
功能描述
设置
Method
参数个数范围。
你可以不使用 param
指定参数类型而是仅使用此方法指定参数个数范围。
特别注意
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun paramCount(conditions: CountConditions): IndexTypeCondition
+
变更记录
v1.1.0
新增
功能描述
设置
Method
参数个数条件。
你可以不使用 param
指定参数类型而是仅使用此方法指定参数个数条件。
特别注意
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun returnType(value: Any): IndexTypeCondition
+
变更记录
v1.0.70
新增
功能描述
设置
Method
返回值。
可不填写返回值。
特别注意
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun returnType(conditions: ObjectConditions): IndexTypeCondition
+
变更记录
v1.1.5
新增
功能描述
设置
Method
返回值条件。
可不填写返回值。
特别注意
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
fun superClass(isOnlySuperClass: Boolean)
+
变更记录
v1.0.80
新增
功能描述
设置在
classSet
的所有父类中查找当前Method
。
注意
若当前 classSet 的父类较多可能会耗时,API 会自动循环到父类继承是 Any 前的最后一个类。
inner class RemedyPlan internal constructor()
+
变更记录
v1.0
添加
功能描述
Method
重查找实现类,可累计失败次数直到查找成功。
inline fun method(initiate: MethodConditions): Result
+
变更记录
v1.0
添加
v1.0.80
修改
将方法体进行 inline
功能描述
创建需要重新查找的
Method
。
你可以添加多个备选 Method
,直到成功为止,若最后依然失败,将停止查找并输出错误日志。
inner class Result internal constructor()
+
变更记录
v1.0.1
新增
功能描述
RemedyPlan
结果实现类。
fun onFind(initiate: MutableList<Method>.() -> Unit)
+
变更记录
v1.0.1
新增
v1.1.0
修改
initiate
参数 Method
变为 HashSet<Method>
v1.2.0
修改
initiate
类型由 HashSet
修改为 MutableList
功能描述
当在
RemedyPlan
中找到结果时。
功能示例
你可以方便地对重查找的 Method
实现 onFind
方法。
示例如下
method {
+ // Your code here.
+}.onFind {
+ // Your code here.
+}
+
inner class Process internal constructor(internal val isNoSuch: Boolean, internal val throwable: Throwable?) : BaseResult
+
变更记录
v1.1.0
新增
功能描述
Method
查找结果处理类,为hookManager
提供。
inline fun result(initiate: Process.() -> Unit): Process
+
变更记录
v1.1.0
新增
功能描述
创建监听结果事件方法体。
功能示例
你可以使用 lambda 形式创建 Result
类。
示例如下
method {
+ // Your code here.
+}.result {
+ all()
+ remedys {}
+ onNoSuchMethod {}
+}
+
fun all(): Process
+
变更记录
v1.1.0
新增
功能描述
设置全部查找条件匹配的多个
Method
实例结果到hookManager
。
inline fun remedys(initiate: RemedyPlan.() -> Unit): Result
+
变更记录
v1.1.0
新增
功能描述
创建
Method
重查找功能。
功能示例
当你遇到一种 Method
可能存在不同形式的存在时,可以使用 RemedyPlan
重新查找它,而没有必要使用 onNoSuchMethod
捕获异常二次查找 Method
。
若第一次查找失败了,你还可以在这里继续添加此方法体直到成功为止。
示例如下
method {
+ // Your code here.
+}.remedys {
+ method {
+ // Your code here.
+ }
+ method {
+ // Your code here.
+ }
+}
+
inline fun onNoSuchMethod(result: (Throwable) -> Unit): Result
+
变更记录
v1.1.0
新增
功能描述
监听找不到
Method
时。
只会返回第一次的错误信息,不会返回 RemedyPlan
的错误信息。
inner class Result internal constructor(internal val isNoSuch: Boolean, private val throwable: Throwable?) : BaseResult
+
变更记录
v1.0
添加
v1.1.0
修改
继承到接口 BaseResult
功能描述
Method
查找结果实现类。
inline fun result(initiate: Result.() -> Unit): Result
+
变更记录
v1.0
添加
v1.0.80
修改
将方法体进行 inline
功能描述
创建监听结果事件方法体。
功能示例
你可以使用 lambda 形式创建 Result
类。
示例如下
method {
+ // Your code here.
+}.result {
+ get(instance).call()
+ all(instance)
+ remedys {}
+ onNoSuchMethod {}
+}
+
fun get(instance: Any?): Instance
+
变更记录
v1.0.2
新增
功能描述
获得
Method
实例处理类。
若有多个 Method
结果只会返回第一个。
特别注意
若你设置了 remedys 请使用 wait 回调结果方法。
功能示例
你可以通过获得方法所在实例来执行 Method
。
示例如下
method {
+ // Your code here.
+}.get(instance).call()
+
若当前为静态方法,你可以不设置实例。
示例如下
method {
+ // Your code here.
+}.get().call()
+
fun all(instance: Any?): MutableList<Instance>
+
变更记录
v1.1.0
新增
v1.2.0
修改
返回值类型由 ArrayList
修改为 MutableList
功能描述
获得
Method
实例处理类数组。
返回全部查找条件匹配的多个 Method
实例结果。
功能示例
你可以通过此方法来获得当前条件结果中匹配的全部 Method
,其方法所在实例用法与 get
相同。
示例如下
method {
+ // Your code here.
+}.all(instance).forEach { instance ->
+ instance.call(...)
+}
+
fun give(): Method?
+
变更记录
v1.0.67
新增
功能描述
得到
Method
本身。
若有多个 Method
结果只会返回第一个。
在查找条件找不到任何结果的时候将返回 null
。
fun giveAll(): MutableList<Method>
+
变更记录
v1.1.0
新增
v1.2.0
修改
返回值类型由 HashSet
修改为 MutableList
功能描述
得到
Method
本身数组。
返回全部查找条件匹配的多个 Method
实例。
在查找条件找不到任何结果的时候将返回空的 MutableList
。
fun wait(instance: Any?, initiate: Instance.() -> Unit)
+
变更记录
v1.0.2
新增
功能描述
获得
Method
实例处理类,配合RemedyPlan
使用。
若有多个 Method
结果只会返回第一个。
特别注意
若你设置了 remedys 必须使用此方法才能获得结果。
若你没有设置 remedys 此方法将不会被回调。
fun waitAll(instance: Any?, initiate: MutableList<Instance>.() -> Unit)
+
变更记录
v1.1.0
新增
v1.2.0
修改
initiate
类型由 ArrayList
修改为 MutableList
功能描述
获得
Method
实例处理类数组,配合RemedyPlan
使用。
返回全部查找条件匹配的多个 Method
实例结果。
特别注意
若你设置了 remedys 必须使用此方法才能获得结果。
若你没有设置 remedys 此方法将不会被回调。
inline fun remedys(initiate: RemedyPlan.() -> Unit): Result
+
变更记录
v1.0
添加
v1.0.80
修改
将方法体进行 inline
功能描述
创建
Method
重查找功能。
功能示例
当你遇到一种 Method
可能存在不同形式的存在时,可以使用 RemedyPlan
重新查找它,而没有必要使用 onNoSuchMethod
捕获异常二次查找 Method
。
若第一次查找失败了,你还可以在这里继续添加此方法体直到成功为止。
示例如下
method {
+ // Your code here.
+}.remedys {
+ method {
+ // Your code here.
+ }
+ method {
+ // Your code here.
+ }
+}
+
inline fun onNoSuchMethod(result: (Throwable) -> Unit): Result
+
变更记录
v1.0
添加
v1.0.80
修改
将方法体进行 inline
功能描述
监听找不到
Method
时。
只会返回第一次的错误信息,不会返回 RemedyPlan
的错误信息。
fun ignored(): Result
+
变更记录
v1.1.0
新增
功能描述
忽略异常并停止打印任何错误日志。
若 MemberBaseFinder.MemberHookerManager.isNotIgnoredNoSuchMemberFailure
为 false
则自动忽略。
注意
此时若要监听异常结果,你需要手动实现 onNoSuchMethod 方法。
变更记录
v1.0.3
新增
v1.1.0
作废
请迁移到新方法 ignored()
inner class Instance internal constructor(private val instance: Any?, private val method: Method?)
+
变更记录
v1.0.2
新增
v1.1.0
修改
新增 method
参数
功能描述
Method
实例处理类。
fun original(): Instance
+
变更记录
v1.1.0
新增
功能描述
标识需要调用当前
Method
未经 Hook 的原始方法。
若当前 Method
并未 Hook 则会使用原始的 Method.invoke
方法调用。
特别注意
你只能在 (Xposed) 宿主环境中使用此功能。
fun call(vararg args: Any?): Any?
+
变更记录
v1.0.2
新增
v1.1.6
修改
修改参数命名 param
为 args
功能描述
执行
Method
,不指定返回值类型。
fun <T> invoke(vararg args: Any?): T?
+
变更记录
v1.0.2
新增
v1.1.6
修改
修改参数命名 param
为 args
功能描述
执行
Method
,指定T
返回值类型。
fun byte(vararg args: Any?): Byte?
+
变更记录
v1.0.68
新增
v1.1.6
修改
修改参数命名 param
为 args
功能描述
执行
Method
,指定 Byte 返回值类型。
fun int(vararg args: Any?): Int
+
变更记录
v1.0.65
新增
v1.0.68
修改
修改 为 callInt
int
v1.1.6
修改
修改参数命名 param
为 args
功能描述
执行
Method
,指定 Int 返回值类型。
fun long(vararg args: Any?): Long
+
变更记录
v1.0.65
新增
v1.0.68
修改
修改 为 callLong
long
v1.1.6
修改
修改参数命名 param
为 args
功能描述
执行
Method
,指定 Long 返回值类型。
fun short(vararg args: Any?): Short
+
变更记录
v1.0.65
新增
v1.0.68
修改
修改 为 callShort
short
v1.1.6
修改
修改参数命名 param
为 args
功能描述
执行
Method
,指定 Short 返回值类型。
fun double(vararg args: Any?): Double
+
变更记录
v1.0.65
新增
v1.0.68
修改
修改 为 callDouble
double
v1.1.6
修改
修改参数命名 param
为 args
功能描述
执行
Method
,指定 Double 返回值类型。
fun float(vararg args: Any?): Float
+
变更记录
v1.0.65
新增
v1.0.68
修改
修改 为 callFloat
float
v1.1.6
修改
修改参数命名 param
为 args
功能描述
执行
Method
,指定 Float 返回值类型。
fun string(vararg args: Any?): String
+
变更记录
v1.0.65
新增
v1.0.68
修改
修改 为 callString
string
v1.1.6
修改
修改参数命名 param
为 args
功能描述
执行
Method
,指定 String 返回值类型。
fun char(vararg args: Any?): Char
+
变更记录
v1.0.68
新增
v1.1.6
修改
修改参数命名 param
为 args
功能描述
执行
Method
,指定 Char 返回值类型。
fun boolean(vararg args: Any?): Boolean
+
变更记录
v1.0.65
新增
v1.0.68
修改
修改 为 callBoolean
boolean
v1.1.6
修改
修改参数命名 param
为 args
功能描述
执行
Method
,指定 Boolean 返回值类型。
inline fun <reified T> array(vararg args: Any?): Array<T>
+
变更记录
v1.0.68
新增
v1.1.6
修改
修改参数命名 param
为 args
功能描述
执行
Method
,指定 Array 返回值类型。
inline fun <reified T> list(vararg args: Any?): List<T>
+
变更记录
v1.0.68
新增
v1.1.6
修改
修改参数命名 param
为 args
功能描述
`,469),l=[p];function c(t,d){return o(),e("div",null,l)}const i=s(n,[["render",c],["__file","MethodFinder.html.vue"]]);export{i as default}; diff --git a/assets/MethodFinder.html-DxYxJsjj.js b/assets/MethodFinder.html-DxYxJsjj.js new file mode 100644 index 00000000..2007a377 --- /dev/null +++ b/assets/MethodFinder.html-DxYxJsjj.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-a4aa4d00","path":"/en/api/public/com/highcapable/yukihookapi/hook/core/finder/members/MethodFinder.html","title":"MethodFinder - class","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"name - field","slug":"name-field","link":"#name-field","children":[]},{"level":2,"title":"paramCount - field","slug":"paramcount-field","link":"#paramcount-field","children":[]},{"level":2,"title":"returnType - field","slug":"returntype-field","link":"#returntype-field","children":[]},{"level":2,"title":"modifiers - method","slug":"modifiers-method","link":"#modifiers-method","children":[]},{"level":2,"title":"emptyParam - method","slug":"emptyparam-method","link":"#emptyparam-method","children":[]},{"level":2,"title":"param - method","slug":"param-method","link":"#param-method","children":[]},{"level":2,"title":"param - method","slug":"param-method-1","link":"#param-method-1","children":[]},{"level":2,"title":"order - method","slug":"order-method","link":"#order-method","children":[]},{"level":2,"title":"name - method","slug":"name-method","link":"#name-method","children":[]},{"level":2,"title":"name - method","slug":"name-method-1","link":"#name-method-1","children":[]},{"level":2,"title":"paramCount - method","slug":"paramcount-method","link":"#paramcount-method","children":[]},{"level":2,"title":"paramCount - method","slug":"paramcount-method-1","link":"#paramcount-method-1","children":[]},{"level":2,"title":"paramCount - method","slug":"paramcount-method-2","link":"#paramcount-method-2","children":[]},{"level":2,"title":"returnType - method","slug":"returntype-method","link":"#returntype-method","children":[]},{"level":2,"title":"returnType - method","slug":"returntype-method-1","link":"#returntype-method-1","children":[]},{"level":2,"title":"superClass - method","slug":"superclass-method","link":"#superclass-method","children":[]},{"level":2,"title":"RemedyPlan - class","slug":"remedyplan-class","link":"#remedyplan-class","children":[{"level":3,"title":"method - method","slug":"method-method","link":"#method-method","children":[]},{"level":3,"title":"Result - class","slug":"result-class","link":"#result-class","children":[]}]},{"level":2,"title":"Process - class","slug":"process-class","link":"#process-class","children":[{"level":3,"title":"result - method","slug":"result-method","link":"#result-method","children":[]},{"level":3,"title":"all - method","slug":"all-method","link":"#all-method","children":[]},{"level":3,"title":"remedys - method","slug":"remedys-method","link":"#remedys-method","children":[]},{"level":3,"title":"onNoSuchMethod - method","slug":"onnosuchmethod-method","link":"#onnosuchmethod-method","children":[]}]},{"level":2,"title":"Result - class","slug":"result-class-1","link":"#result-class-1","children":[{"level":3,"title":"result - method","slug":"result-method-1","link":"#result-method-1","children":[]},{"level":3,"title":"get - method","slug":"get-method","link":"#get-method","children":[]},{"level":3,"title":"all - method","slug":"all-method-1","link":"#all-method-1","children":[]},{"level":3,"title":"give - method","slug":"give-method","link":"#give-method","children":[]},{"level":3,"title":"giveAll - method","slug":"giveall-method","link":"#giveall-method","children":[]},{"level":3,"title":"wait - method","slug":"wait-method","link":"#wait-method","children":[]},{"level":3,"title":"waitAll - method","slug":"waitall-method","link":"#waitall-method","children":[]},{"level":3,"title":"remedys - method","slug":"remedys-method-1","link":"#remedys-method-1","children":[]},{"level":3,"title":"onNoSuchMethod - method","slug":"onnosuchmethod-method-1","link":"#onnosuchmethod-method-1","children":[]},{"level":3,"title":"ignored - method","slug":"ignored-method","link":"#ignored-method","children":[]},{"level":3,"title":"Instance - class","slug":"instance-class","link":"#instance-class","children":[]},{"level":3,"title":"array - method","slug":"array-method","link":"#array-method","children":[]},{"level":3,"title":"list - method","slug":"list-method","link":"#list-method","children":[]}]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":9}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/core/finder/members/MethodFinder.md"}');export{e as data}; diff --git a/assets/MethodRules.html-B2dSoNBv.js b/assets/MethodRules.html-B2dSoNBv.js new file mode 100644 index 00000000..73042e55 --- /dev/null +++ b/assets/MethodRules.html-B2dSoNBv.js @@ -0,0 +1,13 @@ +import{_ as a,o as s,c as e,a as o}from"./app-BpUB8-Q8.js";const n={},t=o(`执行
Method
,指定 List 返回值类型。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
class MethodRules internal constructor(private val rulesData: MethodRulesData) : BaseRules
+
Change Records
v1.1.0
added
Function Illustrate
Method
查找条件实现类。
var name: String
+
Change Records
v1.1.0
added
Function Illustrate
设置
Method
名称。
var paramCount: Int
+
Change Records
v1.1.0
added
Function Illustrate
设置
Method
参数个数。
你可以不使用 param
指定参数类型而是仅使用此变量指定参数个数。
若参数个数小于零则忽略并使用 param
。
var returnType: Any?
+
Change Records
v1.1.0
added
Function Illustrate
设置
Method
返回值。
可不填写返回值。
fun modifiers(conditions: ModifierConditions)
+
Change Records
v1.1.0
added
Function Illustrate
设置
Method
标识符筛选条件。
可不设置筛选条件。
fun emptyParam()
+
Change Records
v1.1.0
added
Function Illustrate
设置
Method
空参数、无参数。
fun param(vararg paramType: Any)
+
Change Records
v1.1.0
added
Function Illustrate
设置
Method
参数。
如果同时使用了 paramCount
则 paramType
的数量必须与 paramCount
完全匹配。
如果 Method
中存在一些无意义又很长的类型,你可以使用 VagueType
来替代它。
Pay Attention
无参 Method 请使用 emptyParam 设置查找条件。
有参 Method 必须使用此方法设定参数或使用 paramCount 指定个数。
fun param(conditions: ObjectsConditions)
+
Change Records
v1.1.5
added
Function Illustrate
设置
Method
参数条件。
Pay Attention
无参 Method 请使用 emptyParam 设置查找条件。
有参 Method 必须使用此方法设定参数或使用 paramCount 指定个数。
fun name(conditions: NameConditions)
+
Change Records
v1.1.0
added
Function Illustrate
设置
Method
名称条件。
fun paramCount(numRange: IntRange)
+
Change Records
v1.1.0
added
Function Illustrate
设置
Method
参数个数范围。
你可以不使用 param
指定参数类型而是仅使用此方法指定参数个数范围。
fun paramCount(conditions: CountConditions)
+
Change Records
v1.1.0
added
Function Illustrate
设置
Method
参数个数条件。
你可以不使用 param
指定参数类型而是仅使用此方法指定参数个数条件。
fun returnType(conditions: ObjectConditions)
+
Change Records
v1.1.5
added
Function Illustrate
设置
Method
返回值条件。
可不填写返回值。
`,85),p=[t];function c(d,l){return s(),e("div",null,p)}const i=a(n,[["render",c],["__file","MethodRules.html.vue"]]);export{i as default}; diff --git a/assets/MethodRules.html-BCtTTlLz.js b/assets/MethodRules.html-BCtTTlLz.js new file mode 100644 index 00000000..f7c32e20 --- /dev/null +++ b/assets/MethodRules.html-BCtTTlLz.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-64827680","path":"/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/MethodRules.html","title":"MethodRules - class","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"name - field","slug":"name-field","link":"#name-field","children":[]},{"level":2,"title":"paramCount - field","slug":"paramcount-field","link":"#paramcount-field","children":[]},{"level":2,"title":"returnType - field","slug":"returntype-field","link":"#returntype-field","children":[]},{"level":2,"title":"modifiers - method","slug":"modifiers-method","link":"#modifiers-method","children":[]},{"level":2,"title":"emptyParam - method","slug":"emptyparam-method","link":"#emptyparam-method","children":[]},{"level":2,"title":"param - method","slug":"param-method","link":"#param-method","children":[]},{"level":2,"title":"param - method","slug":"param-method-1","link":"#param-method-1","children":[]},{"level":2,"title":"name - method","slug":"name-method","link":"#name-method","children":[]},{"level":2,"title":"paramCount - method","slug":"paramcount-method","link":"#paramcount-method","children":[]},{"level":2,"title":"paramCount - method","slug":"paramcount-method-1","link":"#paramcount-method-1","children":[]},{"level":2,"title":"returnType - method","slug":"returntype-method","link":"#returntype-method","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":4}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/MethodRules.md"}');export{e as data}; diff --git a/assets/MethodRules.html-CW03U_a6.js b/assets/MethodRules.html-CW03U_a6.js new file mode 100644 index 00000000..1d38a33d --- /dev/null +++ b/assets/MethodRules.html-CW03U_a6.js @@ -0,0 +1,13 @@ +import{_ as s,o as a,c as o,a as e}from"./app-BpUB8-Q8.js";const n={},p=e(`注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
class MethodRules internal constructor(private val rulesData: MethodRulesData) : BaseRules
+
变更记录
v1.1.0
新增
功能描述
Method
查找条件实现类。
var name: String
+
变更记录
v1.1.0
新增
功能描述
设置
Method
名称。
var paramCount: Int
+
变更记录
v1.1.0
新增
功能描述
设置
Method
参数个数。
你可以不使用 param
指定参数类型而是仅使用此变量指定参数个数。
若参数个数小于零则忽略并使用 param
。
var returnType: Any?
+
变更记录
v1.1.0
新增
功能描述
设置
Method
返回值。
可不填写返回值。
fun modifiers(conditions: ModifierConditions)
+
变更记录
v1.1.0
新增
功能描述
设置
Method
标识符筛选条件。
可不设置筛选条件。
fun emptyParam()
+
变更记录
v1.1.0
新增
功能描述
设置
Method
空参数、无参数。
fun param(vararg paramType: Any)
+
变更记录
v1.1.0
新增
功能描述
设置
Method
参数。
如果同时使用了 paramCount
则 paramType
的数量必须与 paramCount
完全匹配。
如果 Method
中存在一些无意义又很长的类型,你可以使用 VagueType
来替代它。
特别注意
无参 Method 请使用 emptyParam 设置查找条件。
有参 Method 必须使用此方法设定参数或使用 paramCount 指定个数。
fun param(conditions: ObjectsConditions)
+
变更记录
v1.1.5
新增
功能描述
设置
Method
参数条件。
特别注意
无参 Method 请使用 emptyParam 设置查找条件。
有参 Method 必须使用此方法设定参数或使用 paramCount 指定个数。
fun name(conditions: NameConditions)
+
变更记录
v1.1.0
新增
功能描述
设置
Method
名称条件。
fun paramCount(numRange: IntRange)
+
变更记录
v1.1.0
新增
功能描述
设置
Method
参数个数范围。
你可以不使用 param
指定参数类型而是仅使用此方法指定参数个数范围。
fun paramCount(conditions: CountConditions)
+
变更记录
v1.1.0
新增
功能描述
设置
Method
参数个数条件。
你可以不使用 param
指定参数类型而是仅使用此方法指定参数个数条件。
fun returnType(conditions: ObjectConditions)
+
变更记录
v1.1.5
新增
功能描述
设置
Method
返回值条件。
可不填写返回值。
`,84),t=[p];function c(l,d){return a(),o("div",null,t)}const i=s(n,[["render",c],["__file","MethodRules.html.vue"]]);export{i as default}; diff --git a/assets/MethodRules.html-DETSSGJ6.js b/assets/MethodRules.html-DETSSGJ6.js new file mode 100644 index 00000000..32148167 --- /dev/null +++ b/assets/MethodRules.html-DETSSGJ6.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-5388621e","path":"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/MethodRules.html","title":"MethodRules - class","lang":"zh-CN","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"name - field","slug":"name-field","link":"#name-field","children":[]},{"level":2,"title":"paramCount - field","slug":"paramcount-field","link":"#paramcount-field","children":[]},{"level":2,"title":"returnType - field","slug":"returntype-field","link":"#returntype-field","children":[]},{"level":2,"title":"modifiers - method","slug":"modifiers-method","link":"#modifiers-method","children":[]},{"level":2,"title":"emptyParam - method","slug":"emptyparam-method","link":"#emptyparam-method","children":[]},{"level":2,"title":"param - method","slug":"param-method","link":"#param-method","children":[]},{"level":2,"title":"param - method","slug":"param-method-1","link":"#param-method-1","children":[]},{"level":2,"title":"name - method","slug":"name-method","link":"#name-method","children":[]},{"level":2,"title":"paramCount - method","slug":"paramcount-method","link":"#paramcount-method","children":[]},{"level":2,"title":"paramCount - method","slug":"paramcount-method-1","link":"#paramcount-method-1","children":[]},{"level":2,"title":"returnType - method","slug":"returntype-method","link":"#returntype-method","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":5}]},"filePathRelative":"zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/MethodRules.md"}');export{e as data}; diff --git a/assets/ModifierRules.html-B1V1DMvv.js b/assets/ModifierRules.html-B1V1DMvv.js new file mode 100644 index 00000000..8fcf6a08 --- /dev/null +++ b/assets/ModifierRules.html-B1V1DMvv.js @@ -0,0 +1,14 @@ +import{_ as e,o as s,c as o,a}from"./app-BpUB8-Q8.js";const d={},c=a(`Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
class ModifierRules private constructor()
+
Change Records
v1.0.67
added
v1.1.0
modified
新增 Class
的描述符判断
作为 lambda 整体判断条件使用
移动到 base 包名
私有化构造方法
Function Illustrate
这是一个
Class
、Member
描述符条件实现类。
可对 R8 混淆后的 Class
、Member
进行更加详细的定位。
val isPublic: Boolean
+
Change Records
v1.0.67
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
Class
、Member
类型是否包含public
。
val isPrivate: Boolean
+
Change Records
v1.0.67
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
Class
、Member
类型是否包含private
。
val isProtected: Boolean
+
Change Records
v1.0.67
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
Class
、Member
类型是否包含protected
。
val isStatic: Boolean
+
Change Records
v1.0.67
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
Class
、Member
类型是否包含static
。
对于任意的静态 Class
、Member
可添加此描述进行确定。
Notice
Kotlin → Jvm 后的 object 类中的方法并不是静态的。
val isFinal: Boolean
+
Change Records
v1.0.67
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
Class
、Member
类型是否包含final
。
Notice
Kotlin → Jvm 后没有 open 符号标识的 Class、Member 和没有任何关联的 Class、Member 都将为 final。
val isSynchronized: Boolean
+
Change Records
v1.0.67
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
Class
、Member
类型是否包含synchronized
。
val isVolatile: Boolean
+
Change Records
v1.0.67
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
Field
类型是否包含volatile
。
val isTransient: Boolean
+
Change Records
v1.0.67
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
Field
类型是否包含transient
。
val isNative: Boolean
+
Change Records
v1.0.67
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
Method
类型是否包含native
。
对于任意 JNI 对接的 Method
可添加此描述进行确定。
val isInterface: Boolean
+
Change Records
v1.0.67
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
Class
类型是否包含interface
。
val isAbstract: Boolean
+
Change Records
v1.0.67
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
Class
、Member
类型是否包含abstract
。
对于任意的抽象 Class
、Member
可添加此描述进行确定。
val isStrict: Boolean
+
Change Records
v1.0.67
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
`,115),n=[c];function t(i,l){return s(),o("div",null,n)}const r=e(d,[["render",t],["__file","ModifierRules.html.vue"]]);export{r as default}; diff --git a/assets/ModifierRules.html-B9KoNMo6.js b/assets/ModifierRules.html-B9KoNMo6.js new file mode 100644 index 00000000..9b8ae3bf --- /dev/null +++ b/assets/ModifierRules.html-B9KoNMo6.js @@ -0,0 +1 @@ +const i=JSON.parse('{"key":"v-547a3c3c","path":"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/ModifierRules.html","title":"ModifierRules - class","lang":"zh-CN","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"isPublic - i-ext-field","slug":"ispublic-i-ext-field","link":"#ispublic-i-ext-field","children":[]},{"level":2,"title":"isPrivate - i-ext-field","slug":"isprivate-i-ext-field","link":"#isprivate-i-ext-field","children":[]},{"level":2,"title":"isProtected - i-ext-field","slug":"isprotected-i-ext-field","link":"#isprotected-i-ext-field","children":[]},{"level":2,"title":"isStatic - i-ext-field","slug":"isstatic-i-ext-field","link":"#isstatic-i-ext-field","children":[]},{"level":2,"title":"isFinal - i-ext-field","slug":"isfinal-i-ext-field","link":"#isfinal-i-ext-field","children":[]},{"level":2,"title":"isSynchronized - i-ext-field","slug":"issynchronized-i-ext-field","link":"#issynchronized-i-ext-field","children":[]},{"level":2,"title":"isVolatile - i-ext-field","slug":"isvolatile-i-ext-field","link":"#isvolatile-i-ext-field","children":[]},{"level":2,"title":"isTransient - i-ext-field","slug":"istransient-i-ext-field","link":"#istransient-i-ext-field","children":[]},{"level":2,"title":"isNative - i-ext-field","slug":"isnative-i-ext-field","link":"#isnative-i-ext-field","children":[]},{"level":2,"title":"isInterface - i-ext-field","slug":"isinterface-i-ext-field","link":"#isinterface-i-ext-field","children":[]},{"level":2,"title":"isAbstract - i-ext-field","slug":"isabstract-i-ext-field","link":"#isabstract-i-ext-field","children":[]},{"level":2,"title":"isStrict - i-ext-field","slug":"isstrict-i-ext-field","link":"#isstrict-i-ext-field","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":2}]},"filePathRelative":"zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/ModifierRules.md"}');export{i as data}; diff --git a/assets/ModifierRules.html-DD38DB4t.js b/assets/ModifierRules.html-DD38DB4t.js new file mode 100644 index 00000000..26033a1a --- /dev/null +++ b/assets/ModifierRules.html-DD38DB4t.js @@ -0,0 +1,14 @@ +import{_ as e,o as s,c as o,a}from"./app-BpUB8-Q8.js";const c={},d=a(`
Class
、Member
类型是否包含strictfp
。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
class ModifierRules private constructor()
+
变更记录
v1.0.67
新增
v1.1.0
修改
新增 Class
的描述符判断
作为 lambda 整体判断条件使用
移动到 base 包名
私有化构造方法
功能描述
这是一个
Class
、Member
描述符条件实现类。
可对 R8 混淆后的 Class
、Member
进行更加详细的定位。
val isPublic: Boolean
+
变更记录
v1.0.67
新增
v1.1.0
修改
统一合并到扩展方法并改名
功能描述
Class
、Member
类型是否包含public
。
val isPrivate: Boolean
+
变更记录
v1.0.67
新增
v1.1.0
修改
统一合并到扩展方法并改名
功能描述
Class
、Member
类型是否包含private
。
val isProtected: Boolean
+
变更记录
v1.0.67
新增
v1.1.0
修改
统一合并到扩展方法并改名
功能描述
Class
、Member
类型是否包含protected
。
val isStatic: Boolean
+
变更记录
v1.0.67
新增
v1.1.0
修改
统一合并到扩展方法并改名
功能描述
Class
、Member
类型是否包含static
。
对于任意的静态 Class
、Member
可添加此描述进行确定。
注意
Kotlin → Jvm 后的 object 类中的方法并不是静态的。
val isFinal: Boolean
+
变更记录
v1.0.67
新增
v1.1.0
修改
统一合并到扩展方法并改名
功能描述
Class
、Member
类型是否包含final
。
注意
Kotlin → Jvm 后没有 open 符号标识的 Class、Member 和没有任何关联的 Class、Member 都将为 final。
val isSynchronized: Boolean
+
变更记录
v1.0.67
新增
v1.1.0
修改
统一合并到扩展方法并改名
功能描述
Class
、Member
类型是否包含synchronized
。
val isVolatile: Boolean
+
变更记录
v1.0.67
新增
v1.1.0
修改
统一合并到扩展方法并改名
功能描述
Field
类型是否包含volatile
。
val isTransient: Boolean
+
变更记录
v1.0.67
新增
v1.1.0
修改
统一合并到扩展方法并改名
功能描述
Field
类型是否包含transient
。
val isNative: Boolean
+
变更记录
v1.0.67
新增
v1.1.0
修改
统一合并到扩展方法并改名
功能描述
Method
类型是否包含native
。
对于任意 JNI 对接的 Method
可添加此描述进行确定。
val isInterface: Boolean
+
变更记录
v1.0.67
新增
v1.1.0
修改
统一合并到扩展方法并改名
功能描述
Class
类型是否包含interface
。
val isAbstract: Boolean
+
变更记录
v1.0.67
新增
v1.1.0
修改
统一合并到扩展方法并改名
功能描述
Class
、Member
类型是否包含abstract
。
对于任意的抽象 Class
、Member
可添加此描述进行确定。
val isStrict: Boolean
+
变更记录
v1.0.67
新增
v1.1.0
修改
统一合并到扩展方法并改名
功能描述
`,114),n=[d];function l(t,i){return s(),o("div",null,n)}const r=e(c,[["render",l],["__file","ModifierRules.html.vue"]]);export{r as default}; diff --git a/assets/ModifierRules.html-DZnBFn8R.js b/assets/ModifierRules.html-DZnBFn8R.js new file mode 100644 index 00000000..3305fa4d --- /dev/null +++ b/assets/ModifierRules.html-DZnBFn8R.js @@ -0,0 +1 @@ +const i=JSON.parse('{"key":"v-8d5ce71a","path":"/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/ModifierRules.html","title":"ModifierRules - class","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"isPublic - i-ext-field","slug":"ispublic-i-ext-field","link":"#ispublic-i-ext-field","children":[]},{"level":2,"title":"isPrivate - i-ext-field","slug":"isprivate-i-ext-field","link":"#isprivate-i-ext-field","children":[]},{"level":2,"title":"isProtected - i-ext-field","slug":"isprotected-i-ext-field","link":"#isprotected-i-ext-field","children":[]},{"level":2,"title":"isStatic - i-ext-field","slug":"isstatic-i-ext-field","link":"#isstatic-i-ext-field","children":[]},{"level":2,"title":"isFinal - i-ext-field","slug":"isfinal-i-ext-field","link":"#isfinal-i-ext-field","children":[]},{"level":2,"title":"isSynchronized - i-ext-field","slug":"issynchronized-i-ext-field","link":"#issynchronized-i-ext-field","children":[]},{"level":2,"title":"isVolatile - i-ext-field","slug":"isvolatile-i-ext-field","link":"#isvolatile-i-ext-field","children":[]},{"level":2,"title":"isTransient - i-ext-field","slug":"istransient-i-ext-field","link":"#istransient-i-ext-field","children":[]},{"level":2,"title":"isNative - i-ext-field","slug":"isnative-i-ext-field","link":"#isnative-i-ext-field","children":[]},{"level":2,"title":"isInterface - i-ext-field","slug":"isinterface-i-ext-field","link":"#isinterface-i-ext-field","children":[]},{"level":2,"title":"isAbstract - i-ext-field","slug":"isabstract-i-ext-field","link":"#isabstract-i-ext-field","children":[]},{"level":2,"title":"isStrict - i-ext-field","slug":"isstrict-i-ext-field","link":"#isstrict-i-ext-field","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":2}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/ModifierRules.md"}');export{i as data}; diff --git a/assets/ModuleAppActivity.html-BffipQvV.js b/assets/ModuleAppActivity.html-BffipQvV.js new file mode 100644 index 00000000..7552cc0f --- /dev/null +++ b/assets/ModuleAppActivity.html-BffipQvV.js @@ -0,0 +1,3 @@ +import{_ as e,o,c as s,a as t}from"./app-BpUB8-Q8.js";const a={},n=t(`
Class
、Member
类型是否包含strictfp
。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
open class ModuleAppActivity : Activity()
+
Change Records
v1.1.0
added
Function Illustrate
代理
Activity
。
继承于此类的 Activity
可以同时在宿主与模块中启动。
在 (Xposed) 宿主环境需要在宿主启动时调用 Context.registerModuleAppActivities
进行注册。
open val proxyClassName: String
+
Change Records
v1.1.10
added
Function Illustrate
设置当前代理的
Activity
类名。
留空则使用 Context.registerModuleAppActivities
时设置的类名
Pay Attention
代理的 Activity 类名必须存在于宿主的 AndroidMainifest 清单中。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
open class ModuleAppActivity : Activity()
+
变更记录
v1.1.0
新增
功能描述
代理
Activity
。
继承于此类的 Activity
可以同时在宿主与模块中启动。
在 (Xposed) 宿主环境需要在宿主启动时调用 Context.registerModuleAppActivities
进行注册。
open val proxyClassName: String
+
变更记录
v1.1.10
新增
功能描述
设置当前代理的
Activity
类名。
留空则使用 Context.registerModuleAppActivities
时设置的类名
特别注意
代理的 Activity 类名必须存在于宿主的 AndroidMainifest 清单中。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
open class ModuleAppCompatActivity : AppCompatActivity()
+
Change Records
v1.1.0
added
Function Illustrate
代理
AppCompatActivity
。
继承于此类的 Activity
可以同时在宿主与模块中启动。
在 (Xposed) 宿主环境需要在宿主启动时调用 Context.registerModuleAppActivities
进行注册。
在 (Xposed) 宿主环境需要重写 moduleTheme
设置 AppCompat 主题,否则会无法启动。
open val moduleTheme: Int
+
Change Records
v1.1.0
added
Function Illustrate
设置当前代理的
Activity
主题。
open val proxyClassName: String
+
Change Records
v1.1.10
added
Function Illustrate
设置当前代理的
Activity
类名。
留空则使用 Context.registerModuleAppActivities
时设置的类名
Pay Attention
代理的 Activity 类名必须存在于宿主的 AndroidMainifest 清单中。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
open class ModuleAppCompatActivity : AppCompatActivity()
+
变更记录
v1.1.0
新增
功能描述
代理
AppCompatActivity
。
继承于此类的 Activity
可以同时在宿主与模块中启动。
在 (Xposed) 宿主环境需要在宿主启动时调用 Context.registerModuleAppActivities
进行注册。
在 (Xposed) 宿主环境需要重写 moduleTheme
设置 AppCompat 主题,否则会无法启动。
open val moduleTheme: Int
+
变更记录
v1.1.0
新增
功能描述
设置当前代理的
Activity
主题。
open val proxyClassName: String
+
变更记录
v1.1.10
新增
功能描述
设置当前代理的
Activity
类名。
留空则使用 Context.registerModuleAppActivities
时设置的类名
特别注意
代理的 Activity 类名必须存在于宿主的 AndroidMainifest 清单中。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
open class ModuleApplication: Application()
+
变更记录
v1.0.77
新增
功能描述
这是对使用
YukiHookAPI
Xposed 模块实现中的一个扩展功能。
在你的 Xposed 模块的 Application
中继承此类。
或在 AndroidManifest.xml
的 application
标签中指定此类。
目前可实现功能如下
`,10),r=a("全局共享模块中静态的 appContext
在模块与宿主中装载 YukiHookAPI.Config
以确保 YukiHookAPI.Configs.debugTag
不需要重复定义
在模块与宿主中使用 YukiHookDataChannel
进行通讯
功能示例
将此类继承到你的自定义 Application
上。
示例如下
package com.demo
+
+class MyApplication: ModuleApplication() {
+
+ override fun onCreate() {
+ super.onCreate()
+ }
+}
+
在 AndroidManifest.xml
的 application
标签中指定自定义的 Application
。
示例如下
<application
+ android:name="com.demo.MyApplication"
+ ...>
+
如果你不需要自定义 Application
可以直接将 ModuleApplication
设置到 AndroidManifest.xml
的 application
标签中。
示例如下
<application
+ android:name="com.highcapable.yukihookapi.hook.xposed.application.ModuleApplication"
+ ...>
+
val appContext: ModuleApplication
+
变更记录
v1.0.77
新增
功能描述
`,16);function y(b,k){const e=l("ExternalLinkIcon");return p(),c("div",null,[d,s("ul",null,[r,s("li",null,[s("p",null,[n("在模块中使用系统隐藏 API,核心技术引用了开源项目 "),s("a",u,[n("FreeReflection"),i(e)])])]),A]),m])}const D=o(t,[["render",y],["__file","ModuleApplication.html.vue"]]);export{D as default}; diff --git a/assets/ModuleApplication.html-BkkBbb-2.js b/assets/ModuleApplication.html-BkkBbb-2.js new file mode 100644 index 00000000..4f29f706 --- /dev/null +++ b/assets/ModuleApplication.html-BkkBbb-2.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-7fec5836","path":"/en/api/public/com/highcapable/yukihookapi/hook/xposed/application/ModuleApplication.html","title":"ModuleApplication - class","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"appContext - field","slug":"appcontext-field","link":"#appcontext-field","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":2}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/xposed/application/ModuleApplication.md"}');export{e as data}; diff --git a/assets/ModuleApplication.html-C4NqW1gZ.js b/assets/ModuleApplication.html-C4NqW1gZ.js new file mode 100644 index 00000000..b96a67c5 --- /dev/null +++ b/assets/ModuleApplication.html-C4NqW1gZ.js @@ -0,0 +1 @@ +const a=JSON.parse('{"key":"v-4709ad58","path":"/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/application/ModuleApplication.html","title":"ModuleApplication - class","lang":"zh-CN","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"appContext - field","slug":"appcontext-field","link":"#appcontext-field","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":2}]},"filePathRelative":"zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/application/ModuleApplication.md"}');export{a as data}; diff --git a/assets/ModuleApplication.html-DYtHym0q.js b/assets/ModuleApplication.html-DYtHym0q.js new file mode 100644 index 00000000..3e569754 --- /dev/null +++ b/assets/ModuleApplication.html-DYtHym0q.js @@ -0,0 +1,17 @@ +import{_ as o,r as l,o as p,c,b as s,d as e,e as i,a as n}from"./app-BpUB8-Q8.js";const t={},d=n(`获取全局静态
Application
实例。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
open class ModuleApplication: Application()
+
Change Records
v1.0.77
added
Function Illustrate
这是对使用
YukiHookAPI
Xposed 模块实现中的一个扩展功能。
在你的 Xposed 模块的 Application
中继承此类。
或在 AndroidManifest.xml
的 application
标签中指定此类。
目前可实现功能如下
`,11),r=n("全局共享模块中静态的 appContext
在模块与宿主中装载 YukiHookAPI.Config
以确保 YukiHookAPI.Configs.debugTag
不需要重复定义
在模块与宿主中使用 YukiHookDataChannel
进行通讯
Function Example
将此类继承到你的自定义 Application
上。
The following example
package com.demo
+
+class MyApplication: ModuleApplication() {
+
+ override fun onCreate() {
+ super.onCreate()
+ }
+}
+
在 AndroidManifest.xml
的 application
标签中指定自定义的 Application
。
The following example
<application
+ android:name="com.demo.MyApplication"
+ ...>
+
如果你不需要自定义 Application
可以直接将 ModuleApplication
设置到 AndroidManifest.xml
的 application
标签中。
The following example
<application
+ android:name="com.highcapable.yukihookapi.hook.xposed.application.ModuleApplication"
+ ...>
+
val appContext: ModuleApplication
+
Change Records
v1.0.77
added
Function Illustrate
`,16);function y(h,v){const a=l("ExternalLinkIcon");return p(),c("div",null,[d,s("ul",null,[r,s("li",null,[s("p",null,[e("在模块中使用系统隐藏 API,核心技术引用了开源项目 "),s("a",u,[e("FreeReflection"),i(a)])])]),A]),m])}const g=o(t,[["render",y],["__file","ModuleApplication.html.vue"]]);export{g as default}; diff --git a/assets/ModuleClassLoader.html-BFtfl5mt.js b/assets/ModuleClassLoader.html-BFtfl5mt.js new file mode 100644 index 00000000..97bd14c3 --- /dev/null +++ b/assets/ModuleClassLoader.html-BFtfl5mt.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-2d4e0da6","path":"/en/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/reference/ModuleClassLoader.html","title":"ModuleClassLoader - class","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"companion object - object","slug":"companion-object-object","link":"#companion-object-object","children":[{"level":3,"title":"excludeHostClasses - method","slug":"excludehostclasses-method","link":"#excludehostclasses-method","children":[]},{"level":3,"title":"excludeModuleClasses - method","slug":"excludemoduleclasses-method","link":"#excludemoduleclasses-method","children":[]}]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":2}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/reference/ModuleClassLoader.md"}');export{e as data}; diff --git a/assets/ModuleClassLoader.html-BbehDNqJ.js b/assets/ModuleClassLoader.html-BbehDNqJ.js new file mode 100644 index 00000000..e2465912 --- /dev/null +++ b/assets/ModuleClassLoader.html-BbehDNqJ.js @@ -0,0 +1,4 @@ +import{_ as s,o as e,c as o,a}from"./app-BpUB8-Q8.js";const n={},c=a(`获取全局静态
Application
实例。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
class ModuleClassLoader private constructor() : ClassLoader
+
Change Records
v1.1.2
added
Function Illustrate
自动处理 (Xposed) 宿主环境与模块环境的
ClassLoader
。
Change Records
v1.1.2
added
fun excludeHostClasses(vararg name: String)
+
Change Records
v1.1.2
added
Function Illustrate
添加到 Hook APP (宿主)
Class
排除列表。
排除列表中的 Class
将会使用宿主的 ClassLoader
进行装载。
Pay Attention
排除列表仅会在 (Xposed) 宿主环境生效。
fun excludeModuleClasses(vararg name: String)
+
Change Records
v1.1.2
added
Function Illustrate
添加到模块
Class
排除列表。
排除列表中的 Class
将会使用模块 (当前宿主环境的模块注入进程) 的 ClassLoader
进行装载。
Pay Attention
排除列表仅会在 (Xposed) 宿主环境生效。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
class ModuleClassLoader private constructor() : ClassLoader
+
变更记录
v1.1.2
新增
功能描述
自动处理 (Xposed) 宿主环境与模块环境的
ClassLoader
。
变更记录
v1.1.2
新增
fun excludeHostClasses(vararg name: String)
+
变更记录
v1.1.2
新增
功能描述
添加到 Hook APP (宿主)
Class
排除列表。
排除列表中的 Class
将会使用宿主的 ClassLoader
进行装载。
特别注意
排除列表仅会在 (Xposed) 宿主环境生效。
fun excludeModuleClasses(vararg name: String)
+
变更记录
v1.1.2
新增
功能描述
添加到模块
Class
排除列表。
排除列表中的 Class
将会使用模块 (当前宿主环境的模块注入进程) 的 ClassLoader
进行装载。
特别注意
排除列表仅会在 (Xposed) 宿主环境生效。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
class ModuleContextThemeWrapper private constructor(baseContext: Context, theme: Int, configuration: Configuration?) : ContextThemeWrapper
+
Change Records
v1.1.0
added
Function Illustrate
代理
ContextThemeWrapper
。
通过包装,你可以轻松在 (Xposed) 宿主环境使用来自模块的主题资源。
fun applyConfiguration(initiate: Configuration.() -> Unit): ModuleContextThemeWrapper
+
Change Records
v1.1.0
added
Function Illustrate
设置当前
ModuleContextThemeWrapper
的Configuration
。
设置后会自动调用 Resources.updateConfiguration
。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
class ModuleContextThemeWrapper private constructor(baseContext: Context, theme: Int, configuration: Configuration?) : ContextThemeWrapper
+
变更记录
v1.1.0
新增
功能描述
代理
ContextThemeWrapper
。
通过包装,你可以轻松在 (Xposed) 宿主环境使用来自模块的主题资源。
fun applyConfiguration(initiate: Configuration.() -> Unit): ModuleContextThemeWrapper
+
变更记录
v1.1.0
新增
功能描述
设置当前
ModuleContextThemeWrapper
的Configuration
。
设置后会自动调用 Resources.updateConfiguration
。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
abstract class ModulePreferenceFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedPreferenceChangeListener
+
变更记录
v1.0.78
新增
功能描述
这是对使用
YukiHookAPI
Xposed 模块实现中的一个扩展功能。
此类接管了 PreferenceFragmentCompat
并对其实现了 Sp 存储在 Xposed 模块中的全局可读可写。
在你使用 PreferenceFragmentCompat
的实例中,将继承对象换成此类。
然后请将重写方法由 onCreatePreferences
替换为 onCreatePreferencesInModuleApp
即可。
功能示例
使用 ModulePreferenceFragment
创建一个 PreferenceFragmentCompat
对象。
示例如下
class SettingsFragment : ModulePreferenceFragment() {
+
+ override fun onCreatePreferencesInModuleApp(savedInstanceState: Bundle?, rootKey: String?) {
+ setPreferencesFromResource(R.xml.settings_preferences, rootKey)
+ // Your code here.
+ }
+}
+
其余用法与 PreferenceFragmentCompat
保持一致。
abstract fun onCreatePreferencesInModuleApp(savedInstanceState: Bundle?, rootKey: String?)
+
变更记录
v1.0.78
新增
功能描述
对接原始方法
onCreatePreferences
。
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?)
+
变更记录
v1.0.78
新增
功能描述
实现了
SharedPreferences.OnSharedPreferenceChangeListener
的原生监听功能。
功能示例
注意
在使用 onSharedPreferenceChanged 时请保留 super 方法。
示例如下
class SettingsFragment : ModulePreferenceFragment() {
+
+ override fun onCreatePreferencesInModuleApp(savedInstanceState: Bundle?, rootKey: String?) {
+ // ...
+ }
+
+ override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
+ super.onSharedPreferenceChanged(sharedPreferences, key)
+ // Your code here.
+ }
+}
+
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
abstract class ModulePreferenceFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedPreferenceChangeListener
+
Change Records
v1.0.78
added
Function Illustrate
这是对使用
YukiHookAPI
Xposed 模块实现中的一个扩展功能。
此类接管了 PreferenceFragmentCompat
并对其实现了 Sp 存储在 Xposed 模块中的全局可读可写。
在你使用 PreferenceFragmentCompat
的实例中,将继承对象换成此类。
然后请将重写方法由 onCreatePreferences
替换为 onCreatePreferencesInModuleApp
即可。
Function Example
使用 ModulePreferenceFragment
创建一个 PreferenceFragmentCompat
对象。
The following example
class SettingsFragment : ModulePreferenceFragment() {
+
+ override fun onCreatePreferencesInModuleApp(savedInstanceState: Bundle?, rootKey: String?) {
+ setPreferencesFromResource(R.xml.settings_preferences, rootKey)
+ // Your code here.
+ }
+}
+
其余用法与 PreferenceFragmentCompat
保持一致。
abstract fun onCreatePreferencesInModuleApp(savedInstanceState: Bundle?, rootKey: String?)
+
Change Records
v1.0.78
added
Function Illustrate
对接原始方法
onCreatePreferences
。
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?)
+
Change Records
v1.0.78
added
Function Illustrate
实现了
SharedPreferences.OnSharedPreferenceChangeListener
的原生监听功能。
Function Example
Notice
在使用 onSharedPreferenceChanged 时请保留 super 方法。
The following example
class SettingsFragment : ModulePreferenceFragment() {
+
+ override fun onCreatePreferencesInModuleApp(savedInstanceState: Bundle?, rootKey: String?) {
+ // ...
+ }
+
+ override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
+ super.onSharedPreferenceChanged(sharedPreferences, key)
+ // Your code here.
+ }
+}
+
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
class NameRules private constructor()
+
Change Records
v1.0.88
added
v1.1.0
modified
更名为 NameConditions
NameRules
作为 lambda 整体判断条件使用
移动到 base 包名
私有化构造方法
Function Illustrate
这是一个模糊
Class
、Member
名称条件实现类。
可对 R8 混淆后的 Class
、Member
进行更加详细的定位。
fun String.isSynthetic(index: Int): Boolean
+
Change Records
v1.0.88
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
是否为匿名类的主类调用对象。
fun String.isOnlySymbols(): Boolean
+
Change Records
v1.0.88
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
是否只有符号。
fun String.isOnlyLetters(): Boolean
+
Change Records
v1.0.88
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
是否只有字母。
fun String.isOnlyNumbers(): Boolean
+
Change Records
v1.0.88
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
是否只有数字。
fun String.isOnlyLettersNumbers(): Boolean
+
Change Records
v1.0.88
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
是否只有字母或数字。
fun String.isOnlyLowercase(): Boolean
+
Change Records
v1.0.88
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
是否只有小写字母。
在没有其它条件的情况下设置此条件允许判断对象存在字母以外的字符。
fun String.isOnlyUppercase(): Boolean
+
Change Records
v1.0.88
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
是否只有大写字母。
在没有其它条件的情况下设置此条件允许判断对象存在字母以外的字符。
`,72),l=[t];function c(p,d){return e(),o("div",null,l)}const i=s(a,[["render",c],["__file","NameRules.html.vue"]]);export{i as default}; diff --git a/assets/NameRules.html-DopiK4pt.js b/assets/NameRules.html-DopiK4pt.js new file mode 100644 index 00000000..426c9068 --- /dev/null +++ b/assets/NameRules.html-DopiK4pt.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-58c26516","path":"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/NameRules.html","title":"NameRules - class","lang":"zh-CN","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"String.isSynthetic - i-ext-method","slug":"string-issynthetic-i-ext-method","link":"#string-issynthetic-i-ext-method","children":[]},{"level":2,"title":"String.isOnlySymbols - i-ext-method","slug":"string-isonlysymbols-i-ext-method","link":"#string-isonlysymbols-i-ext-method","children":[]},{"level":2,"title":"String.isOnlyLetters - i-ext-method","slug":"string-isonlyletters-i-ext-method","link":"#string-isonlyletters-i-ext-method","children":[]},{"level":2,"title":"String.isOnlyNumbers - i-ext-method","slug":"string-isonlynumbers-i-ext-method","link":"#string-isonlynumbers-i-ext-method","children":[]},{"level":2,"title":"String.isOnlyLettersNumbers - i-ext-method","slug":"string-isonlylettersnumbers-i-ext-method","link":"#string-isonlylettersnumbers-i-ext-method","children":[]},{"level":2,"title":"String.isOnlyLowercase - i-ext-method","slug":"string-isonlylowercase-i-ext-method","link":"#string-isonlylowercase-i-ext-method","children":[]},{"level":2,"title":"String.isOnlyUppercase - i-ext-method","slug":"string-isonlyuppercase-i-ext-method","link":"#string-isonlyuppercase-i-ext-method","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":3}]},"filePathRelative":"zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/NameRules.md"}');export{e as data}; diff --git a/assets/NameRules.html-zuU55Nke.js b/assets/NameRules.html-zuU55Nke.js new file mode 100644 index 00000000..4df0791b --- /dev/null +++ b/assets/NameRules.html-zuU55Nke.js @@ -0,0 +1,9 @@ +import{_ as s,o as e,c as o,a as n}from"./app-BpUB8-Q8.js";const a={},p=n(`注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
class NameRules private constructor()
+
变更记录
v1.0.88
新增
v1.1.0
修改
更名为 NameConditions
NameRules
作为 lambda 整体判断条件使用
移动到 base 包名
私有化构造方法
功能描述
这是一个模糊
Class
、Member
名称条件实现类。
可对 R8 混淆后的 Class
、Member
进行更加详细的定位。
fun String.isSynthetic(index: Int): Boolean
+
变更记录
v1.0.88
新增
v1.1.0
修改
统一合并到扩展方法并改名
功能描述
是否为匿名类的主类调用对象。
fun String.isOnlySymbols(): Boolean
+
变更记录
v1.0.88
新增
v1.1.0
修改
统一合并到扩展方法并改名
功能描述
是否只有符号。
fun String.isOnlyLetters(): Boolean
+
变更记录
v1.0.88
新增
v1.1.0
修改
统一合并到扩展方法并改名
功能描述
是否只有字母。
fun String.isOnlyNumbers(): Boolean
+
变更记录
v1.0.88
新增
v1.1.0
修改
统一合并到扩展方法并改名
功能描述
是否只有数字。
fun String.isOnlyLettersNumbers(): Boolean
+
变更记录
v1.0.88
新增
v1.1.0
修改
统一合并到扩展方法并改名
功能描述
是否只有字母或数字。
fun String.isOnlyLowercase(): Boolean
+
变更记录
v1.0.88
新增
v1.1.0
修改
统一合并到扩展方法并改名
功能描述
是否只有小写字母。
在没有其它条件的情况下设置此条件允许判断对象存在字母以外的字符。
fun String.isOnlyUppercase(): Boolean
+
变更记录
v1.0.88
新增
v1.1.0
修改
统一合并到扩展方法并改名
功能描述
是否只有大写字母。
在没有其它条件的情况下设置此条件允许判断对象存在字母以外的字符。
`,71),l=[p];function t(c,r){return e(),o("div",null,l)}const i=s(a,[["render",t],["__file","NameRules.html.vue"]]);export{i as default}; diff --git a/assets/ObjectRules.html-1b_D9aS8.js b/assets/ObjectRules.html-1b_D9aS8.js new file mode 100644 index 00000000..a8eb85d5 --- /dev/null +++ b/assets/ObjectRules.html-1b_D9aS8.js @@ -0,0 +1,2 @@ +import{_ as e,o as s,c as o,a as t}from"./app-BpUB8-Q8.js";const a={},n=t(`Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
class ObjectRules private constructor(private val instance: Any)
+
Change Records
v1.1.5
added
Function Illustrate
这是一个任意对象条件实现类。
可对 R8 混淆后的 Class
、Member
进行更加详细的定位。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
class ObjectRules private constructor(private val instance: Any)
+
变更记录
v1.1.5
新增
功能描述
这是一个任意对象条件实现类。
可对 R8 混淆后的 Class
、Member
进行更加详细的定位。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
open class PackageParam internal constructor(internal var wrapper: PackageParamWrapper?)
+
变更记录
v1.0
添加
功能描述
装载 Hook 的目标 APP 入口对象实现类。
var appClassLoader:ClassLoader?
+
变更记录
v1.0
添加
v1.1.5
修改
可以动态修改此变量的值
v1.2.0
修改
加入可空类型 (空安全)
功能描述
获取、设置当前 Hook APP 的
ClassLoader
。
你可以在这里手动设置当前 Hook APP 的 ClassLoader
,默认情况下会自动获取。
特别注意
如果设置了错误或无效的 ClassLoader 会造成功能异常,请谨慎操作。
val appInfo: ApplicationInfo
+
变更记录
v1.0
添加
功能描述
获取当前 Hook APP 的
ApplicationInfo
。
val appUserId: Int
+
变更记录
v1.1.0
新增
功能描述
获取当前 Hook APP 的用户 ID。
机主为 0
,应用双开 (分身) 或工作资料因系统环境不同 ID 也各不相同。
val appContext: Application?
+
变更记录
v1.0.72
新增
v1.1.0
修改
加入可空类型 (空安全)
功能描述
获取当前 Hook APP 的
Application
。
特别注意
首次装载可能是空的,请延迟一段时间再获取或使用 onAppLifecycle 监听来完成。
val appResources:Resources?
+
变更记录
v1.0.80
新增
v1.1.0
修改
加入可空类型 (空安全)
功能描述
获取当前 Hook APP 的 Resources。
特别注意
你只能在 HookResources.hook 方法体内或 appContext 装载完毕时进行调用。
val systemContext: Context
+
变更记录
v1.1.0
新增
功能描述
获取当前系统框架的
Context
。
val processName: String
+
变更记录
v1.0
添加
功能描述
获取当前 Hook APP 的进程名称。
val packageName: String
+
变更记录
v1.0
添加
功能描述
获取当前 Hook APP 的包名。
val isFirstApplication: Boolean
+
变更记录
v1.0
添加
功能描述
获取当前 Hook APP 是否为第一个
Application
。
val mainProcessName: String
+
变更记录
v1.0.70
新增
功能描述
获取当前 Hook APP 的主进程名称。
其对应的就是 packageName
。
val moduleAppFilePath: String
+
变更记录
v1.0.80
新增
功能描述
获取当前 Xposed 模块自身 APK 文件路径。
特别注意
作为 Hook API 装载时无法使用,会获取到空字符串。
val moduleAppResources: YukiModuleResources
+
变更记录
v1.0.80
新增
功能描述
获取当前 Xposed 模块自身
Resources
。
特别注意
作为 Hook API 或不支持的 Hook Framework 装载时无法使用,会抛出异常。
val prefs: YukiHookPrefsBridge
+
变更记录
v1.0
添加
功能描述
创建
YukiHookPrefsBridge
对象。
特别注意
作为 Hook API 装载时无法使用,会抛出异常。
fun prefs(name: String): YukiHookPrefsBridge
+
变更记录
v1.0
添加
v1.0.80
修改
将方法体进行 inline
功能描述
创建
YukiHookPrefsBridge
对象。
你可以通过 name
来自定义 Sp 存储的名称。
特别注意
作为 Hook API 装载时无法使用,会抛出异常。
val dataChannel: YukiHookDataChannel.NameSpace
+
变更记录
v1.0.88
新增
功能描述
获取
YukiHookDataChannel
对象。
特别注意
作为 Hook API 装载时无法使用,会抛出异常。
fun resources(): HookResources
+
变更记录
v1.0.80
新增
功能描述
获得当前 Hook APP 的
YukiResources
对象。
请调用 HookResources.hook
方法开始 Hook。
fun refreshModuleAppResources()
+
变更记录
v1.0.87
新增
功能描述
刷新当前 Xposed 模块自身
Resources
。
inline fun onAppLifecycle(isOnFailureThrowToApp: Boolean, initiate: AppLifecycle.() -> Unit)
+
变更记录
v1.0.88
新增
v1.1.5
修改
新增 isOnFailureThrowToApp
参数,可选择将异常在 (Xposed) 宿主环境打印而不是抛出给宿主
功能描述
监听当前 Hook APP 生命周期装载事件。
注意
在 loadZygote 中不会被装载,仅会在 loadSystem、loadApp 中装载。
作为 Hook API 装载时请使用原生的 Application 实现生命周期监听。
inline fun loadApp(name: String, initiate: PackageParam.() -> Unit)
+
fun loadApp(name: String, hooker: YukiBaseHooker)
+
inline fun loadApp(vararg name: String, initiate: PackageParam.() -> Unit)
+
fun loadApp(name: String, vararg hooker: YukiBaseHooker)
+
inline fun loadApp(isExcludeSelf: Boolean, initiate: PackageParam.() -> Unit)
+
fun loadApp(isExcludeSelf: Boolean, hooker: YukiBaseHooker)
+
fun loadApp(isExcludeSelf: Boolean, vararg hooker: YukiBaseHooker)
+
变更记录
v1.0
添加
v1.0.80
修改
将方法体进行 inline
v1.1.4
修改
新增两个方法,可以同时装载多个 APP 与子 Hooker
v1.1.5
修改
新增三个方法,可以使用参数 isExcludeSelf
排除模块自身
功能描述
装载并 Hook 指定、全部包名的 APP。
name
为 APP 的包名,后方的两个参数一个可作为 lambda 方法体使用,一个可以直接装载子 Hooker。
装载并 Hook 指定、全部包名的 APP。
若要装载 APP Zygote 事件,请使用 loadZygote
。
若要 Hook 系统框架,请使用 loadSystem
。
功能示例
你可以使用 loadApp
的 lambda 方法体形式或直接装载一个 Hooker。
示例如下
// 使用 lambda
+loadApp(name = "com.example.test") {
+ // Your code here.
+}
+// 使用 Hooker
+loadApp(name = "com.example.test", CustomHooker)
+
若不指定 name
参数,则此方法体默认会过滤当前系统中全部可被 Hook 的 APP。
示例如下
// 使用 lambda
+loadApp {
+ // Your code here.
+}
+// 使用 Hooker
+loadApp(hooker = CustomHooker)
+
若要在全部可被 Hook 的 APP 中过滤掉模块自身,你只需加入 isExcludeSelf = true
。
示例如下
// 使用 lambda
+loadApp(isExcludeSelf = true) {
+ // Your code here.
+}
+// 使用 Hooker
+loadApp(isExcludeSelf = true, hooker = CustomHooker)
+
若想要同时装载多个需要 Hook 的 APP,可以直接使用如下方式。
示例如下
// 同时装载多个需要 Hook 的 APP
+loadApp("com.example.test", "com.example.next") {
+ // Your code here.
+}
+
若想要同时装载多个子 Hooker,可以直接使用如下方式,但此时只能指定一个需要 Hook 的 APP。
示例如下
// 同时装载多个子 Hooker
+loadApp("com.example.test", CustomHooker1, CustomHooker2)
+
inline fun loadZygote(initiate: PackageParam.() -> Unit)
+
fun loadZygote(hooker: YukiBaseHooker)
+
fun loadZygote(vararg hooker: YukiBaseHooker)
+
变更记录
v1.0.80
新增
v1.1.4
修改
新增一个方法,可以同时装载多个子 Hooker
功能描述
装载 APP Zygote 事件。
方法中的两个参数一个可作为 lambda 方法体使用,一个可以直接装载子 Hooker。
inline fun loadSystem(initiate: PackageParam.() -> Unit)
+
fun loadSystem(hooker: YukiBaseHooker)
+
fun loadSystem(vararg hooker: YukiBaseHooker)
+
变更记录
v1.0.82
新增
v1.1.4
修改
新增一个方法,可以同时装载多个子 Hooker
功能描述
装载并 Hook 系统框架。
方法中的两个参数一个可作为 lambda 方法体使用,一个可以直接装载子 Hooker。
inline fun withProcess(name: String, initiate: PackageParam.() -> Unit)
+
fun withProcess(name: String, hooker: YukiBaseHooker)
+
fun withProcess(vararg name: String, hooker: YukiBaseHooker)
+
fun withProcess(name: String, vararg hooker: YukiBaseHooker)
+
变更记录
v1.0.70
新增
v1.1.4
修改
新增两个方法,可以同时装载多个进程与子 Hooker
功能描述
装载并 Hook APP 的指定进程。
name
为 APP 的进程名称,后方的两个参数一个可作为 lambda 方法体使用,一个可以直接装载子 Hooker。
fun loadHooker(hooker: YukiBaseHooker)
+
变更记录
v1.0
添加
功能描述
装载 Hook 子类。
你可以填入 hooker
在 Hooker 中继续装载 Hooker。
inline fun searchClass(name: String, async: Boolean, initiate: ClassConditions): DexClassFinder.Result
+
变更记录
v1.1.0
新增
功能描述
通过
appClassLoader
按指定条件查找并得到当前 Hook APP Dex 中的Class
。
特别注意
此方法在 Class 数量过多及查找条件复杂时会非常耗时。
建议启用 async 或设置 name 参数,name 参数将在 Hook APP (宿主) 不同版本中自动进行本地缓存以提升效率。
此功能尚在实验阶段,性能与稳定性可能仍然存在问题,使用过程遇到问题请向我们报告并帮助我们改进。
变更记录
v1.0
添加
v1.1.0
作废
请迁移到 toClass(...)
方法
变更记录
v1.0
添加
v1.1.0
作废
请迁移到 hasClass(...)
方法
fun String.toClass(loader: ClassLoader?, initialize: Boolean): Class<*>
+
inline fun <reified T> String.toClass(loader: ClassLoader?, initialize: Boolean): Class<T>
+
fun VariousClass.toClass(loader: ClassLoader?, initialize: Boolean): Class<*>
+
变更记录
v1.1.0
新增
v1.1.5
修改
新增泛型返回值 Class<T>
方法
新增 initialize
参数
功能描述
通过字符串类名、
VariousClass
转换为loader
中的实体类。
默认使用当前 appClassLoader
装载目标 Class
。
功能示例
你可以轻松地将 String
类型的 Class
包名转为 Class
实例。
示例如下
"com.example.demo.DemoClass".toClass()
+
你还可以向 loader
参数传入你自定义的 ClassLoader
。
示例如下
val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader
+"com.example.demo.DemoClass".toClass(customClassLoader)
+
你还可以指定 Class
的目标类型。
示例如下
// 指定的 DemoClass 必须存在或为可访问的 stub
+"com.example.demo.DemoClass".toClass<DemoClass>()
+
你还可以设置在获取到这个 Class
时是否自动执行其默认的静态方法块,默认情况下不会执行。
示例如下
// 获取并执行 DemoClass 默认的静态方法块
+"com.example.demo.DemoClass".toClass(initialize = true)
+
默认的静态方法块在 Java 中使用如下方式定义。
示例如下
public class DemoClass {
+
+ static {
+ // 这里是静态方法块的内容
+ }
+
+ public DemoClass() {
+ // ...
+ }
+}
+
你还可以创建一个 VariousClass
,并转换为实体类。
VariousClass
会枚举所有设置的 Class
并最终获得第一个存在的 Class
。
示例如下
VariousClass("com.example.demo.DemoClass1", "com.example.demo.DemoClass2").toClass()
+
同样地,你还可以向 loader
参数传入你自定义的 ClassLoader
。
示例如下
val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader
+VariousClass("com.example.demo.DemoClass1", "com.example.demo.DemoClass2").toClass(customClassLoader)
+
fun String.toClassOrNull(loader: ClassLoader?, initialize: Boolean): Class<*>?
+
inline fun <reified T> String.toClassOrNull(loader: ClassLoader?, initialize: Boolean): Class<T>?
+
fun VariousClass.toClassOrNull(loader: ClassLoader?, initialize: Boolean): Class<*>?
+
变更记录
v1.1.0
新增
v1.1.5
修改
新增泛型返回值 Class<T>
方法
新增 initialize
参数
功能描述
通过字符串类名、
VariousClass
转换为loader
中的实体类。
默认使用当前 appClassLoader
装载目标 Class
。
找不到 Class
会返回 null
,不会抛出异常。
功能示例
用法请参考 String+VariousClass.toClass 方法。
fun lazyClass(name: String, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.NonNull<Any>
+
inline fun <reified T> lazyClass(name: String, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.NonNull<T>
+
fun lazyClass(variousClass: VariousClass, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.NonNull<Any>
+
变更记录
v1.2.0
新增
功能描述
懒装载
Class
。
fun lazyClassOrNull(name: String, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.Nullable<Any>
+
inline fun <reified T> lazyClassOrNull(name: String, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.Nullable<T>
+
fun lazyClassOrNull(variousClass: VariousClass, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.Nullable<Any>
+
变更记录
v1.2.0
新增
功能描述
懒装载
Class
。
fun String.hasClass(loader: ClassLoader?): Boolean
+
变更记录
v1.1.0
新增
功能描述
通过字符串类名查找是否存在。
默认使用当前 appClassLoader
装载目标 Class
。
功能示例
你可以轻松的使用此方法判断字符串中的类是否存在。
示例如下
if("com.example.demo.DemoClass".hasClass()) {
+ // Your code here.
+}
+
你还可以自定义其中的 loader
参数,默认为 appClassLoader
。
示例如下
val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader
+if("com.example.demo.DemoClass".hasClass(customClassLoader)) {
+ // Your code here.
+}
+
变更记录
v1.0
添加
v1.0.1
修改
移除了 方法findClass(various: VariousClass)
v1.1.0
修改
新增 loader
参数
v1.2.0
作废
请直接使用 String.toClass(...)
或 VariousClass(...)
inline fun Class<*>.hook(isForceUseAbsolute: Boolean, initiate: YukiMemberHookCreator.() -> Unit): YukiMemberHookCreator.Result
+
inline fun VariousClass.hook(initiate: YukiMemberHookCreator.() -> Unit): YukiMemberHookCreator.Result
+
inline fun HookClass.hook(initiate: YukiMemberHookCreator.() -> Unit): YukiMemberHookCreator.Result
+
变更记录
v1.0
添加
v1.0.1
修改
新增 VariousClass
的直接调用 hook
方法
v1.0.2
修改
新增 String
的直接调用 hook
方法
v1.0.3
修改
新增 YukiMemberHookCreator.Result
返回值
v1.0.70
修改
新增 isUseAppClassLoader
参数
v1.0.80
修改
将方法体进行 inline
v1.1.0
修改
移除了 参数isUseAppClassLoader
添加了 isForceUseAbsolute
参数到 Class.hook
方法
v1.2.0
修改
作废了 方法String.hook
功能描述
Hook 方法、构造方法。
inline fun Member.hook(priority: YukiHookPriority): YukiMemberHookCreator.MemberHookCreator
+
inline fun Member.hook(priority: YukiHookPriority, initiate: YukiMemberHookCreator.MemberHookCreator.() -> Unit): YukiMemberHookCreator.MemberHookCreator.Result
+
inline fun BaseFinder.BaseResult.hook(priority: YukiHookPriority): YukiMemberHookCreator.MemberHookCreator
+
inline fun BaseFinder.BaseResult.hook(priority: YukiHookPriority, initiate: YukiMemberHookCreator.MemberHookCreator.() -> Unit): YukiMemberHookCreator.MemberHookCreator.Result
+
变更记录
v1.2.0
新增
功能描述
直接 Hook 方法、构造方法。
注意
此功能尚在实验阶段,在 1.x.x 版本将暂定于此,在 2.0.0 版本将完全合并到新 API。
inline fun Array<Member>.hookAll(priority: YukiHookPriority): YukiMemberHookCreator.MemberHookCreator
+
inline fun Array<Member>.hookAll(priority: YukiHookPriority, initiate: YukiMemberHookCreator.MemberHookCreator.() -> Unit): YukiMemberHookCreator.MemberHookCreator.Result
+
inline fun List<Member>.hookAll(priority: YukiHookPriority): YukiMemberHookCreator.MemberHookCreator
+
inline fun List<Member>.hookAll(priority: YukiHookPriority, initiate: YukiMemberHookCreator.MemberHookCreator.() -> Unit): YukiMemberHookCreator.MemberHookCreator.Result
+
inline fun BaseFinder.BaseResult.hookAll(priority: YukiHookPriority): YukiMemberHookCreator.MemberHookCreator
+
inline fun BaseFinder.BaseResult.hookAll(priority: YukiHookPriority, initiate: YukiMemberHookCreator.MemberHookCreator.() -> Unit): YukiMemberHookCreator.MemberHookCreator.Result
+
变更记录
v1.2.0
新增
功能描述
直接 Hook 方法、构造方法 (批量)。
注意
此功能尚在实验阶段,在 1.x.x 版本将暂定于此,在 2.0.0 版本将完全合并到新 API。
inline fun HookResources.hook(initiate: YukiResourcesHookCreator.() -> Unit)
+
变更记录
v1.0.80
新增
功能描述
Hook APP 的 Resources。
特别注意
此功能将不再默认启用,如需启用,请手动设置 InjectYukiHookWithXposed.isUsingResourcesHook。
功能示例
Resources Hook 为固定用法,获取 resources
对象,然后调用 hook
方法开始 Hook。
示例如下
resources().hook {
+ // Your code here.
+}
+
特别注意
这是固定用法,为了防止发生问题,你不可手动实现任何 HookResources 实例执行 hook 调用。
将 Resources 的 Hook 设置为这样是为了与 String.toClass(...).hook
做到统一,使得调用起来逻辑不会混乱。
inner class AppLifecycle internal constructor(private val isOnFailureThrowToApp: Boolean)
+
变更记录
v1.0.88
新增
v1.1.5
修改
新增 isOnFailureThrowToApp
参数,可选择将异常在 (Xposed) 宿主环境打印而不是抛出给宿主
功能描述
当前 Hook APP 的生命周期实例处理类。
fun attachBaseContext(result: (baseContext: Context, hasCalledSuper: Boolean) -> Unit)
+
变更记录
v1.0.88
新增
功能描述
监听当前 Hook APP 装载
Application.attachBaseContext
。
fun onCreate(initiate: Application.() -> Unit)
+
变更记录
v1.0.88
新增
功能描述
监听当前 Hook APP 装载
Application.onCreate
。
fun onTerminate(initiate: Application.() -> Unit)
+
变更记录
v1.0.88
新增
功能描述
监听当前 Hook APP 装载
Application.onTerminate
。
fun onLowMemory(initiate: Application.() -> Unit)
+
变更记录
v1.0.88
新增
功能描述
监听当前 Hook APP 装载
Application.onLowMemory
。
fun onTrimMemory(result: (self: Application, level: Int) -> Unit)
+
变更记录
v1.0.88
新增
功能描述
监听当前 Hook APP 装载
Application.onTrimMemory
。
fun onConfigurationChanged(result: (self: Application, config: Configuration) -> Unit)
+
变更记录
v1.0.88
新增
功能描述
监听当前 Hook APP 装载
Application.onConfigurationChanged
。
fun registerReceiver(vararg action: String, result: (context: Context, intent: Intent) -> Unit)
+
fun registerReceiver(filter: IntentFilter, result: (context: Context, intent: Intent) -> Unit)
+
变更记录
v1.0.88
新增
v1.1.8
修改
新增直接使用 IntentFilter
注册系统广播监听
功能描述
`,437),p=[l];function c(t,r){return a(),o("div",null,p)}const i=s(n,[["render",c],["__file","PackageParam.html.vue"]]);export{i as default}; diff --git a/assets/PackageParam.html-vqkHjjmt.js b/assets/PackageParam.html-vqkHjjmt.js new file mode 100644 index 00000000..89c9a3b6 --- /dev/null +++ b/assets/PackageParam.html-vqkHjjmt.js @@ -0,0 +1,129 @@ +import{_ as s,o as a,c as o,a as e}from"./app-BpUB8-Q8.js";const n={},l=e(`注册系统广播监听。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
open class PackageParam internal constructor(internal var wrapper: PackageParamWrapper?)
+
Change Records
v1.0
first
Function Illustrate
装载 Hook 的目标 APP 入口对象实现类。
var appClassLoader:ClassLoader?
+
Change Records
v1.0
first
v1.1.5
modified
可以动态修改此变量的值
v1.2.0
modified
加入可空类型 (空安全)
Function Illustrate
获取、设置当前 Hook APP 的
ClassLoader
。
你可以在这里手动设置当前 Hook APP 的 ClassLoader
,默认情况下会自动获取。
Pay Attention
如果设置了错误或无效的 ClassLoader 会造成功能异常,请谨慎操作。
val appInfo: ApplicationInfo
+
Change Records
v1.0
first
Function Illustrate
获取当前 Hook APP 的
ApplicationInfo
。
val appUserId: Int
+
Change Records
v1.1.0
added
Function Illustrate
获取当前 Hook APP 的用户 ID。
机主为 0
,应用双开 (分身) 或工作资料因系统环境不同 ID 也各不相同。
val appContext: Application?
+
Change Records
v1.0.72
added
v1.1.0
modified
加入可空类型 (空安全)
Function Illustrate
获取当前 Hook APP 的
Application
。
Pay Attention
首次装载可能是空的,请延迟一段时间再获取或使用 onAppLifecycle 监听来完成。
val appResources:Resources?
+
Change Records
v1.0.80
added
v1.1.0
modified
加入可空类型 (空安全)
Function Illustrate
获取当前 Hook APP 的 Resources。
Pay Attention
你只能在 HookResources.hook 方法体内或 appContext 装载完毕时进行调用。
val systemContext: Context
+
Change Records
v1.1.0
added
Function Illustrate
获取当前系统框架的
Context
。
val processName: String
+
Change Records
v1.0
first
Function Illustrate
获取当前 Hook APP 的进程名称。
val packageName: String
+
Change Records
v1.0
first
Function Illustrate
获取当前 Hook APP 的包名。
val isFirstApplication: Boolean
+
Change Records
v1.0
first
Function Illustrate
获取当前 Hook APP 是否为第一个
Application
。
val mainProcessName: String
+
Change Records
v1.0.70
added
Function Illustrate
获取当前 Hook APP 的主进程名称。
其对应的就是 packageName
。
val moduleAppFilePath: String
+
Change Records
v1.0.80
added
Function Illustrate
获取当前 Xposed 模块自身 APK 文件路径。
Pay Attention
作为 Hook API 装载时无法使用,会获取到空字符串。
val moduleAppResources: YukiModuleResources
+
Change Records
v1.0.80
added
Function Illustrate
获取当前 Xposed 模块自身
Resources
。
Pay Attention
作为 Hook API 或不支持的 Hook Framework 装载时无法使用,会抛出异常。
val prefs: YukiHookPrefsBridge
+
Change Records
v1.0
first
Function Illustrate
创建
YukiHookPrefsBridge
对象。
Pay Attention
作为 Hook API 装载时无法使用,会抛出异常。
fun prefs(name: String): YukiHookPrefsBridge
+
Change Records
v1.0
first
v1.0.80
modified
将方法体进行 inline
Function Illustrate
创建
YukiHookPrefsBridge
对象。
你可以通过 name
来自定义 Sp 存储的名称。
Pay Attention
作为 Hook API 装载时无法使用,会抛出异常。
val dataChannel: YukiHookDataChannel.NameSpace
+
Change Records
v1.0.88
added
Function Illustrate
获取
YukiHookDataChannel
对象。
Pay Attention
作为 Hook API 装载时无法使用,会抛出异常。
fun resources(): HookResources
+
Change Records
v1.0.80
added
Function Illustrate
获得当前 Hook APP 的
YukiResources
对象。
请调用 HookResources.hook
方法开始 Hook。
fun refreshModuleAppResources()
+
Change Records
v1.0.87
added
Function Illustrate
刷新当前 Xposed 模块自身
Resources
。
inline fun onAppLifecycle(isOnFailureThrowToApp: Boolean, initiate: AppLifecycle.() -> Unit)
+
Change Records
v1.0.88
added
v1.1.5
modified
新增 isOnFailureThrowToApp
参数,可选择将异常在 (Xposed) 宿主环境打印而不是抛出给宿主
Function Illustrate
监听当前 Hook APP 生命周期装载事件。
Notice
在 loadZygote 中不会被装载,仅会在 loadSystem、loadApp 中装载。
作为 Hook API 装载时请使用原生的 Application 实现生命周期监听。
inline fun loadApp(name: String, initiate: PackageParam.() -> Unit)
+
fun loadApp(name: String, hooker: YukiBaseHooker)
+
inline fun loadApp(vararg name: String, initiate: PackageParam.() -> Unit)
+
fun loadApp(name: String, vararg hooker: YukiBaseHooker)
+
inline fun loadApp(isExcludeSelf: Boolean, initiate: PackageParam.() -> Unit)
+
fun loadApp(isExcludeSelf: Boolean, hooker: YukiBaseHooker)
+
fun loadApp(isExcludeSelf: Boolean, vararg hooker: YukiBaseHooker)
+
Change Records
v1.0
first
v1.0.80
modified
将方法体进行 inline
v1.1.4
modified
新增两个方法,可以同时装载多个 APP 与子 Hooker
v1.1.5
modified
新增三个方法,可以使用参数 isExcludeSelf
排除模块自身
Function Illustrate
装载并 Hook 指定、全部包名的 APP。
name
为 APP 的包名,后方的两个参数一个可作为 lambda 方法体使用,一个可以直接装载子 Hooker。
装载并 Hook 指定、全部包名的 APP。
若要装载 APP Zygote 事件,请使用 loadZygote
。
若要 Hook 系统框架,请使用 loadSystem
。
Function Example
你可以使用 loadApp
的 lambda 方法体形式或直接装载一个 Hooker。
The following example
// 使用 lambda
+loadApp(name = "com.example.test") {
+ // Your code here.
+}
+// 使用 Hooker
+loadApp(name = "com.example.test", CustomHooker)
+
若不指定 name
参数,则此方法体默认会过滤当前系统中全部可被 Hook 的 APP。
The following example
// 使用 lambda
+loadApp {
+ // Your code here.
+}
+// 使用 Hooker
+loadApp(hooker = CustomHooker)
+
若要在全部可被 Hook 的 APP 中过滤掉模块自身,你只需加入 isExcludeSelf = true
。
The following example
// 使用 lambda
+loadApp(isExcludeSelf = true) {
+ // Your code here.
+}
+// 使用 Hooker
+loadApp(isExcludeSelf = true, hooker = CustomHooker)
+
若想要同时装载多个需要 Hook 的 APP,可以直接使用如下方式。
The following example
// 同时装载多个需要 Hook 的 APP
+loadApp("com.example.test", "com.example.next") {
+ // Your code here.
+}
+
若想要同时装载多个子 Hooker,可以直接使用如下方式,但此时只能指定一个需要 Hook 的 APP。
The following example
// 同时装载多个子 Hooker
+loadApp("com.example.test", CustomHooker1, CustomHooker2)
+
inline fun loadZygote(initiate: PackageParam.() -> Unit)
+
fun loadZygote(hooker: YukiBaseHooker)
+
fun loadZygote(vararg hooker: YukiBaseHooker)
+
Change Records
v1.0.80
added
v1.1.4
modified
新增一个方法,可以同时装载多个子 Hooker
Function Illustrate
装载 APP Zygote 事件。
方法中的两个参数一个可作为 lambda 方法体使用,一个可以直接装载子 Hooker。
inline fun loadSystem(initiate: PackageParam.() -> Unit)
+
fun loadSystem(hooker: YukiBaseHooker)
+
fun loadSystem(vararg hooker: YukiBaseHooker)
+
Change Records
v1.0.82
added
v1.1.4
modified
新增一个方法,可以同时装载多个子 Hooker
Function Illustrate
装载并 Hook 系统框架。
方法中的两个参数一个可作为 lambda 方法体使用,一个可以直接装载子 Hooker。
inline fun withProcess(name: String, initiate: PackageParam.() -> Unit)
+
fun withProcess(name: String, hooker: YukiBaseHooker)
+
fun withProcess(vararg name: String, hooker: YukiBaseHooker)
+
fun withProcess(name: String, vararg hooker: YukiBaseHooker)
+
Change Records
v1.0.70
added
v1.1.4
modified
新增两个方法,可以同时装载多个进程与子 Hooker
Function Illustrate
装载并 Hook APP 的指定进程。
name
为 APP 的进程名称,后方的两个参数一个可作为 lambda 方法体使用,一个可以直接装载子 Hooker。
fun loadHooker(hooker: YukiBaseHooker)
+
Change Records
v1.0
first
Function Illustrate
装载 Hook 子类。
你可以填入 hooker
在 Hooker 中继续装载 Hooker。
inline fun searchClass(name: String, async: Boolean, initiate: ClassConditions): DexClassFinder.Result
+
Change Records
v1.1.0
added
Function Illustrate
通过
appClassLoader
按指定条件查找并得到当前 Hook APP Dex 中的Class
。
Pay Attention
此方法在 Class 数量过多及查找条件复杂时会非常耗时。
建议启用 async 或设置 name 参数,name 参数将在 Hook APP (宿主) 不同版本中自动进行本地缓存以提升效率。
此功能尚在实验阶段,性能与稳定性可能仍然存在问题,使用过程遇到问题请向我们报告并帮助我们改进。
Change Records
v1.0
first
v1.1.0
deprecated
请迁移到 toClass(...)
方法
Change Records
v1.0
first
v1.1.0
deprecated
请迁移到 hasClass(...)
方法
fun String.toClass(loader: ClassLoader?, initialize: Boolean): Class<*>
+
inline fun <reified T> String.toClass(loader: ClassLoader?, initialize: Boolean): Class<T>
+
fun VariousClass.toClass(loader: ClassLoader?, initialize: Boolean): Class<*>
+
Change Records
v1.1.0
added
v1.1.5
modified
新增泛型返回值 Class<T>
方法
新增 initialize
参数
Function Illustrate
通过字符串类名、
VariousClass
转换为loader
中的实体类。
默认使用当前 appClassLoader
装载目标 Class
。
Function Example
你可以轻松地将 String
类型的 Class
包名转为 Class
实例。
The following example
"com.example.demo.DemoClass".toClass()
+
你还可以向 loader
参数传入你自定义的 ClassLoader
。
The following example
val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader
+"com.example.demo.DemoClass".toClass(customClassLoader)
+
你还可以指定 Class
的目标类型。
The following example
// 指定的 DemoClass 必须存在或为可访问的 stub
+"com.example.demo.DemoClass".toClass<DemoClass>()
+
你还可以设置在获取到这个 Class
时是否自动执行其默认的静态方法块,默认情况下不会执行。
The following example
// 获取并执行 DemoClass 默认的静态方法块
+"com.example.demo.DemoClass".toClass(initialize = true)
+
默认的静态方法块在 Java 中使用如下方式定义。
The following example
public class DemoClass {
+
+ static {
+ // 这里是静态方法块的内容
+ }
+
+ public DemoClass() {
+ // ...
+ }
+}
+
你还可以创建一个 VariousClass
,并转换为实体类。
VariousClass
会枚举所有设置的 Class
并最终获得第一个存在的 Class
。
The following example
VariousClass("com.example.demo.DemoClass1", "com.example.demo.DemoClass2").toClass()
+
同样地,你还可以向 loader
参数传入你自定义的 ClassLoader
。
The following example
val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader
+VariousClass("com.example.demo.DemoClass1", "com.example.demo.DemoClass2").toClass(customClassLoader)
+
fun String.toClassOrNull(loader: ClassLoader?, initialize: Boolean): Class<*>?
+
inline fun <reified T> String.toClassOrNull(loader: ClassLoader?, initialize: Boolean): Class<T>?
+
fun VariousClass.toClassOrNull(loader: ClassLoader?, initialize: Boolean): Class<*>?
+
Change Records
v1.1.0
added
v1.1.5
modified
新增泛型返回值 Class<T>
方法
新增 initialize
参数
Function Illustrate
通过字符串类名、
VariousClass
转换为loader
中的实体类。
默认使用当前 appClassLoader
装载目标 Class
。
找不到 Class
会返回 null
,不会抛出异常。
Function Example
用法请参考 String+VariousClass.toClass 方法。
fun lazyClass(name: String, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.NonNull<Any>
+
inline fun <reified T> lazyClass(name: String, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.NonNull<T>
+
fun lazyClass(variousClass: VariousClass, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.NonNull<Any>
+
Change Records
v1.2.0
added
Function Illustrate
懒装载
Class
。
fun lazyClassOrNull(name: String, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.Nullable<Any>
+
inline fun <reified T> lazyClassOrNull(name: String, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.Nullable<T>
+
fun lazyClassOrNull(variousClass: VariousClass, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.Nullable<Any>
+
Change Records
v1.2.0
added
Function Illustrate
懒装载
Class
。
fun String.hasClass(loader: ClassLoader?): Boolean
+
Change Records
v1.1.0
added
Function Illustrate
通过字符串类名查找是否存在。
默认使用当前 appClassLoader
装载目标 Class
。
Function Example
你可以轻松的使用此方法判断字符串中的类是否存在。
The following example
if("com.example.demo.DemoClass".hasClass()) {
+ // Your code here.
+}
+
你还可以自定义其中的 loader
参数,默认为 appClassLoader
。
The following example
val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader
+if("com.example.demo.DemoClass".hasClass(customClassLoader)) {
+ // Your code here.
+}
+
Change Records
v1.0
first
v1.0.1
modified
移除了 方法findClass(various: VariousClass)
v1.1.0
modified
新增 loader
参数
v1.2.0
deprecated
请直接使用 String.toClass(...)
或 VariousClass(...)
inline fun Class<*>.hook(isForceUseAbsolute: Boolean, initiate: YukiMemberHookCreator.() -> Unit): YukiMemberHookCreator.Result
+
inline fun VariousClass.hook(initiate: YukiMemberHookCreator.() -> Unit): YukiMemberHookCreator.Result
+
inline fun HookClass.hook(initiate: YukiMemberHookCreator.() -> Unit): YukiMemberHookCreator.Result
+
Change Records
v1.0
first
v1.0.1
modified
新增 VariousClass
的直接调用 hook
方法
v1.0.2
modified
新增 String
的直接调用 hook
方法
v1.0.3
modified
新增 YukiMemberHookCreator.Result
返回值
v1.0.70
modified
新增 isUseAppClassLoader
参数
v1.0.80
modified
将方法体进行 inline
v1.1.0
modified
移除了 参数isUseAppClassLoader
添加了 isForceUseAbsolute
参数到 Class.hook
方法
v1.2.0
modified
作废了 方法String.hook
Function Illustrate
Hook 方法、构造方法。
inline fun Member.hook(priority: YukiHookPriority): YukiMemberHookCreator.MemberHookCreator
+
inline fun Member.hook(priority: YukiHookPriority, initiate: YukiMemberHookCreator.MemberHookCreator.() -> Unit): YukiMemberHookCreator.MemberHookCreator.Result
+
inline fun BaseFinder.BaseResult.hook(priority: YukiHookPriority): YukiMemberHookCreator.MemberHookCreator
+
inline fun BaseFinder.BaseResult.hook(priority: YukiHookPriority, initiate: YukiMemberHookCreator.MemberHookCreator.() -> Unit): YukiMemberHookCreator.MemberHookCreator.Result
+
Change Records
v1.2.0
added
Function Illustrate
直接 Hook 方法、构造方法。
Notice
此功能尚在实验阶段,在 1.x.x 版本将暂定于此,在 2.0.0 版本将完全合并到新 API。
inline fun Array<Member>.hookAll(priority: YukiHookPriority): YukiMemberHookCreator.MemberHookCreator
+
inline fun Array<Member>.hookAll(priority: YukiHookPriority, initiate: YukiMemberHookCreator.MemberHookCreator.() -> Unit): YukiMemberHookCreator.MemberHookCreator.Result
+
inline fun List<Member>.hookAll(priority: YukiHookPriority): YukiMemberHookCreator.MemberHookCreator
+
inline fun List<Member>.hookAll(priority: YukiHookPriority, initiate: YukiMemberHookCreator.MemberHookCreator.() -> Unit): YukiMemberHookCreator.MemberHookCreator.Result
+
inline fun BaseFinder.BaseResult.hookAll(priority: YukiHookPriority): YukiMemberHookCreator.MemberHookCreator
+
inline fun BaseFinder.BaseResult.hookAll(priority: YukiHookPriority, initiate: YukiMemberHookCreator.MemberHookCreator.() -> Unit): YukiMemberHookCreator.MemberHookCreator.Result
+
Change Records
v1.2.0
added
Function Illustrate
直接 Hook 方法、构造方法 (批量)。
Notice
此功能尚在实验阶段,在 1.x.x 版本将暂定于此,在 2.0.0 版本将完全合并到新 API。
inline fun HookResources.hook(initiate: YukiResourcesHookCreator.() -> Unit)
+
Change Records
v1.0.80
added
Function Illustrate
Hook APP 的 Resources。
Pay Attention
此功能将不再默认启用,如需启用,请手动设置 InjectYukiHookWithXposed.isUsingResourcesHook。
Function Example
Resources Hook 为固定用法,获取 resources
对象,然后调用 hook
方法开始 Hook。
The following example
resources().hook {
+ // Your code here.
+}
+
Pay Attention
这是固定用法,为了防止发生问题,你不可手动实现任何 HookResources 实例执行 hook 调用。
将 Resources 的 Hook 设置为这样是为了与 String.toClass(...).hook
做到统一,使得调用起来逻辑不会混乱。
inner class AppLifecycle internal constructor(private val isOnFailureThrowToApp: Boolean)
+
Change Records
v1.0.88
added
v1.1.5
modified
新增 isOnFailureThrowToApp
参数,可选择将异常在 (Xposed) 宿主环境打印而不是抛出给宿主
Function Illustrate
当前 Hook APP 的生命周期实例处理类。
fun attachBaseContext(result: (baseContext: Context, hasCalledSuper: Boolean) -> Unit)
+
Change Records
v1.0.88
added
Function Illustrate
监听当前 Hook APP 装载
Application.attachBaseContext
。
fun onCreate(initiate: Application.() -> Unit)
+
Change Records
v1.0.88
added
Function Illustrate
监听当前 Hook APP 装载
Application.onCreate
。
fun onTerminate(initiate: Application.() -> Unit)
+
Change Records
v1.0.88
added
Function Illustrate
监听当前 Hook APP 装载
Application.onTerminate
。
fun onLowMemory(initiate: Application.() -> Unit)
+
Change Records
v1.0.88
added
Function Illustrate
监听当前 Hook APP 装载
Application.onLowMemory
。
fun onTrimMemory(result: (self: Application, level: Int) -> Unit)
+
Change Records
v1.0.88
added
Function Illustrate
监听当前 Hook APP 装载
Application.onTrimMemory
。
fun onConfigurationChanged(result: (self: Application, config: Configuration) -> Unit)
+
Change Records
v1.0.88
added
Function Illustrate
监听当前 Hook APP 装载
Application.onConfigurationChanged
。
fun registerReceiver(vararg action: String, result: (context: Context, intent: Intent) -> Unit)
+
fun registerReceiver(filter: IntentFilter, result: (context: Context, intent: Intent) -> Unit)
+
Change Records
v1.0.88
added
v1.1.8
modified
新增直接使用 IntentFilter
注册系统广播监听
Function Illustrate
`,440),p=[l];function t(c,r){return a(),o("div",null,p)}const i=s(n,[["render",t],["__file","PackageParam.html.vue"]]);export{i as default}; diff --git a/assets/PrefsData.html-B72hWN1s.js b/assets/PrefsData.html-B72hWN1s.js new file mode 100644 index 00000000..184e0add --- /dev/null +++ b/assets/PrefsData.html-B72hWN1s.js @@ -0,0 +1 @@ +const a=JSON.parse('{"key":"v-58ed8298","path":"/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData.html","title":"PrefsData - class","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":4}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData.md"}');export{a as data}; diff --git a/assets/PrefsData.html-BInEpoWz.js b/assets/PrefsData.html-BInEpoWz.js new file mode 100644 index 00000000..8a0d5f41 --- /dev/null +++ b/assets/PrefsData.html-BInEpoWz.js @@ -0,0 +1,18 @@ +import{_ as s,o as a,c as n,a as l}from"./app-BpUB8-Q8.js";const e={},o=l(`注册系统广播监听。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
data class PrefsData<T>(var key: String, var value: T) : Serializable
+
变更记录
v1.0.67
新增
v1.1.5
修改
实现了 Serializable
接口
功能描述
键值对存储构造类。
这个类是对 YukiHookPrefsBridge
的一个扩展用法。
功能示例
建立一个模板类定义模块与宿主需要使用的键值数据。
示例如下
object DataConst {
+
+ val TEST_KV_DATA_1 = PrefsData("test_data_1", "defalut value")
+ val TEST_KV_DATA_2 = PrefsData("test_data_2", false)
+ val TEST_KV_DATA_3 = PrefsData("test_data_3", 0)
+}
+
键值数据定义后,你就可以方便地在模块和宿主中调用所需要的数据。
模块示例如下
// 读取
+val data = prefs().get(DataConst.TEST_KV_DATA_1)
+// 写入
+prefs().edit { put(DataConst.TEST_KV_DATA_1, "written value") }
+
宿主示例如下
// 读取 String
+val dataString = prefs.get(DataConst.TEST_KV_DATA_1)
+// 读取 Boolean
+val dataBoolean = prefs.get(DataConst.TEST_KV_DATA_2)
+
你依然可以不使用模板定义的默认值,随时修改你的默认值。
示例如下
// 读取 - 此时 data 取到的默认值将会是 2 - 并不是模板提供的 0
+val data = prefs.get(DataConst.TEST_KV_DATA_3, 2)
+
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
data class PrefsData<T>(var key: String, var value: T) : Serializable
+
Change Records
v1.0.67
added
v1.1.5
modified
实现了 Serializable
接口
Function Illustrate
键值对存储构造类。
这个类是对 YukiHookPrefsBridge
的一个扩展用法。
Function Example
建立一个模板类定义模块与宿主需要使用的键值数据。
The following example
object DataConst {
+
+ val TEST_KV_DATA_1 = PrefsData("test_data_1", "defalut value")
+ val TEST_KV_DATA_2 = PrefsData("test_data_2", false)
+ val TEST_KV_DATA_3 = PrefsData("test_data_3", 0)
+}
+
键值数据定义后,你就可以方便地在模块和宿主中调用所需要的数据。
模块示例如下
// 读取
+val data = prefs().get(DataConst.TEST_KV_DATA_1)
+// 写入
+prefs().edit { put(DataConst.TEST_KV_DATA_1, "written value") }
+
宿主示例如下
// 读取 String
+val dataString = prefs.get(DataConst.TEST_KV_DATA_1)
+// 读取 Boolean
+val dataBoolean = prefs.get(DataConst.TEST_KV_DATA_2)
+
你依然可以不使用模板定义的默认值,随时修改你的默认值。
The following example
// 读取 - 此时 data 取到的默认值将会是 2 - 并不是模板提供的 0
+val data = prefs.get(DataConst.TEST_KV_DATA_3, 2)
+
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
Change Records
v1.0
first
Function Illustrate
这是自定义
Member
和Class
相关功能的查找匹配以及invoke
的封装类。
enum class MembersType
+
Change Records
v1.1.0
added
Function Illustrate
定义一个
Class
中的Member
类型
ALL
+
Change Records
v1.1.0
added
Function Illustrate
全部
Method
与Constructor
。
METHOD
+
Change Records
v1.1.0
added
Function Illustrate
全部
Method
。
CONSTRUCTOR
+
Change Records
v1.1.0
added
Function Illustrate
全部
Constructor
。
open class LazyClass<T> internal constructor(
+ private val instance: Any,
+ private val initialize: Boolean,
+ private val loader: ClassLoaderInitializer?
+)
+
Change Records
v1.2.0
added
Function Illustrate
懒装载
Class
实例。
fun ClassLoader.listOfClasses(): List<String>
+
Change Records
v1.1.2
added
Function Illustrate
写出当前
ClassLoader
下所有Class
名称数组。
inline fun ClassLoader.searchClass(name: String, async: Boolean, initiate: ClassConditions): DexClassFinder.Result
+
Change Records
v1.1.0
added
Function Illustrate
通过当前
ClassLoader
按指定条件查找并得到 Dex 中的Class
。
Pay Attention
此方法在 Class 数量过多及查找条件复杂时会非常耗时。
建议启用 async 或设置 name 参数,name 参数将在 Hook APP (宿主) 不同版本中自动进行本地缓存以提升效率。
此功能尚在实验阶段,性能与稳定性可能仍然存在问题,使用过程遇到问题请向我们报告并帮助我们改进。
fun ClassLoader.onLoadClass(result: (Class<*>) -> Unit)
+
Change Records
v1.1.0
added
Function Illustrate
监听当前
ClassLoader
的ClassLoader.loadClass
方法装载。
Pay Attention
只有当前 ClassLoader 有主动使用 ClassLoader.loadClass 事件时才能被捕获。
这是一个实验性功能,一般情况下不会用到此方法,不保证不会发生错误。
只能在 (Xposed) 宿主环境使用此功能,其它环境下使用将不生效且会打印警告信息。
Function Example
针对一些使用特定 ClassLoader
装载 Class
的宿主应用,你可以使用此方法来监听 Class
加载情况。
Notice
为了防止发生问题,你需要得到一个存在的 ClassLoader 实例来使用此功能。
比如我们在 PackageParam
中使用 appClassLoader
。
The following example
appClassLoader.onLoadClass { clazz ->
+ // 得到 clazz 即加载对象
+ clazz... // 这里进行你需要的操作
+}
+
或使用你得到的存在的 ClassLoader
实例,可以通过 Hook 获取。
The following example
val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader
+customClassLoader?.onLoadClass { clazz ->
+ // ...
+}
+
在判断到这个 Class
被装载成功时,开始执行你的 Hook 功能。
The following example
val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader
+customClassLoader?.onLoadClass { clazz ->
+ if(clazz.name == /** 你需要的 Class 名称 */) {
+ clazz.hook {
+ // ...
+ }
+ }
+}
+
Change Records
v1.0
first
v1.1.0
removed
HookClass
相关功能不再对外开放
Change Records
v1.0
first
v1.1.0
removed
HookClass
相关功能不再对外开放
Change Records
v1.0
first
v1.1.0
removed
请直接使用 hasClass()
无参方法
val Class<*>.hasExtends: Boolean
+
Change Records
v1.0.80
added
Function Illustrate
当前
Class
是否有继承关系,父类是Any
将被认为没有继承关系。
infix fun Class<*>?.extends(other: Class<*>?): Boolean
+
Change Records
v1.1.5
added
Function Illustrate
当前
Class
是否继承于other
。
如果当前 Class
就是 other
也会返回 true
。
如果当前 Class
为 null
或 other
为 null
会返回 false
。
Function Example
你可以使用此方法来判断两个 Class
是否存在继承关系。
The following example
// 假设下面这两个 Class 就是你需要判断的 Class
+val classA: Class<*>?
+val classB: Class<*>?
+// 判断 A 是否继承于 B
+if (classA extends classB) {
+ // Your code here.
+}
+
infix fun Class<*>?.notExtends(other: Class<*>?): Boolean
+
Change Records
v1.1.5
added
Function Illustrate
当前
Class
是否不继承于other
。
此方法相当于 extends
的反向判断。
Function Example
你可以使用此方法来判断两个 Class
是否不存在继承关系。
The following example
// 假设下面这两个 Class 就是你需要判断的 Class
+val classA: Class<*>?
+val classB: Class<*>?
+// 判断 A 是否不继承于 B
+if (classA notExtends classB) {
+ // Your code here.
+}
+
infix fun Class<*>?.implements(other: Class<*>?): Boolean
+
Change Records
v1.1.5
added
Function Illustrate
当前
Class
是否实现了other
接口类。
如果当前 Class
为 null
或 other
为 null
会返回 false
。
Function Example
你可以使用此方法来判断两个 Class
是否存在依赖关系。
The following example
// 假设下面这两个 Class 就是你需要判断的 Class
+val classA: Class<*>?
+val classB: Class<*>?
+// 判断 A 是否实现了 B 接口类
+if (classA implements classB) {
+ // Your code here.
+}
+
infix fun Class<*>?.notImplements(other: Class<*>?): Boolean
+
Change Records
v1.1.5
added
Function Illustrate
当前
Class
是否未实现other
接口类。
此方法相当于 implements
的反向判断。
Function Example
你可以使用此方法来判断两个 Class
是否不存在依赖关系。
The following example
// 假设下面这两个 Class 就是你需要判断的 Class
+val classA: Class<*>?
+val classB: Class<*>?
+// 判断 A 是否未实现 B 接口类
+if (classA notImplements classB) {
+ // Your code here.
+}
+
fun Class<*>.toJavaPrimitiveType(): Class<*>
+
Change Records
v1.1.5
added
Function Illustrate
自动转换当前
Class
为 Java 原始类型 (Primitive Type)。
如果当前 Class
为 Java 或 Kotlin 基本类型将自动执行类型转换。
当前能够自动转换的基本类型如下。
kotlin.Unit
java.lang.Void
java.lang.Boolean
java.lang.Integer
java.lang.Float
java.lang.Double
java.lang.Long
java.lang.Short
java.lang.Character
java.lang.Byte
Change Records
v1.0
first
v1.1.0
deprecated
请转到 toClass(...)
方法
fun String.toClass(loader: ClassLoader?, initialize: Boolean): Class<*>
+
inline fun <reified T> String.toClass(loader: ClassLoader?, initialize: Boolean): Class<T>
+
Change Records
v1.1.0
added
v1.1.5
modified
新增泛型返回值 Class<T>
方法
新增 initialize
参数
Function Illustrate
通过字符串类名转换为
loader
中的实体类。
Function Example
你可以直接填写你要查找的目标 Class
,必须在默认 ClassLoader
下存在。
The following example
"com.example.demo.DemoClass".toClass()
+
你还可以自定义 Class
所在的 ClassLoader
。
The following example
val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader
+"com.example.demo.DemoClass".toClass(customClassLoader)
+
你还可以指定 Class
的目标类型。
The following example
// 指定的 DemoClass 必须存在或为可访问的 stub
+"com.example.demo.DemoClass".toClass<DemoClass>()
+
你还可以设置在获取到这个 Class
时是否自动执行其默认的静态方法块,默认情况下不会执行。
The following example
// 获取并执行 DemoClass 默认的静态方法块
+"com.example.demo.DemoClass".toClass(initialize = true)
+
默认的静态方法块在 Java 中使用如下方式定义。
The following example
public class DemoClass {
+
+ static {
+ // 这里是静态方法块的内容
+ }
+
+ public DemoClass() {
+ // ...
+ }
+}
+
fun String.toClassOrNull(loader: ClassLoader?, initialize: Boolean): Class<*>?
+
inline fun <reified T> String.toClassOrNull(loader: ClassLoader?, initialize: Boolean): Class<T>?
+
Change Records
v1.1.0
added
v1.1.5
modified
新增泛型返回值 Class<T>
方法
新增 initialize
参数
Function Illustrate
通过字符串类名转换为
loader
中的实体类。
找不到 Class
会返回 null
,不会抛出异常。
Function Example
用法请参考 String.toClass 方法。
inline fun <reified T> classOf(loader: ClassLoader?, initialize: Boolean): Class<T>
+
Change Records
v1.1.0
added
v1.1.5
modified
将返回类型由 Class<*>
cast 为 Class<T>
新增 initialize
参数
Function Illustrate
通过
T
得到其Class
实例并转换为实体类。
Function Example
我们要获取一个 Class
在 Kotlin 下不通过反射时应该这样做。
The following example
DemoClass::class.java
+
现在,你可以直接 cast
一个实例并获取它的 Class
对象,必须在当前 ClassLoader
下存在。
The following example
classOf<DemoClass>()
+
若目标存在的 Class
为 stub
,通过这种方式,你还可以自定义 Class
所在的 ClassLoader
。
The following example
val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader
+classOf<DemoClass>(customClassLoader)
+
fun lazyClass(name: String, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.NonNull<Any>
+
inline fun <reified T> lazyClass(name: String, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.NonNull<T>
+
fun lazyClass(variousClass: VariousClass, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.NonNull<Any>
+
Change Records
v1.2.0
added
Function Illustrate
懒装载
Class
。
fun lazyClassOrNull(name: String, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.Nullable<Any>
+
inline fun <reified T> lazyClassOrNull(name: String, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.Nullable<T>
+
fun lazyClassOrNull(variousClass: VariousClass, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.Nullable<Any>
+
Change Records
v1.2.0
added
Function Illustrate
懒装载
Class
。
fun String.hasClass(loader: ClassLoader?): Boolean
+
Change Records
v1.0
first
v1.1.0
modified
支持直接使用空参数方法使用默认 ClassLoader
进行判断
Function Illustrate
通过字符串类名使用指定的
ClassLoader
查找是否存在。
Function Example
你可以轻松的使用此方法判断字符串中的类是否存在,效果等同于直接使用 Class.forName
。
The following example
if("com.example.demo.DemoClass".hasClass()) {
+ // Your code here.
+}
+
填入方法中的 loader
参数可判断指定的 ClassLoader
中的 Class
是否存在。
The following example
val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader
+if("com.example.demo.DemoClass".hasClass(customClassLoader)) {
+ // Your code here.
+}
+
inline fun Class<*>.hasField(initiate: FieldConditions): Boolean
+
Change Records
v1.0.4
added
v1.0.67
modified
合并到 FieldFinder
v1.0.80
modified
将方法体进行 inline
Function Illustrate
查找变量是否存在。
inline fun Class<*>.hasMethod(initiate: MethodConditions): Boolean
+
Change Records
v1.0
first
v1.0.1
modified
新增 returnType
参数
v1.0.67
modified
合并到 MethodFinder
v1.0.80
modified
将方法体进行 inline
Function Illustrate
查找方法是否存在。
inline fun Class<*>.hasConstructor(initiate: ConstructorConditions): Boolean
+
Change Records
v1.0.2
added
v1.0.67
modified
合并到 ConstructorFinder
v1.0.80
modified
将方法体进行 inline
Function Illustrate
查找构造方法是否存在。
inline fun Member.hasModifiers(conditions: ModifierConditions): Boolean
+
Change Records
v1.0.67
added
v1.0.80
modified
将方法体进行 inline
v1.1.0
modified
合并到 ModifierConditions
Function Illustrate
查找
Member
中匹配的描述符。
inline fun Class<*>.hasModifiers(conditions: ModifierConditions): Boolean
+
Change Records
v1.1.0
added
Function Illustrate
查找
Class
中匹配的描述符。
Change Records
v1.0
first
v1.0.1
removed
Change Records
v1.0
first
v1.0.1
removed
Change Records
v1.0
first
v1.0.1
removed
Change Records
v1.0
first
v1.0.1
removed
inline fun Class<*>.field(initiate: FieldConditions): FieldFinder.Result
+
Change Records
v1.0.2
added
v1.0.80
modified
将方法体进行 inline
Function Illustrate
查找并得到变量。
inline fun Class<*>.method(initiate: MethodConditions): MethodFinder.Result
+
Change Records
v1.0
first
v1.0.1
modified
更名为 obtainMethod
method
新增 returnType
参数
v1.0.2
modified
合并到 MethodFinder
方法体
v1.0.80
modified
将方法体进行 inline
Function Illustrate
查找并得到方法。
inline fun Class<*>.constructor(initiate: ConstructorConditions): ConstructorFinder.Result
+
Change Records
v1.0
first
v1.0.1
modified
更名为 obtainConstructor
constructor
v1.0.2
modified
合并到 ConstructorFinder
方法体
v1.0.80
modified
将方法体进行 inline
Function Illustrate
查找并得到构造方法。
Change Records
v1.0
first
v1.0.1
modified
更名为 invokeStatic
callStatic
v1.0.2
removed
Change Records
v1.0
first
v1.0.1
modified
更名为 invokeAny
call
v1.0.2
removed
fun Class<*>.generic(): GenericClass?
+
Change Records
v1.1.0
added
Function Illustrate
获得当前
Class
的泛型父类。
如果当前实例不存在泛型将返回 null
。
inline fun Class<*>.generic(initiate: GenericClass.() -> Unit): GenericClass?
+
Change Records
v1.1.0
added
Function Illustrate
获得当前
Class
的泛型父类。
如果当前实例不存在泛型将返回 null
。
inline fun <reified T : Any> T.current(ignored: Boolean): CurrentClass
+
inline fun <reified T : Any> T.current(ignored: Boolean, initiate: CurrentClass.() -> Unit): T
+
Change Records
v1.0.70
added
v1.1.0
added
新增 ignored
参数,可以忽略在 CurrentClass
中出现的异常
新增不使用 current { ... }
调用域直接使用 current()
得到实例的类操作对象
Function Illustrate
获得当前实例的类操作对象。
Change Records
v1.0.70
added
v1.0.80
modified
将方法体进行 inline
v1.1.0
deprecated
请迁移到 buildOf
方法
inline fun Class<*>.buildOf(vararg args: Any?, initiate: ConstructorConditions): Any?
+
inline fun <T> Class<*>.buildOf(vararg args: Any?, initiate: ConstructorConditions): T?
+
Change Records
v1.0.70
added
v1.0.80
modified
将方法体进行 inline
v1.1.0
modified
加入无泛型方法 buildOf
v1.1.6
modified
修改参数命名 param
为 args
Function Illustrate
通过构造方法创建新实例,指定类型
T
或任意类型Any
。
inline fun Class<*>.allMethods(isAccessible: Boolean, result: (index: Int, method: Method) -> Unit)
+
Change Records
v1.0.70
added
v1.0.80
modified
将方法体进行 inline
v1.1.5
modified
新增 isAccessible
参数
Function Illustrate
遍历当前类中的所有方法。
inline fun Class<*>.allConstructors(isAccessible: Boolean, result: (index: Int, constructor: Constructor<*>) -> Unit)
+
Change Records
v1.0.70
added
v1.0.80
modified
将方法体进行 inline
v1.1.5
modified
新增 isAccessible
参数
Function Illustrate
遍历当前类中的所有构造方法。
inline fun Class<*>.allFields(isAccessible: Boolean, result: (index: Int, field: Field) -> Unit)
+
Change Records
v1.0.70
added
v1.0.80
modified
将方法体进行 inline
v1.1.5
modified
新增 isAccessible
参数
Function Illustrate
`,422),p=[l];function c(t,d){return a(),o("div",null,p)}const i=s(n,[["render",c],["__file","ReflectionFactory.html.vue"]]);export{i as default}; diff --git a/assets/ReflectionFactory.html-BiQJ-KKx.js b/assets/ReflectionFactory.html-BiQJ-KKx.js new file mode 100644 index 00000000..e6248577 --- /dev/null +++ b/assets/ReflectionFactory.html-BiQJ-KKx.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-213d88b3","path":"/zh-cn/api/public/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.html","title":"ReflectionFactory - kt","lang":"zh-CN","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"MembersType - class","slug":"memberstype-class","link":"#memberstype-class","children":[{"level":3,"title":"ALL - enum","slug":"all-enum","link":"#all-enum","children":[]},{"level":3,"title":"METHOD - enum","slug":"method-enum","link":"#method-enum","children":[]},{"level":3,"title":"CONSTRUCTOR - enum","slug":"constructor-enum","link":"#constructor-enum","children":[]}]},{"level":2,"title":"LazyClass - class","slug":"lazyclass-class","link":"#lazyclass-class","children":[]},{"level":2,"title":"ClassLoader.listOfClasses - ext-method","slug":"classloader-listofclasses-ext-method","link":"#classloader-listofclasses-ext-method","children":[]},{"level":2,"title":"ClassLoader.searchClass - ext-method","slug":"classloader-searchclass-ext-method","link":"#classloader-searchclass-ext-method","children":[]},{"level":2,"title":"ClassLoader.onLoadClass - ext-method","slug":"classloader-onloadclass-ext-method","link":"#classloader-onloadclass-ext-method","children":[]},{"level":2,"title":"Class.hasExtends - ext-field","slug":"class-hasextends-ext-field","link":"#class-hasextends-ext-field","children":[]},{"level":2,"title":"Class?.extends - ext-method","slug":"class-extends-ext-method","link":"#class-extends-ext-method","children":[]},{"level":2,"title":"Class?.notExtends - ext-method","slug":"class-notextends-ext-method","link":"#class-notextends-ext-method","children":[]},{"level":2,"title":"Class?.implements - ext-method","slug":"class-implements-ext-method","link":"#class-implements-ext-method","children":[]},{"level":2,"title":"Class?.notImplements - ext-method","slug":"class-notimplements-ext-method","link":"#class-notimplements-ext-method","children":[]},{"level":2,"title":"Class.toJavaPrimitiveType - ext-method","slug":"class-tojavaprimitivetype-ext-method","link":"#class-tojavaprimitivetype-ext-method","children":[]},{"level":2,"title":"String.toClass - ext-method","slug":"string-toclass-ext-method","link":"#string-toclass-ext-method","children":[]},{"level":2,"title":"String.toClassOrNull - ext-method","slug":"string-toclassornull-ext-method","link":"#string-toclassornull-ext-method","children":[]},{"level":2,"title":"classOf - method","slug":"classof-method","link":"#classof-method","children":[]},{"level":2,"title":"lazyClass - method","slug":"lazyclass-method","link":"#lazyclass-method","children":[]},{"level":2,"title":"lazyClassOrNull - method","slug":"lazyclassornull-method","link":"#lazyclassornull-method","children":[]},{"level":2,"title":"String.hasClass - ext-method","slug":"string-hasclass-ext-method","link":"#string-hasclass-ext-method","children":[]},{"level":2,"title":"Class.hasField - ext-method","slug":"class-hasfield-ext-method","link":"#class-hasfield-ext-method","children":[]},{"level":2,"title":"Class.hasMethod - ext-method","slug":"class-hasmethod-ext-method","link":"#class-hasmethod-ext-method","children":[]},{"level":2,"title":"Class.hasConstructor - ext-method","slug":"class-hasconstructor-ext-method","link":"#class-hasconstructor-ext-method","children":[]},{"level":2,"title":"Member.hasModifiers - ext-method","slug":"member-hasmodifiers-ext-method","link":"#member-hasmodifiers-ext-method","children":[]},{"level":2,"title":"Class.hasModifiers - ext-method","slug":"class-hasmodifiers-ext-method","link":"#class-hasmodifiers-ext-method","children":[]},{"level":2,"title":"Class.field - ext-method","slug":"class-field-ext-method","link":"#class-field-ext-method","children":[]},{"level":2,"title":"Class.method - ext-method","slug":"class-method-ext-method","link":"#class-method-ext-method","children":[]},{"level":2,"title":"Class.constructor - ext-method","slug":"class-constructor-ext-method","link":"#class-constructor-ext-method","children":[]},{"level":2,"title":"Class.generic - ext-method","slug":"class-generic-ext-method","link":"#class-generic-ext-method","children":[]},{"level":2,"title":"Class.generic - ext-method","slug":"class-generic-ext-method-1","link":"#class-generic-ext-method-1","children":[]},{"level":2,"title":"Any.current - ext-method","slug":"any-current-ext-method","link":"#any-current-ext-method","children":[]},{"level":2,"title":"Class.buildOf - ext-method","slug":"class-buildof-ext-method","link":"#class-buildof-ext-method","children":[]},{"level":2,"title":"Class.allMethods - ext-method","slug":"class-allmethods-ext-method","link":"#class-allmethods-ext-method","children":[]},{"level":2,"title":"Class.allConstructors - ext-method","slug":"class-allconstructors-ext-method","link":"#class-allconstructors-ext-method","children":[]},{"level":2,"title":"Class.allFields - ext-method","slug":"class-allfields-ext-method","link":"#class-allfields-ext-method","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":18}]},"filePathRelative":"zh-cn/api/public/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.md"}');export{e as data}; diff --git a/assets/ReflectionFactory.html-Z7mH28Qd.js b/assets/ReflectionFactory.html-Z7mH28Qd.js new file mode 100644 index 00000000..305cf0d1 --- /dev/null +++ b/assets/ReflectionFactory.html-Z7mH28Qd.js @@ -0,0 +1,120 @@ +import{_ as s,o as a,c as o,a as e}from"./app-BpUB8-Q8.js";const n={},l=e(`遍历当前类中的所有变量。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
变更记录
v1.0
添加
功能描述
这是自定义
Member
和Class
相关功能的查找匹配以及invoke
的封装类。
enum class MembersType
+
变更记录
v1.1.0
新增
功能描述
定义一个
Class
中的Member
类型
ALL
+
变更记录
v1.1.0
新增
功能描述
全部
Method
与Constructor
。
METHOD
+
变更记录
v1.1.0
新增
功能描述
全部
Method
。
CONSTRUCTOR
+
变更记录
v1.1.0
新增
功能描述
全部
Constructor
。
open class LazyClass<T> internal constructor(
+ private val instance: Any,
+ private val initialize: Boolean,
+ private val loader: ClassLoaderInitializer?
+)
+
变更记录
v1.2.0
新增
功能描述
懒装载
Class
实例。
fun ClassLoader.listOfClasses(): List<String>
+
变更记录
v1.1.2
新增
功能描述
写出当前
ClassLoader
下所有Class
名称数组。
inline fun ClassLoader.searchClass(name: String, async: Boolean, initiate: ClassConditions): DexClassFinder.Result
+
变更记录
v1.1.0
新增
功能描述
通过当前
ClassLoader
按指定条件查找并得到 Dex 中的Class
。
特别注意
此方法在 Class 数量过多及查找条件复杂时会非常耗时。
建议启用 async 或设置 name 参数,name 参数将在 Hook APP (宿主) 不同版本中自动进行本地缓存以提升效率。
此功能尚在实验阶段,性能与稳定性可能仍然存在问题,使用过程遇到问题请向我们报告并帮助我们改进。
fun ClassLoader.onLoadClass(result: (Class<*>) -> Unit)
+
变更记录
v1.1.0
新增
功能描述
监听当前
ClassLoader
的ClassLoader.loadClass
方法装载。
特别注意
只有当前 ClassLoader 有主动使用 ClassLoader.loadClass 事件时才能被捕获。
这是一个实验性功能,一般情况下不会用到此方法,不保证不会发生错误。
只能在 (Xposed) 宿主环境使用此功能,其它环境下使用将不生效且会打印警告信息。
功能示例
针对一些使用特定 ClassLoader
装载 Class
的宿主应用,你可以使用此方法来监听 Class
加载情况。
注意
为了防止发生问题,你需要得到一个存在的 ClassLoader 实例来使用此功能。
比如我们在 PackageParam
中使用 appClassLoader
。
示例如下
appClassLoader.onLoadClass { clazz ->
+ // 得到 clazz 即加载对象
+ clazz... // 这里进行你需要的操作
+}
+
或使用你得到的存在的 ClassLoader
实例,可以通过 Hook 获取。
示例如下
val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader
+customClassLoader?.onLoadClass { clazz ->
+ // ...
+}
+
在判断到这个 Class
被装载成功时,开始执行你的 Hook 功能。
示例如下
val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader
+customClassLoader?.onLoadClass { clazz ->
+ if(clazz.name == /** 你需要的 Class 名称 */) {
+ clazz.hook {
+ // ...
+ }
+ }
+}
+
变更记录
v1.0
添加
v1.1.0
移除
HookClass
相关功能不再对外开放
变更记录
v1.0
添加
v1.1.0
移除
HookClass
相关功能不再对外开放
变更记录
v1.0
添加
v1.1.0
移除
请直接使用 hasClass()
无参方法
val Class<*>.hasExtends: Boolean
+
变更记录
v1.0.80
新增
功能描述
当前
Class
是否有继承关系,父类是Any
将被认为没有继承关系。
infix fun Class<*>?.extends(other: Class<*>?): Boolean
+
变更记录
v1.1.5
新增
功能描述
当前
Class
是否继承于other
。
如果当前 Class
就是 other
也会返回 true
。
如果当前 Class
为 null
或 other
为 null
会返回 false
。
功能示例
你可以使用此方法来判断两个 Class
是否存在继承关系。
示例如下
// 假设下面这两个 Class 就是你需要判断的 Class
+val classA: Class<*>?
+val classB: Class<*>?
+// 判断 A 是否继承于 B
+if (classA extends classB) {
+ // Your code here.
+}
+
infix fun Class<*>?.notExtends(other: Class<*>?): Boolean
+
变更记录
v1.1.5
新增
功能描述
当前
Class
是否不继承于other
。
此方法相当于 extends
的反向判断。
功能示例
你可以使用此方法来判断两个 Class
是否不存在继承关系。
示例如下
// 假设下面这两个 Class 就是你需要判断的 Class
+val classA: Class<*>?
+val classB: Class<*>?
+// 判断 A 是否不继承于 B
+if (classA notExtends classB) {
+ // Your code here.
+}
+
infix fun Class<*>?.implements(other: Class<*>?): Boolean
+
变更记录
v1.1.5
新增
功能描述
当前
Class
是否实现了other
接口类。
如果当前 Class
为 null
或 other
为 null
会返回 false
。
功能示例
你可以使用此方法来判断两个 Class
是否存在依赖关系。
示例如下
// 假设下面这两个 Class 就是你需要判断的 Class
+val classA: Class<*>?
+val classB: Class<*>?
+// 判断 A 是否实现了 B 接口类
+if (classA implements classB) {
+ // Your code here.
+}
+
infix fun Class<*>?.notImplements(other: Class<*>?): Boolean
+
变更记录
v1.1.5
新增
功能描述
当前
Class
是否未实现other
接口类。
此方法相当于 implements
的反向判断。
功能示例
你可以使用此方法来判断两个 Class
是否不存在依赖关系。
示例如下
// 假设下面这两个 Class 就是你需要判断的 Class
+val classA: Class<*>?
+val classB: Class<*>?
+// 判断 A 是否未实现 B 接口类
+if (classA notImplements classB) {
+ // Your code here.
+}
+
fun Class<*>.toJavaPrimitiveType(): Class<*>
+
变更记录
v1.1.5
新增
功能描述
自动转换当前
Class
为 Java 原始类型 (Primitive Type)。
如果当前 Class
为 Java 或 Kotlin 基本类型将自动执行类型转换。
当前能够自动转换的基本类型如下。
kotlin.Unit
java.lang.Void
java.lang.Boolean
java.lang.Integer
java.lang.Float
java.lang.Double
java.lang.Long
java.lang.Short
java.lang.Character
java.lang.Byte
变更记录
v1.0
添加
v1.1.0
作废
请转到 toClass(...)
方法
fun String.toClass(loader: ClassLoader?, initialize: Boolean): Class<*>
+
inline fun <reified T> String.toClass(loader: ClassLoader?, initialize: Boolean): Class<T>
+
变更记录
v1.1.0
新增
v1.1.5
修改
新增泛型返回值 Class<T>
方法
新增 initialize
参数
功能描述
通过字符串类名转换为
loader
中的实体类。
功能示例
你可以直接填写你要查找的目标 Class
,必须在默认 ClassLoader
下存在。
示例如下
"com.example.demo.DemoClass".toClass()
+
你还可以自定义 Class
所在的 ClassLoader
。
示例如下
val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader
+"com.example.demo.DemoClass".toClass(customClassLoader)
+
你还可以指定 Class
的目标类型。
示例如下
// 指定的 DemoClass 必须存在或为可访问的 stub
+"com.example.demo.DemoClass".toClass<DemoClass>()
+
你还可以设置在获取到这个 Class
时是否自动执行其默认的静态方法块,默认情况下不会执行。
示例如下
// 获取并执行 DemoClass 默认的静态方法块
+"com.example.demo.DemoClass".toClass(initialize = true)
+
默认的静态方法块在 Java 中使用如下方式定义。
示例如下
public class DemoClass {
+
+ static {
+ // 这里是静态方法块的内容
+ }
+
+ public DemoClass() {
+ // ...
+ }
+}
+
fun String.toClassOrNull(loader: ClassLoader?, initialize: Boolean): Class<*>?
+
inline fun <reified T> String.toClassOrNull(loader: ClassLoader?, initialize: Boolean): Class<T>?
+
变更记录
v1.1.0
新增
v1.1.5
修改
新增泛型返回值 Class<T>
方法
新增 initialize
参数
功能描述
通过字符串类名转换为
loader
中的实体类。
找不到 Class
会返回 null
,不会抛出异常。
功能示例
用法请参考 String.toClass 方法。
inline fun <reified T> classOf(loader: ClassLoader?, initialize: Boolean): Class<T>
+
变更记录
v1.1.0
新增
v1.1.5
修改
将返回类型由 Class<*>
cast 为 Class<T>
新增 initialize
参数
功能描述
通过
T
得到其Class
实例并转换为实体类。
功能示例
我们要获取一个 Class
在 Kotlin 下不通过反射时应该这样做。
示例如下
DemoClass::class.java
+
现在,你可以直接 cast
一个实例并获取它的 Class
对象,必须在当前 ClassLoader
下存在。
示例如下
classOf<DemoClass>()
+
若目标存在的 Class
为 stub
,通过这种方式,你还可以自定义 Class
所在的 ClassLoader
。
示例如下
val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader
+classOf<DemoClass>(customClassLoader)
+
fun lazyClass(name: String, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.NonNull<Any>
+
inline fun <reified T> lazyClass(name: String, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.NonNull<T>
+
fun lazyClass(variousClass: VariousClass, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.NonNull<Any>
+
变更记录
v1.2.0
新增
功能描述
懒装载
Class
。
fun lazyClassOrNull(name: String, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.Nullable<Any>
+
inline fun <reified T> lazyClassOrNull(name: String, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.Nullable<T>
+
fun lazyClassOrNull(variousClass: VariousClass, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.Nullable<Any>
+
变更记录
v1.2.0
新增
功能描述
懒装载
Class
。
fun String.hasClass(loader: ClassLoader?): Boolean
+
变更记录
v1.0
添加
v1.1.0
修改
支持直接使用空参数方法使用默认 ClassLoader
进行判断
功能描述
通过字符串类名使用指定的
ClassLoader
查找是否存在。
功能示例
你可以轻松的使用此方法判断字符串中的类是否存在,效果等同于直接使用 Class.forName
。
示例如下
if("com.example.demo.DemoClass".hasClass()) {
+ // Your code here.
+}
+
填入方法中的 loader
参数可判断指定的 ClassLoader
中的 Class
是否存在。
示例如下
val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader
+if("com.example.demo.DemoClass".hasClass(customClassLoader)) {
+ // Your code here.
+}
+
inline fun Class<*>.hasField(initiate: FieldConditions): Boolean
+
变更记录
v1.0.4
新增
v1.0.67
修改
合并到 FieldFinder
v1.0.80
修改
将方法体进行 inline
功能描述
查找变量是否存在。
inline fun Class<*>.hasMethod(initiate: MethodConditions): Boolean
+
变更记录
v1.0
添加
v1.0.1
修改
新增 returnType
参数
v1.0.67
修改
合并到 MethodFinder
v1.0.80
修改
将方法体进行 inline
功能描述
查找方法是否存在。
inline fun Class<*>.hasConstructor(initiate: ConstructorConditions): Boolean
+
变更记录
v1.0.2
新增
v1.0.67
修改
合并到 ConstructorFinder
v1.0.80
修改
将方法体进行 inline
功能描述
查找构造方法是否存在。
inline fun Member.hasModifiers(conditions: ModifierConditions): Boolean
+
变更记录
v1.0.67
新增
v1.0.80
修改
将方法体进行 inline
v1.1.0
修改
合并到 ModifierConditions
功能描述
查找
Member
中匹配的描述符。
inline fun Class<*>.hasModifiers(conditions: ModifierConditions): Boolean
+
变更记录
v1.1.0
新增
功能描述
查找
Class
中匹配的描述符。
变更记录
v1.0
添加
v1.0.1
移除
变更记录
v1.0
添加
v1.0.1
移除
变更记录
v1.0
添加
v1.0.1
移除
变更记录
v1.0
添加
v1.0.1
移除
inline fun Class<*>.field(initiate: FieldConditions): FieldFinder.Result
+
变更记录
v1.0.2
新增
v1.0.80
修改
将方法体进行 inline
功能描述
查找并得到变量。
inline fun Class<*>.method(initiate: MethodConditions): MethodFinder.Result
+
变更记录
v1.0
添加
v1.0.1
修改
更名为 obtainMethod
method
新增 returnType
参数
v1.0.2
修改
合并到 MethodFinder
方法体
v1.0.80
修改
将方法体进行 inline
功能描述
查找并得到方法。
inline fun Class<*>.constructor(initiate: ConstructorConditions): ConstructorFinder.Result
+
变更记录
v1.0
添加
v1.0.1
修改
更名为 obtainConstructor
constructor
v1.0.2
修改
合并到 ConstructorFinder
方法体
v1.0.80
修改
将方法体进行 inline
功能描述
查找并得到构造方法。
变更记录
v1.0
添加
v1.0.1
修改
更名为 invokeStatic
callStatic
v1.0.2
移除
变更记录
v1.0
添加
v1.0.1
修改
更名为 invokeAny
call
v1.0.2
移除
fun Class<*>.generic(): GenericClass?
+
变更记录
v1.1.0
新增
功能描述
获得当前
Class
的泛型父类。
如果当前实例不存在泛型将返回 null
。
inline fun Class<*>.generic(initiate: GenericClass.() -> Unit): GenericClass?
+
变更记录
v1.1.0
新增
功能描述
获得当前
Class
的泛型父类。
如果当前实例不存在泛型将返回 null
。
inline fun <reified T : Any> T.current(ignored: Boolean): CurrentClass
+
inline fun <reified T : Any> T.current(ignored: Boolean, initiate: CurrentClass.() -> Unit): T
+
变更记录
v1.0.70
新增
v1.1.0
新增
新增 ignored
参数,可以忽略在 CurrentClass
中出现的异常
新增不使用 current { ... }
调用域直接使用 current()
得到实例的类操作对象
功能描述
获得当前实例的类操作对象。
变更记录
v1.0.70
新增
v1.0.80
修改
将方法体进行 inline
v1.1.0
作废
请迁移到 buildOf
方法
inline fun Class<*>.buildOf(vararg args: Any?, initiate: ConstructorConditions): Any?
+
inline fun <T> Class<*>.buildOf(vararg args: Any?, initiate: ConstructorConditions): T?
+
变更记录
v1.0.70
新增
v1.0.80
修改
将方法体进行 inline
v1.1.0
修改
加入无泛型方法 buildOf
v1.1.6
修改
修改参数命名 param
为 args
功能描述
通过构造方法创建新实例,指定类型
T
或任意类型Any
。
inline fun Class<*>.allMethods(isAccessible: Boolean, result: (index: Int, method: Method) -> Unit)
+
变更记录
v1.0.70
新增
v1.0.80
修改
将方法体进行 inline
v1.1.5
修改
新增 isAccessible
参数
功能描述
遍历当前类中的所有方法。
inline fun Class<*>.allConstructors(isAccessible: Boolean, result: (index: Int, constructor: Constructor<*>) -> Unit)
+
变更记录
v1.0.70
新增
v1.0.80
修改
将方法体进行 inline
v1.1.5
修改
新增 isAccessible
参数
功能描述
遍历当前类中的所有构造方法。
inline fun Class<*>.allFields(isAccessible: Boolean, result: (index: Int, field: Field) -> Unit)
+
变更记录
v1.0.70
新增
v1.0.80
修改
将方法体进行 inline
v1.1.5
修改
新增 isAccessible
参数
功能描述
`,421),p=[l];function c(t,d){return a(),o("div",null,p)}const i=s(n,[["render",c],["__file","ReflectionFactory.html.vue"]]);export{i as default}; diff --git a/assets/VariableTypeFactory.html-BUNfn5Dn.js b/assets/VariableTypeFactory.html-BUNfn5Dn.js new file mode 100644 index 00000000..172c1fbf --- /dev/null +++ b/assets/VariableTypeFactory.html-BUNfn5Dn.js @@ -0,0 +1 @@ +const a=JSON.parse('{"key":"v-14ec8671","path":"/zh-cn/api/public/com/highcapable/yukihookapi/hook/type/java/VariableTypeFactory.html","title":"VariableTypeFactory - kt","lang":"zh-CN","frontmatter":{"pageClass":"code-page"},"headers":[],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":7}]},"filePathRelative":"zh-cn/api/public/com/highcapable/yukihookapi/hook/type/java/VariableTypeFactory.md"}');export{a as data}; diff --git a/assets/VariableTypeFactory.html-Cel7GBhi.js b/assets/VariableTypeFactory.html-Cel7GBhi.js new file mode 100644 index 00000000..96701537 --- /dev/null +++ b/assets/VariableTypeFactory.html-Cel7GBhi.js @@ -0,0 +1 @@ +import{_ as t,r as c,o as r,c as n,b as o,d as e,e as s,a as i}from"./app-BpUB8-Q8.js";const l={},p=i('遍历当前类中的所有变量。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
变更记录
v1.0
添加
功能描述
',6),d={href:"https://github.com/HighCapable/YukiHookAPI/blob/master/yukihookapi-core/src/main/java/com/highcapable/yukihookapi/hook/type/java/VariableTypeFactory.kt",target:"_blank",rel:"noopener noreferrer"};function k(h,_){const a=c("ExternalLinkIcon");return r(),n("div",null,[p,o("p",null,[e("详情可 "),o("a",d,[e("点击这里"),s(a)]),e(" 进行查看。")])])}const u=t(l,[["render",k],["__file","VariableTypeFactory.html.vue"]]);export{u as default}; diff --git a/assets/VariableTypeFactory.html-DDYYL3th.js b/assets/VariableTypeFactory.html-DDYYL3th.js new file mode 100644 index 00000000..d0c1bbcd --- /dev/null +++ b/assets/VariableTypeFactory.html-DDYYL3th.js @@ -0,0 +1 @@ +const a=JSON.parse('{"key":"v-ba01a600","path":"/en/api/public/com/highcapable/yukihookapi/hook/type/java/VariableTypeFactory.html","title":"VariableTypeFactory - kt","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":7}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/type/java/VariableTypeFactory.md"}');export{a as data}; diff --git a/assets/VariableTypeFactory.html-DqSR6Ejd.js b/assets/VariableTypeFactory.html-DqSR6Ejd.js new file mode 100644 index 00000000..e49d4964 --- /dev/null +++ b/assets/VariableTypeFactory.html-DqSR6Ejd.js @@ -0,0 +1 @@ +import{_ as a,r as n,o as c,c as r,b as o,d as e,e as s,a as i}from"./app-BpUB8-Q8.js";const l={},p=i('这是一个预置反射类型的常量类,主要为 Java 相关基本变量类型的
Class
内容,跟随版本更新会逐一进行增加。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
Change Records
v1.0
first
Function Illustrate
',7),d={href:"https://github.com/HighCapable/YukiHookAPI/blob/master/yukihookapi-core/src/main/java/com/highcapable/yukihookapi/hook/type/java/VariableTypeFactory.kt",target:"_blank",rel:"noopener noreferrer"};function h(u,m){const t=n("ExternalLinkIcon");return c(),r("div",null,[p,o("p",null,[e("详情可 "),o("a",d,[e("点击这里"),s(t)]),e(" 进行查看。")])])}const b=a(l,[["render",h],["__file","VariableTypeFactory.html.vue"]]);export{b as default}; diff --git a/assets/VariousClass.html-3D_jbtJ_.js b/assets/VariousClass.html-3D_jbtJ_.js new file mode 100644 index 00000000..8a4c0361 --- /dev/null +++ b/assets/VariousClass.html-3D_jbtJ_.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-032b1710","path":"/en/api/public/com/highcapable/yukihookapi/hook/bean/VariousClass.html","title":"VariousClass - class","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"get - method","slug":"get-method","link":"#get-method","children":[]},{"level":2,"title":"getOrNull - method","slug":"getornull-method","link":"#getornull-method","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":4}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/bean/VariousClass.md"}');export{e as data}; diff --git a/assets/VariousClass.html-BdAcgrdg.js b/assets/VariousClass.html-BdAcgrdg.js new file mode 100644 index 00000000..3300503e --- /dev/null +++ b/assets/VariousClass.html-BdAcgrdg.js @@ -0,0 +1,4 @@ +import{_ as s,o,c as a,a as e}from"./app-BpUB8-Q8.js";const l={},n=e(`这是一个预置反射类型的常量类,主要为 Java 相关基本变量类型的
Class
内容,跟随版本更新会逐一进行增加。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
class VariousClass(private vararg val name: String)
+
变更记录
v1.0
添加
v1.1.5
修改
私有化 name
参数并设置为不可修改
功能描述
这是一个不确定性
Class
类名装载器,通过name
装载Class
名称数组。
fun get(loader: ClassLoader? = null, initialize: Boolean): Class<*>
+
变更记录
v1.0.70
新增
v1.1.5
修改
新增 initialize
参数
功能描述
获取匹配的实体类。
使用当前 loader
装载目标 Class
。
fun getOrNull(loader: ClassLoader? = null, initialize: Boolean): Class<*>?
+
变更记录
v1.1.0
新增
v1.1.5
修改
新增 initialize
参数
功能描述
获取匹配的实体类。
使用当前 loader
装载目标 Class
。
匹配不到 Class
会返回 null
,不会抛出异常。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
class VariousClass(private vararg val name: String)
+
Change Records
v1.0
first
v1.1.5
modified
私有化 name
参数并设置为不可修改
Function Illustrate
这是一个不确定性
Class
类名装载器,通过name
装载Class
名称数组。
fun get(loader: ClassLoader? = null, initialize: Boolean): Class<*>
+
Change Records
v1.0.70
added
v1.1.5
modified
新增 initialize
参数
Function Illustrate
获取匹配的实体类。
使用当前 loader
装载目标 Class
。
fun getOrNull(loader: ClassLoader? = null, initialize: Boolean): Class<*>?
+
Change Records
v1.1.0
added
v1.1.5
modified
新增 initialize
参数
Function Illustrate
获取匹配的实体类。
使用当前 loader
装载目标 Class
。
匹配不到 Class
会返回 null
,不会抛出异常。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
Change Records
v1.0
first
Function Illustrate
',7),p={href:"https://github.com/HighCapable/YukiHookAPI/blob/master/yukihookapi-core/src/main/java/com/highcapable/yukihookapi/hook/type/android/ViewTypeFactory.kt",target:"_blank",rel:"noopener noreferrer"};function h(u,m){const t=n("ExternalLinkIcon");return c(),r("div",null,[l,o("p",null,[e("详情可 "),o("a",p,[e("点击这里"),s(t)]),e(" 进行查看。")])])}const g=a(d,[["render",h],["__file","ViewTypeFactory.html.vue"]]);export{g as default}; diff --git a/assets/ViewTypeFactory.html-CIPHyInd.js b/assets/ViewTypeFactory.html-CIPHyInd.js new file mode 100644 index 00000000..8278f2f4 --- /dev/null +++ b/assets/ViewTypeFactory.html-CIPHyInd.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-5309e4a0","path":"/en/api/public/com/highcapable/yukihookapi/hook/type/android/ViewTypeFactory.html","title":"ViewTypeFactory - kt","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":6}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/type/android/ViewTypeFactory.md"}');export{e as data}; diff --git a/assets/ViewTypeFactory.html-DPcuUPhN.js b/assets/ViewTypeFactory.html-DPcuUPhN.js new file mode 100644 index 00000000..c661f44b --- /dev/null +++ b/assets/ViewTypeFactory.html-DPcuUPhN.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-ef79cde2","path":"/zh-cn/api/public/com/highcapable/yukihookapi/hook/type/android/ViewTypeFactory.html","title":"ViewTypeFactory - kt","lang":"zh-CN","frontmatter":{"pageClass":"code-page"},"headers":[],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":6}]},"filePathRelative":"zh-cn/api/public/com/highcapable/yukihookapi/hook/type/android/ViewTypeFactory.md"}');export{e as data}; diff --git a/assets/ViewTypeFactory.html-pGgKQdI9.js b/assets/ViewTypeFactory.html-pGgKQdI9.js new file mode 100644 index 00000000..0ff05952 --- /dev/null +++ b/assets/ViewTypeFactory.html-pGgKQdI9.js @@ -0,0 +1 @@ +import{_ as c,r as a,o as r,c as n,b as o,d as e,e as s,a as d}from"./app-BpUB8-Q8.js";const i={},p=d('这是一个预置反射类型的常量类,主要为
Android
相关Widget
的Class
内容,跟随版本更新会逐一进行增加。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
变更记录
v1.0
添加
功能描述
',6),l={href:"https://github.com/HighCapable/YukiHookAPI/blob/master/yukihookapi-core/src/main/java/com/highcapable/yukihookapi/hook/type/android/ViewTypeFactory.kt",target:"_blank",rel:"noopener noreferrer"};function k(h,_){const t=a("ExternalLinkIcon");return r(),n("div",null,[p,o("p",null,[e("详情可 "),o("a",l,[e("点击这里"),s(t)]),e(" 进行查看。")])])}const y=c(i,[["render",k],["__file","ViewTypeFactory.html.vue"]]);export{y as default}; diff --git a/assets/YLog.html-COO68ekD.js b/assets/YLog.html-COO68ekD.js new file mode 100644 index 00000000..8fc6b834 --- /dev/null +++ b/assets/YLog.html-COO68ekD.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-36749c00","path":"/en/api/public/com/highcapable/yukihookapi/hook/log/YLog.html","title":"YLog - object","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"inMemoryData - field","slug":"inmemorydata-field","link":"#inmemorydata-field","children":[]},{"level":2,"title":"contents - field","slug":"contents-field","link":"#contents-field","children":[]},{"level":2,"title":"contents - method","slug":"contents-method","link":"#contents-method","children":[]},{"level":2,"title":"clear - method","slug":"clear-method","link":"#clear-method","children":[]},{"level":2,"title":"saveToFile - method","slug":"savetofile-method","link":"#savetofile-method","children":[]},{"level":2,"title":"Configs - object","slug":"configs-object","link":"#configs-object","children":[{"level":3,"title":"TAG - field","slug":"tag-field","link":"#tag-field","children":[]},{"level":3,"title":"PRIORITY - field","slug":"priority-field","link":"#priority-field","children":[]},{"level":3,"title":"PACKAGE_NAME - field","slug":"package-name-field","link":"#package-name-field","children":[]},{"level":3,"title":"USER_ID - field","slug":"user-id-field","link":"#user-id-field","children":[]},{"level":3,"title":"tag - field","slug":"tag-field-1","link":"#tag-field-1","children":[]},{"level":3,"title":"isEnable - field","slug":"isenable-field","link":"#isenable-field","children":[]},{"level":3,"title":"isRecord - field","slug":"isrecord-field","link":"#isrecord-field","children":[]},{"level":3,"title":"elements - method","slug":"elements-method","link":"#elements-method","children":[]}]},{"level":2,"title":"debug - method","slug":"debug-method","link":"#debug-method","children":[]},{"level":2,"title":"info - method","slug":"info-method","link":"#info-method","children":[]},{"level":2,"title":"warn - method","slug":"warn-method","link":"#warn-method","children":[]},{"level":2,"title":"error - method","slug":"error-method","link":"#error-method","children":[]},{"level":2,"title":"EnvType - class","slug":"envtype-class","link":"#envtype-class","children":[{"level":3,"title":"LOGD - enum","slug":"logd-enum","link":"#logd-enum","children":[]},{"level":3,"title":"XPOSED_ENVIRONMENT - enum","slug":"xposed-environment-enum","link":"#xposed-environment-enum","children":[]},{"level":3,"title":"SCOPE - enum","slug":"scope-enum","link":"#scope-enum","children":[]},{"level":3,"title":"BOTH - enum","slug":"both-enum","link":"#both-enum","children":[]}]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":2}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/log/YLog.md"}');export{e as data}; diff --git a/assets/YLog.html-DvNg4c8I.js b/assets/YLog.html-DvNg4c8I.js new file mode 100644 index 00000000..46282eba --- /dev/null +++ b/assets/YLog.html-DvNg4c8I.js @@ -0,0 +1,29 @@ +import{_ as s,o as e,c as a,a as o}from"./app-BpUB8-Q8.js";const n={},t=o(`这是一个预置反射类型的常量类,主要为
Android
相关Widget
的Class
内容,跟随版本更新会逐一进行增加。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
object YLog
+
Change Records
v1.2.0
added
Function Illustrate
全局 Log 管理类。
val inMemoryData: MutableList<YLogData>
+
Change Records
v1.2.0
added
Function Illustrate
当前全部已记录的日志数据。
Pay Attention
获取到的日志数据在 Hook APP (宿主) 及模块进程中是相互隔离的。
val contents: String
+
Change Records
v1.2.0
added
Function Illustrate
获取当前日志文件内容。
如果当前没有已记录的日志会返回空字符串。
Pay Attention
获取到的日志数据在 Hook APP (宿主) 及模块进程中是相互隔离的。
fun contents(data: List<YLogData>): String
+
Change Records
v1.2.0
added
Function Illustrate
获取、格式化当前日志文件内容。
如果当前没有已记录的日志 (data
为空) 会返回空字符串。
Pay Attention
获取到的日志数据在 Hook APP (宿主) 及模块进程中是相互隔离的。
fun clear()
+
Change Records
v1.2.0
added
Function Illustrate
清除全部已记录的日志。
你也可以直接获取 inMemoryData 来清除。
Pay Attention
获取到的日志数据在 Hook APP (宿主) 及模块进程中是相互隔离的。
fun saveToFile(fileName: String, data: List<YLogData>)
+
Change Records
v1.2.0
added
Function Illustrate
保存当前日志到文件。
若当前未开启 Configs.isRecord
或记录为空则不会进行任何操作。
日志文件会追加到 fileName
的文件结尾,若文件不存在会自动创建。
Pay Attention
文件读写权限取决于当前宿主、模块已获取的权限。
object Configs
+
Change Records
v1.2.0
added
Function Illustrate
配置
YLog
。
const val TAG: Int
+
Change Records
v1.2.0
added
Function Illustrate
标签。
const val PRIORITY: Int
+
Change Records
v1.2.0
added
Function Illustrate
优先级。
const val PACKAGE_NAME: Int
+
Change Records
v1.2.0
added
Function Illustrate
当前宿主的包名。
const val USER_ID: Int
+
Change Records
v1.2.0
added
Function Illustrate
当前宿主的用户 ID (主用户不显示)。
var tag: String
+
Change Records
v1.2.0
added
Function Illustrate
这是一个调试日志的全局标识。
默认文案为 YukiHookAPI
。
你可以修改为你自己的文案。
var isEnable: Boolean
+
Change Records
v1.2.0
added
Function Illustrate
是否启用调试日志的输出功能。
关闭后将会停用 YukiHookAPI
对全部日志的输出。
但是不影响当你手动调用下面这些方法输出日志。
debug
、info
、warn
、error
。
当 isEnable
关闭后 YukiHookAPI.Configs.isDebug
也将同时关闭。
var isRecord: Boolean
+
Change Records
v1.2.0
added
Function Illustrate
是否启用调试日志的记录功能。
开启后将会在内存中记录全部可用的日志和异常堆栈。
需要同时启用 isEnable 才能有效。
Pay Attention
过量的日志可能会导致宿主运行缓慢或造成频繁 GC。
开启后你可以调用 YLog.saveToFile 实时保存日志到文件或使用 YLog.contents 获取实时日志文件。
fun elements(vararg item: Int)
+
Change Records
v1.2.0
added
Function Illustrate
自定义调试日志对外显示的元素。
只对日志记录和 (Xposed) 宿主环境的日志生效。
日志元素的排列将按照你在 item
中设置的顺序进行显示。
你还可以留空 item
以不显示除日志内容外的全部元素。
可用的元素有:TAG
、PRIORITY
、PACKAGE_NAME
、USER_ID
。
功能示例
打印的日志样式将按照你设置的排列顺序和元素内容进行。
示例如下
elements(TAG, PRIORITY, PACKAGE_NAME, USER_ID)
+
以上内容定义的日志将显示为如下样式。
示例如下
[YukiHookAPI][D][com.demo.test][999]--> This is a log
+
如果我们调整元素顺序以及减少个数,那么结果又会不一样。
示例如下
elements(PACKAGE_NAME, USER_ID, PRIORITY)
+
以上内容定义的日志将显示为如下样式。
示例如下
[com.demo.test][999][D]--> This is a log
+
fun debug(msg: String, e: Throwable?, tag: String, env: EnvType)
+
Change Records
v1.2.0
added
Function Illustrate
打印 Debug 级别 Log。
fun info(msg: String, e: Throwable?, tag: String, env: EnvType)
+
Change Records
v1.2.0
added
Function Illustrate
打印 Info 级别 Log。
fun warn(msg: String, e: Throwable?, tag: String, env: EnvType)
+
Change Records
v1.2.0
added
Function Illustrate
打印 Warn 级别 Log。
fun error(msg: String, e: Throwable?, tag: String, env: EnvType)
+
Change Records
v1.2.0
added
Function Illustrate
打印 Error 级别 Log。
enum class EnvType
+
Change Records
v1.2.0
added
Function Illustrate
需要打印的日志环境类型。
决定于模块与 (Xposed) 宿主环境使用的打印方式。
LOGD
+
Change Records
v1.2.0
added
Function Illustrate
仅使用
android.util.Log
。
XPOSED_ENVIRONMENT
+
Change Records
v1.2.0
added
Function Illustrate
仅在 (Xposed) 宿主环境使用。
Pay Attention
只能在 (Xposed) 宿主环境中使用,模块环境将不生效。
SCOPE
+
Change Records
v1.2.0
added
Function Illustrate
分区使用。
(Xposed) 宿主环境仅使用 XPOSED_ENVIRONMENT
。
模块环境仅使用 LOGD
。
BOTH
+
Change Records
v1.2.0
added
Function Illustrate
同时使用。
(Xposed) 宿主环境使用 LOGD
与 XPOSED_ENVIRONMENT
。
模块环境仅使用 LOGD
。
Change Records
v1.0
first
v1.2.0
deprecated
请迁移到 YLog
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
object YLog
+
变更记录
v1.2.0
新增
功能描述
全局 Log 管理类。
val inMemoryData: MutableList<YLogData>
+
变更记录
v1.2.0
新增
功能描述
当前全部已记录的日志数据。
特别注意
获取到的日志数据在 Hook APP (宿主) 及模块进程中是相互隔离的。
val contents: String
+
变更记录
v1.2.0
新增
功能描述
获取当前日志文件内容。
如果当前没有已记录的日志会返回空字符串。
特别注意
获取到的日志数据在 Hook APP (宿主) 及模块进程中是相互隔离的。
fun contents(data: List<YLogData>): String
+
变更记录
v1.2.0
新增
功能描述
获取、格式化当前日志文件内容。
如果当前没有已记录的日志 (data
为空) 会返回空字符串。
特别注意
获取到的日志数据在 Hook APP (宿主) 及模块进程中是相互隔离的。
fun clear()
+
变更记录
v1.2.0
新增
功能描述
清除全部已记录的日志。
你也可以直接获取 inMemoryData 来清除。
特别注意
获取到的日志数据在 Hook APP (宿主) 及模块进程中是相互隔离的。
fun saveToFile(fileName: String, data: List<YLogData>)
+
变更记录
v1.2.0
新增
功能描述
保存当前日志到文件。
若当前未开启 Configs.isRecord
或记录为空则不会进行任何操作。
日志文件会追加到 fileName
的文件结尾,若文件不存在会自动创建。
特别注意
文件读写权限取决于当前宿主、模块已获取的权限。
object Configs
+
变更记录
v1.2.0
新增
功能描述
配置
YukiHookLogger
。
const val TAG: Int
+
变更记录
v1.2.0
新增
功能描述
标签。
const val PRIORITY: Int
+
变更记录
v1.2.0
新增
功能描述
优先级。
const val PACKAGE_NAME: Int
+
变更记录
v1.2.0
新增
功能描述
当前宿主的包名。
const val USER_ID: Int
+
变更记录
v1.2.0
新增
功能描述
当前宿主的用户 ID (主用户不显示)。
var tag: String
+
变更记录
v1.2.0
新增
功能描述
这是一个调试日志的全局标识。
默认文案为 YukiHookAPI
。
你可以修改为你自己的文案。
var isEnable: Boolean
+
变更记录
v1.2.0
新增
功能描述
是否启用调试日志的输出功能。
关闭后将会停用 YukiHookAPI
对全部日志的输出。
但是不影响当你手动调用下面这些方法输出日志。
debug
、info
、warn
、error
。
当 isEnable
关闭后 YukiHookAPI.Configs.isDebug
也将同时关闭。
var isRecord: Boolean
+
变更记录
v1.2.0
新增
功能描述
是否启用调试日志的记录功能。
开启后将会在内存中记录全部可用的日志和异常堆栈。
需要同时启用 isEnable 才能有效。
特别注意
过量的日志可能会导致宿主运行缓慢或造成频繁 GC。
开启后你可以调用 YLog.saveToFile 实时保存日志到文件或使用 YLog.contents 获取实时日志文件。
fun elements(vararg item: Int)
+
变更记录
v1.2.0
新增
功能描述
自定义调试日志对外显示的元素。
只对日志记录和 (Xposed) 宿主环境的日志生效。
日志元素的排列将按照你在 item
中设置的顺序进行显示。
你还可以留空 item
以不显示除日志内容外的全部元素。
可用的元素有:TAG
、PRIORITY
、PACKAGE_NAME
、USER_ID
。
功能示例
打印的日志样式将按照你设置的排列顺序和元素内容进行。
示例如下
elements(TAG, PRIORITY, PACKAGE_NAME, USER_ID)
+
以上内容定义的日志将显示为如下样式。
示例如下
[YukiHookAPI][D][com.demo.test][999]--> This is a log
+
如果我们调整元素顺序以及减少个数,那么结果又会不一样。
示例如下
elements(PACKAGE_NAME, USER_ID, PRIORITY)
+
以上内容定义的日志将显示为如下样式。
示例如下
[com.demo.test][999][D]--> This is a log
+
fun debug(msg: String, e: Throwable?, tag: String, env: EnvType)
+
变更记录
v1.2.0
新增
功能描述
打印 Debug 级别 Log。
fun info(msg: String, e: Throwable?, tag: String, env: EnvType)
+
变更记录
v1.2.0
新增
功能描述
打印 Info 级别 Log。
fun warn(msg: String, e: Throwable?, tag: String, env: EnvType)
+
变更记录
v1.2.0
新增
功能描述
打印 Warn 级别 Log。
fun error(msg: String, e: Throwable?, tag: String, env: EnvType)
+
变更记录
v1.2.0
新增
功能描述
打印 Error 级别 Log。
enum class EnvType
+
变更记录
v1.2.0
新增
功能描述
需要打印的日志环境类型。
决定于模块与 (Xposed) 宿主环境使用的打印方式。
LOGD
+
变更记录
v1.2.0
新增
功能描述
仅使用
android.util.Log
。
XPOSED_ENVIRONMENT
+
变更记录
v1.2.0
新增
功能描述
仅在 (Xposed) 宿主环境使用。
特别注意
只能在 (Xposed) 宿主环境中使用,模块环境将不生效。
SCOPE
+
变更记录
v1.2.0
新增
功能描述
分区使用。
(Xposed) 宿主环境仅使用 XPOSED_ENVIRONMENT
。
模块环境仅使用 LOGD
。
BOTH
+
变更记录
v1.2.0
新增
功能描述
同时使用。
(Xposed) 宿主环境使用 LOGD
与 XPOSED_ENVIRONMENT
。
模块环境仅使用 LOGD
。
变更记录
v1.0
添加
v1.2.0
作废
请迁移到 YLog
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
data class YLogData internal constructor(
+ var timestamp: Long,
+ var time: String,
+ var tag: String,
+ var priority: String,
+ var packageName: String,
+ var userId: Int,
+ var msg: String,
+ var throwable: Throwable?
+) : Serializable
+
Change Records
v1.2.0
added
Function Illustrate
`,8),p=[e];function t(c,r){return a(),n("div",null,p)}const A=s(l,[["render",t],["__file","YLogData.html.vue"]]);export{A as default}; diff --git a/assets/YLogData.html-Bjac08gN.js b/assets/YLogData.html-Bjac08gN.js new file mode 100644 index 00000000..3b1c4998 --- /dev/null +++ b/assets/YLogData.html-Bjac08gN.js @@ -0,0 +1 @@ +const a=JSON.parse('{"key":"v-57e0fa9e","path":"/zh-cn/api/public/com/highcapable/yukihookapi/hook/log/data/YLogData.html","title":"YLogData - class","lang":"zh-CN","frontmatter":{"pageClass":"code-page"},"headers":[],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":2}]},"filePathRelative":"zh-cn/api/public/com/highcapable/yukihookapi/hook/log/data/YLogData.md"}');export{a as data}; diff --git a/assets/YLogData.html-DIaUDgTt.js b/assets/YLogData.html-DIaUDgTt.js new file mode 100644 index 00000000..c587130e --- /dev/null +++ b/assets/YLogData.html-DIaUDgTt.js @@ -0,0 +1,11 @@ +import{_ as s,o as a,c as n,a as o}from"./app-BpUB8-Q8.js";const l={},p=o(`调试日志数据实现类。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
data class YLogData internal constructor(
+ var timestamp: Long,
+ var time: String,
+ var tag: String,
+ var priority: String,
+ var packageName: String,
+ var userId: Int,
+ var msg: String,
+ var throwable: Throwable?
+) : Serializable
+
变更记录
v1.2.0
新增
功能描述
`,7),e=[p];function t(c,r){return a(),n("div",null,e)}const y=s(l,[["render",t],["__file","YLogData.html.vue"]]);export{y as default}; diff --git a/assets/YLogData.html-XHmF_gos.js b/assets/YLogData.html-XHmF_gos.js new file mode 100644 index 00000000..fdde6b12 --- /dev/null +++ b/assets/YLogData.html-XHmF_gos.js @@ -0,0 +1 @@ +const a=JSON.parse('{"key":"v-e37480a6","path":"/en/api/public/com/highcapable/yukihookapi/hook/log/data/YLogData.html","title":"YLogData - class","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":2}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/log/data/YLogData.md"}');export{a as data}; diff --git a/assets/YukiBaseHooker.html-CWm_43km.js b/assets/YukiBaseHooker.html-CWm_43km.js new file mode 100644 index 00000000..e3396ab7 --- /dev/null +++ b/assets/YukiBaseHooker.html-CWm_43km.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-e288ce96","path":"/en/api/public/com/highcapable/yukihookapi/hook/entity/YukiBaseHooker.html","title":"YukiBaseHooker - class","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"onHook - method","slug":"onhook-method","link":"#onhook-method","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":2}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/entity/YukiBaseHooker.md"}');export{e as data}; diff --git a/assets/YukiBaseHooker.html-D01KVdut.js b/assets/YukiBaseHooker.html-D01KVdut.js new file mode 100644 index 00000000..8ba5b84c --- /dev/null +++ b/assets/YukiBaseHooker.html-D01KVdut.js @@ -0,0 +1,3 @@ +import{_ as o,o as s,c as a,a as e}from"./app-BpUB8-Q8.js";const n={},c=e(`调试日志数据实现类。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
abstract class YukiBaseHooker : PackageParam()
+
变更记录
v1.0
添加
功能描述
YukiHookAPI
的子类 Hooker 实现。
fun onHook()
+
变更记录
v1.0
添加
功能描述
`,13),t=[c];function l(p,r){return s(),a("div",null,t)}const i=o(n,[["render",l],["__file","YukiBaseHooker.html.vue"]]);export{i as default}; diff --git a/assets/YukiBaseHooker.html-Dg91Mdnk.js b/assets/YukiBaseHooker.html-Dg91Mdnk.js new file mode 100644 index 00000000..50ac31f9 --- /dev/null +++ b/assets/YukiBaseHooker.html-Dg91Mdnk.js @@ -0,0 +1,3 @@ +import{_ as o,o as e,c as s,a}from"./app-BpUB8-Q8.js";const n={},t=a(`子类 Hook 开始。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
abstract class YukiBaseHooker : PackageParam()
+
Change Records
v1.0
first
Function Illustrate
YukiHookAPI
的子类 Hooker 实现。
fun onHook()
+
Change Records
v1.0
first
Function Illustrate
`,14),c=[t];function l(r,i){return e(),s("div",null,c)}const d=o(n,[["render",l],["__file","YukiBaseHooker.html.vue"]]);export{d as default}; diff --git a/assets/YukiBaseHooker.html-E78OJRmm.js b/assets/YukiBaseHooker.html-E78OJRmm.js new file mode 100644 index 00000000..06ff01a8 --- /dev/null +++ b/assets/YukiBaseHooker.html-E78OJRmm.js @@ -0,0 +1 @@ +const o=JSON.parse('{"key":"v-516df326","path":"/zh-cn/api/public/com/highcapable/yukihookapi/hook/entity/YukiBaseHooker.html","title":"YukiBaseHooker - class","lang":"zh-CN","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"onHook - method","slug":"onhook-method","link":"#onhook-method","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":2}]},"filePathRelative":"zh-cn/api/public/com/highcapable/yukihookapi/hook/entity/YukiBaseHooker.md"}');export{o as data}; diff --git a/assets/YukiHookAPI.html-BRFLeDZT.js b/assets/YukiHookAPI.html-BRFLeDZT.js new file mode 100644 index 00000000..b3ae8218 --- /dev/null +++ b/assets/YukiHookAPI.html-BRFLeDZT.js @@ -0,0 +1,93 @@ +import{_ as s,o as e,c as a,a as n}from"./app-BpUB8-Q8.js";const o={},l=n(`子类 Hook 开始。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
object YukiHookAPI
+
Change Records
v1.0
first
Function Illustrate
这是
YukiHookAPI
的 API 调用总类,Hook 相关功能的开始、Hook 相关功能的配置都在这里。
const val TAG: String
+
Change Records
v1.2.0
added
Function Illustrate
获取当前
YukiHookAPI
的名称 (标签)。
const val VERSION: String
+
Change Records
v1.2.0
added
Function Illustrate
获取当前
YukiHookAPI
的版本。
Change Records
v1.0.4
added
v1.2.0
deprecated
不再区分版本名称和版本号,请迁移到 VERSION
Change Records
v1.0.4
added
v1.2.0
deprecated
不再区分版本名称和版本号,请迁移到 VERSION
Change Records
v1.0.5
added
v1.0.91
removed
请迁移到 Status.Executor.name
Change Records
v1.0.5
added
v1.0.91
removed
请迁移到 Status.Executor.apiLevel
、Status.Executor.versionName
、Status.Executor.versionCode
object Status
+
Change Records
v1.0.91
added
Function Illustrate
当前
YukiHookAPI
的状态。
val compiledTimestamp: Long
+
Change Records
v1.1.0
added
Function Illustrate
获取项目编译完成的时间戳 (当前本地时间)。
val isXposedEnvironment: Boolean
+
Change Records
v1.1.0
added
Function Illustrate
获取当前是否为 (Xposed) 宿主环境。
Change Records
v1.0.91
added
v1.1.5
deprecated
请迁移到 Executor.name
Change Records
v1.0.91
added
v1.1.5
deprecated
请迁移到 Executor.apiLevel
、Executor.versionName
、Executor.versionCode
val isModuleActive: Boolean
+
Change Records
v1.0.91
added
Function Illustrate
判断模块是否在 Xposed 或太极、无极中激活。
Notice
在模块环境中你需要将 Application 继承于 ModuleApplication。
在模块环境中需要启用 InjectYukiHookWithXposed.isUsingXposedModuleStatus。
在 (Xposed) 宿主环境中仅返回非 isTaiChiModuleActive 的激活状态。
val isXposedModuleActive: Boolean
+
Change Records
v1.0.91
added
Function Illustrate
仅判断模块是否在 Xposed 中激活。
Notice
在模块环境中需要启用 InjectYukiHookWithXposed.isUsingXposedModuleStatus。
在 (Xposed) 宿主环境中始终返回 true。
val isTaiChiModuleActive: Boolean
+
Change Records
v1.0.91
added
Function Illustrate
仅判断模块是否在太极、无极中激活。
Notice
在模块环境中你需要将 Application 继承于 ModuleApplication。
在 (Xposed) 宿主环境中始终返回 false。
val isSupportResourcesHook: Boolean
+
Change Records
v1.0.91
added
Function Illustrate
判断当前 Hook Framework 是否支持资源钩子 (Resources Hook)。
Notice
在模块环境中需要启用 InjectYukiHookWithXposed.isUsingXposedModuleStatus。
在 (Xposed) 宿主环境中可能会延迟等待事件回调后才会返回 true。
请注意你需要确保 InjectYukiHookWithXposed.isUsingResourcesHook 已启用,否则始终返回 false。
object Executor
+
Change Records
v1.1.5
added
Function Illustrate
当前
YukiHookAPI
使用的 Hook Framework 相关信息。
val name: String
+
Change Records
v1.1.5
added
Function Illustrate
获取当前 Hook Framework 名称。
Notice
在模块环境中需要启用 InjectYukiHookWithXposed.isUsingXposedModuleStatus。
val type: ExecutorType
+
Change Records
v1.1.9
added
Function Illustrate
获取当前 Hook Framework 类型。
Notice
在模块环境中需要启用 InjectYukiHookWithXposed.isUsingXposedModuleStatus。
val apiLevel: Int
+
Change Records
v1.1.5
added
Function Illustrate
获取当前 Hook Framework 的 API 版本。
Notice
在模块环境中需要启用 InjectYukiHookWithXposed.isUsingXposedModuleStatus。
val versionName: String
+
Change Records
v1.1.5
added
Function Illustrate
获取当前 Hook Framework 版本名称。
Notice
在模块环境中需要启用 InjectYukiHookWithXposed.isUsingXposedModuleStatus。
val versionCode: Int
+
Change Records
v1.1.5
added
Function Illustrate
获取当前 Hook Framework 版本号。
Notice
在模块环境中需要启用 InjectYukiHookWithXposed.isUsingXposedModuleStatus。
object Configs
+
Change Records
v1.0
first
Function Illustrate
对 API 相关功能的配置类。
inline fun debugLog(initiate: YLog.Configs.() -> Unit)
+
Change Records
v1.1.0
added
Function Illustrate
配置
YLog.Configs
相关参数。
Change Records
v1.0
first
v1.1.0
deprecated
请迁移到 YLog.Configs.tag
var isDebug: Boolean
+
Change Records
v1.0
first
Function Illustrate
是否启用 Debug 模式。
默认不启用,启用后模块将会向 Logcat
和 (Xposed) 宿主环境中的日志功能打印详细的 Hook 日志,关闭后仅会打印 E
级别的日志。
Change Records
v1.0.4
added
v1.1.0
deprecated
请迁移到 YLog.Configs.isEnable
Change Records
v1.0.5
added
v1.1.9
deprecated
请迁移到 isEnablePrefsBridgeCache
Change Records
v1.1.9
added
v1.1.11
deprecated
键值的直接缓存功能已被移除,因为其存在内存溢出 (OOM) 问题
var isEnableModuleAppResourcesCache: Boolean
+
Change Records
v1.0.87
added
Function Illustrate
是否启用当前 Xposed 模块自身
Resources
缓存功能。
为防止内存复用过高问题,此功能默认启用。
你可以手动调用 PackageParam.refreshModuleAppResources
来刷新缓存。
Notice
关闭后每次使用 PackageParam.moduleAppResources 都会重新创建,可能会造成运行缓慢。
变更记录
v1.0.88
added
v1.2.0
deprecated
请手动迁移到 InjectYukiHookWithXposed.isUsingXposedModuleStatus
var isEnableHookSharedPreferences: Boolean
+
Change Records
v1.1.0
added
Function Illustrate
是否启用 Hook
SharedPreferences
。
启用后将在模块启动时强制将 SharedPreferences
文件权限调整为 Context.MODE_WORLD_READABLE
(0664)。
Notice
这是一个可选的实验性功能,此功能默认不启用。
仅用于修复某些系统可能会出现在启用了 New XSharedPreferences 后依然出现文件权限错误问题,若你能正常使用 YukiHookPrefsBridge 就不建议启用此功能。
var isEnableDataChannel: Boolean
+
Change Records
v1.0.88
added
Function Illustrate
是否启用当前 Xposed 模块与宿主交互的
YukiHookDataChannel
功能。
请确保 Xposed 模块的 Application
继承于 ModuleApplication
才能有效。
此功能默认启用,关闭后将不会在功能初始化的时候装载 YukiHookDataChannel
。
Change Records
v1.0.68
added
v1.1.11
deprecated
Member
的直接缓存功能已被移除,因为其存在内存溢出 (OOM) 问题
inline fun configs(initiate: Configs.() -> Unit)
+
Change Records
v1.0
first
v1.0.80
modified
将方法体进行 inline
Function Illustrate
对
Configs
类实现了一个 lambda 方法体。
你可以轻松地调用它进行配置。
Function Example
你可以在 Hook 入口类的 onInit
方法中调用 configs
方法和 debugLog
方法完成对 API 的功能配置,实时生效。
The following example
object HookEntry : IYukiHookXposedInit {
+
+ override fun onInit() {
+ YukiHookAPI.configs {
+ debugLog {
+ tag = "YukiHookAPI"
+ isEnable = true
+ isRecord = false
+ elements(TAG, PRIORITY, PACKAGE_NAME, USER_ID)
+ }
+ isDebug = BuildConfig.DEBUG
+ isEnableModuleAppResourcesCache = true
+ isEnableHookModuleStatus = true
+ isEnableHookSharedPreferences = false
+ isEnableDataChannel = true
+ }
+ }
+
+ override fun onHook() {
+ // Your code here.
+ }
+}
+
若觉得上面的写法不美观,你还可以写得更加简洁。
The following example
object HookEntry : IYukiHookXposedInit {
+
+ override fun onInit() = configs {
+ debugLog {
+ tag = "YukiHookAPI"
+ isEnable = true
+ isRecord = false
+ elements(TAG, PRIORITY, PACKAGE_NAME, USER_ID)
+ }
+ isDebug = BuildConfig.DEBUG
+ isEnableModuleAppResourcesCache = true
+ isEnableHookModuleStatus = true
+ isEnableHookSharedPreferences = false
+ isEnableDataChannel = true
+ }
+
+ override fun onHook() {
+ // Your code here.
+ }
+}
+
你也可以不通过 configs
和 debugLog
方法,直接进行配置。
The following example
object HookEntry : IYukiHookXposedInit {
+
+ override fun onInit() {
+ YLog.Configs.tag = "YukiHookAPI"
+ YLog.Configs.isEnable = true
+ YLog.Configs.isRecord = false
+ YLog.Configs.elements(
+ YLog.Configs.TAG,
+ YLog.Configs.PRIORITY,
+ YLog.Configs.PACKAGE_NAME,
+ YLog.Configs.USER_ID
+ )
+ YukiHookAPI.Configs.isDebug = BuildConfig.DEBUG
+ YukiHookAPI.Configs.isEnableModuleAppResourcesCache = true
+ YukiHookAPI.InjectYukiHookWithXposed.isUsingXposedModuleStatus = true
+ YukiHookAPI.Configs.isEnableHookSharedPreferences = false
+ YukiHookAPI.Configs.isEnableDataChannel = true
+ }
+
+ override fun onHook() {
+ // Your code here.
+ }
+}
+
fun encase(initiate: PackageParam.() -> Unit)
+
fun encase(vararg hooker: YukiBaseHooker)
+
fun encase(baseContext: Context?, initiate: PackageParam.() -> Unit)
+
fun encase(baseContext: Context?, vararg hooker: YukiBaseHooker)
+
Change Records
v1.0
first
Function Illustrate
装载 Hook 入口的核心方法。
Function Example
详情请参考
`,242),p=[l];function c(t,d){return e(),a("div",null,p)}const r=s(o,[["render",c],["__file","YukiHookAPI.html.vue"]]);export{r as default}; diff --git a/assets/YukiHookAPI.html-CtkZ6zEO.js b/assets/YukiHookAPI.html-CtkZ6zEO.js new file mode 100644 index 00000000..c5648a16 --- /dev/null +++ b/assets/YukiHookAPI.html-CtkZ6zEO.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-053599a5","path":"/en/api/public/com/highcapable/yukihookapi/YukiHookAPI.html","title":"YukiHookAPI - object","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"TAG - field","slug":"tag-field","link":"#tag-field","children":[]},{"level":2,"title":"VERSION - field","slug":"version-field","link":"#version-field","children":[]},{"level":2,"title":"Status - object","slug":"status-object","link":"#status-object","children":[{"level":3,"title":"compiledTimestamp - field","slug":"compiledtimestamp-field","link":"#compiledtimestamp-field","children":[]},{"level":3,"title":"isXposedEnvironment - field","slug":"isxposedenvironment-field","link":"#isxposedenvironment-field","children":[]},{"level":3,"title":"isModuleActive - field","slug":"ismoduleactive-field","link":"#ismoduleactive-field","children":[]},{"level":3,"title":"isXposedModuleActive - field","slug":"isxposedmoduleactive-field","link":"#isxposedmoduleactive-field","children":[]},{"level":3,"title":"isTaiChiModuleActive - field","slug":"istaichimoduleactive-field","link":"#istaichimoduleactive-field","children":[]},{"level":3,"title":"isSupportResourcesHook - field","slug":"issupportresourceshook-field","link":"#issupportresourceshook-field","children":[]},{"level":3,"title":"Executor - object","slug":"executor-object","link":"#executor-object","children":[]}]},{"level":2,"title":"Configs - object","slug":"configs-object","link":"#configs-object","children":[{"level":3,"title":"debugLog - method","slug":"debuglog-method","link":"#debuglog-method","children":[]},{"level":3,"title":"isDebug - field","slug":"isdebug-field","link":"#isdebug-field","children":[]},{"level":3,"title":"isEnableModuleAppResourcesCache - field","slug":"isenablemoduleappresourcescache-field","link":"#isenablemoduleappresourcescache-field","children":[]},{"level":3,"title":"isEnableHookSharedPreferences - field","slug":"isenablehooksharedpreferences-field","link":"#isenablehooksharedpreferences-field","children":[]},{"level":3,"title":"isEnableDataChannel - field","slug":"isenabledatachannel-field","link":"#isenabledatachannel-field","children":[]}]},{"level":2,"title":"configs - method","slug":"configs-method","link":"#configs-method","children":[]},{"level":2,"title":"encase - method","slug":"encase-method","link":"#encase-method","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":18}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/YukiHookAPI.md"}');export{e as data}; diff --git a/assets/YukiHookAPI.html-DqgBnIkU.js b/assets/YukiHookAPI.html-DqgBnIkU.js new file mode 100644 index 00000000..619aa8f2 --- /dev/null +++ b/assets/YukiHookAPI.html-DqgBnIkU.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-6931cb54","path":"/zh-cn/api/public/com/highcapable/yukihookapi/YukiHookAPI.html","title":"YukiHookAPI - object","lang":"zh-CN","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"TAG - field","slug":"tag-field","link":"#tag-field","children":[]},{"level":2,"title":"VERSION - field","slug":"version-field","link":"#version-field","children":[]},{"level":2,"title":"Status - object","slug":"status-object","link":"#status-object","children":[{"level":3,"title":"compiledTimestamp - field","slug":"compiledtimestamp-field","link":"#compiledtimestamp-field","children":[]},{"level":3,"title":"isXposedEnvironment - field","slug":"isxposedenvironment-field","link":"#isxposedenvironment-field","children":[]},{"level":3,"title":"isModuleActive - field","slug":"ismoduleactive-field","link":"#ismoduleactive-field","children":[]},{"level":3,"title":"isXposedModuleActive - field","slug":"isxposedmoduleactive-field","link":"#isxposedmoduleactive-field","children":[]},{"level":3,"title":"isTaiChiModuleActive - field","slug":"istaichimoduleactive-field","link":"#istaichimoduleactive-field","children":[]},{"level":3,"title":"isSupportResourcesHook - field","slug":"issupportresourceshook-field","link":"#issupportresourceshook-field","children":[]},{"level":3,"title":"Executor - object","slug":"executor-object","link":"#executor-object","children":[]}]},{"level":2,"title":"Configs - object","slug":"configs-object","link":"#configs-object","children":[{"level":3,"title":"debugLog - method","slug":"debuglog-method","link":"#debuglog-method","children":[]},{"level":3,"title":"isDebug - field","slug":"isdebug-field","link":"#isdebug-field","children":[]},{"level":3,"title":"isEnableModuleAppResourcesCache - field","slug":"isenablemoduleappresourcescache-field","link":"#isenablemoduleappresourcescache-field","children":[]},{"level":3,"title":"isEnableHookSharedPreferences - field","slug":"isenablehooksharedpreferences-field","link":"#isenablehooksharedpreferences-field","children":[]},{"level":3,"title":"isEnableDataChannel - field","slug":"isenabledatachannel-field","link":"#isenabledatachannel-field","children":[]}]},{"level":2,"title":"configs - method","slug":"configs-method","link":"#configs-method","children":[]},{"level":2,"title":"encase - method","slug":"encase-method","link":"#encase-method","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":22}]},"filePathRelative":"zh-cn/api/public/com/highcapable/yukihookapi/YukiHookAPI.md"}');export{e as data}; diff --git a/assets/YukiHookAPI.html-DwLoSNWF.js b/assets/YukiHookAPI.html-DwLoSNWF.js new file mode 100644 index 00000000..cb0971bb --- /dev/null +++ b/assets/YukiHookAPI.html-DwLoSNWF.js @@ -0,0 +1,93 @@ +import{_ as s,o as e,c as n,a}from"./app-BpUB8-Q8.js";const o={},l=a(`注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
object YukiHookAPI
+
变更记录
v1.0
添加
功能描述
这是
YukiHookAPI
的 API 调用总类,Hook 相关功能的开始、Hook 相关功能的配置都在这里。
const val TAG: String
+
变更记录
v1.2.0
新增
功能描述
获取当前
YukiHookAPI
的名称 (标签)。
const val VERSION: String
+
变更记录
v1.2.0
新增
功能描述
获取当前
YukiHookAPI
的版本。
变更记录
v1.0.4
新增
v1.2.0
作废
不再区分版本名称和版本号,请迁移到 VERSION
变更记录
v1.0.4
新增
v1.2.0
作废
不再区分版本名称和版本号,请迁移到 VERSION
变更记录
v1.0.5
新增
v1.0.91
移除
请迁移到 Status.Executor.name
变更记录
v1.0.5
新增
v1.0.91
移除
请迁移到 Status.Executor.apiLevel
、Status.Executor.versionName
、Status.Executor.versionCode
object Status
+
变更记录
v1.0.91
新增
功能描述
当前
YukiHookAPI
的状态。
val compiledTimestamp: Long
+
变更记录
v1.1.0
新增
功能描述
获取项目编译完成的时间戳 (当前本地时间)。
val isXposedEnvironment: Boolean
+
变更记录
v1.1.0
新增
功能描述
获取当前是否为 (Xposed) 宿主环境。
变更记录
v1.0.91
新增
v1.1.5
作废
请迁移到 Executor.name
变更记录
v1.0.91
新增
v1.1.5
作废
请迁移到 Executor.apiLevel
、Executor.versionName
、Executor.versionCode
val isModuleActive: Boolean
+
变更记录
v1.0.91
新增
功能描述
判断模块是否在 Xposed 或太极、无极中激活。
注意
在模块环境中你需要将 Application 继承于 ModuleApplication。
在模块环境中需要启用 InjectYukiHookWithXposed.isUsingXposedModuleStatus。
在 (Xposed) 宿主环境中仅返回非 isTaiChiModuleActive 的激活状态。
val isXposedModuleActive: Boolean
+
变更记录
v1.0.91
新增
功能描述
仅判断模块是否在 Xposed 中激活。
注意
在模块环境中需要启用 InjectYukiHookWithXposed.isUsingXposedModuleStatus。
在 (Xposed) 宿主环境中始终返回 true。
val isTaiChiModuleActive: Boolean
+
变更记录
v1.0.91
新增
功能描述
仅判断模块是否在太极、无极中激活。
注意
在模块环境中你需要将 Application 继承于 ModuleApplication。
在 (Xposed) 宿主环境中始终返回 false。
val isSupportResourcesHook: Boolean
+
变更记录
v1.0.91
新增
功能描述
判断当前 Hook Framework 是否支持资源钩子 (Resources Hook)。
注意
在模块环境中需要启用 InjectYukiHookWithXposed.isUsingXposedModuleStatus。
在 (Xposed) 宿主环境中可能会延迟等待事件回调后才会返回 true。
请注意你需要确保 InjectYukiHookWithXposed.isUsingResourcesHook 已启用,否则始终返回 false。
object Executor
+
变更记录
v1.1.5
新增
功能描述
当前
YukiHookAPI
使用的 Hook Framework 相关信息。
val name: String
+
变更记录
v1.1.5
新增
功能描述
获取当前 Hook Framework 名称。
注意
在模块环境中需要启用 InjectYukiHookWithXposed.isUsingXposedModuleStatus。
val type: ExecutorType
+
变更记录
v1.1.9
新增
功能描述
获取当前 Hook Framework 类型。
注意
在模块环境中需要启用 InjectYukiHookWithXposed.isUsingXposedModuleStatus。
val apiLevel: Int
+
变更记录
v1.1.5
新增
功能描述
获取当前 Hook Framework 的 API 版本。
注意
在模块环境中需要启用 InjectYukiHookWithXposed.isUsingXposedModuleStatus。
val versionName: String
+
变更记录
v1.1.5
新增
功能描述
获取当前 Hook Framework 版本名称。
注意
在模块环境中需要启用 InjectYukiHookWithXposed.isUsingXposedModuleStatus。
val versionCode: Int
+
变更记录
v1.1.5
新增
功能描述
获取当前 Hook Framework 版本号。
注意
在模块环境中需要启用 InjectYukiHookWithXposed.isUsingXposedModuleStatus。
object Configs
+
变更记录
v1.0
添加
功能描述
对 API 相关功能的配置类。
inline fun debugLog(initiate: YLog.Configs.() -> Unit)
+
变更记录
v1.1.0
新增
功能描述
配置
YLog.Configs
相关参数。
变更记录
v1.0
添加
v1.1.0
作废
请迁移到 YLog.Configs.tag
var isDebug: Boolean
+
变更记录
v1.0
添加
功能描述
是否启用 Debug 模式。
默认不启用,启用后模块将会向 Logcat
和 (Xposed) 宿主环境中的日志功能打印详细的 Hook 日志,关闭后仅会打印 E
级别的日志。
变更记录
v1.0.4
新增
v1.1.0
作废
请迁移到 YLog.Configs.isEnable
变更记录
v1.0.5
新增
v1.1.9
作废
请迁移到 isEnablePrefsBridgeCache
变更记录
v1.1.9
新增
v1.1.11
作废
键值的直接缓存功能已被移除,因为其存在内存溢出 (OOM) 问题
var isEnableModuleAppResourcesCache: Boolean
+
变更记录
v1.0.87
新增
功能描述
是否启用当前 Xposed 模块自身
Resources
缓存功能。
为防止内存复用过高问题,此功能默认启用。
你可以手动调用 PackageParam.refreshModuleAppResources
来刷新缓存。
注意
关闭后每次使用 PackageParam.moduleAppResources 都会重新创建,可能会造成运行缓慢。
变更记录
v1.0.88
新增
v1.2.0
作废
请手动迁移到 InjectYukiHookWithXposed.isUsingXposedModuleStatus
var isEnableHookSharedPreferences: Boolean
+
变更记录
v1.1.0
新增
功能描述
是否启用 Hook
SharedPreferences
。
启用后将在模块启动时强制将 SharedPreferences
文件权限调整为 Context.MODE_WORLD_READABLE
(0664)。
注意
这是一个可选的实验性功能,此功能默认不启用。
仅用于修复某些系统可能会出现在启用了 New XSharedPreferences 后依然出现文件权限错误问题,若你能正常使用 YukiHookPrefsBridge 就不建议启用此功能。
var isEnableDataChannel: Boolean
+
变更记录
v1.0.88
新增
功能描述
是否启用当前 Xposed 模块与宿主交互的
YukiHookDataChannel
功能。
请确保 Xposed 模块的 Application
继承于 ModuleApplication
才能有效。
此功能默认启用,关闭后将不会在功能初始化的时候装载 YukiHookDataChannel
。
变更记录
v1.0.68
新增
v1.1.11
作废
Member
的直接缓存功能已被移除,因为其存在内存溢出 (OOM) 问题
inline fun configs(initiate: Configs.() -> Unit)
+
变更记录
v1.0
添加
v1.0.80
修改
将方法体进行 inline
功能描述
对
Configs
类实现了一个 lambda 方法体。
你可以轻松地调用它进行配置。
功能示例
你可以在 Hook 入口类的 onInit
方法中调用 configs
方法和 debugLog
方法完成对 API 的功能配置,实时生效。
示例如下
object HookEntry : IYukiHookXposedInit {
+
+ override fun onInit() {
+ YukiHookAPI.configs {
+ debugLog {
+ tag = "YukiHookAPI"
+ isEnable = true
+ isRecord = false
+ elements(TAG, PRIORITY, PACKAGE_NAME, USER_ID)
+ }
+ isDebug = BuildConfig.DEBUG
+ isEnableModuleAppResourcesCache = true
+ isEnableHookModuleStatus = true
+ isEnableHookSharedPreferences = false
+ isEnableDataChannel = true
+ }
+ }
+
+ override fun onHook() {
+ // Your code here.
+ }
+}
+
若觉得上面的写法不美观,你还可以写得更加简洁。
示例如下
object HookEntry : IYukiHookXposedInit {
+
+ override fun onInit() = configs {
+ debugLog {
+ tag = "YukiHookAPI"
+ isEnable = true
+ isRecord = false
+ elements(TAG, PRIORITY, PACKAGE_NAME, USER_ID)
+ }
+ isDebug = BuildConfig.DEBUG
+ isEnableModuleAppResourcesCache = true
+ isEnableHookModuleStatus = true
+ isEnableHookSharedPreferences = false
+ isEnableDataChannel = true
+ }
+
+ override fun onHook() {
+ // Your code here.
+ }
+}
+
你也可以不通过 configs
和 debugLog
方法,直接进行配置。
示例如下
object HookEntry : IYukiHookXposedInit {
+
+ override fun onInit() {
+ YLog.Configs.tag = "YukiHookAPI"
+ YLog.Configs.isEnable = true
+ YLog.Configs.isRecord = false
+ YLog.Configs.elements(
+ YLog.Configs.TAG,
+ YLog.Configs.PRIORITY,
+ YLog.Configs.PACKAGE_NAME,
+ YLog.Configs.USER_ID
+ )
+ YukiHookAPI.Configs.isDebug = BuildConfig.DEBUG
+ YukiHookAPI.Configs.isEnableModuleAppResourcesCache = true
+ YukiHookAPI.InjectYukiHookWithXposed.isUsingXposedModuleStatus = true
+ YukiHookAPI.Configs.isEnableHookSharedPreferences = false
+ YukiHookAPI.Configs.isEnableDataChannel = true
+ }
+
+ override fun onHook() {
+ // Your code here.
+ }
+}
+
fun encase(initiate: PackageParam.() -> Unit)
+
fun encase(vararg hooker: YukiBaseHooker)
+
fun encase(baseContext: Context?, initiate: PackageParam.() -> Unit)
+
fun encase(baseContext: Context?, vararg hooker: YukiBaseHooker)
+
变更记录
v1.0
添加
功能描述
装载 Hook 入口的核心方法。
功能示例
详情请参考
`,241),p=[l];function c(t,i){return e(),n("div",null,p)}const r=s(o,[["render",c],["__file","YukiHookAPI.html.vue"]]);export{r as default}; diff --git a/assets/YukiHookDataChannel.html-0wHuRMGr.js b/assets/YukiHookDataChannel.html-0wHuRMGr.js new file mode 100644 index 00000000..14a27904 --- /dev/null +++ b/assets/YukiHookDataChannel.html-0wHuRMGr.js @@ -0,0 +1,16 @@ +import{_ as s,o as a,c as o,a as e}from"./app-BpUB8-Q8.js";const n={},t=e(`Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
class YukiHookDataChannel private constructor()
+
Change Records
v1.0.88
added
Function Illustrate
实现 Xposed 模块的数据通讯桥。
通过模块与宿主相互注册 BroadcastReceiver
来实现数据的交互。
模块需要将 Application
继承于 ModuleApplication
来实现此功能。
Pay Attention
模块与宿主需要保持存活状态,否则无法建立通讯。
inner class NameSpace internal constructor(private val context: Context?, private val packageName: String)
+
Change Records
v1.0.88
added
v1.0.90
modified
新增 isSecure
参数
v1.1.9
modified
移除 isSecure
参数
Function Illustrate
YukiHookDataChannel
命名空间。
inline fun with(initiate: NameSpace.() -> Unit): NameSpace
+
Change Records
v1.0.88
added
Function Illustrate
创建一个调用空间。
var dataMaxByteSize: Int
+
Change Records
v1.1.9
added
Function Illustrate
YukiHookDataChannel
允许发送的最大数据字节大小。
默认为 500 KB (500 * 1024)
,详情请参考 receiverDataMaxByteSize
的注释。
最小不能低于 100 KB (100 * 1024)
,否则会被重新设置为 100 KB (100 * 1024)
。
设置后将在全局生效,直到当前进程结束。
超出最大数据字节大小后的数据将被自动分段发送。
Pay Attention
请谨慎调整此参数,如果超出了系统能够允许的大小会引发 TransactionTooLargeException 异常。
var dataMaxByteCompressionFactor: Int
+
Change Records
v1.1.9
added
Function Illustrate
YukiHookDataChannel
允许发送的最大数据字节大小倍数 (分段数据)。
默认为 3
,详情请参考 receiverDataMaxByteCompressionFactor
的注释。
最小不能低于 2
,否则会被重新设置为 2
。
设置后将在全局生效,直到当前进程结束。
超出最大数据字节大小后的数据将按照此倍数自动划分 receiverDataMaxByteSize
的大小。
Pay Attention
请谨慎调整此参数,如果超出了系统能够允许的大小会引发 TransactionTooLargeException 异常。
fun allowSendTooLargeData(): NameSpace
+
Change Records
v1.1.5
added
Function Illustrate
解除发送数据的大小限制并禁止开启分段发送功能。
仅会在每次调用时生效,下一次没有调用此方法则此功能将被自动关闭。
你还需要在整个调用域中声明注解 SendTooLargeChannelData
以消除警告。
Pay Attention
若你不知道允许此功能会带来何种后果,请勿使用。
fun <T> put(key: String, value: T)
+
fun <T> put(data: ChannelData<T>, value: T?)
+
fun put(vararg data: ChannelData<*>)
+
Change Records
v1.0.88
added
Function Illustrate
发送键值数据。
fun put(key: String)
+
Change Records
v1.0.88
added
Function Illustrate
仅发送键值监听,使用默认值
VALUE_WAIT_FOR_LISTENER
发送键值数据。
fun <T> wait(key: String, priority: ChannelPriority?, result: (value: T) -> Unit)
+
fun <T> wait(data: ChannelData<T>, priority: ChannelPriority?, result: (value: T) -> Unit)
+
Change Records
v1.0.88
added
v1.0.90
modified
移除默认值 value
v1.1.5
modified
新增 priority
参数
Function Illustrate
获取键值数据。
fun wait(key: String, priority: ChannelPriority?, callback: () -> Unit)
+
Change Records
v1.0.88
added
v1.1.5
modified
新增 priority
参数
Function Illustrate
仅获取监听结果,不获取键值数据。
Pay Attention
仅限使用 VALUE_WAIT_FOR_LISTENER 发送的监听才能被接收。
fun checkingVersionEquals(priority: ChannelPriority?, result: (Boolean) -> Unit)
+
Change Records
v1.0.88
added
v1.1.5
modified
新增 priority
参数
Function Illustrate
获取模块与宿主的版本是否匹配。
通过此方法可原生判断 Xposed 模块更新后宿主并未重新装载造成两者不匹配的情况。
fun obtainLoggerInMemoryData(priority: ChannelPriority?, result: (List<YLogData>) -> Unit)
+
Change Records
v1.1.4
added
v1.1.5
modified
新增 priority
参数
Function Illustrate
获取模块与宿主之间的
List<YLogData>
数据。
由于模块与宿主处于不同的进程,我们可以使用数据通讯桥访问各自的调试日志数据。
Pay Attention
模块与宿主必须启用 YLog.Configs.isRecord 才能获取到调试日志数据。
由于 Android 限制了数据传输大小的最大值,如果调试日志过多将会自动进行分段发送,数据越大速度越慢。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
class YukiHookDataChannel private constructor()
+
变更记录
v1.0.88
新增
功能描述
实现 Xposed 模块的数据通讯桥。
通过模块与宿主相互注册 BroadcastReceiver
来实现数据的交互。
模块需要将 Application
继承于 ModuleApplication
来实现此功能。
特别注意
模块与宿主需要保持存活状态,否则无法建立通讯。
inner class NameSpace internal constructor(private val context: Context?, private val packageName: String)
+
变更记录
v1.0.88
新增
v1.0.90
修改
新增 isSecure
参数
v1.1.9
修改
移除 isSecure
参数
功能描述
YukiHookDataChannel
命名空间。
inline fun with(initiate: NameSpace.() -> Unit): NameSpace
+
变更记录
v1.0.88
新增
功能描述
创建一个调用空间。
var dataMaxByteSize: Int
+
变更记录
v1.1.9
新增
功能描述
YukiHookDataChannel
允许发送的最大数据字节大小。
默认为 500 KB (500 * 1024)
,详情请参考 receiverDataMaxByteSize
的注释。
最小不能低于 100 KB (100 * 1024)
,否则会被重新设置为 100 KB (100 * 1024)
。
设置后将在全局生效,直到当前进程结束。
超出最大数据字节大小后的数据将被自动分段发送。
特别注意
请谨慎调整此参数,如果超出了系统能够允许的大小会引发 TransactionTooLargeException 异常。
var dataMaxByteCompressionFactor: Int
+
变更记录
v1.1.9
新增
功能描述
YukiHookDataChannel
允许发送的最大数据字节大小倍数 (分段数据)。
默认为 3
,详情请参考 receiverDataMaxByteCompressionFactor
的注释。
最小不能低于 2
,否则会被重新设置为 2
。
设置后将在全局生效,直到当前进程结束。
超出最大数据字节大小后的数据将按照此倍数自动划分 receiverDataMaxByteSize
的大小。
特别注意
请谨慎调整此参数,如果超出了系统能够允许的大小会引发 TransactionTooLargeException 异常。
fun allowSendTooLargeData(): NameSpace
+
变更记录
v1.1.5
新增
功能描述
解除发送数据的大小限制并禁止开启分段发送功能。
仅会在每次调用时生效,下一次没有调用此方法则此功能将被自动关闭。
你还需要在整个调用域中声明注解 SendTooLargeChannelData
以消除警告。
特别注意
若你不知道允许此功能会带来何种后果,请勿使用。
fun <T> put(key: String, value: T)
+
fun <T> put(data: ChannelData<T>, value: T?)
+
fun put(vararg data: ChannelData<*>)
+
变更记录
v1.0.88
新增
功能描述
发送键值数据。
fun put(key: String)
+
变更记录
v1.0.88
新增
功能描述
仅发送键值监听,使用默认值
VALUE_WAIT_FOR_LISTENER
发送键值数据。
fun <T> wait(key: String, priority: ChannelPriority?, result: (value: T) -> Unit)
+
fun <T> wait(data: ChannelData<T>, priority: ChannelPriority?, result: (value: T) -> Unit)
+
变更记录
v1.0.88
新增
v1.0.90
修改
移除默认值 value
v1.1.5
修改
新增 priority
参数
功能描述
获取键值数据。
fun wait(key: String, priority: ChannelPriority?, callback: () -> Unit)
+
变更记录
v1.0.88
新增
v1.1.5
修改
新增 priority
参数
功能描述
仅获取监听结果,不获取键值数据。
特别注意
仅限使用 VALUE_WAIT_FOR_LISTENER 发送的监听才能被接收。
fun checkingVersionEquals(priority: ChannelPriority?, result: (Boolean) -> Unit)
+
变更记录
v1.0.88
新增
v1.1.5
修改
新增 priority
参数
功能描述
获取模块与宿主的版本是否匹配。
通过此方法可原生判断 Xposed 模块更新后宿主并未重新装载造成两者不匹配的情况。
fun obtainLoggerInMemoryData(priority: ChannelPriority?, result: (List<YLogData>) -> Unit)
+
变更记录
v1.1.4
新增
v1.1.5
修改
新增 priority
参数
功能描述
获取模块与宿主之间的
List<YLogData>
数据。
由于模块与宿主处于不同的进程,我们可以使用数据通讯桥访问各自的调试日志数据。
特别注意
模块与宿主必须启用 YLog.Configs.isRecord 才能获取到调试日志数据。
由于 Android 限制了数据传输大小的最大值,如果调试日志过多将会自动进行分段发送,数据越大速度越慢。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
Change Records
v1.0
first
v1.0.80
modified
合并到 IYukiHookXposedInit
,将方法体进行 inline
Function Illustrate
这是
YukiHookAPI
相关 lambda 方法的封装类以及部分 API 用法。
inline fun IYukiHookXposedInit.configs(initiate: YukiHookAPI.Configs.() -> Unit)
+
Change Records
v1.0.1
added
v1.0.80
modified
合并到 IYukiHookXposedInit
Function Illustrate
在
IYukiHookXposedInit
中配置Configs
。
fun IYukiHookXposedInit.encase(initiate: PackageParam.() -> Unit)
+
fun IYukiHookXposedInit.encase(vararg hooker: YukiBaseHooker)
+
Change Records
v1.0
first
v1.0.80
modified
合并到 IYukiHookXposedInit
Function Illustrate
在
IYukiHookXposedInit
中调用YukiHookAPI
。
Change Records
v1.0
first
v1.1.9
deprecated
请迁移到 prefs
方法
Change Records
v1.0
first
v1.1.9
deprecated
请迁移到 prefs
方法
fun Context.prefs(name: String): YukiHookPrefsBridge
+
Change Records
v1.1.9
added
Function Illustrate
创建
YukiHookPrefsBridge
对象。
可以同时在模块与 (Xposed) 宿主环境中使用。
如果你想在 (Xposed) 宿主环境将数据存入当前宿主的私有空间,请使用 YukiHookPrefsBridge.native
方法。
在未声明任何条件的情况下 (Xposed) 宿主环境默认读取模块中的数据。
fun Context.dataChannel(packageName: String): YukiHookDataChannel.NameSpace
+
Change Records
v1.0.88
added
Function Illustrate
获取
YukiHookDataChannel
对象。
Pay Attention
只能在模块环境使用此功能,其它环境下使用将不起作用。
val Context.processName: String
+
Change Records
v1.0
first
Function Illustrate
获取当前进程名称。
fun Context.injectModuleAppResources()
+
fun Resources.injectModuleAppResources()
+
Change Records
v1.1.0
added
Function Illustrate
向 Hook APP (宿主)
Context
或Resources
注入当前 Xposed 模块的资源。
注入成功后,你就可以直接使用例如 ImageView.setImageResource
或 Resources.getString
装载当前 Xposed 模块的资源 ID。
注入的资源作用域仅限当前 Context
或 Resources
,你需要在每个用到宿主 Context
或 Resources
的地方重复调用此方法进行注入才能使用。
Pay Attention
只能在 (Xposed) 宿主环境使用此功能,其它环境下使用将不生效且会打印警告信息。
fun Context.registerModuleAppActivities(proxy: Any?)
+
Change Records
v1.1.0
added
v1.1.5
modified
加入最低 API 版本限制
Function Illustrate
向 Hook APP (宿主) 注册当前 Xposed 模块的
Activity
。
注册成功后,你就可以直接使用 Context.startActivity
来启动未在宿主中注册的 Activity
。
使用此方法会在未注册的 Activity
在 Hook APP (宿主) 中启动时自动调用 injectModuleAppResources
注入当前 Xposed 模块的资源。
你要将需要在宿主启动的 Activity
继承于 ModuleAppActivity
或 ModuleAppCompatActivity
。
Pay Attention
只能在 (Xposed) 宿主环境使用此功能,其它环境下使用将不生效且会打印警告信息。
最低支持 Android 7.0 (API 24)。
fun Context.applyModuleTheme(theme: Int, configuration: Configuration?): ModuleContextThemeWrapper
+
Change Records
v1.1.0
added
Function Illustrate
生成一个
ContextThemeWrapper
代理以应用当前 Xposed 模块的主题资源。
在 Hook APP (宿主) 中使用此方法会自动调用 injectModuleAppResources
注入当前 Xposed 模块的资源。
如果在 Hook APP (宿主) 中使用此方法发生 ClassCastException
,请手动设置 configuration
。
Change Records
v1.0.80
added
v1.0.91
removed
请迁移到 YukiHookAPI.Status.isSupportResourcesHook
Change Records
v1.0.6
added
v1.0.91
removed
请迁移到 YukiHookAPI.Status.isModuleActive
Change Records
v1.0.6
added
v1.0.91
removed
请迁移到 YukiHookAPI.Status.isXposedModuleActive
Change Records
v1.0
first
v1.0.91
removed
请迁移到 YukiHookAPI.Status.isTaiChiModuleActive
Change Records
v1.0
first
v1.0.91
deprecated
请迁移到 YukiHookAPI.Status
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
变更记录
v1.0
添加
v1.0.80
修改
合并到 IYukiHookXposedInit
,将方法体进行 inline
功能描述
这是
YukiHookAPI
相关 lambda 方法的封装类以及部分 API 用法。
inline fun IYukiHookXposedInit.configs(initiate: YukiHookAPI.Configs.() -> Unit)
+
变更记录
v1.0.1
新增
v1.0.80
修改
合并到 IYukiHookXposedInit
功能描述
在
IYukiHookXposedInit
中配置Configs
。
fun IYukiHookXposedInit.encase(initiate: PackageParam.() -> Unit)
+
fun IYukiHookXposedInit.encase(vararg hooker: YukiBaseHooker)
+
变更记录
v1.0
添加
v1.0.80
修改
合并到 IYukiHookXposedInit
功能描述
在
IYukiHookXposedInit
中调用YukiHookAPI
。
变更记录
v1.0
添加
v1.1.9
作废
请迁移到 prefs
方法
变更记录
v1.0
添加
v1.1.9
作废
请迁移到 prefs
方法
fun Context.prefs(name: String): YukiHookPrefsBridge
+
变更记录
v1.1.9
新增
功能描述
创建
YukiHookPrefsBridge
对象。
可以同时在模块与 (Xposed) 宿主环境中使用。
如果你想在 (Xposed) 宿主环境将数据存入当前宿主的私有空间,请使用 YukiHookPrefsBridge.native
方法。
在未声明任何条件的情况下 (Xposed) 宿主环境默认读取模块中的数据。
fun Context.dataChannel(packageName: String): YukiHookDataChannel.NameSpace
+
变更记录
v1.0.88
新增
功能描述
获取
YukiHookDataChannel
对象。
特别注意
只能在模块环境使用此功能,其它环境下使用将不起作用。
val Context.processName: String
+
变更记录
v1.0
添加
功能描述
获取当前进程名称。
fun Context.injectModuleAppResources()
+
fun Resources.injectModuleAppResources()
+
变更记录
v1.1.0
新增
功能描述
向 Hook APP (宿主)
Context
或Resources
注入当前 Xposed 模块的资源。
注入成功后,你就可以直接使用例如 ImageView.setImageResource
或 Resources.getString
装载当前 Xposed 模块的资源 ID。
注入的资源作用域仅限当前 Context
或 Resources
,你需要在每个用到宿主 Context
或 Resources
的地方重复调用此方法进行注入才能使用。
特别注意
只能在 (Xposed) 宿主环境使用此功能,其它环境下使用将不生效且会打印警告信息。
fun Context.registerModuleAppActivities(proxy: Any?)
+
变更记录
v1.1.0
新增
v1.1.5
修改
加入最低 API 版本限制
功能描述
向 Hook APP (宿主) 注册当前 Xposed 模块的
Activity
。
注册成功后,你就可以直接使用 Context.startActivity
来启动未在宿主中注册的 Activity
。
使用此方法会在未注册的 Activity
在 Hook APP (宿主) 中启动时自动调用 injectModuleAppResources
注入当前 Xposed 模块的资源。
你要将需要在宿主启动的 Activity
继承于 ModuleAppActivity
或 ModuleAppCompatActivity
。
特别注意
只能在 (Xposed) 宿主环境使用此功能,其它环境下使用将不生效且会打印警告信息。
最低支持 Android 7.0 (API 24)。
fun Context.applyModuleTheme(theme: Int, configuration: Configuration?): ModuleContextThemeWrapper
+
变更记录
v1.1.0
新增
功能描述
生成一个
ContextThemeWrapper
代理以应用当前 Xposed 模块的主题资源。
在 Hook APP (宿主) 中使用此方法会自动调用 injectModuleAppResources
注入当前 Xposed 模块的资源。
如果在 Hook APP (宿主) 中使用此方法发生 ClassCastException
,请手动设置 configuration
。
变更记录
v1.0.80
新增
v1.0.91
移除
请迁移到 YukiHookAPI.Status.isSupportResourcesHook
变更记录
v1.0.6
新增
v1.0.91
移除
请迁移到 YukiHookAPI.Status.isModuleActive
变更记录
v1.0.6
新增
v1.0.91
移除
请迁移到 YukiHookAPI.Status.isXposedModuleActive
变更记录
v1.0
添加
v1.0.91
移除
请迁移到 YukiHookAPI.Status.isTaiChiModuleActive
变更记录
v1.0
添加
v1.0.91
作废
请迁移到 YukiHookAPI.Status
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
class YukiHookPrefsBridge private constructor(private var context: Context?)
+
Change Records
v1.0
first
v1.1.9
modified
更名为 YukiHookModulePrefs
YukiHookPrefsBridge
Function Illustrate
YukiHookAPI
对SharedPreferences
、XSharedPreferences
的扩展存储桥实现。
在不同环境智能选择存取使用的对象。
Pay Attention
模块与宿主之前共享数据存储为实验性功能,仅在 LSPosed 环境测试通过,EdXposed 理论也可以使用但不再推荐。
使用 LSPosed 环境请在 AndroidManifests.xml
中将 xposedminversion
最低设置为 93
。
对于在模块环境中使用 PreferenceFragmentCompat
,YukiHookAPI
提供了 ModulePreferenceFragment
来实现同样的功能。
Optional Configuration
若你不想将你的模块的 xposedminversion
最低设置为 93
,你可以在 AndroidManifest.xml
中添加 xposedsharedprefs
来实现支持。
The following example
<meta-data
+ android:name="xposedsharedprefs"
+ android:value="true"/>
+
Change Records
v1.0.90
added
v1.1.5
deprecated
请迁移到 isPreferencesAvailable
Change Records
v1.0.78
added
v1.1.5
deprecated
请迁移到 isPreferencesAvailable
val isPreferencesAvailable: Boolean
+
Change Records
v1.1.5
added
Function Illustrate
获取当前
YukiHookPrefsBridge
的可用状态。
在 (Xposed) 宿主环境中返回 XSharedPreferences
可用状态 (可读)。
在模块环境中返回当前是否处于 New XSharedPreferences 模式 (可读可写)。
fun name(name: String): YukiHookPrefsBridge
+
Change Records
v1.0
first
Function Illustrate
自定义 Sp 存储名称。
Function Example
在 Activity
中的使用方法。
The following example
prefs("custom_name").getString("custom_key")
+
在 (Xposed) 宿主环境 PackageParam
中的使用方法。
The following example
prefs("custom_name").getString("custom_key")
+
Change Records
v1.0.5
added
v1.1.11
deprecated
键值的直接缓存功能已被移除,因为其存在内存溢出 (OOM) 问题
fun native(): YukiHookPrefsBridge
+
Change Records
v1.1.9
added
Function Illustrate
忽略当前环境直接使用
Context.getSharedPreferences
存取数据。
fun getString(key: String, value: String): String
+
Change Records
v1.0
first
Function Illustrate
获取
String
键值。
fun getStringSet(key: String, value: Set<String>): Set<String>
+
Change Records
v1.0.77
added
Function Illustrate
获取
Set<String>
键值。
fun getBoolean(key: String, value: Boolean): Boolean
+
Change Records
v1.0
first
Function Illustrate
获取
Boolean
键值。
fun getInt(key: String, value: Int): Int
+
Change Records
v1.0
first
Function Illustrate
获取
Int
键值。
fun getLong(key: String, value: Long): Long
+
Change Records
v1.0
first
Function Illustrate
获取
Long
键值。
fun getFloat(key: String, value: Float): Float
+
Change Records
v1.0
first
Function Illustrate
获取
Float
键值。
fun contains(key: String): Boolean
+
Change Records
v1.1.9
added
Function Illustrate
判断当前是否包含
key
键值的数据。
智能识别对应环境读取键值数据。
fun all(): MutableMap<String, Any?>
+
Change Records
v1.0.77
added
Function Illustrate
获取全部存储的键值数据。
智能识别对应环境读取键值数据。
Pay Attention
每次调用都会获取实时的数据,不受缓存控制,请勿在高并发场景中使用。
Change Records
v1.0
first
v1.1.9
deprecated
请迁移到 edit
方法
Change Records
v1.0.77
added
v1.1.9
deprecated
请迁移到 edit
方法
Change Records
v1.0
first
v1.1.9
deprecated
请迁移到 edit
方法
Change Records
v1.0.77
added
v1.1.9
deprecated
请迁移到 edit
方法
Change Records
v1.0
first
v1.1.9
deprecated
请迁移到 edit
方法
Change Records
v1.0
first
v1.1.9
deprecated
请迁移到 edit
方法
Change Records
v1.0
first
v1.1.9
deprecated
请迁移到 edit
方法
Change Records
v1.0
first
v1.1.9
deprecated
请迁移到 edit
方法
inline fun <reified T> get(prefs: PrefsData<T>, value: T): T
+
Change Records
v1.0.67
added
Function Illustrate
智能获取指定类型的键值。
Change Records
v1.0.67
added
v1.1.9
deprecated
请迁移到 edit
方法
fun edit(): Editor
+
Change Records
v1.1.9
added
Function Illustrate
创建新的
Editor
。
在模块环境中或启用了 isUsingNativeStorage
后使用。
Notice
在 (Xposed) 宿主环境下只读,无法使用。
fun edit(initiate: Editor.() -> Unit)
+
Change Records
v1.1.9
added
Function Illustrate
创建新的
Editor
。
自动调用 Editor.apply
方法。
在模块环境中或启用了 isUsingNativeStorage
后使用。
Notice
在 (Xposed) 宿主环境下只读,无法使用。
Change Records
v1.0.5
added
v1.1.11
deprecated
键值的直接缓存功能已被移除,因为其存在内存溢出 (OOM) 问题
inner class Editor internal constructor()
+
Change Records
v1.1.9
added
Function Illustrate
YukiHookPrefsBridge
的存储代理类。
请使用 edit
方法来获取 Editor
。
在模块环境中或启用了 isUsingNativeStorage
后使用。
Notice
在 (Xposed) 宿主环境下只读,无法使用。
fun remove(key: String): Editor
+
Change Records
v1.1.9
added
Function Illustrate
移除全部包含
key
的存储数据。
inline fun <reified T> remove(prefs: PrefsData<T>): Editor
+
Change Records
v1.1.9
added
Function Illustrate
移除
PrefsData.key
的存储数据。
fun clear(): Editor
+
Change Records
v1.1.9
added
Function Illustrate
移除全部存储数据。
fun putString(key: String, value: String): Editor
+
Change Records
v1.1.9
added
Function Illustrate
存储
String
键值。
fun putStringSet(key: String, value: Set<String>): Editor
+
Change Records
v1.1.9
added
Function Illustrate
存储
Set<String>
键值。
fun putBoolean(key: String, value: Boolean): Editor
+
Change Records
v1.1.9
added
Function Illustrate
存储
Boolean
键值。
fun putInt(key: String, value: Int): Editor
+
Change Records
v1.1.9
added
Function Illustrate
存储
Int
键值。
fun putLong(key: String, value: Long): Editor
+
Change Records
v1.1.9
added
Function Illustrate
存储
Long
键值。
fun putFloat(key: String, value: Float): Editor
+
Change Records
v1.1.9
added
Function Illustrate
存储
Float
键值。
inline fun <reified T> put(prefs: PrefsData<T>, value: T): Editor
+
Change Records
v1.1.9
added
Function Illustrate
智能存储指定类型的键值。
fun commit(): Boolean
+
Change Records
v1.1.9
added
Function Illustrate
提交更改 (同步)。
fun apply()
+
Change Records
v1.1.9
added
Function Illustrate
`,249);function k(m,b){const o=p("ExternalLinkIcon");return l(),c("div",null,[r,s("p",null,[e("详见 "),s("a",i,[e("New XSharedPreferences"),a(o)]),e("。")]),g,h,s("p",null,[e("太极请参阅 "),s("a",u,[e("文件权限/配置/XSharedPreference"),a(o)]),e("。")]),y,s("p",null,[e("详见 "),s("a",A,[e("New XSharedPreferences"),a(o)]),e("。")]),D])}const C=t(d,[["render",k],["__file","YukiHookPrefsBridge.html.vue"]]);export{C as default}; diff --git a/assets/YukiHookPrefsBridge.html-Dprm2-90.js b/assets/YukiHookPrefsBridge.html-Dprm2-90.js new file mode 100644 index 00000000..bf1eea90 --- /dev/null +++ b/assets/YukiHookPrefsBridge.html-Dprm2-90.js @@ -0,0 +1,34 @@ +import{_ as p,r as l,o as t,c,b as e,d as s,e as a,a as n}from"./app-BpUB8-Q8.js";const d={},r=n(`提交更改 (异步)。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
class YukiHookPrefsBridge private constructor(private var context: Context?)
+
变更记录
v1.0
添加
v1.1.9
修改
更名为 YukiHookModulePrefs
YukiHookPrefsBridge
功能描述
YukiHookAPI
对SharedPreferences
、XSharedPreferences
的扩展存储桥实现。
在不同环境智能选择存取使用的对象。
特别注意
模块与宿主之前共享数据存储为实验性功能,仅在 LSPosed 环境测试通过,EdXposed 理论也可以使用但不再推荐。
使用 LSPosed 环境请在 AndroidManifests.xml
中将 xposedminversion
最低设置为 93
。
对于在模块环境中使用 PreferenceFragmentCompat
,YukiHookAPI
提供了 ModulePreferenceFragment
来实现同样的功能。
可选配置
若你不想将你的模块的 xposedminversion
最低设置为 93
,你可以在 AndroidManifest.xml
中添加 xposedsharedprefs
来实现支持。
示例如下
<meta-data
+ android:name="xposedsharedprefs"
+ android:value="true"/>
+
变更记录
v1.0.90
新增
v1.1.5
作废
请迁移到 isPreferencesAvailable
变更记录
v1.0.78
新增
v1.1.5
作废
请迁移到 isPreferencesAvailable
val isPreferencesAvailable: Boolean
+
变更记录
v1.1.5
新增
功能描述
获取当前
YukiHookPrefsBridge
的可用状态。
在 (Xposed) 宿主环境中返回 XSharedPreferences
可用状态 (可读)。
在模块环境中返回当前是否处于 New XSharedPreferences 模式 (可读可写)。
fun name(name: String): YukiHookPrefsBridge
+
变更记录
v1.0
添加
功能描述
自定义 Sp 存储名称。
功能示例
在 Activity
中的使用方法。
示例如下
prefs("custom_name").getString("custom_key")
+
在 (Xposed) 宿主环境 PackageParam
中的使用方法。
示例如下
prefs("custom_name").getString("custom_key")
+
变更记录
v1.0.5
新增
v1.1.11
作废
键值的直接缓存功能已被移除,因为其存在内存溢出 (OOM) 问题
fun native(): YukiHookPrefsBridge
+
变更记录
v1.1.9
新增
功能描述
忽略当前环境直接使用
Context.getSharedPreferences
存取数据。
fun getString(key: String, value: String): String
+
变更记录
v1.0
添加
功能描述
获取
String
键值。
fun getStringSet(key: String, value: Set<String>): Set<String>
+
变更记录
v1.0.77
新增
功能描述
获取
Set<String>
键值。
fun getBoolean(key: String, value: Boolean): Boolean
+
变更记录
v1.0
添加
功能描述
获取
Boolean
键值。
fun getInt(key: String, value: Int): Int
+
变更记录
v1.0
添加
功能描述
获取
Int
键值。
fun getLong(key: String, value: Long): Long
+
变更记录
v1.0
添加
功能描述
获取
Long
键值。
fun getFloat(key: String, value: Float): Float
+
变更记录
v1.0
添加
功能描述
获取
Float
键值。
fun contains(key: String): Boolean
+
变更记录
v1.1.9
新增
功能描述
判断当前是否包含
key
键值的数据。
智能识别对应环境读取键值数据。
fun all(): MutableMap<String, Any?>
+
变更记录
v1.0.77
新增
功能描述
获取全部存储的键值数据。
智能识别对应环境读取键值数据。
特别注意
每次调用都会获取实时的数据,不受缓存控制,请勿在高并发场景中使用。
变更记录
v1.0
添加
v1.1.9
作废
请迁移到 edit
方法
变更记录
v1.0.77
新增
v1.1.9
作废
请迁移到 edit
方法
变更记录
v1.0
添加
v1.1.9
作废
请迁移到 edit
方法
变更记录
v1.0.77
新增
v1.1.9
作废
请迁移到 edit
方法
变更记录
v1.0
添加
v1.1.9
作废
请迁移到 edit
方法
变更记录
v1.0
添加
v1.1.9
作废
请迁移到 edit
方法
变更记录
v1.0
添加
v1.1.9
作废
请迁移到 edit
方法
变更记录
v1.0
添加
v1.1.9
作废
请迁移到 edit
方法
inline fun <reified T> get(prefs: PrefsData<T>, value: T): T
+
变更记录
v1.0.67
新增
功能描述
智能获取指定类型的键值。
变更记录
v1.0.67
新增
v1.1.9
作废
请迁移到 edit
方法
fun edit(): Editor
+
变更记录
v1.1.9
新增
功能描述
创建新的
Editor
。
在模块环境中或启用了 isUsingNativeStorage
后使用。
注意
在 (Xposed) 宿主环境下只读,无法使用。
fun edit(initiate: Editor.() -> Unit)
+
变更记录
v1.1.9
新增
功能描述
创建新的
Editor
。
自动调用 Editor.apply
方法。
在模块环境中或启用了 isUsingNativeStorage
后使用。
注意
在 (Xposed) 宿主环境下只读,无法使用。
变更记录
v1.0.5
新增
v1.1.11
作废
键值的直接缓存功能已被移除,因为其存在内存溢出 (OOM) 问题
inner class Editor internal constructor()
+
变更记录
v1.1.9
新增
功能描述
YukiHookPrefsBridge
的存储代理类。
请使用 edit
方法来获取 Editor
。
在模块环境中或启用了 isUsingNativeStorage
后使用。
注意
在 (Xposed) 宿主环境下只读,无法使用。
fun remove(key: String): Editor
+
变更记录
v1.1.9
新增
功能描述
移除全部包含
key
的存储数据。
inline fun <reified T> remove(prefs: PrefsData<T>): Editor
+
变更记录
v1.1.9
新增
功能描述
移除
PrefsData.key
的存储数据。
fun clear(): Editor
+
变更记录
v1.1.9
新增
功能描述
移除全部存储数据。
fun putString(key: String, value: String): Editor
+
变更记录
v1.1.9
新增
功能描述
存储
String
键值。
fun putStringSet(key: String, value: Set<String>): Editor
+
变更记录
v1.1.9
新增
功能描述
存储
Set<String>
键值。
fun putBoolean(key: String, value: Boolean): Editor
+
变更记录
v1.1.9
新增
功能描述
存储
Boolean
键值。
fun putInt(key: String, value: Int): Editor
+
变更记录
v1.1.9
新增
功能描述
存储
Int
键值。
fun putLong(key: String, value: Long): Editor
+
变更记录
v1.1.9
新增
功能描述
存储
Long
键值。
fun putFloat(key: String, value: Float): Editor
+
变更记录
v1.1.9
新增
功能描述
存储
Float
键值。
inline fun <reified T> put(prefs: PrefsData<T>, value: T): Editor
+
变更记录
v1.1.9
新增
功能描述
智能存储指定类型的键值。
fun commit(): Boolean
+
变更记录
v1.1.9
新增
功能描述
提交更改 (同步)。
fun apply()
+
变更记录
v1.1.9
新增
功能描述
`,249);function k(m,b){const o=l("ExternalLinkIcon");return t(),c("div",null,[r,e("p",null,[s("详见 "),e("a",i,[s("New XSharedPreferences"),a(o)]),s("。")]),g,y,e("p",null,[s("太极请参阅 "),e("a",h,[s("文件权限/配置/XSharedPreference"),a(o)]),s("。")]),u,e("p",null,[s("详见 "),e("a",A,[s("New XSharedPreferences"),a(o)]),s("。")]),D])}const v=p(d,[["render",k],["__file","YukiHookPrefsBridge.html.vue"]]);export{v as default}; diff --git a/assets/YukiHookPrefsBridge.html-XzXYFQ1s.js b/assets/YukiHookPrefsBridge.html-XzXYFQ1s.js new file mode 100644 index 00000000..7f19b5eb --- /dev/null +++ b/assets/YukiHookPrefsBridge.html-XzXYFQ1s.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-65c20d2d","path":"/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookPrefsBridge.html","title":"YukiHookPrefsBridge - class","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"isPreferencesAvailable - field","slug":"ispreferencesavailable-field","link":"#ispreferencesavailable-field","children":[]},{"level":2,"title":"name - method","slug":"name-method","link":"#name-method","children":[]},{"level":2,"title":"native - method","slug":"native-method","link":"#native-method","children":[]},{"level":2,"title":"getString - method","slug":"getstring-method","link":"#getstring-method","children":[]},{"level":2,"title":"getStringSet - method","slug":"getstringset-method","link":"#getstringset-method","children":[]},{"level":2,"title":"getBoolean - method","slug":"getboolean-method","link":"#getboolean-method","children":[]},{"level":2,"title":"getInt - method","slug":"getint-method","link":"#getint-method","children":[]},{"level":2,"title":"getLong - method","slug":"getlong-method","link":"#getlong-method","children":[]},{"level":2,"title":"getFloat - method","slug":"getfloat-method","link":"#getfloat-method","children":[]},{"level":2,"title":"contains - method","slug":"contains-method","link":"#contains-method","children":[]},{"level":2,"title":"all - method","slug":"all-method","link":"#all-method","children":[]},{"level":2,"title":"get - method","slug":"get-method","link":"#get-method","children":[]},{"level":2,"title":"edit - method","slug":"edit-method","link":"#edit-method","children":[]},{"level":2,"title":"edit - method","slug":"edit-method-1","link":"#edit-method-1","children":[]},{"level":2,"title":"Editor - class","slug":"editor-class","link":"#editor-class","children":[{"level":3,"title":"remove - method","slug":"remove-method","link":"#remove-method","children":[]},{"level":3,"title":"remove - method","slug":"remove-method-1","link":"#remove-method-1","children":[]},{"level":3,"title":"clear - method","slug":"clear-method","link":"#clear-method","children":[]},{"level":3,"title":"putString - method","slug":"putstring-method","link":"#putstring-method","children":[]},{"level":3,"title":"putStringSet - method","slug":"putstringset-method","link":"#putstringset-method","children":[]},{"level":3,"title":"putBoolean - method","slug":"putboolean-method","link":"#putboolean-method","children":[]},{"level":3,"title":"putInt - method","slug":"putint-method","link":"#putint-method","children":[]},{"level":3,"title":"putLong - method","slug":"putlong-method","link":"#putlong-method","children":[]},{"level":3,"title":"putFloat - method","slug":"putfloat-method","link":"#putfloat-method","children":[]},{"level":3,"title":"put - method","slug":"put-method","link":"#put-method","children":[]},{"level":3,"title":"commit - method","slug":"commit-method","link":"#commit-method","children":[]},{"level":3,"title":"apply - method","slug":"apply-method","link":"#apply-method","children":[]}]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":6}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookPrefsBridge.md"}');export{e as data}; diff --git a/assets/YukiHookPriority.html-AgDP0CYh.js b/assets/YukiHookPriority.html-AgDP0CYh.js new file mode 100644 index 00000000..ac633d50 --- /dev/null +++ b/assets/YukiHookPriority.html-AgDP0CYh.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-3e0afe1e","path":"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/api/priority/YukiHookPriority.html","title":"YukiHookPriority - class","lang":"zh-CN","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"DEFAULT - enum","slug":"default-enum","link":"#default-enum","children":[]},{"level":2,"title":"LOWEST - enum","slug":"lowest-enum","link":"#lowest-enum","children":[]},{"level":2,"title":"HIGHEST - enum","slug":"highest-enum","link":"#highest-enum","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":2}]},"filePathRelative":"zh-cn/api/public/com/highcapable/yukihookapi/hook/core/api/priority/YukiHookPriority.md"}');export{e as data}; diff --git a/assets/YukiHookPriority.html-BzBXrjfk.js b/assets/YukiHookPriority.html-BzBXrjfk.js new file mode 100644 index 00000000..12046815 --- /dev/null +++ b/assets/YukiHookPriority.html-BzBXrjfk.js @@ -0,0 +1,5 @@ +import{_ as o,o as e,c as s,a}from"./app-BpUB8-Q8.js";const n={},c=a(`提交更改 (异步)。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
enum class YukiHookPriority
+
变更记录
v1.1.5
新增
v1.2.0
修改
移除 internal
对外公开
功能描述
Hook 回调优先级配置类。
DEFAULT
+
变更记录
v1.1.5
新增
功能描述
默认 Hook 回调优先级。
LOWEST
+
变更记录
v1.1.5
新增
功能描述
延迟回调 Hook 方法结果。
HIGHEST
+
变更记录
v1.1.5
新增
功能描述
`,27),t=[c];function d(l,p){return e(),s("div",null,t)}const r=o(n,[["render",d],["__file","YukiHookPriority.html.vue"]]);export{r as default}; diff --git a/assets/YukiHookPriority.html-CUgcejgE.js b/assets/YukiHookPriority.html-CUgcejgE.js new file mode 100644 index 00000000..4a1e3b3f --- /dev/null +++ b/assets/YukiHookPriority.html-CUgcejgE.js @@ -0,0 +1,5 @@ +import{_ as e,o,c as s,a}from"./app-BpUB8-Q8.js";const n={},t=a(`更快回调 Hook 方法结果。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
enum class YukiHookPriority
+
Change Records
v1.1.5
added
v1.2.0
modified
移除 internal
对外公开
Function Illustrate
Hook 回调优先级配置类。
DEFAULT
+
Change Records
v1.1.5
added
Function Illustrate
默认 Hook 回调优先级。
LOWEST
+
Change Records
v1.1.5
added
Function Illustrate
延迟回调 Hook 方法结果。
HIGHEST
+
Change Records
v1.1.5
added
Function Illustrate
`,28),c=[t];function d(i,l){return o(),s("div",null,c)}const p=e(n,[["render",d],["__file","YukiHookPriority.html.vue"]]);export{p as default}; diff --git a/assets/YukiHookPriority.html-smxFpy5Q.js b/assets/YukiHookPriority.html-smxFpy5Q.js new file mode 100644 index 00000000..763e2f62 --- /dev/null +++ b/assets/YukiHookPriority.html-smxFpy5Q.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-3895ce22","path":"/en/api/public/com/highcapable/yukihookapi/hook/core/api/priority/YukiHookPriority.html","title":"YukiHookPriority - class","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"DEFAULT - enum","slug":"default-enum","link":"#default-enum","children":[]},{"level":2,"title":"LOWEST - enum","slug":"lowest-enum","link":"#lowest-enum","children":[]},{"level":2,"title":"HIGHEST - enum","slug":"highest-enum","link":"#highest-enum","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":2}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/core/api/priority/YukiHookPriority.md"}');export{e as data}; diff --git a/assets/YukiMemberHookCreator.html-C0fIOtqI.js b/assets/YukiMemberHookCreator.html-C0fIOtqI.js new file mode 100644 index 00000000..6d7edfe2 --- /dev/null +++ b/assets/YukiMemberHookCreator.html-C0fIOtqI.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-3ac40680","path":"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/YukiMemberHookCreator.html","title":"YukiMemberHookCreator - class","lang":"zh-CN","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"injectMember - method","slug":"injectmember-method","link":"#injectmember-method","children":[]},{"level":2,"title":"MemberHookCreator - class","slug":"memberhookcreator-class","link":"#memberhookcreator-class","children":[{"level":3,"title":"before - method","slug":"before-method","link":"#before-method","children":[]},{"level":3,"title":"after - method","slug":"after-method","link":"#after-method","children":[]},{"level":3,"title":"replaceAny - method","slug":"replaceany-method","link":"#replaceany-method","children":[]},{"level":3,"title":"replaceUnit - method","slug":"replaceunit-method","link":"#replaceunit-method","children":[]},{"level":3,"title":"replaceTo - method","slug":"replaceto-method","link":"#replaceto-method","children":[]},{"level":3,"title":"replaceToTrue - method","slug":"replacetotrue-method","link":"#replacetotrue-method","children":[]},{"level":3,"title":"replaceToFalse - method","slug":"replacetofalse-method","link":"#replacetofalse-method","children":[]},{"level":3,"title":"intercept - method","slug":"intercept-method","link":"#intercept-method","children":[]},{"level":3,"title":"removeSelf - method","slug":"removeself-method","link":"#removeself-method","children":[]},{"level":3,"title":"LegacyCreator - class","slug":"legacycreator-class","link":"#legacycreator-class","children":[]},{"level":3,"title":"HookCallback - class","slug":"hookcallback-class","link":"#hookcallback-class","children":[]},{"level":3,"title":"Result - class","slug":"result-class","link":"#result-class","children":[]}]},{"level":2,"title":"Result - class","slug":"result-class-1","link":"#result-class-1","children":[{"level":3,"title":"result - method","slug":"result-method-1","link":"#result-method-1","children":[]},{"level":3,"title":"by - method","slug":"by-method-1","link":"#by-method-1","children":[]},{"level":3,"title":"onPrepareHook - method","slug":"onpreparehook-method","link":"#onpreparehook-method","children":[]},{"level":3,"title":"onHookClassNotFoundFailure - method","slug":"onhookclassnotfoundfailure-method","link":"#onhookclassnotfoundfailure-method","children":[]},{"level":3,"title":"ignoredHookClassNotFoundFailure - method","slug":"ignoredhookclassnotfoundfailure-method","link":"#ignoredhookclassnotfoundfailure-method","children":[]}]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":14}]},"filePathRelative":"zh-cn/api/public/com/highcapable/yukihookapi/hook/core/YukiMemberHookCreator.md"}');export{e as data}; diff --git a/assets/YukiMemberHookCreator.html-C1zPXD2D.js b/assets/YukiMemberHookCreator.html-C1zPXD2D.js new file mode 100644 index 00000000..eaf7cf1e --- /dev/null +++ b/assets/YukiMemberHookCreator.html-C1zPXD2D.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-71147891","path":"/en/api/public/com/highcapable/yukihookapi/hook/core/YukiMemberHookCreator.html","title":"YukiMemberHookCreator - class","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"injectMember - method","slug":"injectmember-method","link":"#injectmember-method","children":[]},{"level":2,"title":"MemberHookCreator - class","slug":"memberhookcreator-class","link":"#memberhookcreator-class","children":[{"level":3,"title":"before - method","slug":"before-method","link":"#before-method","children":[]},{"level":3,"title":"after - method","slug":"after-method","link":"#after-method","children":[]},{"level":3,"title":"replaceAny - method","slug":"replaceany-method","link":"#replaceany-method","children":[]},{"level":3,"title":"replaceUnit - method","slug":"replaceunit-method","link":"#replaceunit-method","children":[]},{"level":3,"title":"replaceTo - method","slug":"replaceto-method","link":"#replaceto-method","children":[]},{"level":3,"title":"replaceToTrue - method","slug":"replacetotrue-method","link":"#replacetotrue-method","children":[]},{"level":3,"title":"replaceToFalse - method","slug":"replacetofalse-method","link":"#replacetofalse-method","children":[]},{"level":3,"title":"intercept - method","slug":"intercept-method","link":"#intercept-method","children":[]},{"level":3,"title":"removeSelf - method","slug":"removeself-method","link":"#removeself-method","children":[]},{"level":3,"title":"LegacyCreator - class","slug":"legacycreator-class","link":"#legacycreator-class","children":[]},{"level":3,"title":"HookCallback - class","slug":"hookcallback-class","link":"#hookcallback-class","children":[]},{"level":3,"title":"Result - class","slug":"result-class","link":"#result-class","children":[]}]},{"level":2,"title":"Result - class","slug":"result-class-1","link":"#result-class-1","children":[{"level":3,"title":"result - method","slug":"result-method-1","link":"#result-method-1","children":[]},{"level":3,"title":"by - method","slug":"by-method-1","link":"#by-method-1","children":[]},{"level":3,"title":"onPrepareHook - method","slug":"onpreparehook-method","link":"#onpreparehook-method","children":[]},{"level":3,"title":"onHookClassNotFoundFailure - method","slug":"onhookclassnotfoundfailure-method","link":"#onhookclassnotfoundfailure-method","children":[]},{"level":3,"title":"ignoredHookClassNotFoundFailure - method","slug":"ignoredhookclassnotfoundfailure-method","link":"#ignoredhookclassnotfoundfailure-method","children":[]}]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":13}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/core/YukiMemberHookCreator.md"}');export{e as data}; diff --git a/assets/YukiMemberHookCreator.html-De9-pEl1.js b/assets/YukiMemberHookCreator.html-De9-pEl1.js new file mode 100644 index 00000000..74d58749 --- /dev/null +++ b/assets/YukiMemberHookCreator.html-De9-pEl1.js @@ -0,0 +1,36 @@ +import{_ as o,o as s,c as e,a}from"./app-BpUB8-Q8.js";const n={},l=a(`更快回调 Hook 方法结果。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
class YukiMemberHookCreator internal constructor(private val packageParam: PackageParam, private val hookClass: HookClass)
+
Change Records
v1.0
first
v1.0.80
modified
对 hookClass
进行 inline 处理
v1.1.0
modified
修正拼写错误的 Creater 命名到 Creator
v1.1.5
modified
私有化构造方法
Function Illustrate
YukiHookAPI
的Member
核心 Hook 实现类。
Change Records
v1.0.80
added
v1.2.0
deprecated
请迁移到 YukiHookPriority
Change Records
v1.0.80
added
v1.2.0
deprecated
请迁移到 YukiHookPriority
Change Records
v1.0.80
added
v1.2.0
deprecated
请迁移到 YukiHookPriority
Change Records
v1.0
first
v1.0.2
modified
更名为 thisClass
instanceClass
v1.2.0
deprecated
不再推荐使用
Change Records
v1.0
first
v1.0.80
modified
将方法体进行 inline
增加 priority
Hook 优先级
v1.2.0
deprecated
请迁移到另一个 injectMember
inline fun injectMember(priority: YukiHookPriority, initiate: MemberHookCreator.LegacyCreator.() -> Unit): MemberHookCreator.Result
+
Change Records
v1.2.0
added
Function Illustrate
注入要 Hook 的
Method
、Constructor
。
Change Records
v1.1.0
added
v1.2.0
deprecated
此功能已被弃用
inner class MemberHookCreator internal constructor(private val priority: YukiHookPriority, private val hookMode: HookMode)
+
Change Records
v1.0
first
v1.0.80
modified
增加 priority
Hook 优先级
v1.0.81
modified
增加 packageName
当前 Hook 的 APP 包名
v1.1.0
modified
移除 packageName
修正拼写错误的 Creater 命名到 Creator
v1.2.0
modified
移除 tag
priority
类型由 Int
变更为 YukiHookPriority
增加 hookMode
Hook 模式
Function Illustrate
Hook 核心功能实现类,查找和处理需要 Hook 的
Method
、Constructor
。
fun before(initiate: HookParam.() -> Unit): HookCallback
+
Change Records
v1.2.0
added
Function Illustrate
在
Member
执行完成前 Hook。
fun after(initiate: HookParam.() -> Unit): HookCallback
+
Change Records
v1.2.0
added
Function Illustrate
在
Member
执行完成后 Hook。
fun replaceAny(initiate: HookParam.() -> Any?)
+
Change Records
v1.0
first
Function Illustrate
拦截并替换此
Member
内容,给出返回值。
fun replaceUnit(initiate: HookParam.() -> Unit)
+
Change Records
v1.0
first
Function Illustrate
拦截并替换此
Member
内容,没有返回值,可以称为Void
。
fun replaceTo(any: Any?)
+
Change Records
v1.0
first
Function Illustrate
拦截并替
Member
返回值。
fun replaceToTrue()
+
Change Records
v1.0
first
Function Illustrate
拦截并替换
Member
返回值为true
。
Pay Attention
确保替换 Member 的返回对象为 Boolean。
fun replaceToFalse()
+
Change Records
v1.0
first
Function Illustrate
拦截并替换
Member
返回值为false
。
Pay Attention
确保替换 Member 的返回对象为 Boolean。
fun intercept()
+
Change Records
v1.0
first
Function Illustrate
拦截此
Member
。
这将会禁止此 Member
执行并返回 null
。
Pay Attention
例如 Int、Long、Boolean 常量返回值的 Member 一旦被设置为 null 可能会造成 Hook APP 抛出异常。
fun removeSelf(result: (Boolean) -> Unit)
+
Change Records
v1.1.0
added
Function Illustrate
移除当前注入的 Hook
Method
、Constructor
(解除 Hook)。
Pay Attention
你只能在 Hook 回调方法中使用此功能。
inner class LegacyCreator internal constructor()
+
Change Records
v1.2.0
added
Function Illustrate
使用
injectMember
创建的 Hook 核心功能实现类 (旧版本)。
Notice
大部分旧版 API 已被迁移至此处,将不再特殊说明其中包含的旧版 API。
inner class HookCallback internal constructor()
+
Change Records
v1.1.0
added
Function Illustrate
Hook 方法体回调实现类。
fun onFailureThrowToApp()
+
Change Records
v1.1.0
added
Function Illustrate
当回调方法体内发生异常时将异常抛出给当前 Hook APP。
inner class Result internal constructor()
+
Change Records
v1.0
first
Function Illustrate
监听 Hook 结果实现类。
inline fun result(initiate: Result.() -> Unit): Result
+
Change Records
v1.0
first
v1.0.5
modified
修改为 failures
result
v1.0.80
modified
将方法体进行 inline
Function Illustrate
创建监听失败事件方法体。
inline fun by(condition: () -> Boolean): Result
+
Change Records
v1.0.5
added
v1.0.80
modified
将方法体进行 inline
Function Illustrate
添加执行 Hook 需要满足的条件,不满足条件将直接停止 Hook。
fun onHooked(result: (Member) -> Unit): Result
+
Change Records
v1.0.70
added
Function Illustrate
监听
members
Hook 成功的回调方法。
在首次 Hook 成功后回调。
在重复 Hook 时会回调 onAlreadyHooked
。
fun onAlreadyHooked(result: (Member) -> Unit): Result
+
Change Records
v1.0.89
added
Function Illustrate
监听
members
重复 Hook 的回调方法。
Notice
同一个 hookClass 中的同一个 members 不会被 API 重复 Hook,若由于各种原因重复 Hook 会回调此方法。
fun onNoSuchMemberFailure(result: (Throwable) -> Unit): Result
+
Change Records
v1.0.5
added
Function Illustrate
监听
members
不存在发生错误的回调方法。
fun onConductFailure(result: (HookParam, Throwable) -> Unit): Result
+
Change Records
v1.0
first
Function Illustrate
监听 Hook 进行过程中发生错误的回调方法。
fun onHookingFailure(result: (Throwable) -> Unit): Result
+
Change Records
v1.0
first
Function Illustrate
监听 Hook 开始时发生的错误的回调方法。
fun onAllFailure(result: (Throwable) -> Unit): Result
+
Change Records
v1.0
first
Function Illustrate
监听全部 Hook 过程发生错误的回调方法。
fun ignoredNoSuchMemberFailure(): Result
+
Change Records
v1.0.5
added
Function Illustrate
忽略
members
不存在发生的错误。
fun ignoredConductFailure(): Result
+
Change Records
v1.0
first
Function Illustrate
忽略 Hook 进行过程中发生的错误。
fun ignoredHookingFailure(): Result
+
Change Records
v1.0
first
Function Illustrate
忽略 Hook 开始时发生的错误。
fun ignoredAllFailure(): Result
+
Change Records
v1.0
first
Function Illustrate
忽略全部 Hook 过程发生的错误。
fun remove(result: (Boolean) -> Unit)
+
Change Records
v1.1.0
added
Function Illustrate
移除当前注入的 Hook
Method
、Constructor
(解除 Hook)。
Notice
你只能在 Hook 成功后才能解除 Hook,可监听 onHooked 事件。
inner class Result internal constructor()
+
Change Records
v1.0.3
added
Function Illustrate
监听全部 Hook 结果实现类。
inline fun result(initiate: Result.() -> Unit): Result
+
Change Records
v1.0.3
added
v1.0.5
modified
修改为 failures
result
v1.0.80
modified
将方法体进行 inline
Function Illustrate
创建监听事件方法体。
inline fun by(condition: () -> Boolean): Result
+
Change Records
v1.0.5
added
v1.0.80
modified
将方法体进行 inline
Function Illustrate
添加执行 Hook 需要满足的条件,不满足条件将直接停止 Hook。
fun onPrepareHook(callback: () -> Unit): Result
+
Change Records
v1.0.70
added
Function Illustrate
监听
hookClass
存在时准备开始 Hook 的操作。
fun onHookClassNotFoundFailure(result: (Throwable) -> Unit): Result
+
Change Records
v1.0.3
added
Function Illustrate
监听
hookClass
找不到时发生错误的回调方法。
fun ignoredHookClassNotFoundFailure(): Result
+
Change Records
v1.0.3
added
Function Illustrate
`,286),t=[l];function c(p,r){return s(),e("div",null,t)}const i=o(n,[["render",c],["__file","YukiMemberHookCreator.html.vue"]]);export{i as default}; diff --git a/assets/YukiMemberHookCreator.html-WvIyCwTr.js b/assets/YukiMemberHookCreator.html-WvIyCwTr.js new file mode 100644 index 00000000..8644a5bd --- /dev/null +++ b/assets/YukiMemberHookCreator.html-WvIyCwTr.js @@ -0,0 +1,36 @@ +import{_ as o,o as s,c as e,a}from"./app-BpUB8-Q8.js";const n={},l=a(`忽略
hookClass
找不到时出现的错误。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
class YukiMemberHookCreator internal constructor(private val packageParam: PackageParam, private val hookClass: HookClass)
+
变更记录
v1.0
添加
v1.0.80
修改
对 hookClass
进行 inline 处理
v1.1.0
修改
修正拼写错误的 Creater 命名到 Creator
v1.1.5
修改
私有化构造方法
功能描述
YukiHookAPI
的Member
核心 Hook 实现类。
变更记录
v1.0.80
新增
v1.2.0
作废
请迁移到 YukiHookPriority
变更记录
v1.0.80
新增
v1.2.0
作废
请迁移到 YukiHookPriority
变更记录
v1.0.80
新增
v1.2.0
作废
请迁移到 YukiHookPriority
变更记录
v1.0
添加
v1.0.2
修改
更名为 thisClass
instanceClass
v1.2.0
作废
不再推荐使用
变更记录
v1.0
添加
v1.0.80
修改
将方法体进行 inline
增加 priority
Hook 优先级
v1.2.0
作废
请迁移到另一个 injectMember
inline fun injectMember(priority: YukiHookPriority, initiate: MemberHookCreator.LegacyCreator.() -> Unit): MemberHookCreator.Result
+
变更记录
v1.2.0
新增
功能描述
注入要 Hook 的
Method
、Constructor
。
变更记录
v1.1.0
新增
v1.2.0
作废
此功能已被弃用
inner class MemberHookCreator internal constructor(private val priority: YukiHookPriority, private val hookMode: HookMode)
+
变更记录
v1.0
添加
v1.0.80
修改
增加 priority
Hook 优先级
v1.0.81
修改
增加 packageName
当前 Hook 的 APP 包名
v1.1.0
修改
移除 packageName
修正拼写错误的 Creater 命名到 Creator
v1.2.0
修改
移除 tag
priority
类型由 Int
变更为 YukiHookPriority
增加 hookMode
Hook 模式
功能描述
Hook 核心功能实现类,查找和处理需要 Hook 的
Method
、Constructor
。
fun before(initiate: HookParam.() -> Unit): HookCallback
+
变更记录
v1.2.0
新增
功能描述
在
Member
执行完成前 Hook。
fun after(initiate: HookParam.() -> Unit): HookCallback
+
变更记录
v1.2.0
新增
功能描述
在
Member
执行完成后 Hook。
fun replaceAny(initiate: HookParam.() -> Any?)
+
变更记录
v1.0
添加
功能描述
拦截并替换此
Member
内容,给出返回值。
fun replaceUnit(initiate: HookParam.() -> Unit)
+
变更记录
v1.0
添加
功能描述
拦截并替换此
Member
内容,没有返回值,可以称为Void
。
fun replaceTo(any: Any?)
+
变更记录
v1.0
添加
功能描述
拦截并替
Member
返回值。
fun replaceToTrue()
+
变更记录
v1.0
添加
功能描述
拦截并替换
Member
返回值为true
。
特别注意
确保替换 Member 的返回对象为 Boolean。
fun replaceToFalse()
+
变更记录
v1.0
添加
功能描述
拦截并替换
Member
返回值为false
。
特别注意
确保替换 Member 的返回对象为 Boolean。
fun intercept()
+
变更记录
v1.0
添加
功能描述
拦截此
Member
。
这将会禁止此 Member
执行并返回 null
。
特别注意
例如 Int、Long、Boolean 常量返回值的 Member 一旦被设置为 null 可能会造成 Hook APP 抛出异常。
fun removeSelf(result: (Boolean) -> Unit)
+
变更记录
v1.1.0
新增
功能描述
移除当前注入的 Hook
Method
、Constructor
(解除 Hook)。
特别注意
你只能在 Hook 回调方法中使用此功能。
inner class LegacyCreator internal constructor()
+
变更记录
v1.2.0
新增
功能描述
使用
injectMember
创建的 Hook 核心功能实现类 (旧版本)。
注意
大部分旧版 API 已被迁移至此处,将不再特殊说明其中包含的旧版 API。
inner class HookCallback internal constructor()
+
变更记录
v1.1.0
新增
功能描述
Hook 方法体回调实现类。
fun onFailureThrowToApp()
+
变更记录
v1.1.0
新增
功能描述
当回调方法体内发生异常时将异常抛出给当前 Hook APP。
inner class Result internal constructor()
+
变更记录
v1.0
添加
功能描述
监听 Hook 结果实现类。
inline fun result(initiate: Result.() -> Unit): Result
+
变更记录
v1.0
添加
v1.0.5
修改
修改为 failures
result
v1.0.80
修改
将方法体进行 inline
功能描述
创建监听失败事件方法体。
inline fun by(condition: () -> Boolean): Result
+
变更记录
v1.0.5
新增
v1.0.80
修改
将方法体进行 inline
功能描述
添加执行 Hook 需要满足的条件,不满足条件将直接停止 Hook。
fun onHooked(result: (Member) -> Unit): Result
+
变更记录
v1.0.70
新增
功能描述
监听
members
Hook 成功的回调方法。
在首次 Hook 成功后回调。
在重复 Hook 时会回调 onAlreadyHooked
。
fun onAlreadyHooked(result: (Member) -> Unit): Result
+
变更记录
v1.0.89
新增
功能描述
监听
members
重复 Hook 的回调方法。
注意
同一个 hookClass 中的同一个 members 不会被 API 重复 Hook,若由于各种原因重复 Hook 会回调此方法。
fun onNoSuchMemberFailure(result: (Throwable) -> Unit): Result
+
变更记录
v1.0.5
新增
功能描述
监听
members
不存在发生错误的回调方法。
fun onConductFailure(result: (HookParam, Throwable) -> Unit): Result
+
变更记录
v1.0
添加
功能描述
监听 Hook 进行过程中发生错误的回调方法。
fun onHookingFailure(result: (Throwable) -> Unit): Result
+
变更记录
v1.0
添加
功能描述
监听 Hook 开始时发生的错误的回调方法。
fun onAllFailure(result: (Throwable) -> Unit): Result
+
变更记录
v1.0
添加
功能描述
监听全部 Hook 过程发生错误的回调方法。
fun ignoredNoSuchMemberFailure(): Result
+
变更记录
v1.0.5
新增
功能描述
忽略
members
不存在发生的错误。
fun ignoredConductFailure(): Result
+
变更记录
v1.0
添加
功能描述
忽略 Hook 进行过程中发生的错误。
fun ignoredHookingFailure(): Result
+
变更记录
v1.0
添加
功能描述
忽略 Hook 开始时发生的错误。
fun ignoredAllFailure(): Result
+
变更记录
v1.0
添加
功能描述
忽略全部 Hook 过程发生的错误。
fun remove(result: (Boolean) -> Unit)
+
变更记录
v1.1.0
新增
功能描述
移除当前注入的 Hook
Method
、Constructor
(解除 Hook)。
注意
你只能在 Hook 成功后才能解除 Hook,可监听 onHooked 事件。
inner class Result internal constructor()
+
变更记录
v1.0.3
新增
功能描述
监听全部 Hook 结果实现类。
inline fun result(initiate: Result.() -> Unit): Result
+
变更记录
v1.0.3
新增
v1.0.5
修改
修改为 failures
result
v1.0.80
修改
将方法体进行 inline
功能描述
创建监听事件方法体。
inline fun by(condition: () -> Boolean): Result
+
变更记录
v1.0.5
新增
v1.0.80
修改
将方法体进行 inline
功能描述
添加执行 Hook 需要满足的条件,不满足条件将直接停止 Hook。
fun onPrepareHook(callback: () -> Unit): Result
+
变更记录
v1.0.70
新增
功能描述
监听
hookClass
存在时准备开始 Hook 的操作。
fun onHookClassNotFoundFailure(result: (Throwable) -> Unit): Result
+
变更记录
v1.0.3
新增
功能描述
监听
hookClass
找不到时发生错误的回调方法。
fun ignoredHookClassNotFoundFailure(): Result
+
变更记录
v1.0.3
新增
功能描述
`,285),p=[l];function c(t,r){return s(),e("div",null,p)}const i=o(n,[["render",c],["__file","YukiMemberHookCreator.html.vue"]]);export{i as default}; diff --git a/assets/YukiModuleResources.html-CAc6ozP1.js b/assets/YukiModuleResources.html-CAc6ozP1.js new file mode 100644 index 00000000..7d5cc2a5 --- /dev/null +++ b/assets/YukiModuleResources.html-CAc6ozP1.js @@ -0,0 +1,3 @@ +import{_ as e,o as s,c as o,a}from"./app-BpUB8-Q8.js";const n={},t=a(`忽略
hookClass
找不到时出现的错误。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
class YukiModuleResources private constructor(private val baseInstance: XModuleResources) : Resources
+
Change Records
v1.0.80
added
Function Illustrate
对接
XModuleResources
的中间层实例。
fun fwd(resId: Int): YukiResForwarder
+
Change Records
v1.0.80
added
Function Illustrate
对接
XModuleResources.fwd
方法。
创建 YukiResForwarder
与 XResForwarder
实例。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
class YukiModuleResources private constructor(private val baseInstance: XModuleResources) : Resources
+
变更记录
v1.0.80
新增
功能描述
对接
XModuleResources
的中间层实例。
fun fwd(resId: Int): YukiResForwarder
+
变更记录
v1.0.80
新增
功能描述
对接
XModuleResources.fwd
方法。
创建 YukiResForwarder
与 XResForwarder
实例。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
class YukiResForwarder private constructor(private val baseInstance: XResForwarder)
+
Change Records
v1.0.80
added
Function Illustrate
对接
XResForwarder
的中间层实例。
Change Records
v1.0.80
added
v1.1.0
deprecated
不再对外公开 instance
参数
val id: Int
+
Change Records
v1.0.80
added
Function Illustrate
获得当前 APP 的 Resources Id。
val resources: Resources
+
Change Records
v1.0.80
added
Function Illustrate
`,25),t=[c];function r(l,d){return s(),o("div",null,t)}const i=e(n,[["render",r],["__file","YukiResForwarder.html.vue"]]);export{i as default}; diff --git a/assets/YukiResForwarder.html-DMGGwbMr.js b/assets/YukiResForwarder.html-DMGGwbMr.js new file mode 100644 index 00000000..de8e88b5 --- /dev/null +++ b/assets/YukiResForwarder.html-DMGGwbMr.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-7b087cce","path":"/en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResForwarder.html","title":"YukiResForwarder - class","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"id - field","slug":"id-field","link":"#id-field","children":[]},{"level":2,"title":"resources - field","slug":"resources-field","link":"#resources-field","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":2}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResForwarder.md"}');export{e as data}; diff --git a/assets/YukiResForwarder.html-PPhoLmXZ.js b/assets/YukiResForwarder.html-PPhoLmXZ.js new file mode 100644 index 00000000..fda9baf6 --- /dev/null +++ b/assets/YukiResForwarder.html-PPhoLmXZ.js @@ -0,0 +1,4 @@ +import{_ as s,o as e,c as o,a}from"./app-BpUB8-Q8.js";const c={},n=a(`获得当前 APP 的 Resources。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
class YukiResForwarder private constructor(private val baseInstance: XResForwarder)
+
变更记录
v1.0.80
新增
功能描述
对接
XResForwarder
的中间层实例。
变更记录
v1.0.80
新增
v1.1.0
作废
不再对外公开 instance
参数
val id: Int
+
变更记录
v1.0.80
新增
功能描述
获得当前 APP 的 Resources Id。
val resources: Resources
+
变更记录
v1.0.80
新增
功能描述
`,24),r=[n];function l(p,d){return e(),o("div",null,r)}const i=s(c,[["render",l],["__file","YukiResForwarder.html.vue"]]);export{i as default}; diff --git a/assets/YukiResources.html--5kriWCV.js b/assets/YukiResources.html--5kriWCV.js new file mode 100644 index 00000000..f1ed3a2a --- /dev/null +++ b/assets/YukiResources.html--5kriWCV.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-21b3b17e","path":"/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResources.html","title":"YukiResources - class","lang":"zh-CN","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"LayoutInflatedParam - class","slug":"layoutinflatedparam-class","link":"#layoutinflatedparam-class","children":[{"level":3,"title":"variantName - field","slug":"variantname-field","link":"#variantname-field","children":[]},{"level":3,"title":"currentView - field","slug":"currentview-field","link":"#currentview-field","children":[]},{"level":3,"title":"findViewByIdentifier - method","slug":"findviewbyidentifier-method","link":"#findviewbyidentifier-method","children":[]}]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":3}]},"filePathRelative":"zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResources.md"}');export{e as data}; diff --git a/assets/YukiResources.html-CwrMMidY.js b/assets/YukiResources.html-CwrMMidY.js new file mode 100644 index 00000000..abde9a9a --- /dev/null +++ b/assets/YukiResources.html-CwrMMidY.js @@ -0,0 +1,7 @@ +import{_ as s,o as a,c as e,a as o}from"./app-BpUB8-Q8.js";const n={},l=o(`获得当前 APP 的 Resources。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
class YukiResources private constructor(private val baseInstance: XResources) : Resources
+
Change Records
v1.0.80
added
Function Illustrate
对接
XResources
的中间层实例。
class LayoutInflatedParam(private val baseParam: XC_LayoutInflated.LayoutInflatedParam)
+
Change Records
v1.0.80
added
Function Illustrate
装载 Hook APP 的目标布局 Resources 实现类。
val variantName: String
+
Change Records
v1.0.80
added
Function Illustrate
获取当前被 Hook 的布局装载目录名称。
例如:layout
、layout-land
、layout-sw600dp
。
val currentView: View
+
Change Records
v1.0.80
added
Function Illustrate
获取当前被 Hook 的布局实例。
inline fun <reified T : View> View.findViewByIdentifier(name: String): T?
+
inline fun <reified T : View> findViewByIdentifier(name: String): T?
+
Change Records
v1.0.80
added
Function Illustrate
使用 Identifier 查找 Hook APP 指定 Id 的
View
。
扩展方法可以使用 Identifier 查找 Hook APP 当前装载布局中指定 Id 的 View
。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
class YukiResources private constructor(private val baseInstance: XResources) : Resources
+
变更记录
v1.0.80
新增
功能描述
对接
XResources
的中间层实例。
class LayoutInflatedParam(private val baseParam: XC_LayoutInflated.LayoutInflatedParam)
+
变更记录
v1.0.80
新增
功能描述
装载 Hook APP 的目标布局 Resources 实现类。
val variantName: String
+
变更记录
v1.0.80
新增
功能描述
获取当前被 Hook 的布局装载目录名称。
例如:layout
、layout-land
、layout-sw600dp
。
val currentView: View
+
变更记录
v1.0.80
新增
功能描述
获取当前被 Hook 的布局实例。
inline fun <reified T : View> View.findViewByIdentifier(name: String): T?
+
inline fun <reified T : View> findViewByIdentifier(name: String): T?
+
变更记录
v1.0.80
新增
功能描述
使用 Identifier 查找 Hook APP 指定 Id 的
View
。
扩展方法可以使用 Identifier 查找 Hook APP 当前装载布局中指定 Id 的 View
。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
class YukiResourcesHookCreator internal constructor(internal val packageParam: PackageParam, internal val hookResources: HookResources)
+
变更记录
v1.0.80
新增
v1.1.0
修改
修正拼写错误的 Creater 命名到 Creator
v1.1.5
修改
私有化构造方法
功能描述
YukiHookAPI
的Resources
核心 Hook 实现类。
inline fun injectResource(tag: String, initiate: ResourceHookCreator.() -> Unit): ResourceHookCreator.Result
+
变更记录
v1.0.80
新增
功能描述
注入要 Hook 的 Resources。
功能示例
你可以注入任意 Resources,使用 injectResource
即可创建一个 Hook
对象。
示例如下
injectResource {
+ // Your code here.
+}
+
你还可以自定义 tag
,方便你在调试的时候能够区分你的 Hook
对象。
示例如下
injectResource(tag = "KuriharaYuki") {
+ // Your code here.
+}
+
inner class ResourcesHookCreator internal constructor(private val tag: String)
+
变更记录
v1.0.80
新增
v1.1.0
修改
移除 packageName
修正拼写错误的 Creater 命名到 Creator
功能描述
Hook 核心功能实现类。
查找和处理需要 Hook 的 Resources。
var resourceId: Int
+
变更记录
v1.0.80
新增
功能描述
直接设置需要替换的 Resources Id。
注意
不建议使用此方法设置目标需要 Hook 的 Resources Id,你可以使用 conditions 方法。
功能示例
你可以直接设置并指定目标 Hook APP 的 Resources Id。
示例如下
injectResource {
+ resourceId = 0x7f060001.toInt()
+ replaceTo(...)
+}
+
inline fun conditions(initiate: ConditionFinder.() -> Unit)
+
变更记录
v1.0.80
新增
功能描述
设置 Resources 查找条件。
若你设置了 resourceId
则此方法将不会被使用。
功能示例
你可参考 ConditionFinder 查看详细用法。
示例如下
injectResource {
+ conditions {
+ name = "test_string"
+ string()
+ }
+ replaceTo(...)
+}
+
fun replaceTo(any: Any)
+
变更记录
v1.0.80
新增
功能描述
替换指定 Resources 为指定的值。
功能示例
你可以替换找到的 Resources 为你想要的值,可以是 String
、Drawable
等。
比如我们要替换一个找到的字符串 Resources。
示例如下
injectResource {
+ conditions {
+ name = "test_string"
+ string()
+ }
+ replaceTo("replace string")
+}
+
或是替换为一个 Drawable
,你无需对目标 Resources 实现 fwd
方法或 DrawableLoader
。
示例如下
injectResource {
+ conditions {
+ name = "test_drawable"
+ drawable()
+ }
+ replaceTo(ColorDrawable(Color.RED))
+}
+
fun replaceToTrue()
+
变更记录
v1.0.80
新增
功能描述
替换指定 Resources 为
true
。
特别注意
确保目标替换 Resources 的类型为 Boolean。
fun replaceToFalse()
+
变更记录
v1.0.80
新增
功能描述
替换指定 Resources 为
false
。
特别注意
确保目标替换 Resources 的类型为 Boolean。
fun replaceToModuleResource(resId: Int)
+
变更记录
v1.0.80
新增
功能描述
替换为当前 Xposed 模块的 Resources。
你可以直接使用模块的 R.string.xxx
、R.mipmap.xxx
、R.drawable.xxx
替换 Hook APP 的 Resources。
功能示例
使用此方法可非常方便地使用当前模块的 Resources 去替换目标 Hook APP 的 Resources。
这个过程你无需对目标 Resources 实现 fwd
方法。
比如我们要替换一个字符串。
示例如下
injectResource {
+ conditions {
+ name = "test_string"
+ string()
+ }
+ replaceToModuleResource(R.string.module_string)
+}
+
还可以替换一些复杂的 Resources,比如 xml
创建的 drawable
。
示例如下
injectResource {
+ conditions {
+ name = "test_drawable"
+ drawable()
+ }
+ replaceToModuleResource(R.drawable.module_drawable)
+}
+
fun replaceTo(result: (original: Any) -> Any?)
+
变更记录
v1.2.0
新增
功能描述
替换指定 Resources 为指定的值。
注意
此方法只支持部分类型,例如 String、Boolean。
此方法不支持在 HookEntryType.ZYGOTE 时使用。
fun replaceToModuleResource(result: (original: Any) -> Int)
+
变更记录
v1.2.0
新增
功能描述
替换为当前 Xposed 模块的 Resources。
你可以直接使用模块的 R.string.xxx
、R.mipmap.xxx
、R.drawable.xxx
替换 Hook APP 的 Resources。
注意
此方法只支持部分类型,例如 String、Boolean。
此方法不支持在 HookEntryType.ZYGOTE 时使用。
fun injectAsLayout(initiate: YukiResources.LayoutInflatedParam.() -> Unit)
+
变更记录
v1.0.80
新增
功能描述
作为装载的布局注入。
功能示例
你可以直接注入一个布局监听并修改它的内部 View
。
示例如下
injectResource {
+ conditions {
+ name = "activity_main"
+ layout()
+ }
+ injectAsLayout {
+ findViewByIdentifier<View>(name = "test_view")?.isVisible = false
+ findViewByIdentifier<TextView>(name = "test_text_view")?.text = "Hook this"
+ }
+}
+
你还可以通过 currentView
拿到 Context
。
示例如下
injectResource {
+ conditions {
+ name = "activity_main"
+ layout()
+ }
+ injectAsLayout {
+ Toast.makeText(currentView.context, "Hook this", Toast.LENGTH_SHORT).show()
+ }
+}
+
inner class ConditionFinder internal constructor()
+
变更记录
v1.0.80
新增
功能描述
Resources 查找条件实现类。
var name: String
+
变更记录
v1.0.80
新增
功能描述
设置 Resources 名称。
fun anim()
+
变更记录
v1.0.80
新增
功能描述
设置 Resources 类型为动画。
fun animator()
+
变更记录
v1.0.80
新增
功能描述
设置 Resources 类型为属性动画。
fun bool()
+
变更记录
v1.0.80
新增
功能描述
设置 Resources 类型为布朗(Boolean)。
fun color()
+
变更记录
v1.0.80
新增
功能描述
设置 Resources 类型为颜色(Color)。
fun dimen()
+
变更记录
v1.0.80
新增
功能描述
设置 Resources 类型为尺寸(Dimention)。
fun drawable()
+
变更记录
v1.0.80
新增
功能描述
设置 Resources 类型为 Drawable。
fun integer()
+
变更记录
v1.0.80
新增
功能描述
设置 Resources 类型为整型(Integer)。
fun layout()
+
变更记录
v1.0.80
新增
功能描述
设置 Resources 类型为布局(Layout)。
fun plurals()
+
变更记录
v1.0.80
新增
功能描述
设置 Resources 类型为 Plurals。
fun string()
+
变更记录
v1.0.80
新增
功能描述
设置 Resources 类型为字符串(String)。
fun xml()
+
变更记录
v1.0.80
新增
功能描述
设置 Resources 类型为 Xml。
fun mipmap()
+
变更记录
v1.0.80
新增
功能描述
设置 Resources 类型为位图(Mipmap)。
fun array()
+
变更记录
v1.1.0
新增
功能描述
设置 Resources 类型为数组(Array)。
inner class Result internal constructor()
+
变更记录
v1.0.80
新增
功能描述
监听全部 Hook 结果实现类,可在这里处理失败事件监听。
inline fun result(initiate: Result.() -> Unit): Result
+
变更记录
v1.0.80
新增
功能描述
创建监听事件方法体。
inline fun by(condition: () -> Boolean): Result
+
变更记录
v1.0.80
新增
功能描述
添加执行 Hook 需要满足的条件,不满足条件将直接停止 Hook。
fun onHookingFailure(result: (Throwable) -> Unit): Result
+
变更记录
v1.0.80
新增
功能描述
监听 Hook 过程发生错误的回调方法。
fun ignoredHookingFailure(): Result
+
变更记录
v1.0.80
新增
功能描述
`,248),p=[l];function c(t,r){return a(),n("div",null,p)}const i=s(o,[["render",c],["__file","YukiResourcesHookCreator.html.vue"]]);export{i as default}; diff --git a/assets/YukiResourcesHookCreator.html-CuPFBHZF.js b/assets/YukiResourcesHookCreator.html-CuPFBHZF.js new file mode 100644 index 00000000..2ccbfc05 --- /dev/null +++ b/assets/YukiResourcesHookCreator.html-CuPFBHZF.js @@ -0,0 +1,97 @@ +import{_ as s,o as a,c as n,a as e}from"./app-BpUB8-Q8.js";const o={},l=e(`忽略 Hook 过程出现的错误。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
class YukiResourcesHookCreator internal constructor(internal val packageParam: PackageParam, internal val hookResources: HookResources)
+
Change Records
v1.0.80
added
v1.1.0
modified
修正拼写错误的 Creater 命名到 Creator
v1.1.5
modified
私有化构造方法
Function Illustrate
YukiHookAPI
的Resources
核心 Hook 实现类。
inline fun injectResource(tag: String, initiate: ResourceHookCreator.() -> Unit): ResourceHookCreator.Result
+
Change Records
v1.0.80
added
Function Illustrate
注入要 Hook 的 Resources。
Function Example
你可以注入任意 Resources,使用 injectResource
即可创建一个 Hook
对象。
The following example
injectResource {
+ // Your code here.
+}
+
你还可以自定义 tag
,方便你在调试的时候能够区分你的 Hook
对象。
The following example
injectResource(tag = "KuriharaYuki") {
+ // Your code here.
+}
+
inner class ResourcesHookCreator internal constructor(private val tag: String)
+
Change Records
v1.0.80
added
v1.1.0
modified
移除 packageName
修正拼写错误的 Creater 命名到 Creator
Function Illustrate
Hook 核心功能实现类。
查找和处理需要 Hook 的 Resources。
var resourceId: Int
+
Change Records
v1.0.80
added
Function Illustrate
直接设置需要替换的 Resources Id。
Notice
不建议使用此方法设置目标需要 Hook 的 Resources Id,你可以使用 conditions 方法。
Function Example
你可以直接设置并指定目标 Hook APP 的 Resources Id。
The following example
injectResource {
+ resourceId = 0x7f060001.toInt()
+ replaceTo(...)
+}
+
inline fun conditions(initiate: ConditionFinder.() -> Unit)
+
Change Records
v1.0.80
added
Function Illustrate
设置 Resources 查找条件。
若你设置了 resourceId
则此方法将不会被使用。
Function Example
你可参考 ConditionFinder 查看详细用法。
The following example
injectResource {
+ conditions {
+ name = "test_string"
+ string()
+ }
+ replaceTo(...)
+}
+
fun replaceTo(any: Any)
+
Change Records
v1.0.80
added
Function Illustrate
替换指定 Resources 为指定的值。
Function Example
你可以替换找到的 Resources 为你想要的值,可以是 String
、Drawable
等。
比如我们要替换一个找到的字符串 Resources。
The following example
injectResource {
+ conditions {
+ name = "test_string"
+ string()
+ }
+ replaceTo("replace string")
+}
+
或是替换为一个 Drawable
,你无需对目标 Resources 实现 fwd
方法或 DrawableLoader
。
The following example
injectResource {
+ conditions {
+ name = "test_drawable"
+ drawable()
+ }
+ replaceTo(ColorDrawable(Color.RED))
+}
+
fun replaceToTrue()
+
Change Records
v1.0.80
added
Function Illustrate
替换指定 Resources 为
true
。
Pay Attention
确保目标替换 Resources 的类型为 Boolean。
fun replaceToFalse()
+
Change Records
v1.0.80
added
Function Illustrate
替换指定 Resources 为
false
。
Pay Attention
确保目标替换 Resources 的类型为 Boolean。
fun replaceToModuleResource(resId: Int)
+
Change Records
v1.0.80
added
Function Illustrate
替换为当前 Xposed 模块的 Resources。
你可以直接使用模块的 R.string.xxx
、R.mipmap.xxx
、R.drawable.xxx
替换 Hook APP 的 Resources。
Function Example
使用此方法可非常方便地使用当前模块的 Resources 去替换目标 Hook APP 的 Resources。
这个过程你无需对目标 Resources 实现 fwd
方法。
比如我们要替换一个字符串。
The following example
injectResource {
+ conditions {
+ name = "test_string"
+ string()
+ }
+ replaceToModuleResource(R.string.module_string)
+}
+
还可以替换一些复杂的 Resources,比如 xml
创建的 drawable
。
The following example
injectResource {
+ conditions {
+ name = "test_drawable"
+ drawable()
+ }
+ replaceToModuleResource(R.drawable.module_drawable)
+}
+
fun replaceTo(result: (original: Any) -> Any?)
+
Change Records
v1.2.0
added
Function Illustrate
替换指定 Resources 为指定的值。
Notice
此方法只支持部分类型,例如 String、Boolean。
此方法不支持在 HookEntryType.ZYGOTE 时使用。
fun replaceToModuleResource(result: (original: Any) -> Int)
+
Change Records
v1.2.0
added
Function Illustrate
替换为当前 Xposed 模块的 Resources。
你可以直接使用模块的 R.string.xxx
、R.mipmap.xxx
、R.drawable.xxx
替换 Hook APP 的 Resources。
Notice
此方法只支持部分类型,例如 String、Boolean。
此方法不支持在 HookEntryType.ZYGOTE 时使用。
fun injectAsLayout(initiate: YukiResources.LayoutInflatedParam.() -> Unit)
+
Change Records
v1.0.80
added
Function Illustrate
作为装载的布局注入。
Function Example
你可以直接注入一个布局监听并修改它的内部 View
。
The following example
injectResource {
+ conditions {
+ name = "activity_main"
+ layout()
+ }
+ injectAsLayout {
+ findViewByIdentifier<View>(name = "test_view")?.isVisible = false
+ findViewByIdentifier<TextView>(name = "test_text_view")?.text = "Hook this"
+ }
+}
+
你还可以通过 currentView
拿到 Context
。
The following example
injectResource {
+ conditions {
+ name = "activity_main"
+ layout()
+ }
+ injectAsLayout {
+ Toast.makeText(currentView.context, "Hook this", Toast.LENGTH_SHORT).show()
+ }
+}
+
inner class ConditionFinder internal constructor()
+
Change Records
v1.0.80
added
Function Illustrate
Resources 查找条件实现类。
var name: String
+
Change Records
v1.0.80
added
Function Illustrate
设置 Resources 名称。
fun anim()
+
Change Records
v1.0.80
added
Function Illustrate
设置 Resources 类型为动画。
fun animator()
+
Change Records
v1.0.80
added
Function Illustrate
设置 Resources 类型为属性动画。
fun bool()
+
Change Records
v1.0.80
added
Function Illustrate
设置 Resources 类型为布朗(Boolean)。
fun color()
+
Change Records
v1.0.80
added
Function Illustrate
设置 Resources 类型为颜色(Color)。
fun dimen()
+
Change Records
v1.0.80
added
Function Illustrate
设置 Resources 类型为尺寸(Dimention)。
fun drawable()
+
Change Records
v1.0.80
added
Function Illustrate
设置 Resources 类型为 Drawable。
fun integer()
+
Change Records
v1.0.80
added
Function Illustrate
设置 Resources 类型为整型(Integer)。
fun layout()
+
Change Records
v1.0.80
added
Function Illustrate
设置 Resources 类型为布局(Layout)。
fun plurals()
+
Change Records
v1.0.80
added
Function Illustrate
设置 Resources 类型为 Plurals。
fun string()
+
Change Records
v1.0.80
added
Function Illustrate
设置 Resources 类型为字符串(String)。
fun xml()
+
Change Records
v1.0.80
added
Function Illustrate
设置 Resources 类型为 Xml。
fun mipmap()
+
Change Records
v1.0.80
added
Function Illustrate
设置 Resources 类型为位图(Mipmap)。
fun array()
+
Change Records
v1.1.0
added
Function Illustrate
设置 Resources 类型为数组(Array)。
inner class Result internal constructor()
+
Change Records
v1.0.80
added
Function Illustrate
监听全部 Hook 结果实现类,可在这里处理失败事件监听。
inline fun result(initiate: Result.() -> Unit): Result
+
Change Records
v1.0.80
added
Function Illustrate
创建监听事件方法体。
inline fun by(condition: () -> Boolean): Result
+
Change Records
v1.0.80
added
Function Illustrate
添加执行 Hook 需要满足的条件,不满足条件将直接停止 Hook。
fun onHookingFailure(result: (Throwable) -> Unit): Result
+
Change Records
v1.0.80
added
Function Illustrate
监听 Hook 过程发生错误的回调方法。
fun ignoredHookingFailure(): Result
+
Change Records
v1.0.80
added
Function Illustrate
`,249),p=[l];function c(t,r){return a(),n("div",null,p)}const i=s(o,[["render",c],["__file","YukiResourcesHookCreator.html.vue"]]);export{i as default}; diff --git a/assets/YukiResourcesHookCreator.html-DW5yilOs.js b/assets/YukiResourcesHookCreator.html-DW5yilOs.js new file mode 100644 index 00000000..f4be449d --- /dev/null +++ b/assets/YukiResourcesHookCreator.html-DW5yilOs.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-5e81af42","path":"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/YukiResourcesHookCreator.html","title":"YukiResourcesHookCreator - class","lang":"zh-CN","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"injectResource - method","slug":"injectresource-method","link":"#injectresource-method","children":[]},{"level":2,"title":"ResourcesHookCreator - class","slug":"resourceshookcreator-class","link":"#resourceshookcreator-class","children":[{"level":3,"title":"resourceId - field","slug":"resourceid-field","link":"#resourceid-field","children":[]},{"level":3,"title":"conditions - method","slug":"conditions-method","link":"#conditions-method","children":[]},{"level":3,"title":"replaceTo - method","slug":"replaceto-method","link":"#replaceto-method","children":[]},{"level":3,"title":"replaceToTrue - method","slug":"replacetotrue-method","link":"#replacetotrue-method","children":[]},{"level":3,"title":"replaceToFalse - method","slug":"replacetofalse-method","link":"#replacetofalse-method","children":[]},{"level":3,"title":"replaceToModuleResource - method","slug":"replacetomoduleresource-method","link":"#replacetomoduleresource-method","children":[]},{"level":3,"title":"replaceTo - method","slug":"replaceto-method-1","link":"#replaceto-method-1","children":[]},{"level":3,"title":"replaceToModuleResource - method","slug":"replacetomoduleresource-method-1","link":"#replacetomoduleresource-method-1","children":[]},{"level":3,"title":"injectAsLayout - method","slug":"injectaslayout-method","link":"#injectaslayout-method","children":[]},{"level":3,"title":"ConditionFinder - class","slug":"conditionfinder-class","link":"#conditionfinder-class","children":[]},{"level":3,"title":"Result - class","slug":"result-class","link":"#result-class","children":[]},{"level":3,"title":"onHookingFailure - method","slug":"onhookingfailure-method","link":"#onhookingfailure-method","children":[]},{"level":3,"title":"ignoredHookingFailure - method","slug":"ignoredhookingfailure-method","link":"#ignoredhookingfailure-method","children":[]}]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":4}]},"filePathRelative":"zh-cn/api/public/com/highcapable/yukihookapi/hook/core/YukiResourcesHookCreator.md"}');export{e as data}; diff --git a/assets/YukiResourcesHookCreator.html-RF6ZJecD.js b/assets/YukiResourcesHookCreator.html-RF6ZJecD.js new file mode 100644 index 00000000..8622227d --- /dev/null +++ b/assets/YukiResourcesHookCreator.html-RF6ZJecD.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-5ed1ceee","path":"/en/api/public/com/highcapable/yukihookapi/hook/core/YukiResourcesHookCreator.html","title":"YukiResourcesHookCreator - class","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"injectResource - method","slug":"injectresource-method","link":"#injectresource-method","children":[]},{"level":2,"title":"ResourcesHookCreator - class","slug":"resourceshookcreator-class","link":"#resourceshookcreator-class","children":[{"level":3,"title":"resourceId - field","slug":"resourceid-field","link":"#resourceid-field","children":[]},{"level":3,"title":"conditions - method","slug":"conditions-method","link":"#conditions-method","children":[]},{"level":3,"title":"replaceTo - method","slug":"replaceto-method","link":"#replaceto-method","children":[]},{"level":3,"title":"replaceToTrue - method","slug":"replacetotrue-method","link":"#replacetotrue-method","children":[]},{"level":3,"title":"replaceToFalse - method","slug":"replacetofalse-method","link":"#replacetofalse-method","children":[]},{"level":3,"title":"replaceToModuleResource - method","slug":"replacetomoduleresource-method","link":"#replacetomoduleresource-method","children":[]},{"level":3,"title":"replaceTo - method","slug":"replaceto-method-1","link":"#replaceto-method-1","children":[]},{"level":3,"title":"replaceToModuleResource - method","slug":"replacetomoduleresource-method-1","link":"#replacetomoduleresource-method-1","children":[]},{"level":3,"title":"injectAsLayout - method","slug":"injectaslayout-method","link":"#injectaslayout-method","children":[]},{"level":3,"title":"ConditionFinder - class","slug":"conditionfinder-class","link":"#conditionfinder-class","children":[]},{"level":3,"title":"Result - class","slug":"result-class","link":"#result-class","children":[]},{"level":3,"title":"onHookingFailure - method","slug":"onhookingfailure-method","link":"#onhookingfailure-method","children":[]},{"level":3,"title":"ignoredHookingFailure - method","slug":"ignoredhookingfailure-method","link":"#ignoredhookingfailure-method","children":[]}]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":4}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/core/YukiResourcesHookCreator.md"}');export{e as data}; diff --git a/assets/YukiXposedEvent.html-BFs-WRvy.js b/assets/YukiXposedEvent.html-BFs-WRvy.js new file mode 100644 index 00000000..1d6d277f --- /dev/null +++ b/assets/YukiXposedEvent.html-BFs-WRvy.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-19e7277e","path":"/en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/event/YukiXposedEvent.html","title":"YukiXposedEvent - object","lang":"en-US","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"events - method","slug":"events-method","link":"#events-method","children":[]},{"level":2,"title":"onInitZygote - method","slug":"oninitzygote-method","link":"#oninitzygote-method","children":[]},{"level":2,"title":"onHandleLoadPackage - method","slug":"onhandleloadpackage-method","link":"#onhandleloadpackage-method","children":[]},{"level":2,"title":"onHandleInitPackageResources - method","slug":"onhandleinitpackageresources-method","link":"#onhandleinitpackageresources-method","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":2}]},"filePathRelative":"en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/event/YukiXposedEvent.md"}');export{e as data}; diff --git a/assets/YukiXposedEvent.html-BIvOGBiv.js b/assets/YukiXposedEvent.html-BIvOGBiv.js new file mode 100644 index 00000000..48543e9e --- /dev/null +++ b/assets/YukiXposedEvent.html-BIvOGBiv.js @@ -0,0 +1,6 @@ +import{_ as e,o as s,c as a,a as o}from"./app-BpUB8-Q8.js";const n={},t=o(`忽略 Hook 过程出现的错误。
Notice
Due to maintenance costs, the YukiHookAPI
will no longer update this document from version 1.3.0
and switch to the API document automatically generated by the Dokka plugin in version 2.0.0
.
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
object YukiXposedEvent
+
Change Records
v1.0.80
first
Function Illustrate
实现对原生 Xposed API 的装载事件监听。
inline fun events(initiate: YukiXposedEvent.() -> Unit)
+
Change Records
v1.0.80
added
Function Illustrate
对
YukiXposedEvent
创建一个方法体。
fun onInitZygote(result: (StartupParam) -> Unit)
+
Change Records
v1.0.80
added
Function Illustrate
设置 initZygote 事件监听。
fun onHandleLoadPackage(result: (LoadPackageParam) -> Unit)
+
Change Records
v1.0.80
added
Function Illustrate
设置 handleLoadPackage 事件监听。
fun onHandleInitPackageResources(result: (InitPackageResourcesParam) -> Unit)
+
Change Records
v1.0.80
added
Function Illustrate
`,32),c=[t];function l(p,d){return s(),a("div",null,c)}const i=e(n,[["render",l],["__file","YukiXposedEvent.html.vue"]]);export{i as default}; diff --git a/assets/YukiXposedEvent.html-C9AS9omI.js b/assets/YukiXposedEvent.html-C9AS9omI.js new file mode 100644 index 00000000..5b50008f --- /dev/null +++ b/assets/YukiXposedEvent.html-C9AS9omI.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-0a4de82f","path":"/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/event/YukiXposedEvent.html","title":"YukiXposedEvent - object","lang":"zh-CN","frontmatter":{"pageClass":"code-page"},"headers":[{"level":2,"title":"events - method","slug":"events-method","link":"#events-method","children":[]},{"level":2,"title":"onInitZygote - method","slug":"oninitzygote-method","link":"#oninitzygote-method","children":[]},{"level":2,"title":"onHandleLoadPackage - method","slug":"onhandleloadpackage-method","link":"#onhandleloadpackage-method","children":[]},{"level":2,"title":"onHandleInitPackageResources - method","slug":"onhandleinitpackageresources-method","link":"#onhandleinitpackageresources-method","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":2}]},"filePathRelative":"zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/event/YukiXposedEvent.md"}');export{e as data}; diff --git a/assets/YukiXposedEvent.html-DtehWaX2.js b/assets/YukiXposedEvent.html-DtehWaX2.js new file mode 100644 index 00000000..93f8aea9 --- /dev/null +++ b/assets/YukiXposedEvent.html-DtehWaX2.js @@ -0,0 +1,6 @@ +import{_ as s,o as e,c as a,a as o}from"./app-BpUB8-Q8.js";const n={},t=o(`设置 handleInitPackageResources 事件监听。
注意
由于维护成本,YukiHookAPI
从 1.3.0
版本开始将不再会对此文档进行更新且在 2.0.0
版本切换为 Dokka 插件自动生成的 API 文档。
object YukiXposedEvent
+
变更记录
v1.0.80
添加
功能描述
实现对原生 Xposed API 的装载事件监听。
inline fun events(initiate: YukiXposedEvent.() -> Unit)
+
变更记录
v1.0.80
新增
功能描述
对
YukiXposedEvent
创建一个方法体。
fun onInitZygote(result: (StartupParam) -> Unit)
+
变更记录
v1.0.80
新增
功能描述
设置 initZygote 事件监听。
fun onHandleLoadPackage(result: (LoadPackageParam) -> Unit)
+
变更记录
v1.0.80
新增
功能描述
设置 handleLoadPackage 事件监听。
fun onHandleInitPackageResources(result: (InitPackageResourcesParam) -> Unit)
+
变更记录
v1.0.80
新增
功能描述
`,31),l=[t];function p(c,d){return e(),a("div",null,l)}const i=s(n,[["render",p],["__file","YukiXposedEvent.html.vue"]]);export{i as default}; diff --git a/assets/about.html-B_eiWEVD.js b/assets/about.html-B_eiWEVD.js new file mode 100644 index 00000000..91c6d24a --- /dev/null +++ b/assets/about.html-B_eiWEVD.js @@ -0,0 +1,16 @@ +import{_ as o,r as c,o as l,c as t,b as a,d as e,e as n,a as p}from"./app-BpUB8-Q8.js";const r={},i=a("h1",{id:"关于此文档",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#关于此文档","aria-hidden":"true"},"#"),e(" 关于此文档")],-1),d={href:"https://v2.vuepress.vuejs.org/zh",target:"_blank",rel:"noopener noreferrer"},h=a("h2",{id:"许可证",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#许可证","aria-hidden":"true"},"#"),e(" 许可证")],-1),b={href:"https://github.com/HighCapable/YukiHookAPI/blob/master/LICENSE",target:"_blank",rel:"noopener noreferrer"},u=p(`设置 handleInitPackageResources 事件监听。
Apache License Version 2.0
+
+Copyright (C) 2019 HighCapable
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
版权所有 © 2019 HighCapable
`,2);function _(y,g){const s=c("ExternalLinkIcon");return l(),t("div",null,[i,a("blockquote",null,[a("p",null,[e("此文档由 "),a("a",d,[e("VuePress"),n(s)]),e(" 强力驱动。")])]),h,a("p",null,[a("a",b,[e("Apache-2.0"),n(s)])]),u])}const m=o(r,[["render",_],["__file","about.html.vue"]]);export{m as default}; diff --git a/assets/about.html-C7A_QXrx.js b/assets/about.html-C7A_QXrx.js new file mode 100644 index 00000000..a6cd775c --- /dev/null +++ b/assets/about.html-C7A_QXrx.js @@ -0,0 +1,16 @@ +import{_ as o,r as t,o as c,c as l,b as e,d as a,e as n,a as p}from"./app-BpUB8-Q8.js";const i={},r=e("h1",{id:"about-this-document",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#about-this-document","aria-hidden":"true"},"#"),a(" About This Document")],-1),d={href:"https://v2.vuepress.vuejs.org/en",target:"_blank",rel:"noopener noreferrer"},h=e("h2",{id:"license",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#license","aria-hidden":"true"},"#"),a(" License")],-1),b={href:"https://github.com/HighCapable/YukiHookAPI/blob/master/LICENSE",target:"_blank",rel:"noopener noreferrer"},u=p(`Apache License Version 2.0
+
+Copyright (C) 2019 HighCapable
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
Copyright © 2019 HighCapable
`,2);function _(y,m){const s=t("ExternalLinkIcon");return c(),l("div",null,[r,e("blockquote",null,[e("p",null,[a("This document is powered by "),e("a",d,[a("VuePress"),n(s)]),a(".")])]),h,e("p",null,[e("a",b,[a("Apache-2.0"),n(s)])]),u])}const f=o(i,[["render",_],["__file","about.html.vue"]]);export{f as default}; diff --git a/assets/about.html-D2yzzIyM.js b/assets/about.html-D2yzzIyM.js new file mode 100644 index 00000000..1b707fc9 --- /dev/null +++ b/assets/about.html-D2yzzIyM.js @@ -0,0 +1 @@ +const t=JSON.parse('{"key":"v-41967128","path":"/zh-cn/about/about.html","title":"关于此文档","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"许可证","slug":"许可证","link":"#许可证","children":[]}],"git":{"updatedTime":1736736532000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":7}]},"filePathRelative":"zh-cn/about/about.md"}');export{t as data}; diff --git a/assets/about.html-DDk-q1tu.js b/assets/about.html-DDk-q1tu.js new file mode 100644 index 00000000..7ac088b8 --- /dev/null +++ b/assets/about.html-DDk-q1tu.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-7a15fe3b","path":"/en/about/about.html","title":"About This Document","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"License","slug":"license","link":"#license","children":[]}],"git":{"updatedTime":1736736532000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":8}]},"filePathRelative":"en/about/about.md"}');export{e as data}; diff --git a/assets/api-example.html-CKw7e9Ka.js b/assets/api-example.html-CKw7e9Ka.js new file mode 100644 index 00000000..221aea9c --- /dev/null +++ b/assets/api-example.html-CKw7e9Ka.js @@ -0,0 +1 @@ +const l=JSON.parse('{"key":"v-c6114c9e","path":"/zh-cn/config/api-example.html","title":"API 基本配置","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"功能配置","slug":"功能配置","link":"#功能配置","children":[{"level":3,"title":"configs 方法","slug":"configs-方法","link":"#configs-方法","children":[]}]},{"level":2,"title":"Hooker 配置","slug":"hooker-配置","link":"#hooker-配置","children":[{"level":3,"title":"通过 lambda 创建","slug":"通过-lambda-创建","link":"#通过-lambda-创建","children":[]},{"level":3,"title":"通过自定义 Hooker 创建","slug":"通过自定义-hooker-创建","link":"#通过自定义-hooker-创建","children":[]},{"level":3,"title":"扩展特性","slug":"扩展特性","link":"#扩展特性","children":[]},{"level":3,"title":"注意事项","slug":"注意事项","link":"#注意事项","children":[]}]},{"level":2,"title":"作为 Hook API 使用需要注意的地方","slug":"作为-hook-api-使用需要注意的地方","link":"#作为-hook-api-使用需要注意的地方","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":9}]},"filePathRelative":"zh-cn/config/api-example.md"}');export{l as data}; diff --git a/assets/api-example.html-DtfHDuEM.js b/assets/api-example.html-DtfHDuEM.js new file mode 100644 index 00000000..0f96bdfe --- /dev/null +++ b/assets/api-example.html-DtfHDuEM.js @@ -0,0 +1,237 @@ +import{_ as s,o as n,c as a,a as e}from"./app-BpUB8-Q8.js";const l={},o=e(`The basic configuration method of
YukiHookAPI
is introduced here.
Either Use as Xposed Module Configs or Use as Hook API Configs, you can specify
YukiHookAPI
for configuration.
fun configs(initiate: Configs.() -> Unit)
+
The configs
method implements a lambda method body on the Configs
class, which you can easily call for configuration.
Tips
For more functions, please refer to the YukiHookAPI.configs method.
The most important part of an Xposed Module or Hook API is the creation and use of Hooker.
YukiHookAPI
provides two ways to use it.
This solution is the simplest. If your module has few functions and a small amount of code, and does not need to be classified, it is recommended to create it in this way.
fun encase(initiate: PackageParam.() -> Unit)
+
The encase
method is the beginning of all Hook life. In a Module App or a Hook process, the encase
method can only be used once to create a Hooker.
PackageParam
is an important instance object of the Host App, and PackageParam
is used to implement all Hook operations on the current Hook object.
Tips
For more functions, please refer to PackageParam.
The encase
method can be created in the onHook
method using two schemes.
Sample Code 1
YukiHookAPI.encase {
+ loadApp(name = "com.example.demo") {
+ "$packageName.DemoClass".toClass()
+ .resolve()
+ .firstMethod {
+ // Your code here.
+ }.hook {
+ // Your code here.
+ }
+ }
+}
+
Sample Code 2
encase {
+ loadApp(name = "com.example.demo") {
+ "$packageName.DemoClass".toClass()
+ .resolve()
+ .firstMethod {
+ // Your code here.
+ }.hook {
+ // Your code here.
+ }
+ }
+}
+
Do your Hook operations in the encase
method.
This scheme is more suitable for large-scale projects, such as the need to classify Hooker or classify the role of Hook.
fun encase(vararg hooker: YukiBaseHooker)
+
Also for the encase
method, the variable array parameter hooker
of the method here provides an object for creating an entry, you can load all Hookers extends YukiBaseHooker
at one time.
YukiBaseHooker
extends PackageParam
, you need to extends your child Hooker from YukiBaseHooker
.
Tips
For more functions, please refer to YukiBaseHooker.
The following example
object CustomHooker : YukiBaseHooker() {
+
+ override fun onHook() {
+ // Your code here.
+ }
+}
+
Child Hooker recommended to use singleton object
to create, you can also use class
but it is generally not recommended.
Notice
You don't need to re-call encase in the onHook method extends YukiBaseHooker, this is wrong and will not take effect, you should start writing your Hook code directly .
The following example
object CustomHooker : YukiBaseHooker() {
+
+ override fun onHook() {
+ loadApp(name = "com.example.demo1") {
+ "$packageName.DemoClass".toClass()
+ .resolve()
+ .firstMethod {
+ // Your code here.
+ }.hook {
+ // Your code here.
+ }
+ }
+ loadApp(name = "com.example.demo2") {
+ "$packageName.CustomClass".toClass()
+ .resolve()
+ .firstMethod {
+ // Your code here.
+ }.hook {
+ // Your code here.
+ }
+ }
+ }
+}
+
As a child hooker, you can also call the loadApp
method externally, and then directly start the Hook internally.
The following example
object HookEntry : IYukiHookXposedInit {
+
+ override fun onHook() = encase {
+ loadApp(name = "com.example.demo", ChildCustomHooker)
+ }
+}
+
+object ChildCustomHooker : YukiBaseHooker() {
+
+ override fun onHook() {
+ "$packageName.DemoClass".toClass()
+ .resolve()
+ .firstMethod {
+ // Your code here.
+ }.hook {
+ // Your code here.
+ }
+ }
+}
+
You can use the loadHooker
method to load another Hooker in multiple layers in the child Hooker, please do as you like.
The following example
object FirstHooker : YukiBaseHooker() {
+
+ override fun onHook() {
+ "$packageName.DemoClass".toClass()
+ .resolve()
+ .firstMethod {
+ // Your code here.
+ }.hook {
+ // Your code here.
+ }
+ loadHooker(SecondHooker)
+ loadHooker(ThirdHooker)
+ }
+}
+
Once all Hookers are set up, you can load your Hooker in the onHook
method of your Hook entry class.
The following example
object HookEntry : IYukiHookXposedInit {
+
+ override fun onHook() =
+ YukiHookAPI.encase(FirstHooker, SecondHooker, ThirdHooker ...)
+}
+
Of course, we can also abbreviate it.
The following example
object HookEntry : IYukiHookXposedInit {
+
+ override fun onHook() = encase(FirstHooker, SecondHooker, ThirdHooker ...)
+}
+
As we mentioned above, it is generally not recommended to use class
to create child Hookers, but there is a special case where it may still be necessary to keep your Hooker supporting multiple instantiations.
There is a rare possibility that there are multiple package names in a process.
In this case, when YukiHookAPI
finds that the child Hooker is a singleton, it will ignore it and print a warning message.
This Hooker "HOOKER" is singleton or reused, but the current process has multiple package name "NAME", the original is "NAME"
+Make sure your Hooker supports multiple instances for this situation
+The process with package name "NAME" will be ignored
+
In this case, we only need to modify object
to class
or determine the package name during loading and then load the child Hooker.
For example, in the above cases, the following forms can be used to load.
The following example
encase {
+ // Assume this is the app package name and child Hooker you need to load
+ loadApp("com.example.demo", YourCustomHooker)
+}
+
If your current Hook Framework supports and enables the Resources Hook feature, you can now create Resources Hooks directly in encase
.
You don't need to separate the initZygote
, handleLoadPackage
, handleInitPackageResources
methods to perform different functions as before using the Xposed API.
In YukiHookAPI
, these functions are seamless.
The following example
encase {
+ loadApp(name = "com.example.demo") {
+ "$packageName.DemoClass".toClass()
+ .resolve()
+ .firstMethod {
+ // Your code here.
+ }.hook {
+ // Your code here.
+ }
+ // Create a Resources Hook (fixed usage)
+ resources().hook {
+ // Your code here.
+ }
+ }
+}
+
You can also use the loadZygote
method to load the first event initZygote
after a new process has been forked.
The following example
encase {
+ loadZygote {
+ Activity::class.resolve().firstMethod {
+ // Your code here.
+ }
+ // Create a Resources Hook in Zygote
+ resources().hook {
+ // Your code here.
+ }
+ }
+ loadApp(name = "com.example.demo") {
+ "$packageName.DemoClass".toClass()
+ .resolve()
+ .firstMethod {
+ // Your code here.
+ }.hook {
+ // Your code here.
+ }
+ // Create a Resources Hook in the app
+ resources().hook {
+ // Your code here.
+ }
+ }
+}
+
It is wrong to load Hooker directly or start Hook directly, encase
event will go through three callbacks after being loaded by Hook Framework.
load initZygote
→ encase
load handleLoadPackage
→ encase
load handleInitPackageResources
→ encase
In this process, you need to use loadApp
, loadSystem
, loadZygote
to distinguish the calling domain of each loading code, otherwise your code will be executed multiple times and cause errors.
Notice
Whether you use encase to create the lambda method body or use the Hooker form directly, you should not directly load the Hooker or start the Hook directly in the first onHook event.
Below are two error examples.
Sample Code 1
encase {
+ // Wrong usage, can't start Hook directly
+ "com.example.demo.DemoClass".toClass()
+ .resolve()
+ .firstMethod {
+ // Your code here.
+ }.hook {
+ // Your code here.
+ }
+ // Wrong usage, can't start Hook directly
+ resources().hook {
+ // ...
+ }
+}
+
Sample Code 2
object HookEntry : IYukiHookXposedInit {
+
+ override fun onHook() {
+ // <Scenario 1>
+ encase {
+ loadHooker(CustomHooker)
+ }
+ // <Scenario 2>
+ encase(CustomHooker)
+ }
+}
+
+object CustomHooker : YukiBaseHooker() {
+
+ override fun onHook() {
+ // Wrong method of use
+ // Because there is no judgment object in the outer layer, you cannot start Hook directly
+ "com.example.demo.DemoClass".toClass()
+ .resolve()
+ .firstMethod {
+ // Your code here.
+ }.hook {
+ // Your code here.
+ }
+ }
+}
+
Below is a correct example of the wrong example above.
Sample Code 1
encase {
+ // ✅ Correct usage, load in Zygote
+ loadZygote(CustomHooker)
+ // ✅ Correct usage, load in Zygote
+ loadZygote {
+ // ✅ Correct usage, Hook in Zygote
+ resources().hook {
+ // ...
+ }
+ }
+ // ✅ The correct way to use it, use the app scope to load
+ loadApp(/** name parameter optional */, hooker = CustomHooker)
+ // ✅ The correct way to use it, load the Hooker after judging the scope of the app
+ loadApp(/** name parameter optional */) {
+ loadHooker(CustomHooker)
+ // ✅ Correct usage, Hook in app scope
+ "com.example.demo.DemoClass".toClass()
+ .resolve()
+ .firstMethod {
+ // Your code here.
+ }.hook {
+ // Your code here.
+ }
+ // ✅ Correct usage, Hook in app scope
+ resources().hook {
+ // ...
+ }
+ }
+}
+
Sample Code 2
object HookEntry : IYukiHookXposedInit {
+
+ override fun onHook() {
+ encase(CustomHooker)
+ }
+}
+
+object CustomHooker : YukiBaseHooker() {
+
+ override fun onHook() {
+ // ✅ The correct method of use, since there is no judgment object in the outer layer
+ // it is necessary to judge the scope of the app before performing Hook
+ loadApp(/** name parameter optional */) {
+ "com.example.demo.DemoClass".toClass()
+ .resolve()
+ .firstMethod {
+ // Your code here.
+ }.hook {
+ // Your code here.
+ }
+ }
+ }
+}
+
If you are using it as a Hook API, then you only need to differentiate the encase
method at the entry point.
Notice
The encase method provides two identical methods for use as a Hook API, but with only one more parameter baseContext than the previous two.
Method 1
fun encase(baseContext: Context?, initiate: PackageParam.() -> Unit)
+
Method 2
fun encase(baseContext: Context?, vararg hooker: YukiBaseHooker)
+
The baseContext
here only needs to fill in the Context
you got at attachBaseContext
, and other usages are exactly the same as the above.
Pay Attention
Never use the encase method in an Xposed way without omitting the baseContext parameter, this will lead to your Hook not work at all.
The Resources Hook feature is not supported as Hook API.
这里介绍了
YukiHookAPI
的基本配置方法。
无论是 作为 Xposed 模块使用 还是 作为 Hook API 使用,你都可以在 API 装载之前或装载过程中对
YukiHookAPI
进行配置。
fun configs(initiate: Configs.() -> Unit)
+
configs
方法对 Configs
类实现了一个 lambda 方法体,你可以轻松地调用它进行配置。
小提示
更多功能请参考 YukiHookAPI.configs 方法。
一个 Xposed 模块或 Hook API 最重要的地方就是 Hooker 的创建与使用,
YukiHookAPI
提供了两种使用方法。
这种方案是最简单的,如果你的模块功能不多,代码数量不大,不需要进行分类处理,推荐使用这种方式进行创建。
fun encase(initiate: PackageParam.() -> Unit)
+
encase
方法是 Hook 一切生命的开始,在一个模块或一个 Hook 过程中,encase
方法只能作用一次,用于创建 Hooker。
PackageParam
为宿主 (目标 APP) 的重要实例对象,通过 PackageParam
来实现对当前 Hook 作用对象的全部 Hook 操作。
小提示
更多功能请参考 PackageParam。
encase
方法可以在 onHook
方法中使用两种方案创建。
示例代码 1
YukiHookAPI.encase {
+ loadApp(name = "com.example.demo") {
+ "$packageName.DemoClass".toClass()
+ .resolve()
+ .firstMethod {
+ // Your code here.
+ }.hook {
+ // Your code here.
+ }
+ }
+}
+
示例代码 2
encase {
+ loadApp(name = "com.example.demo") {
+ "$packageName.DemoClass".toClass()
+ .resolve()
+ .firstMethod {
+ // Your code here.
+ }.hook {
+ // Your code here.
+ }
+ }
+}
+
在 encase
方法中进行你的 Hook 操作。
这种方案更加适用于大型项目,例如需要对 Hooker 进行分类或对 Hook 的作用对象进行分类。
fun encase(vararg hooker: YukiBaseHooker)
+
同样为 encase
方法,这里的方法可变数组参数 hooker
为创建入口提供了一个对象,你可以将所有继承于 YukiBaseHooker
的 Hooker 一次性进行装载。
YukiBaseHooker
继承于 PackageParam
,你需要将你的子 Hooker 继承于 YukiBaseHooker
。
小提示
更多功能请参考 YukiBaseHooker。
示例如下
object CustomHooker : YukiBaseHooker() {
+
+ override fun onHook() {
+ // Your code here.
+ }
+}
+
子 Hooker 建议使用单例 object
创建,你也可以使用 class
但一般情况下不推荐。
注意
你无需再在继承于 YukiBaseHooker 的 onHook 方法中重新调用 encase,这是错误的,且不会生效,你应该直接开始编写你的 Hook 代码。
示例如下
object CustomHooker : YukiBaseHooker() {
+
+ override fun onHook() {
+ loadApp(name = "com.example.demo1") {
+ "$packageName.DemoClass".toClass()
+ .resolve()
+ .firstMethod {
+ // Your code here.
+ }.hook {
+ // Your code here.
+ }
+ }
+ loadApp(name = "com.example.demo2") {
+ "$packageName.CustomClass".toClass()
+ .resolve()
+ .firstMethod {
+ // Your code here.
+ }.hook {
+ // Your code here.
+ }
+ }
+ }
+}
+
作为子 Hooker 使用,你还可以在外部调用 loadApp
方法,然后在内部直接开始 Hook。
示例如下
object HookEntry : IYukiHookXposedInit {
+
+ override fun onHook() = encase {
+ loadApp(name = "com.example.demo", ChildCustomHooker)
+ }
+}
+
+object ChildCustomHooker : YukiBaseHooker() {
+
+ override fun onHook() {
+ "$packageName.DemoClass".toClass()
+ .resolve()
+ .firstMethod {
+ // Your code here.
+ }.hook {
+ // Your code here.
+ }
+ }
+}
+
你可以使用 loadHooker
方法在子 Hooker 中多层装载另一个 Hooker,请按照你的喜好进行即可。
示例如下
object FirstHooker : YukiBaseHooker() {
+
+ override fun onHook() {
+ "$packageName.DemoClass".toClass()
+ .resolve()
+ .firstMethod {
+ // Your code here.
+ }.hook {
+ // Your code here.
+ }
+ loadHooker(SecondHooker)
+ loadHooker(ThirdHooker)
+ }
+}
+
搭建完全部 Hooker 后,你就可以在你的 Hook 入口类中的 onHook
方法中装载你的 Hooker 了。
示例如下
object HookEntry : IYukiHookXposedInit {
+
+ override fun onHook() =
+ YukiHookAPI.encase(FirstHooker, SecondHooker, ThirdHooker ...)
+}
+
当然,我们同样可以对其进行简写。
示例如下
object HookEntry : IYukiHookXposedInit {
+
+ override fun onHook() = encase(FirstHooker, SecondHooker, ThirdHooker ...)
+}
+
上面我们说到,在一般情况下不推荐使用 class
创建子 Hooker,但是有一种特殊情况,它可能依然需要保持你的 Hooker 支持多例。
有极少的可能性会出现在一个进程中存在多个包名的情况,这种情况下,YukiHookAPI
发现子 Hooker 为单例时,将会忽略并打印一条警告信息。
This Hooker "HOOKER" is singleton or reused, but the current process has multiple package name "NAME", the original is "NAME"
+Make sure your Hooker supports multiple instances for this situation
+The process with package name "NAME" will be ignored
+
遇到这种情况时,我们只需要修改 object
为 class
或者在装载时判断包名后再装载子 Hooker。
例如以上情况中可使用以下形式来装载。
示例如下
encase {
+ // 假设这个就是你需要装载的 APP 包名和子 Hooker
+ loadApp("com.example.demo", YourCustomHooker)
+}
+
如果你当前使用的 Hook Framework 支持并启用了资源钩子(Resources Hook)功能,你现在可以直接在 encase
中创建 Resources Hook。
你完全不需要与之前在使用 Xposed API 那样区分 initZygote
、handleLoadPackage
、handleInitPackageResources
方法来执行不同的功能。
在 YukiHookAPI
中,这些功能是无缝的。
示例如下
encase {
+ loadApp(name = "com.example.demo") {
+ "$packageName.DemoClass".toClass()
+ .resolve()
+ .firstMethod {
+ // Your code here.
+ }.hook {
+ // Your code here.
+ }
+ // 创建一个 Resources Hook (固定用法)
+ resources().hook {
+ // Your code here.
+ }
+ }
+}
+
你还可以同时使用 loadZygote
方法来装载新的进程被 fork 后的第一个事件 initZygote
。
示例如下
encase {
+ loadZygote {
+ Activity::class.resolve().firstMethod {
+ // Your code here.
+ }
+ // 在 Zygote 中创建 Resources Hook
+ resources().hook {
+ // Your code here.
+ }
+ }
+ loadApp(name = "com.example.demo") {
+ "$packageName.DemoClass".toClass()
+ .resolve()
+ .firstMethod {
+ // Your code here.
+ }.hook {
+ // Your code here.
+ }
+ // 在 APP 中创建 Resources Hook
+ resources().hook {
+ // Your code here.
+ }
+ }
+}
+
直接装载 Hooker 或直接开始 Hook 是错误的,encase
事件在被 Hook Framework 装载后,会经历三次回调。
装载 initZygote
→ encase
装载 handleLoadPackage
→ encase
装载 handleInitPackageResources
→ encase
在这个过程中,你需要使用 loadApp
、loadSystem
、loadZygote
来区分每一次装载代码的调用域,否则你的代码就会被多次执行造成错误。
注意
无论使用 encase 创建 lambda 方法体还是直接使用 Hooker 形式,你都不应该直接在首个 onHook 事件中直接装载 Hooker 或直接开始 Hook。
下面是两个错误示例。
示例代码 1
encase {
+ // 错误的使用方法,不能直接开始 Hook
+ "com.example.demo.DemoClass".toClass()
+ .resolve()
+ .firstMethod {
+ // Your code here.
+ }.hook {
+ // Your code here.
+ }
+ // 错误的使用方法,不能直接开始 Hook
+ resources().hook {
+ // ...
+ }
+}
+
示例代码 2
object HookEntry : IYukiHookXposedInit {
+
+ override fun onHook() {
+ // <情景1>
+ encase {
+ loadHooker(CustomHooker)
+ }
+ // <情景2>
+ encase(CustomHooker)
+ }
+}
+
+object CustomHooker : YukiBaseHooker() {
+
+ override fun onHook() {
+ // 错误的使用方法,由于外层没有任何判断对象,不能直接开始 Hook
+ "com.example.demo.DemoClass".toClass()
+ .resolve()
+ .firstMethod {
+ // Your code here.
+ }.hook {
+ // Your code here.
+ }
+ }
+}
+
下面是上述错误示例的正确示例。
示例代码 1
encase {
+ // ✅ 正确的使用方法,在 Zygote 中装载
+ loadZygote(CustomHooker)
+ // ✅ 正确的使用方法,在 Zygote 中装载
+ loadZygote {
+ // ✅ 正确的使用方法,在 Zygote 内 Hook
+ resources().hook {
+ // ...
+ }
+ }
+ // ✅ 正确的使用方法,使用 APP 作用域装载
+ loadApp(/** name 参数可选 */, hooker = CustomHooker)
+ // ✅ 正确的使用方法,判断 APP 作用域后再装载 Hooker
+ loadApp(/** name 参数可选 */) {
+ loadHooker(CustomHooker)
+ // ✅ 正确的使用方法,在 APP 作用域内 Hook
+ "com.example.demo.DemoClass".toClass()
+ .resolve()
+ .firstMethod {
+ // Your code here.
+ }.hook {
+ // Your code here.
+ }
+ // ✅ 正确的使用方法,在 APP 作用域内 Hook
+ resources().hook {
+ // ...
+ }
+ }
+}
+
示例代码 2
object HookEntry : IYukiHookXposedInit {
+
+ override fun onHook() {
+ encase(CustomHooker)
+ }
+}
+
+object CustomHooker : YukiBaseHooker() {
+
+ override fun onHook() {
+ // ✅ 正确的使用方法,由于外层没有任何判断对象,需要判断 APP 作用域后再进行 Hook
+ loadApp(/** name 参数可选 */) {
+ "com.example.demo.DemoClass".toClass()
+ .resolve()
+ .firstMethod {
+ // Your code here.
+ }.hook {
+ // Your code here.
+ }
+ }
+ }
+}
+
若你作为 Hook API 使用,那么你只需要在入口处对 encase
方法进行区分。
注意
encase 方法对作为 Hook API 使用提供了两个完全一样的方法,但是比前两者仅多出一个参数 baseContext。
方法 1
fun encase(baseContext: Context?, initiate: PackageParam.() -> Unit)
+
方法 2
fun encase(baseContext: Context?, vararg hooker: YukiBaseHooker)
+
此处的 baseContext
只需填入你在 attachBaseContext
处得到的 Context
即可,其它用法与上述内容完全一致。
特别注意
切勿以 Xposed 方式使用 encase 方法而漏掉 baseContext 参数,否则你的 Hook 将完全不工作。
Resources Hook 功能不支持作为 Hook API 使用。
这些异常不会导致 APP 停止运行 (FC),但是会在控制台打印
E
级别的日志,也可能会停止继续执行相关功能。
loggerE
Could not found any available Hook APIs in current environment! Aborted
异常原因
你的 Hook Framework 未在工作或并未成功装载当前 Hook API。
解决方案
请确认你在正确的地方装载了 YukiHookAPI
的 encase
方法,详情请参考 作为 Xposed 模块使用的相关配置 以及 作为 Hook API 使用的相关配置。
loggerE
You cannot load a hooker in "onInit" or "onXposedEvent" method! Aborted
异常原因
你尝试在继承 IYukiHookXposedInit
的 Hook 入口类的 onInit
或 onXposedEvent
方法中装载了 encase
方法。
示例如下
object HookEntry : IYukiHookXposedInit {
+
+ override fun onInit() {
+ // 错误的使用方法
+ YukiHookAPI.encase {
+ // Your code here.
+ }
+ }
+
+ override fun onXposedEvent() {
+ // 错误的使用方法
+ YukiHookAPI.encase {
+ // Your code here.
+ }
+ }
+
+ override fun onHook() {
+ // Your code here.
+ }
+}
+
解决方案
请在 onHook
方法中装载 encase
方法。
示例如下
object HookEntry : IYukiHookXposedInit {
+
+ override fun onInit() {
+ // 这里只能装载 configs 方法
+ YukiHookAPI.configs {
+ // Your code here.
+ }
+ }
+
+ override fun onHook() {
+ // ✅ 正确的使用方法
+ YukiHookAPI.encase {
+ // Your code here.
+ }
+ }
+}
+
loggerE
An exception occurred in the Hooking Process of YukiHookAPI
异常原因
YukiHookAPI
在装载 Xposed 入口方法时发生异常。
解决方案
这是一个异常汇总,如果你当前的 Hook 进程中发生了任何异常 (Hook 进程崩溃),都会使用此方式打印到控制台,请追溯异常发生的堆栈以定位你的代码问题位置。
loggerE
An exception occurred when hooking internal function
异常原因
YukiHookAPI
在进行自身初始化 Hook 过程中发生异常。
解决方案
通常情况下这种错误不会轻易发生,若一旦发生此错误,可直接提交日志进行反馈。
loggerE
YukiHookAPI try to load hook entry class failed
异常原因
YukiHookAPI
在尝试装载 Hook 入口类 onInit
或 onHook
方法时发生了不能处理的异常或找不到入口类。
解决方案
通常情况下这种错误不会轻易发生,若一旦发生此错误,请自行查看控制台打印的日志定位问题,确定并非自己的代码发生的问题后,可提交日志进行反馈。
loggerE
An exception occurred when YukiHookAPI loading Xposed Module
异常原因
YukiHookAPI
在尝试使用 Xposed 原生接口装载 Xposed 模块时发生了不能处理的异常。
解决方案
通常情况下这种错误不会轻易发生,若一旦发生此错误,请自行查看控制台打印的日志定位问题,确定并非自己的代码发生的问题后,可提交日志进行反馈。
loggerE
Failed to execute method "NAME", maybe your Hook Framework not support Resources Hook
异常原因
YukiHookAPI
在尝试进行 Resources Hook 时发生错误。
解决方案
请仔细检查错误日志的详细信息。
若发生 Resources$NotFoundException
则可能为你查找的 Resources Id 不正确。
若发生 ClassNotFound
或 NoClassDefFoundError
可能是 Hook Framework 不支持 Resources Hook(资源钩子)。
loggerE
HookClass [NAME] not found
异常原因
当前被 Hook 的 Class
没有被找到。
解决方案
请检查目标 Class
是否存在,若想忽略此错误请使用 ignoredHookClassNotFoundFailure
方法。
loggerE
Hook Member [NAME] failed
异常原因
Hook 目标方法、构造方法时发生错误。
解决方案
此问题通常由 Hook Framework 产生,请检查对应的日志内容,若问题持续出现请携带详细日志进行反馈。
loggerE
Hooked Member with a finding error / by CLASS
异常原因
在 Hook 执行后被 Hook 的 member
为 null
且已经设置目标 Hook 方法、构造类。
解决方案
请检查此错误发生前的上一个错误日志,或许在查找方法、构造方法的时候发生了找不到方法、构造方法的错误。
loggerE
Hooked Member cannot be null / by CLASS
异常原因
在 Hook 执行后被 Hook 的 member
为 null
且没有设置目标 Hook 方法、构造类。
示例如下
injectMember {
+ // 这里并没有设置需要 Hook 的方法、构造方法的查找条件
+ after {
+ // ...
+ }
+}
+
解决方案
请确认你已经在 Hook 之前正确设置了要 Hook 的方法、构造方法的查找方式。
示例如下
injectMember {
+ // ✅ 正确的使用方法举例
+ method {
+ // Your code here.
+ }
+ after {
+ // ...
+ }
+}
+
loggerE
Hooked method return type match failed, required [TYPE] but got [TYPE]
异常原因
在 Hook 回调方法体中设置了 HookParam.result
或使用了 replaceHook
但是被 Hook 的方法返回值类型与原返回值类型不匹配。
示例如下
假设这个是被 Hook 的方法。
private boolean test()
+
下面是一个错误的案列。
method {
+ name = "test"
+ emptyParam()
+}.hook {
+ // <情景1> 设置了错误的类型,原类型为 Boolean
+ before {
+ result = 0
+ }
+ // <情景2> 返回了错误的类型,原类型为 Boolean
+ replaceAny {
+ 0
+ }
+ // <情景3> 直接使用了错误的类型,原类型为 Boolean
+ replaceTo(any = 0)
+}
+
注意
若上述场景在 before 或 after 中发生,则会造成被 Hook 的 APP (宿主) 由 XposedBridge 抛出异常 (会对其暴露被 Hook 的事实)。
解决方案
请确认当前被 Hook 方法的正确返回值类型,修改后再试一次。
loggerE
Hook initialization failed because got an exception
异常原因
在准备 Hook 时发生了任意的异常。
解决方案
这是一个准备 Hook 阶段就发生异常的提醒,请仔细查看具体的异常是什么以重新确定问题。
loggerE
Try to hook NAME[NAME] got an exception
异常原因
在 Hook 开始时发生了任意的异常。
解决方案
这是一个 Hook 开始就发生异常的提醒,请仔细查看具体的异常是什么以重新确定问题。
loggerE
Method/Constructor/Field match type "TYPE" not allowed
异常原因
在查找方法、构造方法以及变量时设置了不允许的参数类型。
示例如下
// 查找一个方法
+method {
+ // 设置了无效的类型举例
+ param(false, 1, 0)
+ // 设置了无效的类型举例
+ returnType = false
+}
+
+// 查找一个变量
+field {
+ // 设置了无效的类型举例
+ type = false
+}
+
解决方案
在查找中 param
、returnType
、type
中仅接受 Class
、String
、VariousClass
类型的传值,不可传入参数实例。
示例如下
// 查找一个方法
+method {
+ // ✅ 正确的使用方法举例
+ param(BooleanType, IntType, IntType)
+ // ✅ 正确的使用方法举例
+ returnType = BooleanType
+ // ✅ 以下方案也是正确的
+ returnType = "java.lang.Boolean"
+}
+
+// 查找一个变量
+field {
+ // ✅ 正确的使用方法举例
+ type = BooleanType
+}
+
loggerE
NoSuchMethod/NoSuchConstructor/NoSuchField happend in [NAME]
异常原因
在查找方法、构造方法以及变量时并未找到目标方法、构造方法以及变量。
解决方案
请确认你的查找条件是否能正确匹配到目标 Class
中的指定方法、构造方法以及变量。
loggerE
Trying COUNT times and all failure by RemedyPlan
异常原因
使用 RemedyPlan
重新查找方法、构造方法、变量时依然没有找到方法、构造方法、变量。
解决方案
请确认你设置的 RemedyPlan
参数以及宿主内存在的 Class
,再试一次。
loggerE
Can't find this Class in [CLASSLOADER]: CONTENT Generated by YukiHookAPI#ReflectionTool
异常原因
通过 ClassLoader.searchClass
或 PackageParam.searchClass
找不到需要查找的 Class
对象。
示例如下
customClassLoader?.searchClass {
+ from(...)
+ // ...
+}.get()
+
解决方案
这是一个安全异常,请检查你设置的条件,使用相关工具查看所在 Dex 中的 Class
以及字节码对象特征,并再试一次。
loggerE
Can't find this Method/Constructor/Field in [CLASS]: CONTENT Generated by YukiHookAPI#ReflectionTool
异常原因
通过指定条件找不到需要查找的方法、构造方法以及变量。
示例如下
TargetClass.method {
+ name = "test"
+ param(BooleanType)
+}
+
解决方案
这是一个安全异常,请检查你设置的条件,使用相关工具查看所在 Class
中的字节码对象特征,并再试一次。
loggerE
The number of VagueType must be at least less than the count of paramTypes
异常原因
在 Method
、Constructor
查找条件中错误地使用了 VagueType
。
示例如下
TargetClass.method {
+ name = "test"
+ // <情景1>
+ param(VagueType)
+ // <情景2>
+ param(VagueType, VagueType ...)
+}
+
解决方案
VagueType
不能在方法、构造方法参数中完全填充,若存在这样的需求请使用 paramCount
。
loggerE
Field match type class is not found
异常原因
在查找变量时所设置的查找条件中 type
的 Class
实例未被找到。
示例如下
field {
+ name = "test"
+ // 假设这里设置的 type 的 Class 并不存在
+ type = "com.example.TestClass"
+}
+
解决方案
请检查查找条件中 type
的 Class
是否存在,然后再试一次。
loggerE
Method match returnType class is not found
异常原因
在查找方法时所设置的查找条件中 returnType
的 Class
实例未被找到。
示例如下
method {
+ name = "test"
+ // 假设这里设置的 returnType 的 Class 并不存在
+ returnType = "com.example.TestClass"
+}
+
解决方案
请检查查找条件中 returnType
的 Class
是否存在,然后再试一次。
loggerE
Method/Constructor match paramType[INDEX] class is not found
异常原因
在查找方法、构造方法时所设置的查找条件中 param
的 index
号下标的 Class
实例未被找到。
method {
+ name = "test"
+ // 假设这里设置的 1 号下标的 Class 并不存在
+ param(StringClass, "com.example.TestClass", BooleanType)
+}
+
解决方案
请检查查找条件中 param
的 index
号下标的 Class
是否存在,然后再试一次。
loggerE
Invoke original Member [MEMBER] failed
异常原因
在使用 HookParam.callOriginal
、HookParam.invokeOriginal
、method { ... }.get(...).original()
调用未经 Hook 的原始方法时发生错误。
解决方案
一般情况下,此错误基本上不会发生,若发生此错误,可能为当前使用的 Hook Framework 问题,排除自身代码的问题后,请携带详细日志进行反馈。
loggerE
Failed to got Host Resources
异常原因
在查找 Resources 时使用 replaceTo { ... }
或 replaceToModuleResource { ... }
时未能获取到宿主的原始 Resources 实例对象。
示例如下
conditions {
+ name = "test"
+ string()
+}
+replaceTo { "\${it}_some_text" }
+
解决方案
一般情况下,此错误基本上不会发生,若发生此错误,可能为当前使用的 Hook Framework 问题,排除自身代码的问题后,请携带详细日志进行反馈。
loggerE
Resources Hook condition name/type cannot be empty [TAG]
异常原因
在查找 Resources 时并未设置任何条件。
示例如下
// 情况 1
+conditions {
+ // 这里没有设置任何条件
+}
+// 情况 2
+conditions {
+ name = "test"
+ // 这里缺少了 type 条件
+}
+
解决方案
Resources 的 Hook 并非类似方法的 Hook,其必须拥有完整的名称和类型描述才能查找成功,请将查找条件补充完整并再试一次。
loggerE
Resources Hook type is invalid [TAG]
异常原因
在 Hook Resources 时发生了类型错误的异常。
解决方案
YukiHookAPI
会尝试在 initZygote
与 handleInitPackageResources
中装载 Resources Hook,若全部装载失败可能会发生此异常,当前 Hook Framework 需要支持并启用资源钩子 (Resources Hook) 功能,请检查后再试一次。
loggerE
Resources Hook got an exception [TAG]
异常原因
在 Hook Resources 时发生了任意的异常。
解决方案
这是一个异常汇总,请自行向下查看日志具体的异常是什么,例如找不到 Resources Id 的问题。
loggerE
Received action "ACTION" failed
异常原因
使用 YukiHookDataChannel
时回调广播事件异常。
解决方案
此异常多为一些关联性异常引发,请检查自身代码是否存在问题,排除自身代码的问题后,请携带详细日志进行反馈。
loggerE
Received data type TYPE is not a vailed YukiHookDataChannel's data
异常原因
使用 YukiHookDataChannel
时回调广播收到了不属于 YukiHookDataChannel
的数据。
解决方案
为了确保数据安全性,YukiHookDataChannel
会对发送的数据进行包装,任何第三方广播事件均不能被 YukiHookDataChannel
接收,请检查你的代码是否正确。
loggerE
Unsupported segments data key of "KEY"'s type
异常原因
使用 YukiHookDataChannel
时回调广播收到了不支持的分段数据类型。
解决方案
一般情况下,此错误不可能发生,因为 YukiHookDataChannel
所支持的分段数据类型是固定的,不会动态改变,若发生这种情况,请检查是否改动了 API 相关代码。
loggerE
YukiHookDataChannel cannot merge this segments data key of "KEY"
异常原因
使用 YukiHookDataChannel
时回调广播收到了无法处理的分段数据导致无法合并分段数据。
解决方案
一般情况下,此错误基本上不会发生,除非收到连续发送或重复发送的广播 (时序异常) 或在接收数据时设置了错误的泛型类型,排除自身代码的问题后,请携带详细日志进行反馈。
loggerE
YukiHookDataChannel cannot calculate the byte size of the data key of "KEY" to be sent, so this data cannot be sent
If you want to lift this restriction, use the allowSendTooLargeData function when calling, but this may cause the app crash
异常原因
使用 YukiHookDataChannel
发送广播数据时计算数据大小失败。
解决方案
一般情况下,此错误基本上不会发生,排除自身代码的问题后,请携带详细日志进行反馈。
loggerE
YukiHookDataChannel cannot send this data key of "KEY" type TYPE, because it is too large (total TOTAL KB, limit LIMIT KB) and cannot be segmented
SUGGESTION_MESSAGE
If you want to lift this restriction, use the allowSendTooLargeData function when calling, but this may cause the app crash
异常原因
使用 YukiHookDataChannel
发送广播数据时数据过大,但是此数据类型并不支持被分段发送。
解决方案
当你发送的数据超出系统广播的上限时,YukiHookDataChannel
默认情况下会将此数据分段后依次发送,但仅支持处理 List、Map、Set、String 常见类型的自动分段功能。
小提示
若你仍要使用此功能,请参考 YukiHookDataChannel.NameSpace.allowSendTooLargeData 方法。
但是强烈建议不要这样做,这有可能会导致系统不允许过大的数据发送而造成应用崩溃。
loggerE
Failed to sendBroadcast like "KEY", because got null context in "PACKAGENAME"
异常原因
使用 YukiHookDataChannel
时发送广播取到了空的上下文实例。
解决方案
一般情况下,此错误基本上不会发生,在最新版本中已经修复宿主使用时可能发生的问题,若最新版本依然发生错误,排除自身代码的问题后,请携带详细日志进行反馈。
loggerE
Failed to inject module resources into [RESOURCES]
异常原因
在 (Xposed) 宿主环境中使用 injectModuleAppResources
注入模块资源时发生异常。
解决方案
一般情况下,此错误基本上不会发生,排除自身代码的问题后,请携带详细日志进行反馈。
loggerE
You cannot inject module resources into yourself
异常原因
在 (Xposed) 宿主环境 (模块自身的 Xposed 环境) 中使用 injectModuleAppResources
将模块自身的资源注入自身。
解决方案
由于模块自身也可以被自身 Hook,但你并不可以在模块自身注入自己 (不能递归自身的资源),若你一定要获取模块自身的资源,请直接使用即可,无需任何其它操作。
loggerE
Activity Proxy initialization failed because got an exception
异常原因
在 (Xposed) 宿主环境中使用 registerModuleAppActivities
注入模块 Activity
时发生异常。
解决方案
请检查此错误发生后的下一个错误日志,或许在配置参数上可能发生了一些问题,若找不到相关错误日志的说明,排除自身代码的问题后,请携带详细日志进行反馈。
loggerE
Activity Proxy got an exception in msg.what [WHAT]
异常原因
在 (Xposed) 宿主环境中使用 registerModuleAppActivities
注入模块 Activity
时发生异常。
解决方案
一般情况下,此错误基本上不会发生,但根据系统版本差异性并未做详细测试,排除自身代码的问题后,请携带详细日志进行反馈。
loggerE
This proxy [TYPE] type is not allowed
异常原因
在 (Xposed) 宿主环境中使用 registerModuleAppActivities
注入模块 Activity
时填入了无效的参数。
示例如下
// 这里填入的内容仅为举例,其中 proxy 填入了不能理解的无效参数
+registerModuleAppActivities(proxy = false)
+
解决方案
方法中的 proxy
参数只接受 String
、CharSequence
、Class
类型,请查看相关使用方法正确填入方法参数。
loggerE
Cound not got launch intent for package "NAME"
异常原因
在 (Xposed) 宿主环境中使用 registerModuleAppActivities
注入模块 Activity
时找不到宿主的启动 Activity
。
示例如下
// 使用了默认参数直接进行注册
+registerModuleAppActivities()
+
解决方案
默认参数 (无参) 只能用于可被启动的 APP,若 APP 并未声明启动入口 Activity
,你就需要手动指定方法的 proxy
参数。
loggerE
Could not found "NAME" or Class is not a type of Activity
异常原因
在 (Xposed) 宿主环境中使用 registerModuleAppActivities
注入模块 Activity
时无法找到被填入参数 proxy
的 Activity
。
示例如下
registerModuleAppActivities(proxy = "com.demo.test.TestActivity")
+
解决方案
请确认你填入的 Activity
名称真实有效地存在于宿主中,且目标 Class
继承于 Activity
。
loggerE
You cannot register Activity Proxy into yourself
异常原因
在 (Xposed) 宿主环境 (模块自身的 Xposed 环境) 中使用 registerModuleAppActivities
将模块自身 Activity
注入自身。
解决方案
由于模块自身也可以被自身 Hook,但你并不可以在模块自身注入自己 (不能递归自身的资源),若你一定要获取模块自身的资源,请直接使用即可,无需任何其它操作。
loggerE
Activity Proxy only support for Android 7.0 (API 24) or higher
异常原因
在 (Xposed) 宿主环境 (模块自身的 Xposed 环境) 中使用 registerModuleAppActivities
但是当前系统版本不满足 Android 7.0 (API 24) 最低要求。
解决方案
Activity Proxy 仅支持高于或等于 Android 7.0 (API 24) 的系统,请尝试升级你的系统或对模块 APP 最低系统版本兼容性做出要求,例如设置 Min API 为 24。
loggerE
An exception occurred during AppLifecycle event
异常原因
在 (Xposed) 宿主环境中使用 onAppLifecycle
监听宿主生命周期期间发生异常。
解决方案
此异常为 onAppLifecycle
中抛出,由于你设置了参数 isOnFailureThrowToApp = false
,异常没有在宿主中被抛出而是在 (Xposed) 宿主环境中进行打印,这不属于 API 的异常,请仔细检查自身代码的问题。
这些异常会直接导致 APP 停止运行 (FC),同时会在控制台打印
E
级别的日志,还会造成 Hook 进程“死掉”。
IllegalStateException
YukiHookAPI cannot support current Hook API or cannot found any available Hook APIs in current environment
异常原因
YukiHookAPI
不支持当前环境使用的 Hook API 或不存在 Hook API 可被调用。
解决方案
请确认你在正确的地方装载了 YukiHookAPI
的 encase
方法,详情请参考 作为 Xposed 模块使用的相关配置 以及 作为 Hook API 使用的相关配置。
NoClassDefFoundError
Can't find this Class in [CLASSLOADER]: CONTENT Generated by YukiHookAPI#ReflectionTool
异常原因
通过 String.toClass(...)
或 classOf<...>()
找不到需要查找的 Class
对象。
示例如下
"com.demo.Test".toClass()
+
解决方案
请检查当前字符串或实体匹配到的 Class
是否存在于当前 ClassLoader
,并再试一次。
IllegalStateException
ClassLoader [CLASSLOADER] is not a DexClassLoader
异常原因
使用 ClassLoader.searchClass
或 PackageParam.searchClass
查找 Class
但是当前 ClassLoader
并不继承于 BaseDexClassLoader
。
解决方案
这种情况基本不存在,除非当前 APP 引用了非 ART 平台的可执行文件 (但是这种情况还是不会存在) 或当前 ClassLoader
为空。
IllegalStateException
Failed to got SystemContext
异常原因
在被 Hook 的宿主内调用了 systemContext
但并未成功获取到实例对象。
示例如下
encase {
+ // 调用了此变量
+ systemContext...
+}
+
解决方案
这种情况不应该存在,由于 systemContext
通过反射从 ActivityThread
中得到,除非系统进程发生异常,否则获取到的对象不会为空。
IllegalStateException
App is dead, You cannot call to appContext
异常原因
第一种情况
在被 Hook 的宿主内调用了 ModuleApplication
的 appContext
。
示例如下
encase {
+ // 调用了此变量
+ ModuleApplication.appContext...
+}
+
第二种情况
使用 ModuleApplication
时调用了 appContext
但是 APP 可能已经被销毁或没有正确启动。
示例如下
// 调用了此变量但是 APP 可能已被销毁或没有正确启动
+ModuleApplication.appContext...
+
解决方案
第一种情况
你只能在模块内使用 ModuleApplication
的 appContext
,在宿主内请使用 PackageParam
中的 appContext
,请确认你使用的是否正确。
第二种情况
这种情况基本不存在,由于 appContext
是在 onCreate
中被赋值的,除非遇到多进程并发启动或 APP 没有启动完成前被反射调用了父类的 onCreate
方法。
IllegalStateException
YukiHookPrefsBridge not allowed in Custom Hook API
异常原因
在 Hook 自身 APP(非 Xposed 模块) 中使用了 YukiHookPrefsBridge
。
示例如下
class MyApplication : Application() {
+
+ override fun attachBaseContext(base: Context?) {
+ YukiHookAPI.encase(base) {
+ // 不能在这种情况下使用 prefs
+ prefs.getBoolean("test_data")
+ }
+ super.attachBaseContext(base)
+ }
+}
+
解决方案
你只能在 作为 Xposed 模块使用 时使用 YukiHookPrefsBridge
,在 Hook 自身 APP 中请使用原生的 Sp
存储。
IllegalStateException
Cannot load the XSharedPreferences, maybe is your Hook Framework not support it
异常原因
在 (Xposed) 宿主环境使用了 YukiHookPrefsBridge
但是无法得到 XSharedPreferences
对象。
示例如下
encase {
+ // 调用了此变量
+ prefs...
+}
+
解决方案
一般情况下不会发生此问题,若持续无法获取 XSharedPreferences
对象则可能是你使用的 Hook Framework 不支持此功能或自身存在错误。
IllegalStateException
YukiHookDataChannel not allowed in Custom Hook API
异常原因
在 Hook 自身 APP(非 Xposed 模块) 中使用了 YukiHookDataChannel
。
示例如下
class MyApplication : Application() {
+
+ override fun attachBaseContext(base: Context?) {
+ YukiHookAPI.encase(base) {
+ // 不能在这种情况下使用 dataChannel
+ dataChannel.wait(key = "test_data") {
+ // ...
+ }
+ }
+ super.attachBaseContext(base)
+ }
+}
+
解决方案
你只能在 作为 Xposed 模块使用 时使用 YukiHookDataChannel
。
IllegalStateException
Xposed modulePackageName load failed, please reset and rebuild it
异常原因
在 Hook 过程中使用 YukiHookPrefsBridge
或 YukiHookDataChannel
时无法读取装载时的 modulePackageName
导致不能确定自身模块的包名。
解决方案
请仔细阅读 这里 的帮助文档,正确配置模块的 Hook 入口类包名。
IllegalStateException
YukiHookPrefsBridge missing Context instance
异常原因
在模块中使用了 YukiHookPrefsBridge
存储数据但并未传入 Context
实例。
示例如下
class MainActivity : AppCompatActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ // 错误的使用方法
+ // 构造方法已在 API 1.0.88 及以后的版本中设置为 private
+ YukiHookPrefsBridge().getBoolean("test_data")
+ }
+}
+
解决方案
在 Activity
中推荐使用 prefs(...)
方法来装载 YukiHookPrefsBridge
。
示例如下
class MainActivity : AppCompatActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ // ✅ 正确的使用方法
+ prefs().getBoolean("test_data")
+ }
+}
+
IllegalStateException
The Host App's Context has not yet initialized successfully, the native function cannot be used at this time
异常原因
在 (Xposed) 宿主环境 PackageParam
中使用了 YukiHookPrefsBridge
并调用了 native
方法但此时宿主的生命周期并未初始化。
示例如下
encase {
+ // 调用了此方法
+ prefs.native()
+}
+
解决方案
native
方法需要一个存在的 Context
对象用于存储数据,你可以在监听宿主生命周期状态中使用此方法。
IllegalStateException
Key-Value type TYPE is not allowed
异常原因
在使用 YukiHookPrefsBridge
的 get
或 put
方法或 YukiHookDataChannel
的 wait
或 put
方法时传入了不支持的存储类型。
解决方案
YukiHookPrefsBridge
支持的类型只有 String
、Set<String>
、Int
、Float
、Long
、Boolean
,请传入支持的类型。
YukiHookDataChannel
支持的类型为 Intent.putExtra
限制的类型,请传入支持的类型。
IllegalStateException
loadApp/loadZygote/loadSystem/withProcess method need a "NAME" param
异常原因
在 loadApp
、loadZygote
、loadSystem
、withProcess
中缺少了需要填写的可变数组变量参数。
示例如下
// <情景 1>
+loadApp()
+// <情景 2>
+loadZygote()
+// <情景 3>
+loadSystem()
+// <情景 4>
+withProcess()
+
解决方案
请查看 PackageParam
中的用法正确地使用此功能。
IllegalStateException
YukiHookDataChannel cannot used in zygote
异常原因
在 loadZygote
中使用了 YukiHookDataChannel
。
示例如下
loadZygote {
+ // 调用了此变量
+ dataChannel...
+}
+
解决方案
YukiHookDataChannel
只能在 loadSystem
、loadApp
中使用。
IllegalStateException
Custom Hooking Members is empty
异常原因
在 MemberHookCreator
中调用 members()
但是未设置需要 Hook 的 Member
实例。
示例如下
injectMember {
+ // 括号里的方法参数被留空了
+ members()
+ after {
+ // ...
+ }
+}
+
解决方案
若要使用 members()
设置自定义 Hook 方法,你必须保证其方法参数里的 Member
数组对象不能为空。
IllegalStateException
HookParam Method args index must be >= 0
异常原因
在 HookParam
中调用 args().last()
但是目标 param
为空或 args
中的 index
设置了小于 0 的数值。
示例如下
injectMember {
+ // ...
+ after {
+ // 假设 param 是空的
+ args().last()...
+ // 设置了小于 0 的 index
+ args(index = -5)...
+ }
+}
+
解决方案
请确认你 Hook 的目标方法、构造方法的方法参数数量是否不为空,且不能对 args
的下标设置小于 0 的数值。
IllegalStateException
HookParam instance got null! Is this a static member?
异常原因
在 HookParam
中调用 instance
变量或 instance
方法但获取不到当前实例的对象。
示例如下
injectMember {
+ // ...
+ after {
+ // 调用了此变量
+ instance...
+ // 调用了此方法
+ instance<Any>()...
+ }
+}
+
解决方案
请确认你 Hook 的方法是否为静态类型,静态类型的方法没有实例,不能使用此功能,若非静态方法,请检查实例是否已经销毁。
IllegalStateException
Current hooked Member args is null
异常原因
在 HookParam
中调用 args
变量但获取不到当前实例方法、构造方法的参数数组。
示例如下
injectMember {
+ // ...
+ after {
+ // 调用了此变量
+ args...
+ }
+}
+
解决方案
这种问题一般不会发生,真的发生了此问题,请携带详细日志进行反馈。
IllegalStateException
Current hooked Member is null
异常原因
在 HookParam
中调用 member
变量但获取不到当前实例的方法、构造方法实例。
示例如下
injectMember {
+ // ...
+ after {
+ // 调用了此变量
+ member...
+ }
+}
+
解决方案
这种问题一般不会发生,真的发生了此问题,请携带详细日志进行反馈。
IllegalStateException
Current hooked Member is not a Method
异常原因
在 HookParam
中调用 method
变量但获取不到当前实例的方法实例。
示例如下
injectMember {
+ // ...
+ after {
+ // 调用了此变量
+ method...
+ }
+}
+
解决方案
请确认你 Hook 的方法是构造方法还是普通方法并使用对应类型的方法获取指定的实例,若不知道字节码的类型可以直接使用 member
来获取。
IllegalStateException
Current hooked Member is not a Constructor
异常原因
在 HookParam
中调用 constructor
变量但获取不到当前实例的方法实例。
示例如下
injectMember {
+ // ...
+ after {
+ // 调用了此变量
+ constructor...
+ }
+}
+
解决方案
请确认你 Hook 的方法是普通方法还是构造方法并使用对应类型的方法获取指定的实例,若不知道字节码的类型可以直接使用 member
来获取。
IllegalStateException
HookParam instance cannot cast to TYPE
异常原因
在 HookParam
中调用 instance
方法指定了错误的类型。
示例如下
injectMember {
+ // ...
+ after {
+ // 类型被 cast 为 Activity 但假设当前实例的类型并非此类型
+ instance<Activity>()...
+ }
+}
+
解决方案
请确认当前 Hook 实例的正确类型并重新填写泛型中的类型,若不能确定请使用 Any
或直接使用 instance
变量。
IllegalStateException
HookParam Method args is empty, mabe not has args
异常原因
在 HookParam
中调用 ArgsModifyer.set
方法但是当前实例的方法参数数组为空。
示例如下
injectMember {
+ // ...
+ after {
+ // 调用了此方法
+ args(...).set(...)
+ }
+}
+
解决方案
请确认你 Hook 的目标方法、构造方法的方法参数数量是否不为空,否则你无法使用此功能。
IllegalStateException
HookParam Method args index out of bounds, max is NUMBER
异常原因
在 HookParam
中调用 ArgsModifyer.set
方法指定了超出方法参数下标的数组序号。
示例如下
injectMember {
+ // ...
+ after {
+ // 下标从 0 开始,假设原始的参数下标是 5 个,但是这里填写了 6
+ args(index = 6).set(...)
+ }
+}
+
解决方案
请确认你 Hook 的目标方法、构造方法的方法参数个数,并重新设置数组下标。
IllegalStateException
Current Hook Framework not support moduleAppResources
异常原因
在 PackageParam
中调用了 moduleAppResources
变量但是无法获取到实例对象。
示例如下
encase {
+ // 调用了此变量
+ moduleAppResources...
+}
+
解决方案
这种情况几乎不存在,除非目标 Hook Framework 自身存在问题,若真的发生了此问题,请携带详细日志进行反馈。
IllegalStateException
VariousClass match failed of those CLASSES
异常原因
在使用 VariousClass
创建不确定的 Class
对象时全部的 Class
都没有被找到。
解决方案
检查当前 Hook 的宿主内是否存在其中能够匹配的 Class
后,再试一次。
IllegalStateException
Cannot get hook class "NAME" cause THROWABLE
异常原因
在 hook
方法体非 onPrepareHook
方法内调用了 instanceClass
变量且当前 Hook 的 Class
不存在。
示例如下
TargetClass.hook {
+ // 可能的情况为在非 onPrepareHook 方法体内调用了 instanceClass 变量用于打印日志
+ loggerD(msg = "$instanceClass hook start")
+}
+
解决方案
在 hook
内直接使用 instanceClass
是很危险的,若 Class 不存在则会直接导致 Hook 进程“死掉”。
详情请参考 状态监听。
IllegalStateException
Use of searchClass { ... }.hook { ... } is an error, please use like searchClass { ... }.get()?.hook { ... }
异常原因
使用 searchClass { ... }.hook { ... }
方式直接创建了 Hook 实例。
解决方案
请使用 searchClass { ... }.get()?.hook { ... }
方式创建 Hook 实例。
IllegalStateException
This type [TYPE] not support to hook, supported are Constructors and Methods
异常原因
使用 Member.hook { ... }
时创建了不支持 Hook 的成员对象,例如 Field
。
解决方案
你只能 Hook Constructor
和 Method
。
IllegalStateException
LayoutInflatedParam View instance got null
异常原因
在布局 Hook 回调中调用了 currentView
但没取到实例对象。
示例如下
injectResource {
+ conditions {
+ name = "activity_main"
+ layout()
+ }
+ injectAsLayout {
+ // 调用了此变量
+ currentView...
+ }
+}
+
解决方案
这种情况基本上不存在,除非被 Hook 的宿主当前 Activity
已经销毁或 Hook Framework 自身存在问题。
IllegalStateException
XResForwarder is invalid
异常原因
在 YukiResForwarder
中调用了 resources
但没取到实例对象。
示例如下
// 调用了此变量
+moduleAppResources.fwd(...).resources
+
解决方案
这种情况基本上不存在,除非 Hook Framework 自身存在问题。
IllegalStateException
paramTypes is empty, please use emptyParam() instead
异常原因
在查找方法、构造方法时保留了空的 param
方法。
示例如下
method {
+ name = "test"
+ // 括号内没有填写任何参数
+ param()
+}
+
解决方案
若要标识此方法、构造方法没有参数,你可以有如下设置方法。
第一种,设置 emptyParam
(推荐)
示例如下
method {
+ name = "test"
+ emptyParam()
+}
+
第二种,设置 paramCount = 0
示例如下
method {
+ name = "test"
+ paramCount = 0
+}
+
IllegalStateException
Invalid YukiHookCallback type
异常原因
YukiHookAPI
的核心 Hook 功能发生故障。
解决方案
这种情况基本上不存在,若发生上述问题,确定并非自己的代码发生的问题后,可提交日志进行反馈。
IllegalStateException
ModuleContextThemeWrapper already loaded
异常原因
在 Context
中使用 applyModuleTheme
方法时重复进行调用。
示例如下
// 假设这就是当前的 Context 对象
+context.applyModuleTheme(R.style.Theme_AppCompat).applyModuleTheme(R.style.Theme_AppCompat)
+
解决方案
在 Context
中只能创建一次 ModuleContextThemeWrapper
,请检查代码是否有循环调用问题。
IllegalStateException
Cannot create classes cache for "android", please remove "name" param
异常原因
在系统框架 (android) 宿主使用了 DexClassFinder
的缓存功能 searchClass(name = ...)
。
示例如下
loadSystem {
+ searchClass(name = "test") {
+ from(...)
+ // ...
+ }.get()
+}
+
解决方案
由于缓存会将找到的 Class
名称存入 SharedPreferences
,但是系统框架不存在 data 目录,所以请不要在系统框架中使用此功能。
IllegalStateException
Target Class type cannot cast to TYPE
异常原因
使用 Class.toClass
、Class.toClassOrNull
、GenericClass.argument
方法将字符串类名转换为目标 Class
时声明了错误的类型。
以下使用 Class.toClass
方法来进行示例。
示例如下
// 假设目标类型是 Activity 但是被错误地转换为了 WrongClass 类型
+val clazz = "android.app.Activity".toClass<WrongClass>()
+
解决方案
示例如下
// <解决方案 1> 填写正确的类型
+val clazz1 = "android.app.Activity".toClass<Activity>()
+// <解决方案 2> 不填写泛型声明
+val clazz2 = "android.app.Activity".toClass()
+
请确保执行方法后声明的泛型是指定的目标 Class
类型,在不确定目标类型的情况下你可以不需要填写泛型声明。
These exceptions will not cause the app to stop running (FC), but will print
E
level logs on the console, and may also stop continuing to execute related functions.
loggerE
Could not found any available Hook APIs in current environment! Aborted
Abnormal
Your Hook Framework is not working or did not successfully load the current Hook API.
Solution
Please make sure you have loaded the encase
method of YukiHookAPI
in the correct place. For details, please refer to Use as Xposed Module Configs and Use as Hook API Configs.
loggerE
You cannot load a hooker in "onInit" or "onXposedEvent" method! Aborted
Abnormal
You try to load the encase
method in the onInit
or onXposedEvent
method of the Hook entry class that implements IYukiHookXposedInit
.
The following example
object HookEntry : IYukiHookXposedInit {
+
+ override fun onInit() {
+ // Wrong usage
+ YukiHookAPI.encase {
+ // Your code here.
+ }
+ }
+
+ override fun onXposedEvent() {
+ // Wrong usage
+ YukiHookAPI.encase {
+ // Your code here.
+ }
+ }
+
+ override fun onHook() {
+ // Your code here.
+ }
+}
+
Solution
Please load the encase
method in the onHook
method.
The following example
object HookEntry : IYukiHookXposedInit {
+
+ override fun onInit() {
+ // Only the configs method can be loaded here
+ YukiHookAPI.configs {
+ // Your code here.
+ }
+ }
+
+ override fun onHook() {
+ // ✅ Correct usage
+ YukiHookAPI.encase {
+ // Your code here.
+ }
+ }
+}
+
loggerE
An exception occurred in the Hooking Process of YukiHookAPI
Abnormal
YukiHookAPI
exception occurred while loading Xposed entry method.
Solution
This is an exception summary.
If any exception occurs in your current Hook Process (Hook Process crashes), it will be printed to the console using this method.
Please trace the stack where the exception occurred to locate your code problem.
loggerE
An exception occurred when hooking internal function
Abnormal
YukiHookAPI
throws an exception during its own initialization hook.
Solution
Usually, this kind of error does not happen easily. If this error occurs, you can directly submit the log for feedback.
loggerE
YukiHookAPI try to load hook entry class failed
Abnormal
YukiHookAPI
encountered an unhandled exception or the entry class could not be found when trying to load the hook entry class onInit
or onHook
method.
Solution
Usually, this kind of error does not occur easily.
If this error occurs, please check the log printed on the console to locate the problem.
After confirming that the problem is not caused by your own code, you can submit the log for feedback.
loggerE
An exception occurred when YukiHookAPI loading Xposed Module
Abnormal
YukiHookAPI
encountered an unhandled exception when trying to load a Xposed Module using the Xposed native interface.
Solution
Usually, this kind of error does not occur easily.
If this error occurs, please check the log printed on the console to locate the problem.
After confirming that the problem is not caused by your own code, you can submit the log for feedback.
loggerE
Failed to execute method "NAME", maybe your Hook Framework not support Resources Hook
Abnormal
YukiHookAPI
An error occurred while trying to do a Resources Hook.
Solution
Please double check the error log for details.
If a Resources$NotFoundException
occurs, you may be looking for an incorrect Resources Id.
If ClassNotFound
or NoClassDefFoundError
occurs, it may be that Hook Framework does not support Resources Hook.
loggerE
HookClass [NAME] not found
Abnormal
The Class
currently being hooked was not found.
Solution
Please check if the target Class
exists, to ignore this error use the ignoredHookClassNotFoundFailure
method.
loggerE
Hook Member [NAME] failed
Abnormal
An error occurred while hooking the target method, constructor.
Solution
This problem is usually caused by Hook Framework.
Please check the corresponding log content.
If the problem persists, please bring detailed logs for feedback.
loggerE
Hooked Member with a finding error / by CLASS
Abnormal
After the Hook is executed, the member
of the Hook is null
and the target Hook method and constructed class have been set.
Solution
Please check the previous error log before this error occurs, maybe there is an error that the method and constructor cannot be found when searching for methods and constructors.
loggerE
Hooked Member cannot be null / by CLASS
Abnormal
After the Hook is executed, the member
of the Hook is null
and the target Hook method and constructed class are not set.
The following example
injectMember {
+ // There are no search conditions for methods and constructors that require hooks
+ after {
+ // ...
+ }
+}
+
Solution
Please confirm that you have correctly set the method to be hooked and the way to find the constructor before hooking.
The following example
injectMember {
+ // ✅ Examples of correct usage
+ method {
+ // Your code here.
+ }
+ after {
+ // ...
+ }
+}
+
loggerE
Hooked method return type match failed, required [TYPE] but got [TYPE]
Abnormal
HookParam.result
is set in the Hook callback method body or replaceHook
is used but the return value type of the hooked method does not match the original return value type.
The following example
Suppose this is the method being Hooked.
private boolean test()
+
Below is an error case.
method {
+ name = "test"
+ emptyParam()
+}.hook {
+ // <Scenario 1> Set the wrong type, the original type is Boolean
+ before {
+ result = 0
+ }
+ // <Scenario 2> Return the wrong type, the original type is Boolean
+ replaceAny {
+ 0
+ }
+ // <Scenario 3> Use the wrong type directly, the original type is Boolean
+ replaceTo(any = 0)
+}
+
Notice
If the above scenario occurs in before or after, it will cause the Host App to throw an exception from XposedBridge (which will expose the fact of being Hooked).
Solution
Please confirm the correct return value type of the current Hook method, modify it and try again.
loggerE
Hook initialization failed because got an exception
Abnormal
An arbitrary exception occurred while preparing the Hook.
Solution
This is a reminder that an exception occurred during the Hook preparation stage, please carefully check what the specific exception is to re-determine the problem.
loggerE
Try to hook NAME[NAME] got an exception
Abnormal
An arbitrary exception occurred at the start of the Hook.
Solution
This is a reminder that an exception occurred at the beginning of the Hook, please check carefully what the specific exception is to re-determine the problem.
loggerE
Method/Constructor/Field match type "TYPE" not allowed
Abnormal
A disallowed parameter type was set when looking up methods, constructors, and variables.
The following example
// Find a method
+method {
+ // Invalid type example is set
+ param(false, 1, 0)
+ // Invalid type example is set
+ returnType = false
+}
+
+// Find a variable
+field {
+ // Invalid type example is set
+ type = false
+}
+
Solution
In the search, param
, returnType
, type
only accept Class
, String
, VariousClass
types, and parameter instances cannot be passed in.
The following example
// Find a method
+method {
+ // ✅ Examples of correct usage
+ param(BooleanType, IntType, IntType)
+ // ✅ Examples of correct usage
+ returnType = BooleanType
+ // ✅ The following scheme is also correct
+ returnType = "java.lang.Boolean"
+}
+
+// Find a variable
+field {
+ // ✅ Examples of correct usage
+ type = BooleanType
+}
+
loggerE
NoSuchMethod/NoSuchConstructor/NoSuchField happend in [NAME]
Abnormal
The target method, constructor, and variable were not found when looking for methods, constructors, and variables.
Solution
Please confirm that your search criteria can correctly match the specified methods, constructors and variables in the target Class
.
loggerE
Trying COUNT times and all failure by RemedyPlan
Abnormal
When using RemedyPlan
to search for methods, constructors, and variables, the methods, constructors, and variables are still not found.
Solution
Please confirm the RemedyPlan
parameter you set and the Class
that exists in the Host App, and try again.
loggerE
Can't find this Class in [CLASSLOADER]: CONTENT Generated by YukiHookAPI#ReflectionTool
Abnormal
The Class
object to be searched for was not found via ClassLoader.searchClass
or PackageParam.searchClass
.
The following example
customClassLoader?.searchClass {
+ from(...)
+ // ...
+}.get()
+
Solution
This is a security exception, please check the conditions you set, use the relevant tools to view the Class
and bytecode object characteristics in the Dex and try again.
loggerE
Can't find this Method/Constructor/Field in [CLASS]: CONTENT Generated by YukiHookAPI#ReflectionTool
Abnormal
The methods, constructors, and variables that need to be found cannot be found by specifying conditions.
The following example
TargetClass.method {
+ name = "test"
+ param(BooleanType)
+}
+
Solution
This is a security exception, please check the conditions you set, use the relevant tools to view the bytecode object characteristics in the Class
, and try again.
loggerE
The number of VagueType must be at least less than the count of paramTypes
Abnormal
Incorrect use of VagueType
in Method
, Constructor
lookup conditions.
The following example
TargetClass.method {
+ name = "test"
+ // <Scenario 1>
+ param(VagueType)
+ // <Scenario 2>
+ param(VagueType, VagueType ...)
+}
+
Solution
VagueType
cannot be completely filled in method and constructor parameters. If there is such a requirement, please use paramCount
.
loggerE
Field match type class is not found
Abnormal
An instance of Class
for type
was not found in the lookup criteria set when looking up the variable.
The following example
field {
+ name = "test"
+ // Assume that the Class of the type set here does not exist
+ type = "com.example.TestClass"
+}
+
Solution
Please check if Class
of type
in the lookup condition exists and try again.
loggerE
Method match returnType class is not found
Abnormal
An instance of Class
of returnType
was not found in the search criteria set when looking up the method.
The following example
method {
+ name = "test"
+ // Assume that the Class of returnType set here does not exist
+ returnType = "com.example.TestClass"
+}
+
Solution
Please check if Class
of returnType
in the lookup condition exists and try again.
loggerE
Method/Constructor match paramType[INDEX] class is not found
Abnormal
The Class
instance subscripted by the index
number of param
was not found in the search conditions set when searching for methods and constructors.
method {
+ name = "test"
+ // Assume that the Class with subscript "No.1" set here does not exist
+ param(StringClass, "com.example.TestClass", BooleanType)
+}
+
Solution
Please check if the Class
subscripted by the index
number of param
in the lookup condition exists and try again.
loggerE
Invoke original Member [MEMBER] failed
Abnormal
An error occurred when using HookParam.callOriginal
, HookParam.invokeOriginal
, method { ... }.get(...).original()
to call the original method without Hook.
Solution
Under normal circumstances, this error will basically not occur.
If this error occurs, it may be a problem with the currently used Hook Framework.
After troubleshooting your own code problems, please provide detailed logs for feedback.
loggerE
Failed to got Host Resources
Abnormal
Failed to obtain the Host App's original Resources instance object when using replaceTo { ... }
or replaceToModuleResource { ... }
when finding Resources.
The following example
conditions {
+ name = "test"
+ string()
+}
+replaceTo { "\${it}_some_text" }
+
Solution
Under normal circumstances, this error will basically not occur.
If this error occurs, it may be a problem with the currently used Hook Framework.
After troubleshooting your own code problems, please provide detailed logs for feedback.
loggerE
Resources Hook condition name/type cannot be empty [TAG]
Abnormal
No conditions were set when looking for Resources.
The following example
// Case 1
+conditions {
+ // No conditions are set here
+}
+// Case 2
+conditions {
+ name = "test"
+ // The type condition is missing here
+}
+
Solution
The Hook of Resources is not a Hook similar to a method.
It must have a complete name and type description in order to find it successfully.
Please complete the search conditions and try again.
loggerE
Resources Hook type is invalid [TAG]
Abnormal
An exception of the wrong type occurred while Hooking Resources.
Solution
YukiHookAPI
will try to load Resources Hook in initZygote
and handleInitPackageResources
.
If all loading fails, this exception may occur.
The current Hook Framework needs to support and enable the Resources Hook function, please check and try again.
loggerE
Resources Hook got an exception [TAG]
Abnormal
An arbitrary exception occurred while Hooking Resources.
Solution
This is a summary of exceptions, please check down the log for the specific exception, such as the problem that the Resources Id cannot be found.
loggerE
Received action "ACTION" failed
Abnormal
Callback broadcast event exception when using YukiHookDataChannel
.
Solution
This exception is mostly caused by some related exceptions.
Please check whether there is any problem in your own code.
After troubleshooting your own code, please bring detailed logs to give feedback.
loggerE
Received data type TYPE is not a vailed YukiHookDataChannel's data
Abnormal
When using YukiHookDataChannel
, the callback broadcast received data that does not belong to YukiHookDataChannel
.
Solution
In order to ensure data security, YukiHookDataChannel
will wrap the sent data, any third-party broadcast events cannot be received by YukiHookDataChannel
, please check whether your code is correct.
loggerE
Unsupported segments data key of "KEY"'s type
Abnormal
Callback broadcast received unsupported segments data type when using YukiHookDataChannel
.
Solution
Under normal circumstances, this error cannot occur, because the segments data type supported by YukiHookDataChannel
is fixed and will not change dynamically.
If this happens, please check whether the API-related code has been changed.
loggerE
YukiHookDataChannel cannot merge this segments data key of "KEY"
Abnormal
When using YukiHookDataChannel
, the callback broadcast received segments data that could not be processed, so the segments data could not be merged.
Solution
Under normal circumstances, this error will basically not occur, unless you receive broadcasts that are continuously sent or repeatedly sent (timing exceptions) or you set the wrong generic type when receiving data, after troubleshooting your own code problems, please bring detailed logs give feedback.
loggerE
YukiHookDataChannel cannot calculate the byte size of the data key of "KEY" to be sent, so this data cannot be sent
If you want to lift this restriction, use the allowSendTooLargeData function when calling, but this may cause the app crash
Abnormal
Failed to calculate data size when sending broadcast data using YukiHookDataChannel
.
Solution
Under normal circumstances, this error will basically not occur.
After troubleshooting your own code problems, please bring detailed logs for feedback.
loggerE
YukiHookDataChannel cannot send this data key of "KEY" type TYPE, because it is too large (total TOTAL KB, limit LIMIT KB) and cannot be segmented
SUGGESTION_MESSAGE
If you want to lift this restriction, use the allowSendTooLargeData function when calling, but this may cause the app crash
Abnormal
When using YukiHookDataChannel
to send broadcast data, the data is too large, but this data type does not support being sent in segments.
Solution
When the data you send exceeds the upper limit of the system broadcast, YukiHookDataChannel
will send the data in segments by default, but only supports processing List, Map, Set, String automatic segmentation function for common types.
Tips
If you still want to use this feature, please refer to YukiHookDataChannel.NameSpace.allowSendTooLargeData method.
But it is strongly recommended not to do this, this may cause the system to not allow too large data to be sent and cause the app crash.
loggerE
Failed to sendBroadcast like "KEY", because got null context in "PACKAGENAME"
Abnormal
Sending a broadcast when using YukiHookDataChannel
got an empty context instance.
Solution
Under normal circumstances, this error basically does not occur.
In the latest version, the problems that may occur when the host is used have been fixed.
If the latest version still has errors, after eliminating the problem of your own code, please bring detailed logs for feedback.
loggerE
Failed to inject module resources into [RESOURCES]
Abnormal
An exception occurred when injecting Module App's Resources using injectModuleAppResources
in a (Xposed) Host environment.
Solution
Under normal circumstances, this error basically does not occur. After eliminating the problem of your own code, please bring detailed logs for feedback.
loggerE
You cannot inject module resources into yourself
Abnormal
Use injectModuleAppResources
in the (Xposed) Host environment (the Module App's own Xposed Environment) to inject the Module App's own resources into itself.
Solution
Since the Module App itself can also be Hooked by itself, you cannot inject yourself into the Module App itself (you cannot recurse its own resources).
If you must obtain the resources of the Module App itself, please use it directly without any other operations.
loggerE
Activity Proxy initialization failed because got an exception
Abnormal
An exception occurred when injecting a Module App's Activity
using registerModuleAppActivities
in a (Xposed) Host environment.
Solution
Please check the next error log after this error occurs.
Maybe some problems may have occurred in the configuration parameters.
If you cannot find the description of the relevant error log, after eliminating the problem of your own code, please bring the detailed log for feedback.
loggerE
Activity Proxy got an exception in msg.what [WHAT]
Abnormal
An exception occurred when injecting a Module App's Activity
using registerModuleAppActivities
in a (Xposed) Host environment.
Solution
Under normal circumstances, this error basically does not occur, but according to the difference of the system version, no detailed testing has been done.
After eliminating the problem of your own code, please bring detailed logs for feedback.
loggerE
This proxy [TYPE] type is not allowed
Abnormal
Invalid parameters were filled in when injecting Module App's Activity
using registerModuleAppActivities
in a (Xposed) Host environment.
The following example
// The content filled in here is just an example
+// And the proxy is filled with invalid parameters that cannot be understood
+registerModuleAppActivities(proxy = false)
+
Solution
The proxy
parameter in the method only accepts String
, CharSequence
, Class
types, please refer to the related usage method to fill in the method parameters correctly.
loggerE
Cound not got launch intent for package "NAME"
Abnormal
When injecting Module App's Activity
using registerModuleAppActivities
in a (Xposed) Host environment, the Host App's launching Activity
cannot be found.
The following example
// Register directly with default parameters
+registerModuleAppActivities()
+
Solution
The default parameter (no parameter) can only be used for the app that can be launched.
If the app does not declare the startup entry Activity
, you need to manually specify the proxy
parameter of the method.
loggerE
Could not found "NAME" or Class is not a type of Activity
Abnormal
When injecting Module App's Activity
with registerModuleAppActivities
in a (Xposed) Host environment, the Activity
filled with the parameter proxy
cannot be found.
The following example
registerModuleAppActivities(proxy = "com.demo.test.TestActivity")
+
Solution
Please make sure that the Activity
name you fill in really and effectively exists in the Host App, and the target Class
extends Activity
.
loggerE
You cannot register Activity Proxy into yourself
Abnormal
Use registerModuleAppActivities
to inject the Module App's own Activity
into itself in the (Xposed) Host environment (the Module App's own Xposed Environment).
Solution
Since the Module App itself can also be Hooked by itself, you cannot inject yourself into the Module App itself (you cannot recurse its own resources).
If you must obtain the resources of the Module App itself, please use it directly without any other operations.
loggerE
Activity Proxy only support for Android 7.0 (API 24) or higher
Abnormal
Use registerModuleAppActivities
in the (Xposed) Host environment but the current system version does not meet the minimum requirements of Android 7.0 (API 24).
Solution
Activity Proxy only supports systems higher than or equal to Android 7.0 (API 24).
Please try to upgrade your system or make requirements for the minimum api version compatibility of the Module App, for example, set the minimum api to 24.
loggerE
An exception occurred during AppLifecycle event
Abnormal
Use onAppLifecycle
in the (Xposed) Host environment to listen for exceptions during the Host App's lifecycle.
Solution
This exception is thrown in onAppLifecycle
.
Since you set the parameter isOnFailureThrowToApp = false
, the exception is not thrown in the Host App but printed in the (Xposed) Host environment.
This is not an API exception, please be careful check your own code for problems.
These exceptions will directly cause the app to stop running (FC), at the same time print
E
level logs on the console, and also cause the Hook process to "die".
IllegalStateException
YukiHookAPI cannot support current Hook API or cannot find any available Hook APIs in current environment
Abnormal
YukiHookAPI
does not support the Hook API used by the current environment or there is no Hook API that can be called.
Solution
Please make sure you have loaded the encase
method of YukiHookAPI
in the correct place. For details, please refer to Use as Xposed Module Configs and Use as Hook API Configs.
NoClassDefFoundError
Can't find this Class in [CLASSLOADER]: CONTENT Generated by YukiHookAPI#ReflectionTool
Abnormal
The Class
object you were looking for was not found via String.toClass(...)
or classOf<...>()
.
The following example
"com.demo.Test".toClass()
+
Solution
Please check if the Class
matched by the current string or entity exists in the current ClassLoader
and try again.
IllegalStateException
ClassLoader [CLASSLOADER] is not a DexClassLoader
Abnormal
Use ClassLoader.searchClass
or PackageParam.searchClass
to find Class
but currently ClassLoader
does not extends BaseDexClassLoader
.
Solution
This situation basically does not exist, unless the current app references a Non-ART platform executable (which not realistic) or the current ClassLoader
is null.
IllegalStateException
Failed to got SystemContext
Abnormal
systemContext
was called in the Host App but the instance object was not successfully obtained.
The following example
encase {
+ // This variable is called
+ systemContext...
+}
+
Solution
This situation should not exist, since systemContext
is obtained from ActivityThread
through reflection, unless the system process fails, the obtained object will not be null.
IllegalStateException
App is dead, You cannot call to appContext
Abnormal
The first case
The appContext
of the ModuleApplication
is called within the Hook App.
The following example
encase {
+ // This variable is called
+ ModuleApplication.appContext...
+}
+
The second case
appContext
was called when using ModuleApplication
but the app may have been destroyed or not started correctly.
The following example
// This variable is called but the app may have been destroyed or not started correctly
+ModuleApplication.appContext...
+
Solution
The first case
You can only use the appContext
of ModuleApplication
in the Module App, please use the appContext
in the PackageParam
in the Host App, please make sure you use it correctly.
The second case
This situation basically does not exist, because appContext
is assigned in onCreate
, unless the onCreate
method of the parent class is called by reflection before multi-process concurrent startup or app is not started and completed.
IllegalStateException
YukiHookPrefsBridge not allowed in Custom Hook API
Abnormal
YukiHookPrefsBridge
is used in Hook's own app (not Xposed Module).
The following example
class MyApplication : Application() {
+
+ override fun attachBaseContext(base: Context?) {
+ YukiHookAPI.encase(base) {
+ // Can't use prefs in this case
+ prefs.getBoolean("test_data")
+ }
+ super.attachBaseContext(base)
+ }
+}
+
Solution
You can only use YukiHookPrefsBridge
when Use as Xposed Module Configs, please use the native Sp
storage in the Hook's own app.
IllegalStateException
Cannot load the XSharedPreferences, maybe is your Hook Framework not support it
Abnormal
Using YukiHookPrefsBridge
in (Xposed) Host environment but unable to get XSharedPreferences
object.
The following example
encase {
+ // This variable is called
+ prefs...
+}
+
Solution
Under normal circumstances, this problem does not occur.
If you continue to fail to obtain the XSharedPreferences
object, it may be that the Hook Framework you are using does not support this function or has an error.
IllegalStateException
YukiHookDataChannel not allowed in Custom Hook API
Abnormal
YukiHookDataChannel
is used in Hook's own app (not Xposed Module).
The following example
class MyApplication : Application() {
+
+ override fun attachBaseContext(base: Context?) {
+ YukiHookAPI.encase(base) {
+ // dataChannel cannot be used in this case
+ dataChannel.wait(key = "test_data") {
+ // ...
+ }
+ }
+ super.attachBaseContext(base)
+ }
+}
+
Solution
You can only use YukiHookDataChannel
when Use as Xposed Module Configs.
IllegalStateException
Xposed modulePackageName load failed, please reset and rebuild it
Abnormal
When using YukiHookPrefsBridge
or YukiHookDataChannel
in the Hook process, the modulePackageName
at load time cannot be read, resulting in the package name of the own Module App cannot be determined.
Solution
Please read the help document here carefully, and configure the Module App's Hook entry class package name correctly.
IllegalStateException
YukiHookPrefsBridge missing Context instance
Abnormal
YukiHookPrefsBridge
is used in the Module App to store data but no Context
instance is passed in.
The following example
class MainActivity : AppCompatActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ // Wrong usage
+ // Constructor has been set to private in API 1.0.88 and later
+ YukiHookPrefsBridge().getBoolean("test_data")
+ }
+}
+
Solution
It is recommended to use the prefs(...)
method to load YukiHookPrefsBridge
in Activity
.
The following example
class MainActivity : AppCompatActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ // ✅ Correct usage
+ prefs().getBoolean("test_data")
+ }
+}
+
IllegalStateException
The Host App's Context has not yet initialized successfully, the native function cannot be used at this time
Abnormal
In the (Xposed) Host environment PackageParam
, YukiHookPrefsBridge
is used and the native
method is called, but the lifecycle of the Host App is not initialized at this time.
The following example
encase {
+ // This method was called
+ prefs.native()
+}
+
Solution
The native
method requires an existing Context
object to store data in, and you can use this method in listening to the Host App lifecycle state.
IllegalStateException
Key-Value type TYPE is not allowed
Abnormal
An unsupported storage type was passed in when using the get
or put
methods of YukiHookPrefsBridge
or the wait
or put
methods of YukiHookDataChannel
.
Solution
The supported types of YukiHookPrefsBridge
are only String
, Set<String>
, Int
, Float
, Long
, Boolean
, please pass in the supported types.
The supported types of YukiHookDataChannel
are the types restricted by Intent.putExtra
, please pass in the supported types.
IllegalStateException
loadApp/loadZygote/loadSystem/withProcess method need a "NAME" param
Abnormal
The variable array variable parameter that needs to be filled is missing in loadApp
, loadZygote
, loadSystem
, withProcess
.
The following example
// <Scenario 1>
+loadApp()
+// <Scenario 2>
+loadZygote()
+// <Scenario 3>
+loadSystem()
+// <Scenario 4>
+withProcess()
+
Solution
Please see the usage in PackageParam
to use this function correctly.
IllegalStateException
YukiHookDataChannel cannot be used in zygote
Abnormal
YukiHookDataChannel
is used in loadZygote
.
The following example
loadZygote {
+ // This variable is called
+ dataChannel...
+}
+
Solution
YukiHookDataChannel
can only be used in loadSystem
, loadApp
.
IllegalStateException
Custom Hooking Members is empty
Abnormal
members()
is called in MemberHookCreator
but the Member
instance that requires the Hook is not set.
The following example
injectMember {
+ // Method parameters in parentheses are left blank
+ members()
+ after {
+ // ...
+ }
+}
+
Solution
To use members()
to set a custom Hook method, you must ensure that the Member
array object in its method parameter cannot be empty.
IllegalStateException
HookParam Method args index must be >= 0
Abnormal
args().last()
is called in HookParam
but the target param
is empty or the index
in args
is set to a value less than 0.
The following example
injectMember {
+ // ...
+ after {
+ // Assume param is empty
+ args().last()...
+ // Set an index less than 0
+ args(index = -5)...
+ }
+}
+
Solution
Please make sure that the number of method parameters of the target method and constructor of your Hook is not empty, and the subscript of args
cannot be set to a value less than 0.
IllegalStateException
HookParam instance got null! Is this a static member?
Abnormal
An object that calls an instance
variable or instance
method in a HookParam
but cannot get the current instance.
The following example
injectMember {
+ // ...
+ after {
+ // This variable is called
+ instance...
+ // This method is called
+ instance<Any>()...
+ }
+}
+
Solution
Please confirm whether the method of your Hook is a static type.
The static type method has no instance and cannot use this function.
If it is not a static method, please check whether the instance has been destroyed.
IllegalStateException
Current hooked Member args is null
Abnormal
The args
variable is called in HookParam
, but the parameter array of the current instance method and constructor cannot be obtained.
The following example
injectMember {
+ // ...
+ after {
+ // This variable is called
+ args...
+ }
+}
+
Solution
This kind of problem generally does not occur.
If this problem does occur, please bring detailed logs for feedback.
IllegalStateException
Current hooked Member is null
Abnormal
Call the member
variable in HookParam
but cannot get the method and constructor instance of the current instance.
The following example
injectMember {
+ // ...
+ after {
+ // This variable is called
+ member...
+ }
+}
+
Solution
This kind of problem generally does not occur.
If this problem does occur, please bring detailed logs for feedback.
IllegalStateException
Current hooked Member is not a Method
Abnormal
Calling the method
variable in HookParam
but not getting the method instance of the current instance.
The following example
injectMember {
+ // ...
+ after {
+ // This variable is called
+ method...
+ }
+}
+
Solution
Please confirm whether the method of your Hook is a constructor or a common method and use the method of the corresponding type to obtain the specified instance.
If you do not know the type of the bytecode, you can directly use member
to obtain it.
IllegalStateException
Current hooked Member is not a Constructor
Abnormal
A method instance for calling a constructor
variable in a HookParam
but not getting the current instance.
The following example
injectMember {
+ // ...
+ after {
+ // This variable is called
+ constructor...
+ }
+}
+
Solution
Please confirm whether the method of your Hook is a common method or a constructor method and use the method of the corresponding type to obtain the specified instance.
If you do not know the type of the bytecode, you can directly use member
to obtain it.
IllegalStateException
HookParam instance cannot cast to TYPE
Abnormal
Invoking the instance
method in a HookParam
specifies the wrong type.
The following example
injectMember {
+ // ...
+ after {
+ // The type is cast to Activity
+ // But assumes the current instance's type is not this type
+ instance<Activity>()...
+ }
+}
+
Solution
Please confirm the correct type of the current Hook instance and refill the type in the generic.
If you are not sure, please use Any
or directly use the instance
variable.
IllegalStateException
HookParam Method args is empty, mabe not has args
Abnormal
The ArgsModifyer.set
method is called in HookParam
but the method parameter array for the current instance is empty.
The following example
injectMember {
+ // ...
+ after {
+ // This method is called
+ args(...).set(...)
+ }
+}
+
Solution
Please make sure that the number of method parameters of the target method and constructor of your Hook is not empty, otherwise you cannot use this function.
IllegalStateException
HookParam Method args index out of bounds, max is NUMBER
Abnormal
Calling the ArgsModifyer.set
method in HookParam
specifies an array number beyond the subscript of the method parameter.
The following example
injectMember {
+ // ...
+ after {
+ // The subscript starts from 0
+ // Assuming the original parameter subscript is 5, but fill in 6 here
+ args(index = 6).set(...)
+ }
+}
+
Solution
Please confirm the target method of your Hook, the number of method parameters of the constructor, and reset the array subscript.
IllegalStateException
Current Hook Framework not support moduleAppResources
Abnormal
The moduleAppResources
variable was called in PackageParam
but the instance object could not be obtained.
The following example
encase {
+ // This variable is called
+ moduleAppResources...
+}
+
Solution
This situation hardly exists, unless there is a problem with the target Hook Framework itself.
If this problem does occur, please provide feedback with detailed logs.
IllegalStateException
VariousClass match failed of those CLASSES
Abnormal
All Class
were not found when creating indeterminate Class
objects using VariousClass
.
Solution
After checking whether there is a matching Class
in the Host App of the current Hook, try again.
IllegalStateException
Cannot get hook class "NAME" cause THROWABLE
Abnormal
The instanceClass
variable is called in the hook
method body other than the onPrepareHook
method and the Class
of the current Hook does not exist.
The following example
TargetClass.hook {
+ // The possible case is that the instanceClass variable
+ // Who is called in the body of the non-onPrepareHook method to print the log
+ loggerD(msg = "$instanceClass hook start")
+}
+
Solution
Using instanceClass
directly in hook
is very dangerous, if the Class does not exist, it will directly cause the Hook process to "die".
For details, please refer to Status Monitor.
IllegalStateException
Use of searchClass { ... }.hook { ... } is an error, please use like searchClass { ... }.get()?.hook { ... }
Abnormal
The Hook instance are created directly using the searchClass { ... }.hook { ... }
method.
Solution
Please use searchClass { ... }.get()?.hook { ... }
to create a Hook instance.
IllegalStateException
This type [TYPE] not support to hook, supported are Constructors and Methods
Abnormal
Using Member.hook { ... }
creates member objects that do not support Hooks, such as Field
.
Solution
You can only Hook Constructor
and Method
.
IllegalStateException
LayoutInflatedParam View instance got null
Abnormal
currentView
was called in the layout hook callback but no instance object was obtained.
The following example
injectResource {
+ conditions {
+ name = "activity_main"
+ layout()
+ }
+ injectAsLayout {
+ // This variable is called
+ currentView...
+ }
+}
+
Solution
This situation basically does not exist, unless the current Activity
of the Host App has been destroyed or there is a problem with the Hook Framework itself.
IllegalStateException
XResForwarder is invalid
Abnormal
resources
was called in YukiResForwarder
but no instance object was obtained.
The following example
// This variable is called
+moduleAppResources.fwd(...).resources
+
Solution
This basically doesn't exist unless there is a problem with the Hook Framework itself.
IllegalStateException
paramTypes is empty, please use emptyParam() instead
Abnormal
The empty param
method is preserved when looking up methods, constructors.
The following example
method {
+ name = "test"
+ // No parameters are filled in parentheses
+ param()
+}
+
Solution
To identify this method, the constructor has no parameters, you can have a setter method as follows.
The first way, set emptyParam
(recommended)
The following example
method {
+ name = "test"
+ emptyParam()
+}
+
The second way, set paramCount = 0
The following example
method {
+ name = "test"
+ paramCount = 0
+}
+
IllegalStateException
Invalid YukiHookCallback type
Abnormal
The core Hook functionality of YukiHookAPI
is broken.
Solution
This situation basically does not exist.
If the above problem occurs, after confirming that the problem is not in your own code, you can submit a log for feedback.
IllegalStateException
ModuleContextThemeWrapper already loaded
Abnormal
Called repeatedly when using the applyModuleTheme
method in the Context
.
The following example
// Assume this is the current Context object
+context.applyModuleTheme(R.style.Theme_AppCompat).applyModuleTheme(R.style.Theme_AppCompat)
+
Solution
The ModuleContextThemeWrapper
can only be created once in the Context
, please check the code for loop call problems.
IllegalStateException
Cannot create classes cache for "android", please remove "name" param
Abnormal
The DexClassFinder
cache function searchClass(name = ...)
is used in the System Framework ("android") Host App.
The following example
loadSystem {
+ searchClass(name = "test") {
+ from(...)
+ // ...
+ }.get()
+}
+
Solution
Since the cache will store the found Class
name in SharedPreferences
, but the data directory does not exist in the System Framework, so please do not use this function in the System Framework.
IllegalStateException
Target Class type cannot cast to TYPE
Abnormal
Wrong type declared when converting string class name to target Class
using Class.toClass
, Class.toClassOrNull
, GenericClass.argument
methods.
The following uses the Class.toClass
method as an example.
The following example
// Assume the target type is Activity but it was wrongly cast to WrongClass type
+val clazz = "android.app.Activity".toClass<WrongClass>()
+
Solution
The following example
// <Solution 1> Fill in the correct type
+val clazz1 = "android.app.Activity".toClass<Activity>()
+// <Solution 2> Do not fill in the generic declaration
+val clazz2 = "android.app.Activity".toClass()
+
Please ensure that the generic type declared after executing the method is the specified target Class
type, and you do not need to fill in the generic declaration if the target type is not sure.
As a Hook API, it is usually used for Hook operations for hot updates or functional needs of its own app and product testing.
You just need to integrate the com.highcapable.yukihookapi:api
dependency.
Then please integrate the Hook Framework
dependencies used by your target.
Create your custom Application
.
Add YukiHookAPI.encase
method to attachBaseContext
.
The following example
class MyApplication : Application() {
+
+ override fun attachBaseContext(base: Context?) {
+ // Load Hook Framework
+ //
+ // Your code here.
+ //
+ // Configure YukiHookAPI
+ YukiHookApi.configs {
+ // Your code here.
+ }
+ // Load YukiHookAPI
+ YukiHookAPI.encase(base) {
+ // Your code here.
+ }
+ super.attachBaseContext(base)
+ }
+}
+
In this way, you have completed the relevant configuration of the API.
You can click here to see the similarities, differences and caveats.
Notice
You can no longer wrap with loadApp and start writing your Hook code directly.
`,15),d={id:"pine",tabindex:"-1"},A=s("a",{class:"header-anchor",href:"#pine","aria-hidden":"true"},"#",-1),u={href:"https://github.com/canyie/pine",target:"_blank",rel:"noopener noreferrer"},y=o(`Here are some related ways of how to connect the
Hook Framework
with theYukiHookAPI
, which is widely used.
Required Xposed API dependencies
top.canyie.pine:xposed
The following example
override fun attachBaseContext(base: Context?) {
+ // Load Pine
+ PineConfig.debug = true
+ PineConfig.debuggable = BuildConfig.DEBUG
+ // Load YukiHookAPI
+ YukiHookAPI.encase(base) {
+ // Your code here.
+ }
+ super.attachBaseContext(base)
+}
+
Required Xposed API dependencies
com.swift.sandhook:xposedcompat
orcom.swift.sandhook:xposedcompat_new
The following example
override fun attachBaseContext(base: Context?) {
+ // Load SandHook
+ SandHookConfig.DEBUG = BuildConfig.DEBUG
+ XposedCompat.cacheDir = base?.cacheDir
+ XposedCompat.context = base
+ XposedCompat.classLoader = javaClass.classLoader
+ XposedCompat.isFirstApplication = base?.processName == base?.packageName
+ // Load YukiHookAPI
+ YukiHookAPI.encase(base) {
+ // Your code here.
+ }
+ super.attachBaseContext(base)
+}
+
The following example
override fun attachBaseContext(base: Context?) {
+ // Loading Whale does not require any configuration
+ // Load YukiHookAPI
+ YukiHookAPI.encase(base) {
+ // Your code here.
+ }
+ super.attachBaseContext(base)
+}
+
作为 Hook API 通常为做自身 APP 热更新或功能需要以及产品测试的 Hook 操作。
你只需要集成 com.highcapable.yukihookapi:api
依赖即可。
然后请集成你目标使用的 Hook Framework
依赖。
创建你的自定义 Application
。
在 attachBaseContext
中添加 YukiHookAPI.encase
方法。
示例如下
class MyApplication : Application() {
+
+ override fun attachBaseContext(base: Context?) {
+ // 装载 Hook Framework
+ //
+ // Your code here.
+ //
+ // 配置 YukiHookAPI
+ YukiHookApi.configs {
+ // Your code here.
+ }
+ // 装载 YukiHookAPI
+ YukiHookAPI.encase(base) {
+ // Your code here.
+ }
+ super.attachBaseContext(base)
+ }
+}
+
这样,你就完成了 API 的相关配置。
你可以 点击这里 查看异同点和注意事项。
注意
你不能再使用 loadApp 进行包装,可直接开始编写你的 Hook 代码。
`,15),d={id:"pine",tabindex:"-1"},A=s("a",{class:"header-anchor",href:"#pine","aria-hidden":"true"},"#",-1),y={href:"https://github.com/canyie/pine",target:"_blank",rel:"noopener noreferrer"},u=o(`这里给出了一些较高使用率的
Hook Framework
如何对接YukiHookAPI
的相关方式。
所需 Xposed API 依赖
top.canyie.pine:xposed
示例如下
override fun attachBaseContext(base: Context?) {
+ // 装载 Pine
+ PineConfig.debug = true
+ PineConfig.debuggable = BuildConfig.DEBUG
+ // 装载 YukiHookAPI
+ YukiHookAPI.encase(base) {
+ // Your code here.
+ }
+ super.attachBaseContext(base)
+}
+
所需 Xposed API 依赖
com.swift.sandhook:xposedcompat
或com.swift.sandhook:xposedcompat_new
示例如下
override fun attachBaseContext(base: Context?) {
+ // 装载 SandHook
+ SandHookConfig.DEBUG = BuildConfig.DEBUG
+ XposedCompat.cacheDir = base?.cacheDir
+ XposedCompat.context = base
+ XposedCompat.classLoader = javaClass.classLoader
+ XposedCompat.isFirstApplication = base?.processName == base?.packageName
+ // 装载 YukiHookAPI
+ YukiHookAPI.encase(base) {
+ // Your code here.
+ }
+ super.attachBaseContext(base)
+}
+
示例如下
override fun attachBaseContext(base: Context?) {
+ // 装载 Whale 不需要任何配置
+ // 装载 YukiHookAPI
+ YukiHookAPI.encase(base) {
+ // Your code here.
+ }
+ super.attachBaseContext(base)
+}
+
Z?Fe(p,A,w,!0,!1,q):b(f,v,E,A,w,$,S,N,q)},ze=(p,f,v,E,A,w,$,S,N)=>{let D=0;const Z=f.length;let q=p.length-1,Q=Z-1;for(;D<=q&&D<=Q;){const ne=p[D],ae=f[D]=N?At(f[D]):lt(f[D]);if($t(ne,ae))L(ne,ae,v,null,A,w,$,S,N);else break;D++}for(;D<=q&&D<=Q;){const ne=p[q],ae=f[Q]=N?At(f[Q]):lt(f[Q]);if($t(ne,ae))L(ne,ae,v,null,A,w,$,S,N);else break;q--,Q--}if(D>q){if(D<=Q){const ne=Q+1,ae=neQ)for(;D<=q;)Me(p[D],A,w,!0),D++;else{const ne=D,ae=D,be=new Map;for(D=ae;D<=Q;D++){const Ke=f[D]=N?At(f[D]):lt(f[D]);Ke.key!=null&&be.set(Ke.key,D)}let _e,Ae=0;const tt=Q-ae+1;let Qt=!1,Go=0;const _l=new Array(tt);for(D=0;D=tt){Me(Ke,A,w,!0);continue}let rt;if(Ke.key!=null)rt=be.get(Ke.key);else for(_e=ae;_e<=Q;_e++)if(_l[_e-ae]===0&&$t(Ke,f[_e])){rt=_e;break}rt===void 0?Me(Ke,A,w,!0):(_l[rt-ae]=D+1,rt>=Go?Go=rt:Qt=!0,L(Ke,f[rt],v,null,A,w,$,S,N),Ae++)}const Jo=Qt?Ic(_l):ol;for(_e=Jo.length-1,D=tt-1;D>=0;D--){const Ke=ae+D,rt=f[Ke],Zo=Ke+1 {const{el:w,type:$,transition:S,children:N,shapeFlag:D}=p;if(D&6){Ye(p.component.subTree,f,v,E);return}if(D&128){p.suspense.move(f,v,E);return}if(D&64){$.move(p,f,v,V);return}if($===xe){i(w,f,v);for(let q=0;q S.enter(w),A);else{const{leave:q,delayLeave:Q,afterLeave:ne}=S,ae=()=>i(w,f,v),be=()=>{q(w,()=>{ae(),ne&&ne()})};Q?Q(w,ae,be):be()}else i(w,f,v)},Me=(p,f,v,E=!1,A=!1)=>{const{type:w,props:$,ref:S,children:N,dynamicChildren:D,shapeFlag:Z,patchFlag:q,dirs:Q}=p;if(S!=null&&bi(S,null,v,p,!0),Z&256){f.ctx.deactivate(p);return}const ne=Z&1&&Q,ae=!al(p);let be;if(ae&&(be=$&&$.onVnodeBeforeUnmount)&&Qe(be,f,p),Z&6)st(p.component,v,E);else{if(Z&128){p.suspense.unmount(v,E);return}ne&&at(p,null,f,"beforeUnmount"),Z&64?p.type.remove(p,f,v,A,V,E):D&&(w!==xe||q>0&&q&64)?Fe(D,f,v,!1,!0):(w===xe&&q&384||!A&&Z&16)&&Fe(N,f,v),E&&yt(p)}(ae&&(be=$&&$.onVnodeUnmounted)||ne)&&Ue(()=>{be&&Qe(be,f,p),ne&&at(p,null,f,"unmounted")},v)},yt=p=>{const{type:f,el:v,anchor:E,transition:A}=p;if(f===xe){xt(v,E);return}if(f===Al){y(p);return}const w=()=>{o(v),A&&!A.persisted&&A.afterLeave&&A.afterLeave()};if(p.shapeFlag&1&&A&&!A.persisted){const{leave:$,delayLeave:S}=A,N=()=>$(v,w);S?S(p.el,w,N):N()}else w()},xt=(p,f)=>{let v;for(;p!==f;)v=m(p),o(p),p=v;o(f)},st=(p,f,v)=>{const{bum:E,scope:A,update:w,subTree:$,um:S}=p;E&&Vi(E),A.stop(),w&&(w.active=!1,Me($,p,f,v)),S&&Ue(S,f),Ue(()=>{p.isUnmounted=!0},f),f&&f.pendingBranch&&!f.isUnmounted&&p.asyncDep&&!p.asyncResolved&&p.suspenseId===f.pendingId&&(f.deps--,f.deps===0&&f.resolve())},Fe=(p,f,v,E=!1,A=!1,w=0)=>{for(let $=w;$ p.shapeFlag&6?R(p.component.subTree):p.shapeFlag&128?p.suspense.next():m(p.anchor||p.el),U=(p,f,v)=>{p==null?f._vnode&&Me(f._vnode,null,null,!0):L(f._vnode||null,p,f,null,null,null,v),an(),fi(),f._vnode=p},V={p:L,um:Me,m:Ye,r:yt,mt:ie,mc:b,pc:W,pbc:O,n:R,o:e};let G,de;return t&&([G,de]=t(V)),{render:U,hydrate:G,createApp:yc(U,G)}}function Ht({effect:e,update:t},l){e.allowRecurse=t.allowRecurse=l}function ir(e,t){return(!e||e&&!e.pendingBranch)&&t&&!t.persisted}function or(e,t,l=!1){const i=e.children,o=t.children;if(ee(i)&&ee(o))for(let n=0;n >1,e[l[a]] 0&&(t[i]=l[n-1]),l[n]=i)}}for(n=l.length,s=l[n-1];n-- >0;)l[n]=s,s=t[s];return l}const wc=e=>e.__isTeleport,xe=Symbol.for("v-fgt"),dl=Symbol.for("v-txt"),Je=Symbol.for("v-cmt"),Al=Symbol.for("v-stc"),Tl=[];let ot=null;function Y(e=!1){Tl.push(ot=e?null:[])}function Oc(){Tl.pop(),ot=Tl[Tl.length-1]||null}let zl=1;function bn(e){zl+=e}function nr(e){return e.dynamicChildren=zl>0?ot||ol:null,Oc(),zl>0&&ot&&ot.push(e),e}function te(e,t,l,i,o,n){return nr(pe(e,t,l,i,o,n,!0))}function Te(e,t,l,i,o){return nr(oe(e,t,l,i,o,!0))}function yi(e){return e?e.__v_isVNode===!0:!1}function $t(e,t){return e.type===t.type&&e.key===t.key}const Fi="__vInternal",sr=({key:e})=>e??null,di=({ref:e,ref_key:t,ref_for:l})=>(typeof e=="number"&&(e=""+e),e!=null?ge(e)||Ne(e)||se(e)?{i:He,r:e,k:t,f:!!l}:e:null);function pe(e,t=null,l=null,i=0,o=null,n=e===xe?0:1,s=!1,a=!1){const r={__v_isVNode:!0,__v_skip:!0,type:e,props:t,key:t&&sr(t),ref:t&&di(t),scopeId:js,slotScopeIds:null,children:l,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetAnchor:null,staticCount:0,shapeFlag:n,patchFlag:i,dynamicProps:o,dynamicChildren:null,appContext:null,ctx:He};return a?(Fo(r,l),n&128&&e.normalize(r)):l&&(r.shapeFlag|=ge(l)?8:16),zl>0&&!s&&ot&&(r.patchFlag>0||n&6)&&r.patchFlag!==32&&ot.push(r),r}const oe=Dc;function Dc(e,t=null,l=null,i=0,o=null,n=!1){if((!e||e===Ja)&&(e=Je),yi(e)){const a=Ft(e,t,!0);return l&&Fo(a,l),zl>0&&!n&&ot&&(a.shapeFlag&6?ot[ot.indexOf(e)]=a:ot.push(a)),a.patchFlag|=-2,a}if(Yc(e)&&(e=e.__vccOpts),t){t=Fc(t);let{class:a,style:r}=t;a&&!ge(a)&&(t.class=We(a)),Le(r)&&(Ds(r)&&!ee(r)&&(r=Oe({},r)),t.style=Nl(r))}const s=ge(e)?1:Qa(e)?128:wc(e)?64:Le(e)?4:se(e)?2:0;return pe(e,t,l,i,o,s,n,!0)}function Fc(e){return e?Ds(e)||Fi in e?Oe({},e):e:null}function Ft(e,t,l=!1){const{props:i,ref:o,patchFlag:n,children:s}=e,a=t?uo(i||{},t):i;return{__v_isVNode:!0,__v_skip:!0,type:e.type,props:a,key:a&&sr(a),ref:t&&t.ref?l&&o?ee(o)?o.concat(di(t)):[o,di(t)]:di(t):o,scopeId:e.scopeId,slotScopeIds:e.slotScopeIds,children:s,target:e.target,targetAnchor:e.targetAnchor,staticCount:e.staticCount,shapeFlag:e.shapeFlag,patchFlag:t&&e.type!==xe?n===-1?16:n|16:n,dynamicProps:e.dynamicProps,dynamicChildren:e.dynamicChildren,appContext:e.appContext,dirs:e.dirs,transition:e.transition,component:e.component,suspense:e.suspense,ssContent:e.ssContent&&Ft(e.ssContent),ssFallback:e.ssFallback&&Ft(e.ssFallback),el:e.el,anchor:e.anchor,ctx:e.ctx,ce:e.ce}}function zt(e=" ",t=0){return oe(dl,null,e,t)}function zc(e,t){const l=oe(Al,null,e);return l.staticCount=t,l}function Re(e="",t=!1){return t?(Y(),Te(Je,null,e)):oe(Je,null,e)}function lt(e){return e==null||typeof e=="boolean"?oe(Je):ee(e)?oe(xe,null,e.slice()):typeof e=="object"?At(e):oe(dl,null,String(e))}function At(e){return e.el===null&&e.patchFlag!==-1||e.memo?e:Ft(e)}function Fo(e,t){let l=0;const{shapeFlag:i}=e;if(t==null)t=null;else if(ee(t))l=16;else if(typeof t=="object")if(i&65){const o=t.default;o&&(o._c&&(o._d=!1),Fo(e,o()),o._c&&(o._d=!0));return}else{l=32;const o=t._;!o&&!(Fi in t)?t._ctx=He:o===3&&He&&(He.slots._===1?t._=1:(t._=2,e.patchFlag|=1024))}else se(t)?(t={default:t,_ctx:He},l=32):(t=String(t),i&64?(l=16,t=[zt(t)]):l=8);e.children=t,e.shapeFlag|=l}function uo(...e){const t={};for(let l=0;l Ie||He;let So,el,yn="__VUE_INSTANCE_SETTERS__";(el=eo()[yn])||(el=eo()[yn]=[]),el.push(e=>Ie=e),So=e=>{el.length>1?el.forEach(t=>t(e)):el[0](e)};const hl=e=>{So(e),e.scope.on()},Xt=()=>{Ie&&Ie.scope.off(),So(null)};function rr(e){return e.vnode.shapeFlag&4}let ul=!1;function Vc(e,t=!1){ul=t;const{props:l,children:i}=e.vnode,o=rr(e);xc(e,l,o,t),Pc(e,i);const n=o?Nc(e,t):void 0;return ul=!1,n}function Nc(e,t){const l=e.type;e.accessCache=Object.create(null),e.proxy=Fs(new Proxy(e.ctx,pc));const{setup:i}=l;if(i){const o=e.setupContext=i.length>1?$c(e):null;hl(e),vl();const n=wt(i,e,0,[e.props,o]);if(kl(),Xt(),gs(n)){if(n.then(Xt,Xt),t)return n.then(s=>{xn(e,s,t)}).catch(s=>{Bl(s,e,0)});e.asyncDep=n}else xn(e,n,t)}else ar(e,t)}function xn(e,t,l){se(t)?e.type.__ssrInlineRender?e.ssrRender=t:e.render=t:Le(t)&&(e.setupState=Ss(t)),ar(e,l)}let En;function ar(e,t,l){const i=e.type;if(!e.render){if(!t&&En&&!i.render){const o=i.template||Oo(e).template;if(o){const{isCustomElement:n,compilerOptions:s}=e.appContext.config,{delimiters:a,compilerOptions:r}=i,c=Oe(Oe({isCustomElement:n,delimiters:a},s),r);i.render=En(o,c)}}e.render=i.render||dt}{hl(e),vl();try{fc(e)}finally{kl(),Xt()}}}function jc(e){return e.attrsProxy||(e.attrsProxy=new Proxy(e.attrs,{get(t,l){return Xe(e,"get","$attrs"),t[l]}}))}function $c(e){const t=l=>{e.exposed=l||{}};return{get attrs(){return jc(e)},slots:e.slots,emit:e.emit,expose:t}}function zi(e){if(e.exposed)return e.exposeProxy||(e.exposeProxy=new Proxy(Ss(Fs(e.exposed)),{get(t,l){if(l in t)return t[l];if(l in Cl)return Cl[l](e)},has(t,l){return l in t||l in Cl}}))}function Bc(e,t=!0){return se(e)?e.displayName||e.name:e.name||t&&e.__name}function Yc(e){return se(e)&&"__vccOpts"in e}const B=(e,t)=>Va(e,t,ul);function ce(e,t,l){const i=arguments.length;return i===2?Le(t)&&!ee(t)?yi(t)?oe(e,null,[t]):oe(e,t):oe(e,null,t):(i>3?l=Array.prototype.slice.call(arguments,2):i===3&&yi(l)&&(l=[l]),oe(e,t,l))}const Uc=Symbol.for("v-scx"),Wc=()=>Ce(Uc),Xc="3.3.12",Kc="http://www.w3.org/2000/svg",Bt=typeof document<"u"?document:null,Ln=Bt&&Bt.createElement("template"),qc={insert:(e,t,l)=>{t.insertBefore(e,l||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,l,i)=>{const o=t?Bt.createElementNS(Kc,e):Bt.createElement(e,l?{is:l}:void 0);return e==="select"&&i&&i.multiple!=null&&o.setAttribute("multiple",i.multiple),o},createText:e=>Bt.createTextNode(e),createComment:e=>Bt.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>Bt.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,l,i,o,n){const s=l?l.previousSibling:t.lastChild;if(o&&(o===n||o.nextSibling))for(;t.insertBefore(o.cloneNode(!0),l),!(o===n||!(o=o.nextSibling)););else{Ln.innerHTML=i?``:e;const a=Ln.content;if(i){const r=a.firstChild;for(;r.firstChild;)a.appendChild(r.firstChild);a.removeChild(r)}t.insertBefore(a,l)}return[s?s.nextSibling:t.firstChild,l?l.previousSibling:t.lastChild]}},Pt="transition",bl="animation",Sl=Symbol("_vtc"),Xl=(e,{slots:t})=>ce(ic,Gc(e),t);Xl.displayName="Transition";const cr={name:String,type:String,css:{type:Boolean,default:!0},duration:[String,Number,Object],enterFromClass:String,enterActiveClass:String,enterToClass:String,appearFromClass:String,appearActiveClass:String,appearToClass:String,leaveFromClass:String,leaveActiveClass:String,leaveToClass:String};Xl.props=Oe({},Us,cr);const Mt=(e,t=[])=>{ee(e)?e.forEach(l=>l(...t)):e&&e(...t)},Pn=e=>e?ee(e)?e.some(t=>t.length>1):e.length>1:!1;function Gc(e){const t={};for(const P in e)P in cr||(t[P]=e[P]);if(e.css===!1)return t;const{name:l="v",type:i,duration:o,enterFromClass:n=`${l}-enter-from`,enterActiveClass:s=`${l}-enter-active`,enterToClass:a=`${l}-enter-to`,appearFromClass:r=n,appearActiveClass:c=s,appearToClass:d=a,leaveFromClass:u=`${l}-leave-from`,leaveActiveClass:m=`${l}-leave-active`,leaveToClass:g=`${l}-leave-to`}=e,x=Jc(o),L=x&&x[0],C=x&&x[1],{onBeforeEnter:I,onEnter:T,onEnterCancelled:_,onLeave:y,onLeaveCancelled:j,onBeforeAppear:K=I,onAppear:M=T,onAppearCancelled:b=_}=t,z=(P,H,ie)=>{Vt(P,H?d:a),Vt(P,H?c:s),ie&&ie()},O=(P,H)=>{P._isLeaving=!1,Vt(P,u),Vt(P,g),Vt(P,m),H&&H()},X=P=>(H,ie)=>{const re=P?M:T,F=()=>z(H,P,ie);Mt(re,[H,F]),Rn(()=>{Vt(H,P?r:n),Rt(H,P?d:a),Pn(re)||Cn(H,i,L,F)})};return Oe(t,{onBeforeEnter(P){Mt(I,[P]),Rt(P,n),Rt(P,s)},onBeforeAppear(P){Mt(K,[P]),Rt(P,r),Rt(P,c)},onEnter:X(!1),onAppear:X(!0),onLeave(P,H){P._isLeaving=!0;const ie=()=>O(P,H);Rt(P,u),ed(),Rt(P,m),Rn(()=>{P._isLeaving&&(Vt(P,u),Rt(P,g),Pn(y)||Cn(P,i,C,ie))}),Mt(y,[P,ie])},onEnterCancelled(P){z(P,!1),Mt(_,[P])},onAppearCancelled(P){z(P,!0),Mt(b,[P])},onLeaveCancelled(P){O(P),Mt(j,[P])}})}function Jc(e){if(e==null)return null;if(Le(e))return[Ui(e.enter),Ui(e.leave)];{const t=Ui(e);return[t,t]}}function Ui(e){return ta(e)}function Rt(e,t){t.split(/\s+/).forEach(l=>l&&e.classList.add(l)),(e[Sl]||(e[Sl]=new Set)).add(t)}function Vt(e,t){t.split(/\s+/).forEach(i=>i&&e.classList.remove(i));const l=e[Sl];l&&(l.delete(t),l.size||(e[Sl]=void 0))}function Rn(e){requestAnimationFrame(()=>{requestAnimationFrame(e)})}let Zc=0;function Cn(e,t,l,i){const o=e._endId=++Zc,n=()=>{o===e._endId&&i()};if(l)return setTimeout(n,l);const{type:s,timeout:a,propCount:r}=Qc(e,t);if(!s)return i();const c=s+"end";let d=0;const u=()=>{e.removeEventListener(c,m),n()},m=g=>{g.target===e&&++d>=r&&u()};setTimeout(()=>{d (l[x]||"").split(", "),o=i(`${Pt}Delay`),n=i(`${Pt}Duration`),s=An(o,n),a=i(`${bl}Delay`),r=i(`${bl}Duration`),c=An(a,r);let d=null,u=0,m=0;t===Pt?s>0&&(d=Pt,u=s,m=n.length):t===bl?c>0&&(d=bl,u=c,m=r.length):(u=Math.max(s,c),d=u>0?s>c?Pt:bl:null,m=d?d===Pt?n.length:r.length:0);const g=d===Pt&&/\b(transform|all)(,|$)/.test(i(`${Pt}Property`).toString());return{type:d,timeout:u,propCount:m,hasTransform:g}}function An(e,t){for(;e.length Tn(l)+Tn(e[i])))}function Tn(e){return e==="auto"?0:Number(e.slice(0,-1).replace(",","."))*1e3}function ed(){return document.body.offsetHeight}function td(e,t,l){const i=e[Sl];i&&(t=(t?[t,...i]:[...i]).join(" ")),t==null?e.removeAttribute("class"):l?e.setAttribute("class",t):e.className=t}const Ho=Symbol("_vod"),xi={beforeMount(e,{value:t},{transition:l}){e[Ho]=e.style.display==="none"?"":e.style.display,l&&t?l.beforeEnter(e):yl(e,t)},mounted(e,{value:t},{transition:l}){l&&t&&l.enter(e)},updated(e,{value:t,oldValue:l},{transition:i}){!t!=!l&&(i?t?(i.beforeEnter(e),yl(e,!0),i.enter(e)):i.leave(e,()=>{yl(e,!1)}):yl(e,t))},beforeUnmount(e,{value:t}){yl(e,t)}};function yl(e,t){e.style.display=t?e[Ho]:"none"}const ld=Symbol("");function id(e,t,l){const i=e.style,o=ge(l);if(l&&!o){if(t&&!ge(t))for(const n in t)l[n]==null&&mo(i,n,"");for(const n in l)mo(i,n,l[n])}else{const n=i.display;if(o){if(t!==l){const s=i[ld];s&&(l+=";"+s),i.cssText=l}}else t&&e.removeAttribute("style");Ho in e&&(i.display=n)}}const In=/\s*!important$/;function mo(e,t,l){if(ee(l))l.forEach(i=>mo(e,t,i));else if(l==null&&(l=""),t.startsWith("--"))e.setProperty(t,l);else{const i=od(e,t);In.test(l)?e.setProperty(Gt(i),l.replace(In,""),"important"):e[i]=l}}const wn=["Webkit","Moz","ms"],Wi={};function od(e,t){const l=Wi[t];if(l)return l;let i=ht(t);if(i!=="filter"&&i in e)return Wi[t]=i;i=Ci(i);for(let o=0;o Xi||(hd.then(()=>Xi=0),Xi=Date.now());function md(e,t){const l=i=>{if(!i._vts)i._vts=Date.now();else if(i._vts<=l.attached)return;et(pd(i,l.value),t,5,[i])};return l.value=e,l.attached=ud(),l}function pd(e,t){if(ee(t)){const l=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{l.call(e),e._stopped=!0},t.map(i=>o=>!o._stopped&&i&&i(o))}else return t}const zn=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&e.charCodeAt(2)>96&&e.charCodeAt(2)<123,fd=(e,t,l,i,o=!1,n,s,a,r)=>{t==="class"?td(e,i,o):t==="style"?id(e,l,i):Vl(t)?ko(t)||cd(e,t,l,i,s):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):gd(e,t,i,o))?sd(e,t,i,n,s,a,r):(t==="true-value"?e._trueValue=i:t==="false-value"&&(e._falseValue=i),nd(e,t,i,o))};function gd(e,t,l,i){if(i)return!!(t==="innerHTML"||t==="textContent"||t in e&&zn(t)&&se(l));if(t==="spellcheck"||t==="draggable"||t==="translate"||t==="form"||t==="list"&&e.tagName==="INPUT"||t==="type"&&e.tagName==="TEXTAREA")return!1;if(t==="width"||t==="height"){const o=e.tagName;if(o==="IMG"||o==="VIDEO"||o==="CANVAS"||o==="SOURCE")return!1}return zn(t)&&ge(l)?!1:t in e}const vd={esc:"escape",space:" ",up:"arrow-up",left:"arrow-left",right:"arrow-right",down:"arrow-down",delete:"backspace"},kd=(e,t)=>e._withKeys||(e._withKeys=l=>{if(!("key"in l))return;const i=Gt(l.key);if(t.some(o=>o===i||vd[o]===i))return e(l)}),_d=Oe({patchProp:fd},qc);let Ki,Sn=!1;function bd(){return Ki=Sn?Ki:Ac(_d),Sn=!0,Ki}const yd=(...e)=>{const t=bd().createApp(...e),{mount:l}=t;return t.mount=i=>{const o=xd(i);if(o)return l(o,!0,o instanceof SVGElement)},t};function xd(e){return ge(e)?document.querySelector(e):e}const Ed="modulepreload",Ld=function(e){return"/YukiHookAPI/"+e},Hn={},h=function(t,l,i){let o=Promise.resolve();return l&&l.length>0&&(document.getElementsByTagName("link"),o=Promise.all(l.map(n=>{if(n=Ld(n),n in Hn)return;Hn[n]=!0;const s=n.endsWith(".css"),a=s?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${n}"]${a}`))return;const r=document.createElement("link");if(r.rel=s?"stylesheet":Ed,s||(r.as="script",r.crossOrigin=""),r.href=n,document.head.appendChild(r),s)return new Promise((c,d)=>{r.addEventListener("load",c),r.addEventListener("error",()=>d(new Error(`Unable to preload CSS for ${n}`)))})}))),o.then(()=>t()).catch(n=>{const s=new Event("vite:preloadError",{cancelable:!0});if(s.payload=n,window.dispatchEvent(s),!s.defaultPrevented)throw n})},Pd={"v-8daa1a0e":()=>h(()=>import("./index.html-D6YZKtoe.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2d0a870d":()=>h(()=>import("./index.html-CHgP8geU.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-c0c85b84":()=>h(()=>import("./index.html-Bo0olcew.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7a15fe3b":()=>h(()=>import("./about.html-DDk-q1tu.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-3f851d14":()=>h(()=>import("./changelog.html-Bti1NzlA.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-193cf592":()=>h(()=>import("./contacts.html-BSRuPKMe.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-ae7b83f2":()=>h(()=>import("./future.html-L0gip76T.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-64fc7bb8":()=>h(()=>import("./home.html-BWNdBIZw.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-9cfea7fc":()=>h(()=>import("./api-example.html-pCpzRhE2.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-72c12b7d":()=>h(()=>import("./api-exception.html-Dw1mqBwg.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-793879e8":()=>h(()=>import("./api-using.html-zXrI7_0R.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-de1c6dbe":()=>h(()=>import("./move-to-api-1-2-x.html-CCb8Xv2u.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-0e5a1400":()=>h(()=>import("./move-to-api-1-3-x.html-f3TZzPCU.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-29d6c1ba":()=>h(()=>import("./r8-proguard.html-Y47fgLwe.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-24e71de7":()=>h(()=>import("./xposed-using.html-CgLVQrdV.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7b22efaf":()=>h(()=>import("./example.html-CnT6OQuI.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-efb45d4c":()=>h(()=>import("./home.html-Bhz1Th03.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-277b35ca":()=>h(()=>import("./knowledge.html-BJFcZiJH.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-77d752a2":()=>h(()=>import("./move-to-new-api.html-Bd10LyS9.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-72889797":()=>h(()=>import("./quick-start.html-teZCSUoB.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-68fd81d0":()=>h(()=>import("./supportive.html-bOj3zBC_.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-55c11626":()=>h(()=>import("./yukihookapi-projectbuilder.html-xbo0Krpt.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-41967128":()=>h(()=>import("./about.html-D2yzzIyM.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-0e6c3476":()=>h(()=>import("./changelog.html-B8UfyBpi.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-6cf86266":()=>h(()=>import("./contacts.html-BfIGgEZ9.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-3106ca14":()=>h(()=>import("./future.html-BJR2WZUb.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-c8deafb2":()=>h(()=>import("./home.html-DAJQxBy-.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-c6114c9e":()=>h(()=>import("./api-example.html-CKw7e9Ka.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5b43296c":()=>h(()=>import("./api-exception.html-Pu6YF45s.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2ee67152":()=>h(()=>import("./api-using.html-CsMd954C.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4b553790":()=>h(()=>import("./move-to-api-1-2-x.html-D8SebGDZ.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-99933722":()=>h(()=>import("./move-to-api-1-3-x.html-CPnNzAVm.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-154d6f69":()=>h(()=>import("./r8-proguard.html-DnD4WWCL.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-af73b3d0":()=>h(()=>import("./xposed-using.html-sNzVArkO.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-13b430a0":()=>h(()=>import("./example.html-DBLcpd3T.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-6a609e09":()=>h(()=>import("./home.html-Cg57uIpM.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-b4f1a468":()=>h(()=>import("./knowledge.html-CFMQgPep.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-c0d5dada":()=>h(()=>import("./move-to-new-api.html-kyRByfpu.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-24840ff0":()=>h(()=>import("./quick-start.html-Dq2QHQuy.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4f5c6182":()=>h(()=>import("./supportive.html-DFnCbU7r.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-a2fab4d6":()=>h(()=>import("./yukihookapi-projectbuilder.html-DnghHaiT.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-12042f1f":()=>h(()=>import("./host-inject.html-BRZka0o7.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-deaff1d0":()=>h(()=>import("./host-lifecycle.html-BgnOErBM.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-33c1dc26":()=>h(()=>import("./logger.html-Dfs7bQRS.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-581ddb9c":()=>h(()=>import("./reflection.html-BohdUWGg.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2e6ad66c":()=>h(()=>import("./xposed-channel.html-DWoHNeKf.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-68bebbf4":()=>h(()=>import("./xposed-storage.html-ByKfNh6r.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-6ac5be8e":()=>h(()=>import("./host-inject.html-COD96F06.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-357a8d49":()=>h(()=>import("./host-lifecycle.html-C7PzYAZN.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1f0f591e":()=>h(()=>import("./logger.html-BW4Gjfc-.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-001858e3":()=>h(()=>import("./reflection.html-DXPuhLBz.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-598546c6":()=>h(()=>import("./xposed-channel.html-B7eDf6ix.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-0d914225":()=>h(()=>import("./xposed-storage.html-CZy1SL3y.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-053599a5":()=>h(()=>import("./YukiHookAPI.html-CtkZ6zEO.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-6931cb54":()=>h(()=>import("./YukiHookAPI.html-DqgBnIkU.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-818b3ca6":()=>h(()=>import("./InjectYukiHookWithXposed.html-BGS_DJ2i.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-b6a815c4":()=>h(()=>import("./CurrentClass.html-BT6y6bjW.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-0183e3fc":()=>h(()=>import("./GenericClass.html-CsB6lKmB.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-57506200":()=>h(()=>import("./HookClass.html-CW_9kHEG.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-9af56c1a":()=>h(()=>import("./HookResources.html-B9Np_jgF.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-032b1710":()=>h(()=>import("./VariousClass.html-3D_jbtJ_.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-71147891":()=>h(()=>import("./YukiMemberHookCreator.html-C1zPXD2D.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5ed1ceee":()=>h(()=>import("./YukiResourcesHookCreator.html-RF6ZJecD.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-e288ce96":()=>h(()=>import("./YukiBaseHooker.html-CWm_43km.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-0d0fcec2":()=>h(()=>import("./ReflectionFactory.html-BTXWRqP4.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-65091354":()=>h(()=>import("./YukiHookFactory.html-BKpat8zr.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-36749c00":()=>h(()=>import("./YLog.html-COO68ekD.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-60cbe1b4":()=>h(()=>import("./HookParam.html-CQJSudBe.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-b381a126":()=>h(()=>import("./PackageParam.html-356ELE7K.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-30f3ba1e":()=>h(()=>import("./InjectYukiHookWithXposed.html-C_GfVAhD.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-6e47300f":()=>h(()=>import("./CurrentClass.html-Drrw8tv5.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-69c1c226":()=>h(()=>import("./GenericClass.html-DO13T8ug.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-735374af":()=>h(()=>import("./HookClass.html-CszRm9Er.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1c516d22":()=>h(()=>import("./HookResources.html-DA2dINvc.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-66735bfe":()=>h(()=>import("./VariousClass.html-CKljcU2t.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-3ac40680":()=>h(()=>import("./YukiMemberHookCreator.html-C0fIOtqI.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5e81af42":()=>h(()=>import("./YukiResourcesHookCreator.html-DW5yilOs.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-516df326":()=>h(()=>import("./YukiBaseHooker.html-E78OJRmm.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-213d88b3":()=>h(()=>import("./ReflectionFactory.html-BiQJ-KKx.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-448e9585":()=>h(()=>import("./YukiHookFactory.html-CoBstbjt.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-3a7c33ef":()=>h(()=>import("./YLog.html-KE-5aK_7.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-75a9b636":()=>h(()=>import("./HookParam.html-SbRyLaGf.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-100b529c":()=>h(()=>import("./PackageParam.html-B3y0YF_m.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-e37480a6":()=>h(()=>import("./YLogData.html-XHmF_gos.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-8293d958":()=>h(()=>import("./ComponentTypeFactory.html-DptIpBn2.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7b0abf86":()=>h(()=>import("./GraphicsTypeFactory.html-CnqF4An8.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5309e4a0":()=>h(()=>import("./ViewTypeFactory.html-CIPHyInd.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-a2615d0c":()=>h(()=>import("./DefinedTypeFactory.html-DI2zOcK2.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-ba01a600":()=>h(()=>import("./VariableTypeFactory.html-DDYYL3th.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7fec5836":()=>h(()=>import("./ModuleApplication.html-BkkBbb-2.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7414265a":()=>h(()=>import("./YukiHookDataChannel.html-DgdZw6CE.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-65c20d2d":()=>h(()=>import("./YukiHookPrefsBridge.html-XzXYFQ1s.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1d680acc":()=>h(()=>import("./IYukiHookXposedInit.html-DEGewXhq.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-57e0fa9e":()=>h(()=>import("./YLogData.html-Bjac08gN.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5e874c45":()=>h(()=>import("./ComponentTypeFactory.html-VD1JaHTz.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4ea62475":()=>h(()=>import("./GraphicsTypeFactory.html-Dq_zQQPa.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-ef79cde2":()=>h(()=>import("./ViewTypeFactory.html-DPcuUPhN.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5acc12ab":()=>h(()=>import("./DefinedTypeFactory.html-C97GePUm.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-14ec8671":()=>h(()=>import("./VariableTypeFactory.html-BUNfn5Dn.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4709ad58":()=>h(()=>import("./ModuleApplication.html-C4NqW1gZ.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-632be8ee":()=>h(()=>import("./YukiHookDataChannel.html-Citru5C3.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-395d721c":()=>h(()=>import("./YukiHookPrefsBridge.html-BG7-Nq7V.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-763140ee":()=>h(()=>import("./IYukiHookXposedInit.html-Dr7_YjoO.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-3895ce22":()=>h(()=>import("./YukiHookPriority.html-smxFpy5Q.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4fca92c0":()=>h(()=>import("./BaseFinder.html-C6lfjJ7s.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2a898c66":()=>h(()=>import("./DexClassFinder.html-BAaqClmM.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-a71937aa":()=>h(()=>import("./ConstructorFinder.html-DuJIkaTM.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-42e0f0ab":()=>h(()=>import("./FieldFinder.html-CoQdzzYH.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-a4aa4d00":()=>h(()=>import("./MethodFinder.html-DxYxJsjj.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-19e7277e":()=>h(()=>import("./YukiXposedEvent.html-BFs-WRvy.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-8455e04e":()=>h(()=>import("./YukiModuleResources.html-jRWj4Ooi.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-7b087cce":()=>h(()=>import("./YukiResForwarder.html-DMGGwbMr.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-a00b4de6":()=>h(()=>import("./YukiResources.html-DzFxHHne.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2f64a2d4":()=>h(()=>import("./ChannelData.html-BX_rAvQg.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-87027140":()=>h(()=>import("./ChannelPriority.html-BGoRh-pu.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2d4e0da6":()=>h(()=>import("./ModuleClassLoader.html-BFtfl5mt.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-58ed8298":()=>h(()=>import("./PrefsData.html-B72hWN1s.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-23e1a817":()=>h(()=>import("./ModulePreferenceFragment.html-CXpIHn7Z.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-3e0afe1e":()=>h(()=>import("./YukiHookPriority.html-AgDP0CYh.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-0f719471":()=>h(()=>import("./BaseFinder.html-CAvlkbqd.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-45111efc":()=>h(()=>import("./DexClassFinder.html-CGIuabI3.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1e2cbc9c":()=>h(()=>import("./ConstructorFinder.html-CmDHOksx.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-22449c48":()=>h(()=>import("./FieldFinder.html-C9KHPG3N.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-fd738322":()=>h(()=>import("./MethodFinder.html-BepwXG9K.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-0a4de82f":()=>h(()=>import("./YukiXposedEvent.html-C9AS9omI.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-8266e0ec":()=>h(()=>import("./YukiModuleResources.html-DZnAa6JN.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-aa38fa86":()=>h(()=>import("./YukiResForwarder.html-CtCGVu9N.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-21b3b17e":()=>h(()=>import("./YukiResources.html--5kriWCV.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-493d37f6":()=>h(()=>import("./ChannelData.html-C7ktasrE.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-b57870de":()=>h(()=>import("./ChannelPriority.html-BHp-ErCM.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-4b468415":()=>h(()=>import("./ModuleClassLoader.html-BwGRnYn5.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-d99f7f36":()=>h(()=>import("./PrefsData.html-BbIfbfIq.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-53bcae06":()=>h(()=>import("./ModulePreferenceFragment.html-DSUkMTGs.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-f150b17c":()=>h(()=>import("./ExecutorType.html-Crao5k7G.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-52995ef7":()=>h(()=>import("./CountRules.html-lW3FW-Bi.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-8d5ce71a":()=>h(()=>import("./ModifierRules.html-DZnBFn8R.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-f5b1ffb2":()=>h(()=>import("./NameRules.html-BWk6zL2M.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-652b815b":()=>h(()=>import("./ObjectRules.html-Dxosvxi0.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-08b70f7f":()=>h(()=>import("./ConstructorRules.html-BuW8PcLh.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-21f64ebf":()=>h(()=>import("./FieldRules.html-DnAEAxmC.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-77f11cf9":()=>h(()=>import("./MemberRules.html-CzY4xHkS.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-64827680":()=>h(()=>import("./MethodRules.html-BCtTTlLz.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2d5d16db":()=>h(()=>import("./ModuleAppActivity.html-CrhmOsh-.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-cadbe48e":()=>h(()=>import("./ModuleAppCompatActivity.html-JFvN5vF4.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-78731c50":()=>h(()=>import("./ModuleContextThemeWrapper.html-DNoARGj7.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2728e033":()=>h(()=>import("./ExecutorType.html-tZrR-ZDE.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1b2ad030":()=>h(()=>import("./CountRules.html-BiTeupWL.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-547a3c3c":()=>h(()=>import("./ModifierRules.html-B9KoNMo6.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-58c26516":()=>h(()=>import("./NameRules.html-DopiK4pt.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-80fd32ec":()=>h(()=>import("./ObjectRules.html-DjhVlNAH.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-a42f54a4":()=>h(()=>import("./ConstructorRules.html-phFNNXJ8.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-3e67a42e":()=>h(()=>import("./FieldRules.html-DePoZYvp.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-2cab152c":()=>h(()=>import("./MemberRules.html-r3ZOm1rb.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5388621e":()=>h(()=>import("./MethodRules.html-DETSSGJ6.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-1446bdca":()=>h(()=>import("./ModuleAppActivity.html-BwDznH0J.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-c7cef530":()=>h(()=>import("./ModuleAppCompatActivity.html-BCax3oQU.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-44efb702":()=>h(()=>import("./ModuleContextThemeWrapper.html-D3JVFalR.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-5e375d98":()=>h(()=>import("./MemberRulesResult.html-DVBlYWR7.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-b8000f3a":()=>h(()=>import("./MemberRulesResult.html-4uRTQRQi.js"),__vite__mapDeps([])).then(({data:e})=>e),"v-3706649a":()=>h(()=>import("./404.html-5sy5zeZP.js"),__vite__mapDeps([])).then(({data:e})=>e)},Rd=JSON.parse('{"base":"/YukiHookAPI/","lang":"en-US","title":"Yuki Hook API","description":"An efficient Hook API and Xposed Module solution built in Kotlin","head":[["link",{"rel":"icon","href":"/YukiHookAPI/images/logo.png"}]],"locales":{"/en/":{"lang":"en-US","description":"An efficient Hook API and Xposed Module solution built in Kotlin"},"/zh-cn/":{"lang":"zh-CN","description":"一个使用 Kotlin 构建的高效 Hook API 与 Xposed 模块解决方案"}}}');var Cd=([e,t,l])=>e==="meta"&&t.name?`${e}.${t.name}`:["title","base"].includes(e)?e:e==="template"&&t.id?`${e}.${t.id}`:JSON.stringify([e,t,l]),Ad=e=>{const t=new Set,l=[];return e.forEach(i=>{const o=Cd(i);t.has(o)||(t.add(o),l.push(i))}),l},Kl=e=>/^(https?:)?\/\//.test(e),Td=e=>/^[a-z][a-z0-9+.-]*:/.test(e),Mo=e=>Object.prototype.toString.call(e)==="[object Object]",dr=e=>e[e.length-1]==="/"?e.slice(0,-1):e,hr=e=>e[0]==="/"?e.slice(1):e,ur=(e,t)=>{const l=Object.keys(e).sort((i,o)=>{const n=o.split("/").length-i.split("/").length;return n!==0?n:o.length-i.length});for(const i of l)if(t.startsWith(i))return i;return"/"};const mr={"v-8daa1a0e":k(()=>h(()=>import("./index.html-5uusgM1u.js"),__vite__mapDeps([]))),"v-2d0a870d":k(()=>h(()=>import("./index.html-NYRlXN7n.js"),__vite__mapDeps([]))),"v-c0c85b84":k(()=>h(()=>import("./index.html-CB7-jiwu.js"),__vite__mapDeps([]))),"v-7a15fe3b":k(()=>h(()=>import("./about.html-C7A_QXrx.js"),__vite__mapDeps([]))),"v-3f851d14":k(()=>h(()=>import("./changelog.html-BQ5AB5_x.js"),__vite__mapDeps([]))),"v-193cf592":k(()=>h(()=>import("./contacts.html-CGQemCaU.js"),__vite__mapDeps([]))),"v-ae7b83f2":k(()=>h(()=>import("./future.html-aS7aVBMr.js"),__vite__mapDeps([]))),"v-64fc7bb8":k(()=>h(()=>import("./home.html-CSP-y2Sx.js"),__vite__mapDeps([]))),"v-9cfea7fc":k(()=>h(()=>import("./api-example.html-DtfHDuEM.js"),__vite__mapDeps([]))),"v-72c12b7d":k(()=>h(()=>import("./api-exception.html-vCoW3MFk.js"),__vite__mapDeps([]))),"v-793879e8":k(()=>h(()=>import("./api-using.html-DtbSeeEs.js"),__vite__mapDeps([]))),"v-de1c6dbe":k(()=>h(()=>import("./move-to-api-1-2-x.html-etgyp2HF.js"),__vite__mapDeps([]))),"v-0e5a1400":k(()=>h(()=>import("./move-to-api-1-3-x.html-C6uNfo-e.js"),__vite__mapDeps([]))),"v-29d6c1ba":k(()=>h(()=>import("./r8-proguard.html-BruKL-ec.js"),__vite__mapDeps([]))),"v-24e71de7":k(()=>h(()=>import("./xposed-using.html-7rTJRpMs.js"),__vite__mapDeps([]))),"v-7b22efaf":k(()=>h(()=>import("./example.html-Cp22GGCP.js"),__vite__mapDeps([]))),"v-efb45d4c":k(()=>h(()=>import("./home.html-Hj1hpUN3.js"),__vite__mapDeps([]))),"v-277b35ca":k(()=>h(()=>import("./knowledge.html-BvjZCte4.js"),__vite__mapDeps([]))),"v-77d752a2":k(()=>h(()=>import("./move-to-new-api.html-CtQJCJWD.js"),__vite__mapDeps([]))),"v-72889797":k(()=>h(()=>import("./quick-start.html-CnOHbn2J.js"),__vite__mapDeps([]))),"v-68fd81d0":k(()=>h(()=>import("./supportive.html-Cd4sY_Jm.js"),__vite__mapDeps([]))),"v-55c11626":k(()=>h(()=>import("./yukihookapi-projectbuilder.html-0qjforhM.js"),__vite__mapDeps([]))),"v-41967128":k(()=>h(()=>import("./about.html-B_eiWEVD.js"),__vite__mapDeps([]))),"v-0e6c3476":k(()=>h(()=>import("./changelog.html-D0nYCScY.js"),__vite__mapDeps([]))),"v-6cf86266":k(()=>h(()=>import("./contacts.html-Co35EHVH.js"),__vite__mapDeps([]))),"v-3106ca14":k(()=>h(()=>import("./future.html-BS9bLph2.js"),__vite__mapDeps([]))),"v-c8deafb2":k(()=>h(()=>import("./home.html-DwzlpDun.js"),__vite__mapDeps([]))),"v-c6114c9e":k(()=>h(()=>import("./api-example.html-t4M0wmt4.js"),__vite__mapDeps([]))),"v-5b43296c":k(()=>h(()=>import("./api-exception.html-9Je71x4B.js"),__vite__mapDeps([]))),"v-2ee67152":k(()=>h(()=>import("./api-using.html-P_EkKVX5.js"),__vite__mapDeps([]))),"v-4b553790":k(()=>h(()=>import("./move-to-api-1-2-x.html-IonwGaOH.js"),__vite__mapDeps([]))),"v-99933722":k(()=>h(()=>import("./move-to-api-1-3-x.html-DBMmjUYq.js"),__vite__mapDeps([]))),"v-154d6f69":k(()=>h(()=>import("./r8-proguard.html-C9EyjikD.js"),__vite__mapDeps([]))),"v-af73b3d0":k(()=>h(()=>import("./xposed-using.html-B9LNrU2W.js"),__vite__mapDeps([]))),"v-13b430a0":k(()=>h(()=>import("./example.html-l_t2vpgR.js"),__vite__mapDeps([]))),"v-6a609e09":k(()=>h(()=>import("./home.html-DVG1oAZg.js"),__vite__mapDeps([]))),"v-b4f1a468":k(()=>h(()=>import("./knowledge.html-CabyS3rt.js"),__vite__mapDeps([]))),"v-c0d5dada":k(()=>h(()=>import("./move-to-new-api.html-DwX5LqED.js"),__vite__mapDeps([]))),"v-24840ff0":k(()=>h(()=>import("./quick-start.html-pUciT6Ob.js"),__vite__mapDeps([]))),"v-4f5c6182":k(()=>h(()=>import("./supportive.html-CTTW-ar9.js"),__vite__mapDeps([]))),"v-a2fab4d6":k(()=>h(()=>import("./yukihookapi-projectbuilder.html-Bq3KEpgx.js"),__vite__mapDeps([]))),"v-12042f1f":k(()=>h(()=>import("./host-inject.html-DyCVxqXv.js"),__vite__mapDeps([]))),"v-deaff1d0":k(()=>h(()=>import("./host-lifecycle.html-BqYisHbJ.js"),__vite__mapDeps([]))),"v-33c1dc26":k(()=>h(()=>import("./logger.html-C9kwF_yM.js"),__vite__mapDeps([]))),"v-581ddb9c":k(()=>h(()=>import("./reflection.html-D65pVYER.js"),__vite__mapDeps([]))),"v-2e6ad66c":k(()=>h(()=>import("./xposed-channel.html-DZ4m7tlI.js"),__vite__mapDeps([]))),"v-68bebbf4":k(()=>h(()=>import("./xposed-storage.html-DYzzLHun.js"),__vite__mapDeps([]))),"v-6ac5be8e":k(()=>h(()=>import("./host-inject.html-BNOoOrx_.js"),__vite__mapDeps([]))),"v-357a8d49":k(()=>h(()=>import("./host-lifecycle.html-BsjcaKw0.js"),__vite__mapDeps([]))),"v-1f0f591e":k(()=>h(()=>import("./logger.html-B-OHJyal.js"),__vite__mapDeps([]))),"v-001858e3":k(()=>h(()=>import("./reflection.html-BZdJSVZS.js"),__vite__mapDeps([]))),"v-598546c6":k(()=>h(()=>import("./xposed-channel.html-BeC6v_Qb.js"),__vite__mapDeps([]))),"v-0d914225":k(()=>h(()=>import("./xposed-storage.html-CFhC-RoM.js"),__vite__mapDeps([]))),"v-053599a5":k(()=>h(()=>import("./YukiHookAPI.html-BRFLeDZT.js"),__vite__mapDeps([]))),"v-6931cb54":k(()=>h(()=>import("./YukiHookAPI.html-DwLoSNWF.js"),__vite__mapDeps([]))),"v-818b3ca6":k(()=>h(()=>import("./InjectYukiHookWithXposed.html-B4v_FVid.js"),__vite__mapDeps([]))),"v-b6a815c4":k(()=>h(()=>import("./CurrentClass.html-CF1c04UQ.js"),__vite__mapDeps([]))),"v-0183e3fc":k(()=>h(()=>import("./GenericClass.html-8gR9C4nD.js"),__vite__mapDeps([]))),"v-57506200":k(()=>h(()=>import("./HookClass.html-CIc4FkOC.js"),__vite__mapDeps([]))),"v-9af56c1a":k(()=>h(()=>import("./HookResources.html-_3fh2QXJ.js"),__vite__mapDeps([]))),"v-032b1710":k(()=>h(()=>import("./VariousClass.html-DXVXaoSY.js"),__vite__mapDeps([]))),"v-71147891":k(()=>h(()=>import("./YukiMemberHookCreator.html-De9-pEl1.js"),__vite__mapDeps([]))),"v-5ed1ceee":k(()=>h(()=>import("./YukiResourcesHookCreator.html-CuPFBHZF.js"),__vite__mapDeps([]))),"v-e288ce96":k(()=>h(()=>import("./YukiBaseHooker.html-Dg91Mdnk.js"),__vite__mapDeps([]))),"v-0d0fcec2":k(()=>h(()=>import("./ReflectionFactory.html-BVjwrqby.js"),__vite__mapDeps([]))),"v-65091354":k(()=>h(()=>import("./YukiHookFactory.html-B7vz7jla.js"),__vite__mapDeps([]))),"v-36749c00":k(()=>h(()=>import("./YLog.html-DvNg4c8I.js"),__vite__mapDeps([]))),"v-60cbe1b4":k(()=>h(()=>import("./HookParam.html-BjAineUd.js"),__vite__mapDeps([]))),"v-b381a126":k(()=>h(()=>import("./PackageParam.html-vqkHjjmt.js"),__vite__mapDeps([]))),"v-30f3ba1e":k(()=>h(()=>import("./InjectYukiHookWithXposed.html-4oxD2_xz.js"),__vite__mapDeps([]))),"v-6e47300f":k(()=>h(()=>import("./CurrentClass.html-Dwxk2yiw.js"),__vite__mapDeps([]))),"v-69c1c226":k(()=>h(()=>import("./GenericClass.html-DQHoN7CN.js"),__vite__mapDeps([]))),"v-735374af":k(()=>h(()=>import("./HookClass.html-CJV3GEVs.js"),__vite__mapDeps([]))),"v-1c516d22":k(()=>h(()=>import("./HookResources.html-zBrjRa5p.js"),__vite__mapDeps([]))),"v-66735bfe":k(()=>h(()=>import("./VariousClass.html-BdAcgrdg.js"),__vite__mapDeps([]))),"v-3ac40680":k(()=>h(()=>import("./YukiMemberHookCreator.html-WvIyCwTr.js"),__vite__mapDeps([]))),"v-5e81af42":k(()=>h(()=>import("./YukiResourcesHookCreator.html-CKh6FwjE.js"),__vite__mapDeps([]))),"v-516df326":k(()=>h(()=>import("./YukiBaseHooker.html-D01KVdut.js"),__vite__mapDeps([]))),"v-213d88b3":k(()=>h(()=>import("./ReflectionFactory.html-Z7mH28Qd.js"),__vite__mapDeps([]))),"v-448e9585":k(()=>h(()=>import("./YukiHookFactory.html-Dp3ev0qR.js"),__vite__mapDeps([]))),"v-3a7c33ef":k(()=>h(()=>import("./YLog.html-g2dfXKDH.js"),__vite__mapDeps([]))),"v-75a9b636":k(()=>h(()=>import("./HookParam.html-ArPvy40F.js"),__vite__mapDeps([]))),"v-100b529c":k(()=>h(()=>import("./PackageParam.html-Bti7eWUt.js"),__vite__mapDeps([]))),"v-e37480a6":k(()=>h(()=>import("./YLogData.html-4aWpXHE7.js"),__vite__mapDeps([]))),"v-8293d958":k(()=>h(()=>import("./ComponentTypeFactory.html-B-t1GVQa.js"),__vite__mapDeps([]))),"v-7b0abf86":k(()=>h(()=>import("./GraphicsTypeFactory.html-B1x8cclg.js"),__vite__mapDeps([]))),"v-5309e4a0":k(()=>h(()=>import("./ViewTypeFactory.html-2ZSLUHiw.js"),__vite__mapDeps([]))),"v-a2615d0c":k(()=>h(()=>import("./DefinedTypeFactory.html-DyzA4S0r.js"),__vite__mapDeps([]))),"v-ba01a600":k(()=>h(()=>import("./VariableTypeFactory.html-DqSR6Ejd.js"),__vite__mapDeps([]))),"v-7fec5836":k(()=>h(()=>import("./ModuleApplication.html-DYtHym0q.js"),__vite__mapDeps([]))),"v-7414265a":k(()=>h(()=>import("./YukiHookDataChannel.html-0wHuRMGr.js"),__vite__mapDeps([]))),"v-65c20d2d":k(()=>h(()=>import("./YukiHookPrefsBridge.html-DVZoJTsa.js"),__vite__mapDeps([]))),"v-1d680acc":k(()=>h(()=>import("./IYukiHookXposedInit.html-DTEi8nM4.js"),__vite__mapDeps([]))),"v-57e0fa9e":k(()=>h(()=>import("./YLogData.html-DIaUDgTt.js"),__vite__mapDeps([]))),"v-5e874c45":k(()=>h(()=>import("./ComponentTypeFactory.html-357LuQ82.js"),__vite__mapDeps([]))),"v-4ea62475":k(()=>h(()=>import("./GraphicsTypeFactory.html-pywoj7PR.js"),__vite__mapDeps([]))),"v-ef79cde2":k(()=>h(()=>import("./ViewTypeFactory.html-pGgKQdI9.js"),__vite__mapDeps([]))),"v-5acc12ab":k(()=>h(()=>import("./DefinedTypeFactory.html-B0M9p-6D.js"),__vite__mapDeps([]))),"v-14ec8671":k(()=>h(()=>import("./VariableTypeFactory.html-Cel7GBhi.js"),__vite__mapDeps([]))),"v-4709ad58":k(()=>h(()=>import("./ModuleApplication.html--_5n76BL.js"),__vite__mapDeps([]))),"v-632be8ee":k(()=>h(()=>import("./YukiHookDataChannel.html-iKhC7MJd.js"),__vite__mapDeps([]))),"v-395d721c":k(()=>h(()=>import("./YukiHookPrefsBridge.html-Dprm2-90.js"),__vite__mapDeps([]))),"v-763140ee":k(()=>h(()=>import("./IYukiHookXposedInit.html-CjNI4nFN.js"),__vite__mapDeps([]))),"v-3895ce22":k(()=>h(()=>import("./YukiHookPriority.html-CUgcejgE.js"),__vite__mapDeps([]))),"v-4fca92c0":k(()=>h(()=>import("./BaseFinder.html-DvwHVrKn.js"),__vite__mapDeps([]))),"v-2a898c66":k(()=>h(()=>import("./DexClassFinder.html-DDicCU5w.js"),__vite__mapDeps([]))),"v-a71937aa":k(()=>h(()=>import("./ConstructorFinder.html-CVpWcXzr.js"),__vite__mapDeps([]))),"v-42e0f0ab":k(()=>h(()=>import("./FieldFinder.html-Cj74NK2V.js"),__vite__mapDeps([]))),"v-a4aa4d00":k(()=>h(()=>import("./MethodFinder.html-CtgDtD9U.js"),__vite__mapDeps([]))),"v-19e7277e":k(()=>h(()=>import("./YukiXposedEvent.html-BIvOGBiv.js"),__vite__mapDeps([]))),"v-8455e04e":k(()=>h(()=>import("./YukiModuleResources.html-CAc6ozP1.js"),__vite__mapDeps([]))),"v-7b087cce":k(()=>h(()=>import("./YukiResForwarder.html-DHpOwzIq.js"),__vite__mapDeps([]))),"v-a00b4de6":k(()=>h(()=>import("./YukiResources.html-CwrMMidY.js"),__vite__mapDeps([]))),"v-2f64a2d4":k(()=>h(()=>import("./ChannelData.html-CFQv84Ul.js"),__vite__mapDeps([]))),"v-87027140":k(()=>h(()=>import("./ChannelPriority.html-DFUm-PWb.js"),__vite__mapDeps([]))),"v-2d4e0da6":k(()=>h(()=>import("./ModuleClassLoader.html-BbehDNqJ.js"),__vite__mapDeps([]))),"v-58ed8298":k(()=>h(()=>import("./PrefsData.html-BbtXNnuS.js"),__vite__mapDeps([]))),"v-23e1a817":k(()=>h(()=>import("./ModulePreferenceFragment.html-XrU_e4rC.js"),__vite__mapDeps([]))),"v-3e0afe1e":k(()=>h(()=>import("./YukiHookPriority.html-BzBXrjfk.js"),__vite__mapDeps([]))),"v-0f719471":k(()=>h(()=>import("./BaseFinder.html-CAOGJdjR.js"),__vite__mapDeps([]))),"v-45111efc":k(()=>h(()=>import("./DexClassFinder.html-BbI_zWlb.js"),__vite__mapDeps([]))),"v-1e2cbc9c":k(()=>h(()=>import("./ConstructorFinder.html-DrSYr7fy.js"),__vite__mapDeps([]))),"v-22449c48":k(()=>h(()=>import("./FieldFinder.html-Di6mgVKf.js"),__vite__mapDeps([]))),"v-fd738322":k(()=>h(()=>import("./MethodFinder.html-DLZMTsEY.js"),__vite__mapDeps([]))),"v-0a4de82f":k(()=>h(()=>import("./YukiXposedEvent.html-DtehWaX2.js"),__vite__mapDeps([]))),"v-8266e0ec":k(()=>h(()=>import("./YukiModuleResources.html-DyrSatFK.js"),__vite__mapDeps([]))),"v-aa38fa86":k(()=>h(()=>import("./YukiResForwarder.html-PPhoLmXZ.js"),__vite__mapDeps([]))),"v-21b3b17e":k(()=>h(()=>import("./YukiResources.html-DZg6eRc4.js"),__vite__mapDeps([]))),"v-493d37f6":k(()=>h(()=>import("./ChannelData.html-Bp3A6ogd.js"),__vite__mapDeps([]))),"v-b57870de":k(()=>h(()=>import("./ChannelPriority.html-CEzIYSdp.js"),__vite__mapDeps([]))),"v-4b468415":k(()=>h(()=>import("./ModuleClassLoader.html-a6gisn52.js"),__vite__mapDeps([]))),"v-d99f7f36":k(()=>h(()=>import("./PrefsData.html-BInEpoWz.js"),__vite__mapDeps([]))),"v-53bcae06":k(()=>h(()=>import("./ModulePreferenceFragment.html-BozNh-bQ.js"),__vite__mapDeps([]))),"v-f150b17c":k(()=>h(()=>import("./ExecutorType.html-lxG6aiIx.js"),__vite__mapDeps([]))),"v-52995ef7":k(()=>h(()=>import("./CountRules.html-CAljrhzL.js"),__vite__mapDeps([]))),"v-8d5ce71a":k(()=>h(()=>import("./ModifierRules.html-B1V1DMvv.js"),__vite__mapDeps([]))),"v-f5b1ffb2":k(()=>h(()=>import("./NameRules.html-DOue2ksg.js"),__vite__mapDeps([]))),"v-652b815b":k(()=>h(()=>import("./ObjectRules.html-1b_D9aS8.js"),__vite__mapDeps([]))),"v-08b70f7f":k(()=>h(()=>import("./ConstructorRules.html-Bxffddpr.js"),__vite__mapDeps([]))),"v-21f64ebf":k(()=>h(()=>import("./FieldRules.html-DzJvDeKO.js"),__vite__mapDeps([]))),"v-77f11cf9":k(()=>h(()=>import("./MemberRules.html-DBoFuxYs.js"),__vite__mapDeps([]))),"v-64827680":k(()=>h(()=>import("./MethodRules.html-B2dSoNBv.js"),__vite__mapDeps([]))),"v-2d5d16db":k(()=>h(()=>import("./ModuleAppActivity.html-BffipQvV.js"),__vite__mapDeps([]))),"v-cadbe48e":k(()=>h(()=>import("./ModuleAppCompatActivity.html-C5B-6ZTc.js"),__vite__mapDeps([]))),"v-78731c50":k(()=>h(()=>import("./ModuleContextThemeWrapper.html-BylfEIpg.js"),__vite__mapDeps([]))),"v-2728e033":k(()=>h(()=>import("./ExecutorType.html-DyWI3DE3.js"),__vite__mapDeps([]))),"v-1b2ad030":k(()=>h(()=>import("./CountRules.html-cCBf7VmB.js"),__vite__mapDeps([]))),"v-547a3c3c":k(()=>h(()=>import("./ModifierRules.html-DD38DB4t.js"),__vite__mapDeps([]))),"v-58c26516":k(()=>h(()=>import("./NameRules.html-zuU55Nke.js"),__vite__mapDeps([]))),"v-80fd32ec":k(()=>h(()=>import("./ObjectRules.html-DA4rLBnV.js"),__vite__mapDeps([]))),"v-a42f54a4":k(()=>h(()=>import("./ConstructorRules.html-CjPJ9499.js"),__vite__mapDeps([]))),"v-3e67a42e":k(()=>h(()=>import("./FieldRules.html-D50kuywF.js"),__vite__mapDeps([]))),"v-2cab152c":k(()=>h(()=>import("./MemberRules.html-WT4l8b-Y.js"),__vite__mapDeps([]))),"v-5388621e":k(()=>h(()=>import("./MethodRules.html-CW03U_a6.js"),__vite__mapDeps([]))),"v-1446bdca":k(()=>h(()=>import("./ModuleAppActivity.html-e7GuQiJo.js"),__vite__mapDeps([]))),"v-c7cef530":k(()=>h(()=>import("./ModuleAppCompatActivity.html-Csob9Ceu.js"),__vite__mapDeps([]))),"v-44efb702":k(()=>h(()=>import("./ModuleContextThemeWrapper.html-UouAIg96.js"),__vite__mapDeps([]))),"v-5e375d98":k(()=>h(()=>import("./MemberRulesResult.html-CPcOEYiz.js"),__vite__mapDeps([]))),"v-b8000f3a":k(()=>h(()=>import("./MemberRulesResult.html-C2cLl89Y.js"),__vite__mapDeps([]))),"v-3706649a":k(()=>h(()=>import("./404.html-BkgNjMhp.js"),__vite__mapDeps([])))};var Id=Symbol(""),pr=Symbol(""),wd=$l({key:"",path:"",title:"",lang:"",frontmatter:{},headers:[]}),Kt=()=>{const e=Ce(pr);if(!e)throw new Error("pageData() is called without provider.");return e},fr=Symbol(""),vt=()=>{const e=Ce(fr);if(!e)throw new Error("usePageFrontmatter() is called without provider.");return e},gr=Symbol(""),Od=()=>{const e=Ce(gr);if(!e)throw new Error("usePageHead() is called without provider.");return e},Dd=Symbol(""),vr=Symbol(""),Fd=()=>{const e=Ce(vr);if(!e)throw new Error("usePageLang() is called without provider.");return e},kr=Symbol(""),zd=()=>{const e=Ce(kr);if(!e)throw new Error("usePageLayout() is called without provider.");return e},Sd=ke(Pd),Vo=Symbol(""),ql=()=>{const e=Ce(Vo);if(!e)throw new Error("useRouteLocale() is called without provider.");return e},il=ke(Rd),_r=()=>il,br=Symbol(""),No=()=>{const e=Ce(br);if(!e)throw new Error("useSiteLocaleData() is called without provider.");return e},Hd=Symbol(""),Md="Layout",Vd="NotFound",mt=jl({resolveLayouts:e=>e.reduce((t,l)=>({...t,...l.layouts}),{}),resolvePageData:async e=>{const t=Sd.value[e];return await(t==null?void 0:t())??wd},resolvePageFrontmatter:e=>e.frontmatter,resolvePageHead:(e,t,l)=>{const i=ge(t.description)?t.description:l.description,o=[...ee(t.head)?t.head:[],...l.head,["title",{},e],["meta",{name:"description",content:i}]];return Ad(o)},resolvePageHeadTitle:(e,t)=>[e.title,t.title].filter(l=>!!l).join(" | "),resolvePageLang:(e,t)=>e.lang||t.lang||"en-US",resolvePageLayout:(e,t)=>{let l;if(e.path){const i=e.frontmatter.layout;ge(i)?l=i:l=Md}else l=Vd;return t[l]},resolveRouteLocale:(e,t)=>ur(e,t),resolveSiteLocaleData:(e,t)=>({...e,...e.locales[t]})}),jo=he({name:"ClientOnly",setup(e,t){const l=ke(!1);return Be(()=>{l.value=!0}),()=>{var i,o;return l.value?(o=(i=t.slots).default)==null?void 0:o.call(i):null}}}),Nd=he({name:"Content",props:{pageKey:{type:String,required:!1,default:""}},setup(e){const t=Kt(),l=B(()=>mr[e.pageKey||t.value.key]);return()=>l.value?ce(l.value):ce("div","404 Not Found")}}),St=(e={})=>e,$o=e=>Kl(e)?e:`/YukiHookAPI/${hr(e)}`;function yr(e,t,l){var i,o,n;t===void 0&&(t=50),l===void 0&&(l={});var s=(i=l.isImmediate)!=null&&i,a=(o=l.callback)!=null&&o,r=l.maxWait,c=Date.now(),d=[];function u(){if(r!==void 0){var g=Date.now()-c;if(g+t>=r)return r-g}return t}var m=function(){var g=[].slice.call(arguments),x=this;return new Promise(function(L,C){var I=s&&n===void 0;if(n!==void 0&&clearTimeout(n),n=setTimeout(function(){if(n=void 0,c=Date.now(),!s){var _=e.apply(x,g);a&&a(_),d.forEach(function(y){return(0,y.resolve)(_)}),d=[]}},u()),I){var T=e.apply(x,g);return a&&a(T),L(T)}d.push({resolve:L,reject:C})})};return m.cancel=function(g){n!==void 0&&clearTimeout(n),d.forEach(function(x){return(0,x.reject)(g)}),d=[]},m}/*! + * vue-router v4.2.5 + * (c) 2023 Eduardo San Martin Morote + * @license MIT + */const ll=typeof window<"u";function jd(e){return e.__esModule||e[Symbol.toStringTag]==="Module"}const ve=Object.assign;function qi(e,t){const l={};for(const i in t){const o=t[i];l[i]=nt(o)?o.map(e):e(o)}return l}const Il=()=>{},nt=Array.isArray,$d=/\/$/,Bd=e=>e.replace($d,"");function Gi(e,t,l="/"){let i,o={},n="",s="";const a=t.indexOf("#");let r=t.indexOf("?");return a =0&&(r=-1),r>-1&&(i=t.slice(0,r),n=t.slice(r+1,a>-1?a:t.length),o=e(n)),a>-1&&(i=i||t.slice(0,a),s=t.slice(a,t.length)),i=Xd(i??t,l),{fullPath:i+(n&&"?")+n+s,path:i,query:o,hash:s}}function Yd(e,t){const l=t.query?e(t.query):"";return t.path+(l&&"?")+l+(t.hash||"")}function Mn(e,t){return!t||!e.toLowerCase().startsWith(t.toLowerCase())?e:e.slice(t.length)||"/"}function Ud(e,t,l){const i=t.matched.length-1,o=l.matched.length-1;return i>-1&&i===o&&ml(t.matched[i],l.matched[o])&&xr(t.params,l.params)&&e(t.query)===e(l.query)&&t.hash===l.hash}function ml(e,t){return(e.aliasOf||e)===(t.aliasOf||t)}function xr(e,t){if(Object.keys(e).length!==Object.keys(t).length)return!1;for(const l in e)if(!Wd(e[l],t[l]))return!1;return!0}function Wd(e,t){return nt(e)?Vn(e,t):nt(t)?Vn(t,e):e===t}function Vn(e,t){return nt(t)?e.length===t.length&&e.every((l,i)=>l===t[i]):e.length===1&&e[0]===t}function Xd(e,t){if(e.startsWith("/"))return e;if(!e)return t;const l=t.split("/"),i=e.split("/"),o=i[i.length-1];(o===".."||o===".")&&i.push("");let n=l.length-1,s,a;for(s=0;s 1&&n--;else break;return l.slice(0,n).join("/")+"/"+i.slice(s-(s===i.length?1:0)).join("/")}var Hl;(function(e){e.pop="pop",e.push="push"})(Hl||(Hl={}));var wl;(function(e){e.back="back",e.forward="forward",e.unknown=""})(wl||(wl={}));function Kd(e){if(!e)if(ll){const t=document.querySelector("base");e=t&&t.getAttribute("href")||"/",e=e.replace(/^\w+:\/\/[^\/]+/,"")}else e="/";return e[0]!=="/"&&e[0]!=="#"&&(e="/"+e),Bd(e)}const qd=/^[^#]+#/;function Gd(e,t){return e.replace(qd,"#")+t}function Jd(e,t){const l=document.documentElement.getBoundingClientRect(),i=e.getBoundingClientRect();return{behavior:t.behavior,left:i.left-l.left-(t.left||0),top:i.top-l.top-(t.top||0)}}const Si=()=>({left:window.pageXOffset,top:window.pageYOffset});function Zd(e){let t;if("el"in e){const l=e.el,i=typeof l=="string"&&l.startsWith("#"),o=typeof l=="string"?i?document.getElementById(l.slice(1)):document.querySelector(l):l;if(!o)return;t=Jd(o,e)}else t=e;"scrollBehavior"in document.documentElement.style?window.scrollTo(t):window.scrollTo(t.left!=null?t.left:window.pageXOffset,t.top!=null?t.top:window.pageYOffset)}function Nn(e,t){return(history.state?history.state.position-t:-1)+e}const po=new Map;function Qd(e,t){po.set(e,t)}function eh(e){const t=po.get(e);return po.delete(e),t}let th=()=>location.protocol+"//"+location.host;function Er(e,t){const{pathname:l,search:i,hash:o}=t,n=e.indexOf("#");if(n>-1){let a=o.includes(e.slice(n))?e.slice(n).length:1,r=o.slice(a);return r[0]!=="/"&&(r="/"+r),Mn(r,"")}return Mn(l,e)+i+o}function lh(e,t,l,i){let o=[],n=[],s=null;const a=({state:m})=>{const g=Er(e,location),x=l.value,L=t.value;let C=0;if(m){if(l.value=g,t.value=m,s&&s===x){s=null;return}C=L?m.position-L.position:0}else i(g);o.forEach(I=>{I(l.value,x,{delta:C,type:Hl.pop,direction:C?C>0?wl.forward:wl.back:wl.unknown})})};function r(){s=l.value}function c(m){o.push(m);const g=()=>{const x=o.indexOf(m);x>-1&&o.splice(x,1)};return n.push(g),g}function d(){const{history:m}=window;m.state&&m.replaceState(ve({},m.state,{scroll:Si()}),"")}function u(){for(const m of n)m();n=[],window.removeEventListener("popstate",a),window.removeEventListener("beforeunload",d)}return window.addEventListener("popstate",a),window.addEventListener("beforeunload",d,{passive:!0}),{pauseListeners:r,listen:c,destroy:u}}function jn(e,t,l,i=!1,o=!1){return{back:e,current:t,forward:l,replaced:i,position:window.history.length,scroll:o?Si():null}}function ih(e){const{history:t,location:l}=window,i={value:Er(e,l)},o={value:t.state};o.value||n(i.value,{back:null,current:i.value,forward:null,position:t.length-1,replaced:!0,scroll:null},!0);function n(r,c,d){const u=e.indexOf("#"),m=u>-1?(l.host&&document.querySelector("base")?e:e.slice(u))+r:th()+e+r;try{t[d?"replaceState":"pushState"](c,"",m),o.value=c}catch(g){console.error(g),l[d?"replace":"assign"](m)}}function s(r,c){const d=ve({},t.state,jn(o.value.back,r,o.value.forward,!0),c,{position:o.value.position});n(r,d,!0),i.value=r}function a(r,c){const d=ve({},o.value,t.state,{forward:r,scroll:Si()});n(d.current,d,!0);const u=ve({},jn(i.value,r,null),{position:d.position+1},c);n(r,u,!1),i.value=r}return{location:i,state:o,push:a,replace:s}}function oh(e){e=Kd(e);const t=ih(e),l=lh(e,t.state,t.location,t.replace);function i(n,s=!0){s||l.pauseListeners(),history.go(n)}const o=ve({location:"",base:e,go:i,createHref:Gd.bind(null,e)},t,l);return Object.defineProperty(o,"location",{enumerable:!0,get:()=>t.location.value}),Object.defineProperty(o,"state",{enumerable:!0,get:()=>t.state.value}),o}function nh(e){return typeof e=="string"||e&&typeof e=="object"}function Lr(e){return typeof e=="string"||typeof e=="symbol"}const pt={path:"/",name:void 0,params:{},query:{},hash:"",fullPath:"/",matched:[],meta:{},redirectedFrom:void 0},Pr=Symbol("");var $n;(function(e){e[e.aborted=4]="aborted",e[e.cancelled=8]="cancelled",e[e.duplicated=16]="duplicated"})($n||($n={}));function pl(e,t){return ve(new Error,{type:e,[Pr]:!0},t)}function ut(e,t){return e instanceof Error&&Pr in e&&(t==null||!!(e.type&t))}const Bn="[^/]+?",sh={sensitive:!1,strict:!1,start:!0,end:!0},rh=/[.+*?^${}()[\]/\\]/g;function ah(e,t){const l=ve({},sh,t),i=[];let o=l.start?"^":"";const n=[];for(const c of e){const d=c.length?[]:[90];l.strict&&!c.length&&(o+="/");for(let u=0;u t.length?t.length===1&&t[0]===80?1:-1:0}function dh(e,t){let l=0;const i=e.score,o=t.score;for(;l 0&&t[t.length-1]<0}const hh={type:0,value:""},uh=/[a-zA-Z0-9_]/;function mh(e){if(!e)return[[]];if(e==="/")return[[hh]];if(!e.startsWith("/"))throw new Error(`Invalid path "${e}"`);function t(g){throw new Error(`ERR (${l})/"${c}": ${g}`)}let l=0,i=l;const o=[];let n;function s(){n&&o.push(n),n=[]}let a=0,r,c="",d="";function u(){c&&(l===0?n.push({type:0,value:c}):l===1||l===2||l===3?(n.length>1&&(r==="*"||r==="+")&&t(`A repeatable param (${c}) must be alone in its segment. eg: '/:ids+.`),n.push({type:1,value:c,regexp:d,repeatable:r==="*"||r==="+",optional:r==="*"||r==="?"})):t("Invalid state to consume buffer"),c="")}function m(){c+=r}for(;a {s(T)}:Il}function s(d){if(Lr(d)){const u=i.get(d);u&&(i.delete(d),l.splice(l.indexOf(u),1),u.children.forEach(s),u.alias.forEach(s))}else{const u=l.indexOf(d);u>-1&&(l.splice(u,1),d.record.name&&i.delete(d.record.name),d.children.forEach(s),d.alias.forEach(s))}}function a(){return l}function r(d){let u=0;for(;u =0&&(d.record.path!==l[u].record.path||!Rr(d,l[u]));)u++;l.splice(u,0,d),d.record.name&&!Wn(d)&&i.set(d.record.name,d)}function c(d,u){let m,g={},x,L;if("name"in d&&d.name){if(m=i.get(d.name),!m)throw pl(1,{location:d});L=m.record.name,g=ve(Un(u.params,m.keys.filter(T=>!T.optional).map(T=>T.name)),d.params&&Un(d.params,m.keys.map(T=>T.name))),x=m.stringify(g)}else if("path"in d)x=d.path,m=l.find(T=>T.re.test(x)),m&&(g=m.parse(x),L=m.record.name);else{if(m=u.name?i.get(u.name):l.find(T=>T.re.test(u.path)),!m)throw pl(1,{location:d,currentLocation:u});L=m.record.name,g=ve({},u.params,d.params),x=m.stringify(g)}const C=[];let I=m;for(;I;)C.unshift(I.record),I=I.parent;return{name:L,path:x,params:g,matched:C,meta:kh(C)}}return e.forEach(d=>n(d)),{addRoute:n,resolve:c,removeRoute:s,getRoutes:a,getRecordMatcher:o}}function Un(e,t){const l={};for(const i of t)i in e&&(l[i]=e[i]);return l}function gh(e){return{path:e.path,redirect:e.redirect,name:e.name,meta:e.meta||{},aliasOf:void 0,beforeEnter:e.beforeEnter,props:vh(e),children:e.children||[],instances:{},leaveGuards:new Set,updateGuards:new Set,enterCallbacks:{},components:"components"in e?e.components||null:e.component&&{default:e.component}}}function vh(e){const t={},l=e.props||!1;if("component"in e)t.default=l;else for(const i in e.components)t[i]=typeof l=="object"?l[i]:l;return t}function Wn(e){for(;e;){if(e.record.aliasOf)return!0;e=e.parent}return!1}function kh(e){return e.reduce((t,l)=>ve(t,l.meta),{})}function Xn(e,t){const l={};for(const i in e)l[i]=i in t?t[i]:e[i];return l}function Rr(e,t){return t.children.some(l=>l===e||Rr(e,l))}const Cr=/#/g,_h=/&/g,bh=/\//g,yh=/=/g,xh=/\?/g,Ar=/\+/g,Eh=/%5B/g,Lh=/%5D/g,Tr=/%5E/g,Ph=/%60/g,Ir=/%7B/g,Rh=/%7C/g,wr=/%7D/g,Ch=/%20/g;function Bo(e){return encodeURI(""+e).replace(Rh,"|").replace(Eh,"[").replace(Lh,"]")}function Ah(e){return Bo(e).replace(Ir,"{").replace(wr,"}").replace(Tr,"^")}function fo(e){return Bo(e).replace(Ar,"%2B").replace(Ch,"+").replace(Cr,"%23").replace(_h,"%26").replace(Ph,"`").replace(Ir,"{").replace(wr,"}").replace(Tr,"^")}function Th(e){return fo(e).replace(yh,"%3D")}function Ih(e){return Bo(e).replace(Cr,"%23").replace(xh,"%3F")}function wh(e){return e==null?"":Ih(e).replace(bh,"%2F")}function Ei(e){try{return decodeURIComponent(""+e)}catch{}return""+e}function Oh(e){const t={};if(e===""||e==="?")return t;const i=(e[0]==="?"?e.slice(1):e).split("&");for(let o=0;o n&&fo(n)):[i&&fo(i)]).forEach(n=>{n!==void 0&&(t+=(t.length?"&":"")+l,n!=null&&(t+="="+n))})}return t}function Dh(e){const t={};for(const l in e){const i=e[l];i!==void 0&&(t[l]=nt(i)?i.map(o=>o==null?null:""+o):i==null?i:""+i)}return t}const Fh=Symbol(""),qn=Symbol(""),Hi=Symbol(""),Yo=Symbol(""),go=Symbol("");function xl(){let e=[];function t(i){return e.push(i),()=>{const o=e.indexOf(i);o>-1&&e.splice(o,1)}}function l(){e=[]}return{add:t,list:()=>e.slice(),reset:l}}function Tt(e,t,l,i,o){const n=i&&(i.enterCallbacks[o]=i.enterCallbacks[o]||[]);return()=>new Promise((s,a)=>{const r=u=>{u===!1?a(pl(4,{from:l,to:t})):u instanceof Error?a(u):nh(u)?a(pl(2,{from:t,to:u})):(n&&i.enterCallbacks[o]===n&&typeof u=="function"&&n.push(u),s())},c=e.call(i&&i.instances[o],t,l,r);let d=Promise.resolve(c);e.length<3&&(d=d.then(r)),d.catch(u=>a(u))})}function Ji(e,t,l,i){const o=[];for(const n of e)for(const s in n.components){let a=n.components[s];if(!(t!=="beforeRouteEnter"&&!n.instances[s]))if(zh(a)){const c=(a.__vccOpts||a)[t];c&&o.push(Tt(c,l,i,n,s))}else{let r=a();o.push(()=>r.then(c=>{if(!c)return Promise.reject(new Error(`Couldn't resolve component "${s}" at "${n.path}"`));const d=jd(c)?c.default:c;n.components[s]=d;const m=(d.__vccOpts||d)[t];return m&&Tt(m,l,i,n,s)()}))}}return o}function zh(e){return typeof e=="object"||"displayName"in e||"props"in e||"__vccOpts"in e}function Gn(e){const t=Ce(Hi),l=Ce(Yo),i=B(()=>t.resolve(le(e.to))),o=B(()=>{const{matched:r}=i.value,{length:c}=r,d=r[c-1],u=l.matched;if(!d||!u.length)return-1;const m=u.findIndex(ml.bind(null,d));if(m>-1)return m;const g=Jn(r[c-2]);return c>1&&Jn(d)===g&&u[u.length-1].path!==g?u.findIndex(ml.bind(null,r[c-2])):m}),n=B(()=>o.value>-1&&Vh(l.params,i.value.params)),s=B(()=>o.value>-1&&o.value===l.matched.length-1&&xr(l.params,i.value.params));function a(r={}){return Mh(r)?t[le(e.replace)?"replace":"push"](le(e.to)).catch(Il):Promise.resolve()}return{route:i,href:B(()=>i.value.href),isActive:n,isExactActive:s,navigate:a}}const Sh=he({name:"RouterLink",compatConfig:{MODE:3},props:{to:{type:[String,Object],required:!0},replace:Boolean,activeClass:String,exactActiveClass:String,custom:Boolean,ariaCurrentValue:{type:String,default:"page"}},useLink:Gn,setup(e,{slots:t}){const l=jl(Gn(e)),{options:i}=Ce(Hi),o=B(()=>({[Zn(e.activeClass,i.linkActiveClass,"router-link-active")]:l.isActive,[Zn(e.exactActiveClass,i.linkExactActiveClass,"router-link-exact-active")]:l.isExactActive}));return()=>{const n=t.default&&t.default(l);return e.custom?n:ce("a",{"aria-current":l.isExactActive?e.ariaCurrentValue:null,href:l.href,onClick:l.navigate,class:o.value},n)}}}),Hh=Sh;function Mh(e){if(!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)&&!e.defaultPrevented&&!(e.button!==void 0&&e.button!==0)){if(e.currentTarget&&e.currentTarget.getAttribute){const t=e.currentTarget.getAttribute("target");if(/\b_blank\b/i.test(t))return}return e.preventDefault&&e.preventDefault(),!0}}function Vh(e,t){for(const l in t){const i=t[l],o=e[l];if(typeof i=="string"){if(i!==o)return!1}else if(!nt(o)||o.length!==i.length||i.some((n,s)=>n!==o[s]))return!1}return!0}function Jn(e){return e?e.aliasOf?e.aliasOf.path:e.path:""}const Zn=(e,t,l)=>e??t??l,Nh=he({name:"RouterView",inheritAttrs:!1,props:{name:{type:String,default:"default"},route:Object},compatConfig:{MODE:3},setup(e,{attrs:t,slots:l}){const i=Ce(go),o=B(()=>e.route||i.value),n=Ce(qn,0),s=B(()=>{let c=le(n);const{matched:d}=o.value;let u;for(;(u=d[c])&&!u.components;)c++;return c}),a=B(()=>o.value.matched[s.value]);Wt(qn,B(()=>s.value+1)),Wt(Fh,a),Wt(go,o);const r=ke();return Ge(()=>[r.value,a.value,e.name],([c,d,u],[m,g,x])=>{d&&(d.instances[u]=c,g&&g!==d&&c&&c===m&&(d.leaveGuards.size||(d.leaveGuards=g.leaveGuards),d.updateGuards.size||(d.updateGuards=g.updateGuards))),c&&d&&(!g||!ml(d,g)||!m)&&(d.enterCallbacks[u]||[]).forEach(L=>L(c))},{flush:"post"}),()=>{const c=o.value,d=e.name,u=a.value,m=u&&u.components[d];if(!m)return Qn(l.default,{Component:m,route:c});const g=u.props[d],x=g?g===!0?c.params:typeof g=="function"?g(c):g:null,C=ce(m,ve({},x,t,{onVnodeUnmounted:I=>{I.component.isUnmounted&&(u.instances[d]=null)},ref:r}));return Qn(l.default,{Component:C,route:c})||C}}});function Qn(e,t){if(!e)return null;const l=e(t);return l.length===1?l[0]:l}const Or=Nh;function jh(e){const t=fh(e.routes,e),l=e.parseQuery||Oh,i=e.stringifyQuery||Kn,o=e.history,n=xl(),s=xl(),a=xl(),r=To(pt);let c=pt;ll&&e.scrollBehavior&&"scrollRestoration"in history&&(history.scrollRestoration="manual");const d=qi.bind(null,R=>""+R),u=qi.bind(null,wh),m=qi.bind(null,Ei);function g(R,U){let V,G;return Lr(R)?(V=t.getRecordMatcher(R),G=U):G=R,t.addRoute(G,V)}function x(R){const U=t.getRecordMatcher(R);U&&t.removeRoute(U)}function L(){return t.getRoutes().map(R=>R.record)}function C(R){return!!t.getRecordMatcher(R)}function I(R,U){if(U=ve({},U||r.value),typeof R=="string"){const v=Gi(l,R,U.path),E=t.resolve({path:v.path},U),A=o.createHref(v.fullPath);return ve(v,E,{params:m(E.params),hash:Ei(v.hash),redirectedFrom:void 0,href:A})}let V;if("path"in R)V=ve({},R,{path:Gi(l,R.path,U.path).path});else{const v=ve({},R.params);for(const E in v)v[E]==null&&delete v[E];V=ve({},R,{params:u(v)}),U.params=u(U.params)}const G=t.resolve(V,U),de=R.hash||"";G.params=d(m(G.params));const p=Yd(i,ve({},R,{hash:Ah(de),path:G.path})),f=o.createHref(p);return ve({fullPath:p,hash:de,query:i===Kn?Dh(R.query):R.query||{}},G,{redirectedFrom:void 0,href:f})}function T(R){return typeof R=="string"?Gi(l,R,r.value.path):ve({},R)}function _(R,U){if(c!==R)return pl(8,{from:U,to:R})}function y(R){return M(R)}function j(R){return y(ve(T(R),{replace:!0}))}function K(R){const U=R.matched[R.matched.length-1];if(U&&U.redirect){const{redirect:V}=U;let G=typeof V=="function"?V(R):V;return typeof G=="string"&&(G=G.includes("?")||G.includes("#")?G=T(G):{path:G},G.params={}),ve({query:R.query,hash:R.hash,params:"path"in G?{}:R.params},G)}}function M(R,U){const V=c=I(R),G=r.value,de=R.state,p=R.force,f=R.replace===!0,v=K(V);if(v)return M(ve(T(v),{state:typeof v=="object"?ve({},de,v.state):de,force:p,replace:f}),U||V);const E=V;E.redirectedFrom=U;let A;return!p&&Ud(i,G,V)&&(A=pl(16,{to:E,from:G}),Ye(G,G,!0,!1)),(A?Promise.resolve(A):O(E,G)).catch(w=>ut(w)?ut(w,2)?w:ze(w):W(w,E,G)).then(w=>{if(w){if(ut(w,2))return M(ve({replace:f},T(w.to),{state:typeof w.to=="object"?ve({},de,w.to.state):de,force:p}),U||E)}else w=P(E,G,!0,f,de);return X(E,G,w),w})}function b(R,U){const V=_(R,U);return V?Promise.reject(V):Promise.resolve()}function z(R){const U=xt.values().next().value;return U&&typeof U.runWithContext=="function"?U.runWithContext(R):R()}function O(R,U){let V;const[G,de,p]=$h(R,U);V=Ji(G.reverse(),"beforeRouteLeave",R,U);for(const v of G)v.leaveGuards.forEach(E=>{V.push(Tt(E,R,U))});const f=b.bind(null,R,U);return V.push(f),Fe(V).then(()=>{V=[];for(const v of n.list())V.push(Tt(v,R,U));return V.push(f),Fe(V)}).then(()=>{V=Ji(de,"beforeRouteUpdate",R,U);for(const v of de)v.updateGuards.forEach(E=>{V.push(Tt(E,R,U))});return V.push(f),Fe(V)}).then(()=>{V=[];for(const v of p)if(v.beforeEnter)if(nt(v.beforeEnter))for(const E of v.beforeEnter)V.push(Tt(E,R,U));else V.push(Tt(v.beforeEnter,R,U));return V.push(f),Fe(V)}).then(()=>(R.matched.forEach(v=>v.enterCallbacks={}),V=Ji(p,"beforeRouteEnter",R,U),V.push(f),Fe(V))).then(()=>{V=[];for(const v of s.list())V.push(Tt(v,R,U));return V.push(f),Fe(V)}).catch(v=>ut(v,8)?v:Promise.reject(v))}function X(R,U,V){a.list().forEach(G=>z(()=>G(R,U,V)))}function P(R,U,V,G,de){const p=_(R,U);if(p)return p;const f=U===pt,v=ll?history.state:{};V&&(G||f?o.replace(R.fullPath,ve({scroll:f&&v&&v.scroll},de)):o.push(R.fullPath,de)),r.value=R,Ye(R,U,V,f),ze()}let H;function ie(){H||(H=o.listen((R,U,V)=>{if(!st.listening)return;const G=I(R),de=K(G);if(de){M(ve(de,{replace:!0}),G).catch(Il);return}c=G;const p=r.value;ll&&Qd(Nn(p.fullPath,V.delta),Si()),O(G,p).catch(f=>ut(f,12)?f:ut(f,2)?(M(f.to,G).then(v=>{ut(v,20)&&!V.delta&&V.type===Hl.pop&&o.go(-1,!1)}).catch(Il),Promise.reject()):(V.delta&&o.go(-V.delta,!1),W(f,G,p))).then(f=>{f=f||P(G,p,!1),f&&(V.delta&&!ut(f,8)?o.go(-V.delta,!1):V.type===Hl.pop&&ut(f,20)&&o.go(-1,!1)),X(G,p,f)}).catch(Il)}))}let re=xl(),F=xl(),J;function W(R,U,V){ze(R);const G=F.list();return G.length?G.forEach(de=>de(R,U,V)):console.error(R),Promise.reject(R)}function De(){return J&&r.value!==pt?Promise.resolve():new Promise((R,U)=>{re.add([R,U])})}function ze(R){return J||(J=!R,ie(),re.list().forEach(([U,V])=>R?V(R):U()),re.reset()),R}function Ye(R,U,V,G){const{scrollBehavior:de}=e;if(!ll||!de)return Promise.resolve();const p=!V&&eh(Nn(R.fullPath,0))||(G||!V)&&history.state&&history.state.scroll||null;return Yl().then(()=>de(R,U,p)).then(f=>f&&Zd(f)).catch(f=>W(f,R,U))}const Me=R=>o.go(R);let yt;const xt=new Set,st={currentRoute:r,listening:!0,addRoute:g,removeRoute:x,hasRoute:C,getRoutes:L,resolve:I,options:e,push:y,replace:j,go:Me,back:()=>Me(-1),forward:()=>Me(1),beforeEach:n.add,beforeResolve:s.add,afterEach:a.add,onError:F.add,isReady:De,install(R){const U=this;R.component("RouterLink",Hh),R.component("RouterView",Or),R.config.globalProperties.$router=U,Object.defineProperty(R.config.globalProperties,"$route",{enumerable:!0,get:()=>le(r)}),ll&&!yt&&r.value===pt&&(yt=!0,y(o.location).catch(de=>{}));const V={};for(const de in pt)Object.defineProperty(V,de,{get:()=>r.value[de],enumerable:!0});R.provide(Hi,U),R.provide(Yo,Os(V)),R.provide(go,r);const G=R.unmount;xt.add(R),R.unmount=function(){xt.delete(R),xt.size<1&&(c=pt,H&&H(),H=null,r.value=pt,yt=!1,J=!1),G()}}};function Fe(R){return R.reduce((U,V)=>U.then(()=>z(V)),Promise.resolve())}return st}function $h(e,t){const l=[],i=[],o=[],n=Math.max(t.matched.length,e.matched.length);for(let s=0;s ml(c,a))?i.push(a):l.push(a));const r=e.matched[s];r&&(t.matched.find(c=>ml(c,r))||o.push(r))}return[l,i,o]}function Jt(){return Ce(Hi)}function Zt(){return Ce(Yo)}const Bh=({headerLinkSelector:e,headerAnchorSelector:t,delay:l,offset:i=5})=>{const o=Jt(),s=yr(()=>{var L,C;const a=Math.max(window.scrollY,document.documentElement.scrollTop,document.body.scrollTop);if(Math.abs(a-0)m.some(T=>T.hash===I.hash));for(let I=0;I =(((L=T.parentElement)==null?void 0:L.offsetTop)??0)-i,j=!_||a<(((C=_.parentElement)==null?void 0:C.offsetTop)??0)-i;if(!(y&&j))continue;const M=decodeURIComponent(o.currentRoute.value.hash),b=decodeURIComponent(T.hash);if(M===b)return;if(u){for(let z=I+1;z {window.addEventListener("scroll",s)}),Wl(()=>{window.removeEventListener("scroll",s)})},es=async(e,t)=>{const{scrollBehavior:l}=e.options;e.options.scrollBehavior=void 0,await e.replace({query:e.currentRoute.value.query,hash:t}).finally(()=>e.options.scrollBehavior=l)},Yh="a.sidebar-item",Uh=".header-anchor",Wh=300,Xh=5,Kh=St({setup(){Bh({headerLinkSelector:Yh,headerAnchorSelector:Uh,delay:Wh,offset:Xh})}}),ts=()=>window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0,qh=()=>window.scrollTo({top:0,behavior:"smooth"}),Gh=he({name:"BackToTop",setup(){const e=ke(0),t=B(()=>e.value>300),l=yr(()=>{e.value=ts()},100);Be(()=>{e.value=ts(),window.addEventListener("scroll",()=>l())});const i=ce("div",{class:"back-to-top",onClick:qh});return()=>ce(Xl,{name:"back-to-top"},()=>t.value?i:null)}}),Jh=St({rootComponents:[Gh]}),Zh=ce("svg",{class:"external-link-icon",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",focusable:"false",x:"0px",y:"0px",viewBox:"0 0 100 100",width:"15",height:"15"},[ce("path",{fill:"currentColor",d:"M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"}),ce("polygon",{fill:"currentColor",points:"45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"})]),Qh=he({name:"ExternalLinkIcon",props:{locales:{type:Object,required:!1,default:()=>({})}},setup(e){const t=ql(),l=B(()=>e.locales[t.value]??{openInNewWindow:"open in new window"});return()=>ce("span",[Zh,ce("span",{class:"external-link-icon-sr-only"},l.value.openInNewWindow)])}});var eu={"/en/":{openInNewWindow:"open in new window"},"/zh-cn/":{openInNewWindow:"在新窗口中打开"},"/":{openInNewWindow:"open in new window"}};const tu=eu,lu=St({enhance({app:e}){e.component("ExternalLinkIcon",ce(Qh,{locales:tu}))}});/*! medium-zoom 1.1.0 | MIT License | https://github.com/francoischalifour/medium-zoom */var Nt=Object.assign||function(e){for(var t=1;t 1&&arguments[1]!==void 0?arguments[1]:{},i=window.Promise||function(P){function H(){}P(H,H)},o=function(P){var H=P.target;if(H===z){x();return}_.indexOf(H)!==-1&&L({target:H})},n=function(){if(!(j||!b.original)){var P=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0;Math.abs(K-P)>M.scrollOffset&&setTimeout(x,150)}},s=function(P){var H=P.key||P.keyCode;(H==="Escape"||H==="Esc"||H===27)&&x()},a=function(){var P=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},H=P;if(P.background&&(z.style.background=P.background),P.container&&P.container instanceof Object&&(H.container=Nt({},M.container,P.container)),P.template){var ie=hi(P.template)?P.template:document.querySelector(P.template);H.template=ie}return M=Nt({},M,H),_.forEach(function(re){re.dispatchEvent(tl("medium-zoom:update",{detail:{zoom:O}}))}),O},r=function(){var P=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};return e(Nt({},M,P))},c=function(){for(var P=arguments.length,H=Array(P),ie=0;ie 0?H.reduce(function(F,J){return[].concat(F,is(J))},[]):_;return re.forEach(function(F){F.classList.remove("medium-zoom-image"),F.dispatchEvent(tl("medium-zoom:detach",{detail:{zoom:O}}))}),_=_.filter(function(F){return re.indexOf(F)===-1}),O},u=function(P,H){var ie=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{};return _.forEach(function(re){re.addEventListener("medium-zoom:"+P,H,ie)}),y.push({type:"medium-zoom:"+P,listener:H,options:ie}),O},m=function(P,H){var ie=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{};return _.forEach(function(re){re.removeEventListener("medium-zoom:"+P,H,ie)}),y=y.filter(function(re){return!(re.type==="medium-zoom:"+P&&re.listener.toString()===H.toString())}),O},g=function(){var P=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},H=P.target,ie=function(){var F={width:document.documentElement.clientWidth,height:document.documentElement.clientHeight,left:0,top:0,right:0,bottom:0},J=void 0,W=void 0;if(M.container)if(M.container instanceof Object)F=Nt({},F,M.container),J=F.width-F.left-F.right-M.margin*2,W=F.height-F.top-F.bottom-M.margin*2;else{var De=hi(M.container)?M.container:document.querySelector(M.container),ze=De.getBoundingClientRect(),Ye=ze.width,Me=ze.height,yt=ze.left,xt=ze.top;F=Nt({},F,{width:Ye,height:Me,left:yt,top:xt})}J=J||F.width-M.margin*2,W=W||F.height-M.margin*2;var st=b.zoomedHd||b.original,Fe=ls(st)?J:st.naturalWidth||J,R=ls(st)?W:st.naturalHeight||W,U=st.getBoundingClientRect(),V=U.top,G=U.left,de=U.width,p=U.height,f=Math.min(Math.max(de,Fe),J)/de,v=Math.min(Math.max(p,R),W)/p,E=Math.min(f,v),A=(-G+(J-de)/2+M.margin+F.left)/E,w=(-V+(W-p)/2+M.margin+F.top)/E,$="scale("+E+") translate3d("+A+"px, "+w+"px, 0)";b.zoomed.style.transform=$,b.zoomedHd&&(b.zoomedHd.style.transform=$)};return new i(function(re){if(H&&_.indexOf(H)===-1){re(O);return}var F=function Ye(){j=!1,b.zoomed.removeEventListener("transitionend",Ye),b.original.dispatchEvent(tl("medium-zoom:opened",{detail:{zoom:O}})),re(O)};if(b.zoomed){re(O);return}if(H)b.original=H;else if(_.length>0){var J=_;b.original=J[0]}else{re(O);return}if(b.original.dispatchEvent(tl("medium-zoom:open",{detail:{zoom:O}})),K=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0,j=!0,b.zoomed=nu(b.original),document.body.appendChild(z),M.template){var W=hi(M.template)?M.template:document.querySelector(M.template);b.template=document.createElement("div"),b.template.appendChild(W.content.cloneNode(!0)),document.body.appendChild(b.template)}if(b.original.parentElement&&b.original.parentElement.tagName==="PICTURE"&&b.original.currentSrc&&(b.zoomed.src=b.original.currentSrc),document.body.appendChild(b.zoomed),window.requestAnimationFrame(function(){document.body.classList.add("medium-zoom--opened")}),b.original.classList.add("medium-zoom-image--hidden"),b.zoomed.classList.add("medium-zoom-image--opened"),b.zoomed.addEventListener("click",x),b.zoomed.addEventListener("transitionend",F),b.original.getAttribute("data-zoom-src")){b.zoomedHd=b.zoomed.cloneNode(),b.zoomedHd.removeAttribute("srcset"),b.zoomedHd.removeAttribute("sizes"),b.zoomedHd.removeAttribute("loading"),b.zoomedHd.src=b.zoomed.getAttribute("data-zoom-src"),b.zoomedHd.onerror=function(){clearInterval(De),console.warn("Unable to reach the zoom image target "+b.zoomedHd.src),b.zoomedHd=null,ie()};var De=setInterval(function(){b.zoomedHd.complete&&(clearInterval(De),b.zoomedHd.classList.add("medium-zoom-image--opened"),b.zoomedHd.addEventListener("click",x),document.body.appendChild(b.zoomedHd),ie())},10)}else if(b.original.hasAttribute("srcset")){b.zoomedHd=b.zoomed.cloneNode(),b.zoomedHd.removeAttribute("sizes"),b.zoomedHd.removeAttribute("loading");var ze=b.zoomedHd.addEventListener("load",function(){b.zoomedHd.removeEventListener("load",ze),b.zoomedHd.classList.add("medium-zoom-image--opened"),b.zoomedHd.addEventListener("click",x),document.body.appendChild(b.zoomedHd),ie()})}else ie()})},x=function(){return new i(function(P){if(j||!b.original){P(O);return}var H=function ie(){b.original.classList.remove("medium-zoom-image--hidden"),document.body.removeChild(b.zoomed),b.zoomedHd&&document.body.removeChild(b.zoomedHd),document.body.removeChild(z),b.zoomed.classList.remove("medium-zoom-image--opened"),b.template&&document.body.removeChild(b.template),j=!1,b.zoomed.removeEventListener("transitionend",ie),b.original.dispatchEvent(tl("medium-zoom:closed",{detail:{zoom:O}})),b.original=null,b.zoomed=null,b.zoomedHd=null,b.template=null,P(O)};j=!0,document.body.classList.remove("medium-zoom--opened"),b.zoomed.style.transform="",b.zoomedHd&&(b.zoomedHd.style.transform=""),b.template&&(b.template.style.transition="opacity 150ms",b.template.style.opacity=0),b.original.dispatchEvent(tl("medium-zoom:close",{detail:{zoom:O}})),b.zoomed.addEventListener("transitionend",H)})},L=function(){var P=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},H=P.target;return b.original?x():g({target:H})},C=function(){return M},I=function(){return _},T=function(){return b.original},_=[],y=[],j=!1,K=0,M=l,b={original:null,zoomed:null,zoomedHd:null,template:null};Object.prototype.toString.call(t)==="[object Object]"?M=t:(t||typeof t=="string")&&c(t),M=Nt({margin:0,background:"#fff",scrollOffset:40,container:null,template:null},M);var z=ou(M.background);document.addEventListener("click",o),document.addEventListener("keyup",s),document.addEventListener("scroll",n),window.addEventListener("resize",x);var O={open:g,close:x,toggle:L,update:a,clone:r,attach:c,detach:d,on:u,off:m,getOptions:C,getImages:I,getZoomedImage:T};return O};function ru(e,t){t===void 0&&(t={});var l=t.insertAt;if(!(typeof document>"u")){var i=document.head||document.getElementsByTagName("head")[0],o=document.createElement("style");o.type="text/css",l==="top"&&i.firstChild?i.insertBefore(o,i.firstChild):i.appendChild(o),o.styleSheet?o.styleSheet.cssText=e:o.appendChild(document.createTextNode(e))}}var au=".medium-zoom-overlay{position:fixed;top:0;right:0;bottom:0;left:0;opacity:0;transition:opacity .3s;will-change:opacity}.medium-zoom--opened .medium-zoom-overlay{cursor:pointer;cursor:zoom-out;opacity:1}.medium-zoom-image{cursor:pointer;cursor:zoom-in;transition:transform .3s cubic-bezier(.2,0,.2,1)!important}.medium-zoom-image--hidden{visibility:hidden}.medium-zoom-image--opened{position:relative;cursor:pointer;cursor:zoom-out;will-change:transform}";ru(au);const cu=Symbol("mediumZoom");var du={};const hu=".theme-default-content > img, .theme-default-content :not(a) > img",uu=du,mu=300,pu=St({enhance({app:e,router:t}){const l=su(uu);l.refresh=(i=hu)=>{l.detach(),l.attach(i)},e.provide(cu,l),t.afterEach(()=>{setTimeout(()=>l.refresh(),mu)})}});/** + * NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress + * @license MIT + */const ue={settings:{minimum:.08,easing:"ease",speed:200,trickle:!0,trickleRate:.02,trickleSpeed:800,barSelector:'[role="bar"]',parent:"body",template:'
'},status:null,set:e=>{const t=ue.isStarted();e=Zi(e,ue.settings.minimum,1),ue.status=e===1?null:e;const l=ue.render(!t),i=l.querySelector(ue.settings.barSelector),o=ue.settings.speed,n=ue.settings.easing;return l.offsetWidth,fu(s=>{si(i,{transform:"translate3d("+os(e)+"%,0,0)",transition:"all "+o+"ms "+n}),e===1?(si(l,{transition:"none",opacity:"1"}),l.offsetWidth,setTimeout(function(){si(l,{transition:"all "+o+"ms linear",opacity:"0"}),setTimeout(function(){ue.remove(),s()},o)},o)):setTimeout(()=>s(),o)}),ue},isStarted:()=>typeof ue.status=="number",start:()=>{ue.status||ue.set(0);const e=()=>{setTimeout(()=>{ue.status&&(ue.trickle(),e())},ue.settings.trickleSpeed)};return ue.settings.trickle&&e(),ue},done:e=>!e&&!ue.status?ue:ue.inc(.3+.5*Math.random()).set(1),inc:e=>{let t=ue.status;return t?(typeof e!="number"&&(e=(1-t)*Zi(Math.random()*t,.1,.95)),t=Zi(t+e,0,.994),ue.set(t)):ue.start()},trickle:()=>ue.inc(Math.random()*ue.settings.trickleRate),render:e=>{if(ue.isRendered())return document.getElementById("nprogress");ns(document.documentElement,"nprogress-busy");const t=document.createElement("div");t.id="nprogress",t.innerHTML=ue.settings.template;const l=t.querySelector(ue.settings.barSelector),i=e?"-100":os(ue.status||0),o=document.querySelector(ue.settings.parent);return si(l,{transition:"all 0 linear",transform:"translate3d("+i+"%,0,0)"}),o!==document.body&&ns(o,"nprogress-custom-parent"),o==null||o.appendChild(t),t},remove:()=>{ss(document.documentElement,"nprogress-busy"),ss(document.querySelector(ue.settings.parent),"nprogress-custom-parent");const e=document.getElementById("nprogress");e&&gu(e)},isRendered:()=>!!document.getElementById("nprogress")},Zi=(e,t,l)=>el?l:e,os=e=>(-1+e)*100,fu=function(){const e=[];function t(){const l=e.shift();l&&l(t)}return function(l){e.push(l),e.length===1&&t()}}(),si=function(){const e=["Webkit","O","Moz","ms"],t={};function l(s){return s.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,function(a,r){return r.toUpperCase()})}function i(s){const a=document.body.style;if(s in a)return s;let r=e.length;const c=s.charAt(0).toUpperCase()+s.slice(1);let d;for(;r--;)if(d=e[r]+c,d in a)return d;return s}function o(s){return s=l(s),t[s]??(t[s]=i(s))}function n(s,a,r){a=o(a),s.style[a]=r}return function(s,a){for(const r in a){const c=a[r];c!==void 0&&Object.prototype.hasOwnProperty.call(a,r)&&n(s,r,c)}}}(),Dr=(e,t)=>(typeof e=="string"?e:Uo(e)).indexOf(" "+t+" ")>=0,ns=(e,t)=>{const l=Uo(e),i=l+t;Dr(l,t)||(e.className=i.substring(1))},ss=(e,t)=>{const l=Uo(e);if(!Dr(e,t))return;const i=l.replace(" "+t+" "," ");e.className=i.substring(1,i.length-1)},Uo=e=>(" "+(e.className||"")+" ").replace(/\s+/gi," "),gu=e=>{e&&e.parentNode&&e.parentNode.removeChild(e)},vu=()=>{Be(()=>{const e=Jt(),t=new Set;t.add(e.currentRoute.value.path),e.beforeEach(l=>{t.has(l.path)||ue.start()}),e.afterEach(l=>{t.add(l.path),ue.done()})})},ku=St({setup(){vu()}}),_u=JSON.parse(`{"logo":"/images/logo.png","repo":"https://github.com/HighCapable/YukiHookAPI","docsRepo":"https://github.com/HighCapable/YukiHookAPI","docsBranch":"master","docsDir":"docs-source/src","editLinkPattern":":repo/edit/:branch/:path","sidebar":{"/en/":[{"text":"Get Started","collapsible":true,"children":["/en/guide/home","/en/guide/supportive","/en/guide/knowledge","/en/guide/quick-start","/en/guide/example","/en/guide/move-to-new-api"]},{"text":"Configs","collapsible":true,"children":["/en/config/api-example","/en/config/api-exception","/en/config/xposed-using","/en/config/api-using","/en/config/move-to-api-1-2-x","/en/config/move-to-api-1-3-x","/en/config/r8-proguard"]},{"text":"Tools","collapsible":true,"children":["/en/tools/yukihookapi-projectbuilder"]},{"text":"API Document","collapsible":true,"children":["/en/api/home",{"text":"Public API ","collapsible":true,"children":["/en/api/public/com/highcapable/yukihookapi/YukiHookAPI","/en/api/public/com/highcapable/yukihookapi/hook/param/PackageParam","/en/api/public/com/highcapable/yukihookapi/hook/param/HookParam","/en/api/public/com/highcapable/yukihookapi/annotation/xposed/InjectYukiHookWithXposed","/en/api/public/com/highcapable/yukihookapi/hook/xposed/proxy/IYukiHookXposedInit","/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookPrefsBridge","/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/ui/ModulePreferenceFragment","/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData","/en/api/public/com/highcapable/yukihookapi/hook/xposed/channel/YukiHookDataChannel","/en/api/public/com/highcapable/yukihookapi/hook/xposed/channel/data/ChannelData","/en/api/public/com/highcapable/yukihookapi/hook/xposed/channel/priority/ChannelPriority","/en/api/public/com/highcapable/yukihookapi/hook/xposed/application/ModuleApplication","/en/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/base/ModuleAppActivity","/en/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/base/ModuleAppCompatActivity","/en/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/context/wrapper/ModuleContextThemeWrapper","/en/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/reference/ModuleClassLoader","/en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiModuleResources","/en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResources","/en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResForwarder","/en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/event/YukiXposedEvent","/en/api/public/com/highcapable/yukihookapi/hook/type/android/ComponentTypeFactory","/en/api/public/com/highcapable/yukihookapi/hook/type/android/GraphicsTypeFactory","/en/api/public/com/highcapable/yukihookapi/hook/type/android/ViewTypeFactory","/en/api/public/com/highcapable/yukihookapi/hook/type/java/VariableTypeFactory","/en/api/public/com/highcapable/yukihookapi/hook/type/defined/DefinedTypeFactory","/en/api/public/com/highcapable/yukihookapi/hook/log/YLog","/en/api/public/com/highcapable/yukihookapi/hook/log/data/YLogData","/en/api/public/com/highcapable/yukihookapi/hook/factory/ReflectionFactory","/en/api/public/com/highcapable/yukihookapi/hook/factory/YukiHookFactory","/en/api/public/com/highcapable/yukihookapi/hook/entity/YukiBaseHooker","/en/api/public/com/highcapable/yukihookapi/hook/core/api/compat/type/ExecutorType","/en/api/public/com/highcapable/yukihookapi/hook/core/api/priority/YukiHookPriority","/en/api/public/com/highcapable/yukihookapi/hook/core/YukiMemberHookCreator","/en/api/public/com/highcapable/yukihookapi/hook/core/YukiResourcesHookCreator","/en/api/public/com/highcapable/yukihookapi/hook/core/finder/members/MethodFinder","/en/api/public/com/highcapable/yukihookapi/hook/core/finder/members/ConstructorFinder","/en/api/public/com/highcapable/yukihookapi/hook/core/finder/members/FieldFinder","/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/DexClassFinder","/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/result/MemberRulesResult","/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/MemberRules","/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/FieldRules","/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/MethodRules","/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/ConstructorRules","/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/BaseFinder","/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/CountRules","/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/ModifierRules","/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/NameRules","/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/ObjectRules","/en/api/public/com/highcapable/yukihookapi/hook/bean/HookClass","/en/api/public/com/highcapable/yukihookapi/hook/bean/VariousClass","/en/api/public/com/highcapable/yukihookapi/hook/bean/CurrentClass","/en/api/public/com/highcapable/yukihookapi/hook/bean/GenericClass","/en/api/public/com/highcapable/yukihookapi/hook/bean/HookResources"]},{"text":"Special Features ","collapsible":true,"children":["/en/api/special-features/reflection","/en/api/special-features/logger","/en/api/special-features/xposed-storage","/en/api/special-features/xposed-channel","/en/api/special-features/host-lifecycle","/en/api/special-features/host-inject"]}]},{"text":"About","collapsible":true,"children":["/en/about/changelog","/en/about/future","/en/about/contacts","/en/about/about"]}],"/zh-cn/":[{"text":"入门","collapsible":true,"children":["/zh-cn/guide/home","/zh-cn/guide/supportive","/zh-cn/guide/knowledge","/zh-cn/guide/quick-start","/zh-cn/guide/example","/zh-cn/guide/move-to-new-api"]},{"text":"配置","collapsible":true,"children":["/zh-cn/config/api-example","/zh-cn/config/api-exception","/zh-cn/config/xposed-using","/zh-cn/config/api-using","/zh-cn/config/move-to-api-1-2-x","/zh-cn/config/move-to-api-1-3-x","/zh-cn/config/r8-proguard"]},{"text":"工具","collapsible":true,"children":["/zh-cn/tools/yukihookapi-projectbuilder"]},{"text":"API 文档","collapsible":true,"children":["/zh-cn/api/home",{"text":"Public API ","collapsible":true,"children":["/zh-cn/api/public/com/highcapable/yukihookapi/YukiHookAPI","/zh-cn/api/public/com/highcapable/yukihookapi/hook/param/PackageParam","/zh-cn/api/public/com/highcapable/yukihookapi/hook/param/HookParam","/zh-cn/api/public/com/highcapable/yukihookapi/annotation/xposed/InjectYukiHookWithXposed","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/proxy/IYukiHookXposedInit","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookPrefsBridge","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/ui/ModulePreferenceFragment","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/channel/YukiHookDataChannel","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/channel/data/ChannelData","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/channel/priority/ChannelPriority","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/application/ModuleApplication","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/base/ModuleAppActivity","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/base/ModuleAppCompatActivity","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/context/wrapper/ModuleContextThemeWrapper","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/reference/ModuleClassLoader","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiModuleResources","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResources","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResForwarder","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/event/YukiXposedEvent","/zh-cn/api/public/com/highcapable/yukihookapi/hook/type/android/ComponentTypeFactory","/zh-cn/api/public/com/highcapable/yukihookapi/hook/type/android/GraphicsTypeFactory","/zh-cn/api/public/com/highcapable/yukihookapi/hook/type/android/ViewTypeFactory","/zh-cn/api/public/com/highcapable/yukihookapi/hook/type/java/VariableTypeFactory","/zh-cn/api/public/com/highcapable/yukihookapi/hook/type/defined/DefinedTypeFactory","/zh-cn/api/public/com/highcapable/yukihookapi/hook/log/YLog","/zh-cn/api/public/com/highcapable/yukihookapi/hook/log/data/YLogData","/zh-cn/api/public/com/highcapable/yukihookapi/hook/factory/ReflectionFactory","/zh-cn/api/public/com/highcapable/yukihookapi/hook/factory/YukiHookFactory","/zh-cn/api/public/com/highcapable/yukihookapi/hook/entity/YukiBaseHooker","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/api/compat/type/ExecutorType","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/api/priority/YukiHookPriority","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/YukiMemberHookCreator","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/YukiResourcesHookCreator","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/members/MethodFinder","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/members/ConstructorFinder","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/members/FieldFinder","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/DexClassFinder","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/result/MemberRulesResult","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/MemberRules","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/FieldRules","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/MethodRules","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/ConstructorRules","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/base/BaseFinder","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/CountRules","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/ModifierRules","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/NameRules","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/ObjectRules","/zh-cn/api/public/com/highcapable/yukihookapi/hook/bean/HookClass","/zh-cn/api/public/com/highcapable/yukihookapi/hook/bean/VariousClass","/zh-cn/api/public/com/highcapable/yukihookapi/hook/bean/CurrentClass","/zh-cn/api/public/com/highcapable/yukihookapi/hook/bean/GenericClass","/zh-cn/api/public/com/highcapable/yukihookapi/hook/bean/HookResources"]},{"text":"特色功能 ","collapsible":true,"children":["/zh-cn/api/special-features/reflection","/zh-cn/api/special-features/logger","/zh-cn/api/special-features/xposed-storage","/zh-cn/api/special-features/xposed-channel","/zh-cn/api/special-features/host-lifecycle","/zh-cn/api/special-features/host-inject"]}]},{"text":"关于","collapsible":true,"children":["/zh-cn/about/changelog","/zh-cn/about/future","/zh-cn/about/contacts","/zh-cn/about/about"]}]},"sidebarDepth":2,"locales":{"/en/":{"navbar":[{"text":"Navigation","children":[{"text":"Get Started","children":[{"text":"Introduce","link":"/en/guide/home"},{"text":"Supportive","link":"/en/guide/supportive"},{"text":"Basic Knowledge","link":"/en/guide/knowledge"},{"text":"Quick Start","link":"/en/guide/quick-start"},{"text":"Usage Example","link":"/en/guide/example"},{"text":"Migrate from Other Hook APIs","link":"/en/guide/move-to-new-api"}]},{"text":"Configs","children":[{"text":"API Basic Configs","link":"/en/config/api-example"},{"text":"API Exception Handling","link":"/en/config/api-exception"},{"text":"Use as Xposed Module Configs","link":"/en/config/xposed-using"},{"text":"Use as Hook API Configs","link":"/en/config/api-using"},{"text":"Migrate to YukiHookAPI 1.2.x","link":"/en/config/move-to-api-1-2-x"},{"text":"Migrate to YukiHookAPI 1.3.x","link":"/en/config/move-to-api-1-3-x"},{"text":"R8 & Proguard Obfuscate","link":"/en/config/r8-proguard"}]},{"text":"Tools","children":[{"text":"YukiHookAPI Project Builder","link":"/en/tools/yukihookapi-projectbuilder"}]},{"text":"API Document","children":[{"text":"Document Introduction","link":"/en/api/home"},{"text":"Public API","link":"/en/api/public/com/highcapable/yukihookapi/YukiHookAPI","activeMatch":"/en/api/public/"},{"text":"Special Features","link":"/en/api/special-features/reflection","activeMatch":"/en/api/special-features/"}]},{"text":"About","children":[{"text":"Changelog","link":"/en/about/changelog"},{"text":"Looking for Future","link":"/en/about/future"},{"text":"Contact Us","link":"/en/about/contacts"},{"text":"About this Document","link":"/en/about/about"}]}]},{"text":"Contact Us","link":"/en/about/contacts"}],"selectLanguageText":"English (US)","selectLanguageName":"English","editLinkText":"Edit this page on GitHub","tip":"Tips","warning":"Notice","danger":"Pay Attention"},"/zh-cn/":{"navbar":[{"text":"导航","children":[{"text":"入门","children":[{"text":"介绍","link":"/zh-cn/guide/home"},{"text":"支持性","link":"/zh-cn/guide/supportive"},{"text":"基础知识","link":"/zh-cn/guide/knowledge"},{"text":"快速开始","link":"/zh-cn/guide/quick-start"},{"text":"用法示例","link":"/zh-cn/guide/example"},{"text":"从其它 Hook API 迁移","link":"/zh-cn/guide/move-to-new-api"}]},{"text":"配置","children":[{"text":"API 基本配置","link":"/zh-cn/config/api-example"},{"text":"API 异常处理","link":"/zh-cn/config/api-exception"},{"text":"作为 Xposed 模块使用的相关配置","link":"/zh-cn/config/xposed-using"},{"text":"作为 Hook API 使用的相关配置","link":"/zh-cn/config/api-using"},{"text":"迁移至 YukiHookAPI 1.2.x","link":"/zh-cn/config/move-to-api-1-2-x"},{"text":"迁移至 YukiHookAPI 1.3.x","link":"/zh-cn/config/move-to-api-1-3-x"},{"text":"R8 与 Proguard 混淆","link":"/zh-cn/config/r8-proguard"}]},{"text":"工具","children":[{"text":"YukiHookAPI 构建工具","link":"/zh-cn/tools/yukihookapi-projectbuilder"}]},{"text":"API 文档","children":[{"text":"文档介绍","link":"/zh-cn/api/home"},{"text":"Public API","link":"/zh-cn/api/public/com/highcapable/yukihookapi/YukiHookAPI","activeMatch":"/zh-cn/api/public/"},{"text":"特色功能","link":"/zh-cn/api/special-features/reflection","activeMatch":"/zh-cn/api/special-features/"}]},{"text":"关于","children":[{"text":"更新日志","link":"/zh-cn/about/changelog"},{"text":"展望未来","link":"/zh-cn/about/future"},{"text":"联系我们","link":"/zh-cn/about/contacts"},{"text":"关于此文档","link":"/zh-cn/about/about"}]}]},{"text":"联系我们","link":"/zh-cn/about/contacts"}],"selectLanguageText":"简体中文 (CN)","selectLanguageName":"简体中文","editLinkText":"在 GitHub 上编辑此页","notFound":["这里什么都没有","我们怎么到这来了?","这是一个 404 页面","看起来我们进入了错误的链接"],"backToHome":"回到首页","contributorsText":"贡献者","lastUpdatedText":"上次更新","tip":"小提示","warning":"注意","danger":"特别注意","openInNewWindow":"在新窗口中打开","toggleColorMode":"切换颜色模式"},"/":{"selectLanguageName":"English"}},"colorMode":"auto","colorModeSwitch":true,"navbar":[],"selectLanguageText":"Languages","selectLanguageAriaLabel":"Select language","editLink":true,"editLinkText":"Edit this page","lastUpdated":true,"lastUpdatedText":"Last Updated","contributors":true,"contributorsText":"Contributors","notFound":["There's nothing here.","How did we get here?","That's a Four-Oh-Four.","Looks like we've got some broken links."],"backToHome":"Take me home","openInNewWindow":"open in new window","toggleColorMode":"toggle color mode","toggleSidebar":"toggle sidebar"}`),bu=ke(_u),Fr=()=>bu,zr=Symbol(""),yu=()=>{const e=Ce(zr);if(!e)throw new Error("useThemeLocaleData() is called without provider.");return e},xu=(e,t)=>{const{locales:l,...i}=e;return{...i,...l==null?void 0:l[t]}},Eu=St({enhance({app:e}){const t=Fr(),l=e._context.provides[Vo],i=B(()=>xu(t.value,l.value));e.provide(zr,i),Object.defineProperties(e.config.globalProperties,{$theme:{get(){return t.value}},$themeLocale:{get(){return i.value}}})}}),Lu=he({__name:"Badge",props:{type:{type:String,required:!1,default:"tip"},text:{type:String,required:!1,default:""},vertical:{type:String,required:!1,default:void 0}},setup(e){return(t,l)=>(Y(),te("span",{class:We(["badge",e.type]),style:Nl({verticalAlign:e.vertical})},[ye(t.$slots,"default",{},()=>[zt(we(e.text),1)])],6))}}),Pe=(e,t)=>{const l=e.__vccOpts||e;for(const[i,o]of t)l[i]=o;return l},Pu=Pe(Lu,[["__file","Badge.vue"]]);function rs(e,t){var l;const i=To();return Bs(()=>{i.value=e()},{...t,flush:(l=void 0)!=null?l:"sync"}),$l(i)}function Ru(e,t){let l,i,o;const n=ke(!0),s=()=>{n.value=!0,o()};Ge(e,s,{flush:"sync"});const a=typeof t=="function"?t:t.get,r=typeof t=="function"?void 0:t.set,c=za((d,u)=>(i=d,o=u,{get(){return n.value&&(l=a(),n.value=!1),i(),l},set(m){r==null||r(m)}}));return Object.isExtensible(c)&&(c.trigger=s),c}function Sr(e){return ys()?(da(e),!0):!1}function fl(e){return typeof e=="function"?e():le(e)}const Cu=typeof window<"u"&&typeof document<"u";typeof WorkerGlobalScope<"u"&&globalThis instanceof WorkerGlobalScope;const Au=Object.prototype.toString,Tu=e=>Au.call(e)==="[object Object]",Iu=()=>{};function wu(e,t){function l(...i){return new Promise((o,n)=>{Promise.resolve(e(()=>t.apply(this,i),{fn:t,thisArg:this,args:i})).then(o).catch(n)})}return l}const Hr=e=>e();function Ou(e=Hr){const t=ke(!0);function l(){t.value=!1}function i(){t.value=!0}const o=(...n)=>{t.value&&e(...n)};return{isActive:$l(t),pause:l,resume:i,eventFilter:o}}function Du(e){return zo()}function Fu(e,t,l={}){const{eventFilter:i=Hr,...o}=l;return Ge(e,wu(i,t),o)}function zu(e,t,l={}){const{eventFilter:i,...o}=l,{eventFilter:n,pause:s,resume:a,isActive:r}=Ou(i);return{stop:Fu(e,t,{...o,eventFilter:n}),pause:s,resume:a,isActive:r}}function Su(e,t=!0,l){const i=Du();i?Be(e,i):t?e():Yl(e)}function Hu(e=!1,t={}){const{truthyValue:l=!0,falsyValue:i=!1}=t,o=Ne(e),n=ke(e);function s(a){if(arguments.length)return n.value=a,n.value;{const r=fl(l);return n.value=n.value===r?fl(i):r,n.value}}return o?s:[n,s]}function Mu(e){var t;const l=fl(e);return(t=l==null?void 0:l.$el)!=null?t:l}const Li=Cu?window:void 0;function as(...e){let t,l,i,o;if(typeof e[0]=="string"||Array.isArray(e[0])?([l,i,o]=e,t=Li):[t,l,i,o]=e,!t)return Iu;Array.isArray(l)||(l=[l]),Array.isArray(i)||(i=[i]);const n=[],s=()=>{n.forEach(d=>d()),n.length=0},a=(d,u,m,g)=>(d.addEventListener(u,m,g),()=>d.removeEventListener(u,m,g)),r=Ge(()=>[Mu(t),fl(o)],([d,u])=>{if(s(),!d)return;const m=Tu(u)?{...u}:u;n.push(...l.flatMap(g=>i.map(x=>a(d,g,x,m))))},{immediate:!0,flush:"post"}),c=()=>{r(),s()};return Sr(c),c}function Vu(){const e=ke(!1);return zo()&&Be(()=>{e.value=!0}),e}function Nu(e){const t=Vu();return B(()=>(t.value,!!e()))}function ju(e,t={}){const{window:l=Li}=t,i=Nu(()=>l&&"matchMedia"in l&&typeof l.matchMedia=="function");let o;const n=ke(!1),s=c=>{n.value=c.matches},a=()=>{o&&("removeEventListener"in o?o.removeEventListener("change",s):o.removeListener(s))},r=Bs(()=>{i.value&&(a(),o=l.matchMedia(fl(e)),"addEventListener"in o?o.addEventListener("change",s):o.addListener(s),n.value=o.matches)});return Sr(()=>{r(),a(),o=void 0}),n}const ri=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{},ai="__vueuse_ssr_handlers__",$u=Bu();function Bu(){return ai in ri||(ri[ai]=ri[ai]||{}),ri[ai]}function Yu(e,t){return $u[e]||t}function Uu(e){return e==null?"any":e instanceof Set?"set":e instanceof Map?"map":e instanceof Date?"date":typeof e=="boolean"?"boolean":typeof e=="string"?"string":typeof e=="object"?"object":Number.isNaN(e)?"any":"number"}const Wu={boolean:{read:e=>e==="true",write:e=>String(e)},object:{read:e=>JSON.parse(e),write:e=>JSON.stringify(e)},number:{read:e=>Number.parseFloat(e),write:e=>String(e)},any:{read:e=>e,write:e=>String(e)},string:{read:e=>e,write:e=>String(e)},map:{read:e=>new Map(JSON.parse(e)),write:e=>JSON.stringify(Array.from(e.entries()))},set:{read:e=>new Set(JSON.parse(e)),write:e=>JSON.stringify(Array.from(e))},date:{read:e=>new Date(e),write:e=>e.toISOString()}},cs="vueuse-storage";function Mr(e,t,l,i={}){var o;const{flush:n="pre",deep:s=!0,listenToStorageChanges:a=!0,writeDefaults:r=!0,mergeDefaults:c=!1,shallow:d,window:u=Li,eventFilter:m,onError:g=z=>{console.error(z)},initOnMounted:x}=i,L=(d?To:ke)(typeof t=="function"?t():t);if(!l)try{l=Yu("getDefaultStorage",()=>{var z;return(z=Li)==null?void 0:z.localStorage})()}catch(z){g(z)}if(!l)return L;const C=fl(t),I=Uu(C),T=(o=i.serializer)!=null?o:Wu[I],{pause:_,resume:y}=zu(L,()=>j(L.value),{flush:n,deep:s,eventFilter:m});return u&&a&&Su(()=>{as(u,"storage",b),as(u,cs,M),x&&b()}),x||b(),L;function j(z){try{if(z==null)l.removeItem(e);else{const O=T.write(z),X=l.getItem(e);X!==O&&(l.setItem(e,O),u&&u.dispatchEvent(new CustomEvent(cs,{detail:{key:e,oldValue:X,newValue:O,storageArea:l}})))}}catch(O){g(O)}}function K(z){const O=z?z.newValue:l.getItem(e);if(O==null)return r&&C!=null&&l.setItem(e,T.write(C)),C;if(!z&&c){const X=T.read(O);return typeof c=="function"?c(X,C):I==="object"&&!Array.isArray(X)?{...C,...X}:X}else return typeof O!="string"?O:T.read(O)}function M(z){b(z.detail)}function b(z){if(!(z&&z.storageArea!==l)){if(z&&z.key==null){L.value=C;return}if(!(z&&z.key!==e)){_();try{(z==null?void 0:z.newValue)!==T.write(L.value)&&(L.value=K(z))}catch(O){g(O)}finally{z?Yl(y):y()}}}}}function Xu(e){return ju("(prefers-color-scheme: dark)",e)}const Ku=he({name:"CodeGroup",slots:Object,setup(e,{slots:t}){const l=ke([]),i=ke(-1),o=Mr("vuepress-code-group",{}),n=B(()=>l.value.map(c=>c.innerText).join(","));Be(()=>{Ge(()=>o.value[n.value],(c=-1)=>{i.value!==c&&(i.value=c)},{immediate:!0}),Ge(i,c=>{o.value[n.value]!==c&&(o.value[n.value]=c)})});const s=(c=i.value)=>{c {c>0?i.value=c-1:i.value=l.value.length-1,l.value[i.value].focus()},r=(c,d)=>{c.key===" "||c.key==="Enter"?(c.preventDefault(),i.value=d):c.key==="ArrowRight"?(c.preventDefault(),s(d)):c.key==="ArrowLeft"&&(c.preventDefault(),a(d))};return()=>{var d;const c=(((d=t.default)==null?void 0:d.call(t))||[]).filter(u=>u.type.name==="CodeGroupItem").map(u=>(u.props===null&&(u.props={}),u));return c.length===0?null:(i.value<0||i.value>c.length-1?(i.value=c.findIndex(u=>u.props.active===""||u.props.active===!0),i.value===-1&&(i.value=0)):c.forEach((u,m)=>{u.props.active=m===i.value}),ce("div",{class:"code-group"},[ce("div",{class:"code-group__nav"},ce("ul",{class:"code-group__ul"},c.map((u,m)=>{const g=m===i.value;return ce("li",{class:"code-group__li"},ce("button",{ref:x=>{x&&(l.value[m]=x)},class:{"code-group__nav-tab":!0,"code-group__nav-tab-active":g},ariaPressed:g,ariaExpanded:g,onClick:()=>i.value=m,onKeydown:x=>r(x,m)},u.props.title))}))),c]))}}}),qu=["aria-selected"],Gu=he({name:"CodeGroupItem"}),Ju=he({...Gu,props:{title:{type:String,required:!0},active:{type:Boolean,required:!1,default:!1}},setup(e){return(t,l)=>(Y(),te("div",{class:We(["code-group-item",{"code-group-item__active":e.active}]),"aria-selected":e.active},[ye(t.$slots,"default")],10,qu))}}),Zu=Pe(Ju,[["__file","CodeGroupItem.vue"]]),Qu=()=>Fr(),$e=()=>yu(),Vr=Symbol(""),Wo=()=>{const e=Ce(Vr);if(!e)throw new Error("useDarkMode() is called without provider.");return e},em=()=>{const e=$e(),t=Xu(),l=Mr("vuepress-color-scheme",e.value.colorMode),i=B({get(){return e.value.colorModeSwitch?l.value==="auto"?t.value:l.value==="dark":e.value.colorMode==="dark"},set(o){o===t.value?l.value="auto":l.value=o?"dark":"light"}});Wt(Vr,i),tm(i)},tm=e=>{const t=(l=e.value)=>{const i=window==null?void 0:window.document.querySelector("html");i==null||i.classList.toggle("dark",l)};Be(()=>{Ge(e,t,{immediate:!0})}),Di(()=>t())},Nr=(...e)=>{const l=Jt().resolve(...e),i=l.matched[l.matched.length-1];if(!(i!=null&&i.redirect))return l;const{redirect:o}=i,n=se(o)?o(l):o,s=ge(n)?{path:n}:n;return Nr({hash:l.hash,query:l.query,params:l.params,...s})},Xo=e=>{const t=Nr(encodeURI(e));return{text:t.meta.title||e,link:t.name==="404"?e:t.fullPath}};let Qi=null,El=null;const lm={wait:()=>Qi,pending:()=>{Qi=new Promise(e=>El=e)},resolve:()=>{El==null||El(),Qi=null,El=null}},jr=()=>lm,$r=Symbol("sidebarItems"),Ko=()=>{const e=Ce($r);if(!e)throw new Error("useSidebarItems() is called without provider.");return e},im=()=>{const e=$e(),t=vt(),l=B(()=>om(t.value,e.value));Wt($r,l)},om=(e,t)=>{const l=e.sidebar??t.sidebar??"auto",i=e.sidebarDepth??t.sidebarDepth??2;return e.home||l===!1?[]:l==="auto"?sm(i):ee(l)?Br(l,i):Mo(l)?rm(l,i):[]},nm=(e,t)=>({text:e.title,link:e.link,children:qo(e.children,t)}),qo=(e,t)=>t>0?e.map(l=>nm(l,t-1)):[],sm=e=>{const t=Kt();return[{text:t.value.title,children:qo(t.value.headers,e)}]},Br=(e,t)=>{const l=Zt(),i=Kt(),o=n=>{var a;let s;if(ge(n)?s=Xo(n):s=n,s.children)return{...s,children:s.children.map(r=>o(r))};if(s.link===l.path){const r=((a=i.value.headers[0])==null?void 0:a.level)===1?i.value.headers[0].children:i.value.headers;return{...s,children:qo(r,t)}}return s};return e.map(n=>o(n))},rm=(e,t)=>{const l=Zt(),i=ur(e,l.path),o=e[i]??[];return Br(o,t)},am="719px",cm={mobile:am};var Ml;(function(e){e.MOBILE="mobile"})(Ml||(Ml={}));var ps;const dm={[Ml.MOBILE]:Number.parseInt((ps=cm.mobile)==null?void 0:ps.replace("px",""),10)},Yr=(e,t)=>{const l=dm[e];Number.isInteger(l)&&Be(()=>{t(l),window.addEventListener("resize",()=>t(l),!1),window.addEventListener("orientationchange",()=>t(l),!1)})},hm={},um={class:"theme-default-content"};function mm(e,t){const l=_t("Content");return Y(),te("div",um,[oe(l)])}const pm=Pe(hm,[["render",mm],["__file","HomeContent.vue"]]),fm={key:0,class:"features"},gm=he({__name:"HomeFeatures",setup(e){const t=vt(),l=B(()=>ee(t.value.features)?t.value.features:[]);return(i,o)=>l.value.length?(Y(),te("div",fm,[(Y(!0),te(xe,null,Dt(l.value,n=>(Y(),te("div",{key:n.title,class:"feature"},[pe("h2",null,we(n.title),1),pe("p",null,we(n.details),1)]))),128))])):Re("v-if",!0)}}),vm=Pe(gm,[["__file","HomeFeatures.vue"]]),km=["innerHTML"],_m=["textContent"],bm=he({__name:"HomeFooter",setup(e){const t=vt(),l=B(()=>t.value.footer),i=B(()=>t.value.footerHtml);return(o,n)=>l.value?(Y(),te(xe,{key:0},[Re(" eslint-disable-next-line vue/no-v-html "),i.value?(Y(),te("div",{key:0,class:"footer",innerHTML:l.value},null,8,km)):(Y(),te("div",{key:1,class:"footer",textContent:we(l.value)},null,8,_m))],64)):Re("v-if",!0)}}),ym=Pe(bm,[["__file","HomeFooter.vue"]]),xm=["href","rel","target","aria-label"],Em=he({inheritAttrs:!1}),Lm=he({...Em,__name:"AutoLink",props:{item:{type:Object,required:!0}},setup(e){const t=e,l=Zt(),i=_r(),{item:o}=Ti(t),n=B(()=>Kl(o.value.link)),s=B(()=>!n.value&&Td(o.value.link)),a=B(()=>{if(!s.value){if(o.value.target)return o.value.target;if(n.value)return"_blank"}}),r=B(()=>a.value==="_blank"),c=B(()=>!n.value&&!s.value&&!r.value),d=B(()=>{if(!s.value){if(o.value.rel)return o.value.rel;if(r.value)return"noopener noreferrer"}}),u=B(()=>o.value.ariaLabel||o.value.text),m=B(()=>{const L=Object.keys(i.value.locales);return L.length?!L.some(C=>C===o.value.link):o.value.link!=="/"}),g=B(()=>m.value?l.path.startsWith(o.value.link):!1),x=B(()=>c.value?o.value.activeMatch?new RegExp(o.value.activeMatch).test(l.path):g.value:!1);return(L,C)=>{const I=_t("RouterLink"),T=_t("AutoLinkExternalIcon");return c.value?(Y(),Te(I,uo({key:0,class:{"router-link-active":x.value},to:le(o).link,"aria-label":u.value},L.$attrs),{default:Se(()=>[ye(L.$slots,"before"),zt(" "+we(le(o).text)+" ",1),ye(L.$slots,"after")]),_:3},16,["class","to","aria-label"])):(Y(),te("a",uo({key:1,class:"external-link",href:le(o).link,rel:d.value,target:a.value,"aria-label":u.value},L.$attrs),[ye(L.$slots,"before"),zt(" "+we(le(o).text)+" ",1),r.value?(Y(),Te(T,{key:0})):Re("v-if",!0),ye(L.$slots,"after")],16,xm))}}}),kt=Pe(Lm,[["__file","AutoLink.vue"]]),Pm={class:"hero"},Rm={key:0,id:"main-title"},Cm={key:1,class:"description"},Am={key:2,class:"actions"},Tm=he({__name:"HomeHero",setup(e){const t=vt(),l=No(),i=Wo(),o=B(()=>i.value&&t.value.heroImageDark!==void 0?t.value.heroImageDark:t.value.heroImage),n=B(()=>t.value.heroAlt||a.value||"hero"),s=B(()=>t.value.heroHeight||280),a=B(()=>t.value.heroText===null?null:t.value.heroText||l.value.title||"Hello"),r=B(()=>t.value.tagline===null?null:t.value.tagline||l.value.description||"Welcome to your VuePress site"),c=B(()=>ee(t.value.actions)?t.value.actions.map(({text:u,link:m,type:g="primary"})=>({text:u,link:m,type:g})):[]),d=()=>{if(!o.value)return null;const u=ce("img",{src:$o(o.value),alt:n.value,height:s.value});return t.value.heroImageDark===void 0?u:ce(jo,()=>u)};return(u,m)=>(Y(),te("header",Pm,[oe(d),a.value?(Y(),te("h1",Rm,we(a.value),1)):Re("v-if",!0),r.value?(Y(),te("p",Cm,we(r.value),1)):Re("v-if",!0),c.value.length?(Y(),te("p",Am,[(Y(!0),te(xe,null,Dt(c.value,g=>(Y(),Te(kt,{key:g.text,class:We(["action-button",[g.type]]),item:g},null,8,["class","item"]))),128))])):Re("v-if",!0)]))}}),Im=Pe(Tm,[["__file","HomeHero.vue"]]),wm={class:"home"},Om=he({__name:"Home",setup(e){return(t,l)=>(Y(),te("main",wm,[oe(Im),oe(vm),oe(pm),oe(ym)]))}}),Dm=Pe(Om,[["__file","Home.vue"]]),Fm=he({__name:"NavbarBrand",setup(e){const t=ql(),l=No(),i=$e(),o=Wo(),n=B(()=>i.value.home||t.value),s=B(()=>l.value.title),a=B(()=>o.value&&i.value.logoDark!==void 0?i.value.logoDark:i.value.logo),r=()=>{if(!a.value)return null;const c=ce("img",{class:"logo",src:$o(a.value),alt:s.value});return i.value.logoDark===void 0?c:ce(jo,()=>c)};return(c,d)=>{const u=_t("RouterLink");return Y(),Te(u,{to:n.value},{default:Se(()=>[oe(r),s.value?(Y(),te("span",{key:0,class:We(["site-name",{"can-hide":a.value}])},we(s.value),3)):Re("v-if",!0)]),_:1},8,["to"])}}}),zm=Pe(Fm,[["__file","NavbarBrand.vue"]]),Sm=he({__name:"DropdownTransition",setup(e){const t=i=>{i.style.height=i.scrollHeight+"px"},l=i=>{i.style.height=""};return(i,o)=>(Y(),Te(Xl,{name:"dropdown",onEnter:t,onAfterEnter:l,onBeforeLeave:t},{default:Se(()=>[ye(i.$slots,"default")]),_:3}))}}),Ur=Pe(Sm,[["__file","DropdownTransition.vue"]]),Hm=["aria-label"],Mm={class:"title"},Vm=pe("span",{class:"arrow down"},null,-1),Nm=["aria-label"],jm={class:"title"},$m={class:"navbar-dropdown"},Bm={class:"navbar-dropdown-subtitle"},Ym={key:1},Um={class:"navbar-dropdown-subitem-wrapper"},Wm=he({__name:"NavbarDropdown",props:{item:{type:Object,required:!0}},setup(e){const t=e,{item:l}=Ti(t),i=B(()=>l.value.ariaLabel||l.value.text),o=ke(!1),n=Zt();Ge(()=>n.path,()=>{o.value=!1});const s=r=>{r.detail===0?o.value=!o.value:o.value=!1},a=(r,c)=>c[c.length-1]===r;return(r,c)=>(Y(),te("div",{class:We(["navbar-dropdown-wrapper",{open:o.value}])},[pe("button",{class:"navbar-dropdown-title",type:"button","aria-label":i.value,onClick:s},[pe("span",Mm,we(le(l).text),1),Vm],8,Hm),pe("button",{class:"navbar-dropdown-title-mobile",type:"button","aria-label":i.value,onClick:c[0]||(c[0]=d=>o.value=!o.value)},[pe("span",jm,we(le(l).text),1),pe("span",{class:We(["arrow",o.value?"down":"right"])},null,2)],8,Nm),oe(Ur,null,{default:Se(()=>[vi(pe("ul",$m,[(Y(!0),te(xe,null,Dt(le(l).children,d=>(Y(),te("li",{key:d.text,class:"navbar-dropdown-item"},[d.children?(Y(),te(xe,{key:0},[pe("h4",Bm,[d.link?(Y(),Te(kt,{key:0,item:d,onFocusout:u=>a(d,le(l).children)&&d.children.length===0&&(o.value=!1)},null,8,["item","onFocusout"])):(Y(),te("span",Ym,we(d.text),1))]),pe("ul",Um,[(Y(!0),te(xe,null,Dt(d.children,u=>(Y(),te("li",{key:u.link,class:"navbar-dropdown-subitem"},[oe(kt,{item:u,onFocusout:m=>a(u,d.children)&&a(d,le(l).children)&&(o.value=!1)},null,8,["item","onFocusout"])]))),128))])],64)):(Y(),Te(kt,{key:1,item:d,onFocusout:u=>a(d,le(l).children)&&(o.value=!1)},null,8,["item","onFocusout"]))]))),128))],512),[[xi,o.value]])]),_:1})],2))}}),Xm=Pe(Wm,[["__file","NavbarDropdown.vue"]]),ds=e=>decodeURI(e).replace(/#.*$/,"").replace(/(index)?\.(md|html)$/,""),Km=(e,t)=>{if(t.hash===e)return!0;const l=ds(t.path),i=ds(e);return l===i},Wr=(e,t)=>e.link&&Km(e.link,t)?!0:e.children?e.children.some(l=>Wr(l,t)):!1,Xr=e=>!Kl(e)||/github\.com/.test(e)?"GitHub":/bitbucket\.org/.test(e)?"Bitbucket":/gitlab\.com/.test(e)?"GitLab":/gitee\.com/.test(e)?"Gitee":null,qm={GitHub:":repo/edit/:branch/:path",GitLab:":repo/-/edit/:branch/:path",Gitee:":repo/edit/:branch/:path",Bitbucket:":repo/src/:branch/:path?mode=edit&spa=0&at=:branch&fileviewer=file-view-default"},Gm=({docsRepo:e,editLinkPattern:t})=>{if(t)return t;const l=Xr(e);return l!==null?qm[l]:null},Jm=({docsRepo:e,docsBranch:t,docsDir:l,filePathRelative:i,editLinkPattern:o})=>{if(!i)return null;const n=Gm({docsRepo:e,editLinkPattern:o});return n?n.replace(/:repo/,Kl(e)?e:`https://github.com/${e}`).replace(/:branch/,t).replace(/:path/,hr(`${dr(l)}/${i}`)):null},Zm={key:0,class:"navbar-items"},Qm=he({__name:"NavbarItems",setup(e){const t=()=>{const d=Jt(),u=ql(),m=_r(),g=No(),x=Qu(),L=$e();return B(()=>{const C=Object.keys(m.value.locales);if(C.length<2)return[];const I=d.currentRoute.value.path,T=d.currentRoute.value.fullPath;return[{text:`${L.value.selectLanguageText}`,ariaLabel:`${L.value.selectLanguageAriaLabel??L.value.selectLanguageText}`,children:C.map(y=>{var O,X;const j=((O=m.value.locales)==null?void 0:O[y])??{},K=((X=x.value.locales)==null?void 0:X[y])??{},M=`${j.lang}`,b=K.selectLanguageName??M;let z;if(M===g.value.lang)z=T;else{const P=I.replace(u.value,y);d.getRoutes().some(H=>H.path===P)?z=T.replace(I,P):z=K.home??y}return{text:b,link:z}})}]})},l=()=>{const d=$e(),u=B(()=>d.value.repo),m=B(()=>u.value?Xr(u.value):null),g=B(()=>u.value&&!Kl(u.value)?`https://github.com/${u.value}`:u.value),x=B(()=>g.value?d.value.repoLabel?d.value.repoLabel:m.value===null?"Source":m.value:null);return B(()=>!g.value||!x.value?[]:[{text:x.value,link:g.value}])},i=d=>ge(d)?Xo(d):d.children?{...d,children:d.children.map(i)}:d,o=()=>{const d=$e();return B(()=>(d.value.navbar||[]).map(i))},n=ke(!1),s=o(),a=t(),r=l(),c=B(()=>[...s.value,...a.value,...r.value]);return Yr(Ml.MOBILE,d=>{window.innerWidth c.value.length?(Y(),te("nav",Zm,[(Y(!0),te(xe,null,Dt(c.value,m=>(Y(),te("div",{key:m.text,class:"navbar-item"},[m.children?(Y(),Te(Xm,{key:0,item:m,class:We(n.value?"mobile":"")},null,8,["item","class"])):(Y(),Te(kt,{key:1,item:m},null,8,["item"]))]))),128))])):Re("v-if",!0)}}),Kr=Pe(Qm,[["__file","NavbarItems.vue"]]),ep=["title"],tp={class:"icon",focusable:"false",viewBox:"0 0 32 32"},lp=zc(' ',9),ip=[lp],op={class:"icon",focusable:"false",viewBox:"0 0 32 32"},np=pe("path",{d:"M13.502 5.414a15.075 15.075 0 0 0 11.594 18.194a11.113 11.113 0 0 1-7.975 3.39c-.138 0-.278.005-.418 0a11.094 11.094 0 0 1-3.2-21.584M14.98 3a1.002 1.002 0 0 0-.175.016a13.096 13.096 0 0 0 1.825 25.981c.164.006.328 0 .49 0a13.072 13.072 0 0 0 10.703-5.555a1.01 1.01 0 0 0-.783-1.565A13.08 13.08 0 0 1 15.89 4.38A1.015 1.015 0 0 0 14.98 3z",fill:"currentColor"},null,-1),sp=[np],rp=he({__name:"ToggleColorModeButton",setup(e){const t=$e(),l=Wo(),i=()=>{l.value=!l.value};return(o,n)=>(Y(),te("button",{class:"toggle-color-mode-button",title:le(t).toggleColorMode,onClick:i},[vi((Y(),te("svg",tp,ip,512)),[[xi,!le(l)]]),vi((Y(),te("svg",op,sp,512)),[[xi,le(l)]])],8,ep))}}),ap=Pe(rp,[["__file","ToggleColorModeButton.vue"]]),cp=["title"],dp=pe("div",{class:"icon","aria-hidden":"true"},[pe("span"),pe("span"),pe("span")],-1),hp=[dp],up=he({__name:"ToggleSidebarButton",emits:["toggle"],setup(e){const t=$e();return(l,i)=>(Y(),te("div",{class:"toggle-sidebar-button",title:le(t).toggleSidebar,"aria-expanded":"false",role:"button",tabindex:"0",onClick:i[0]||(i[0]=o=>l.$emit("toggle"))},hp,8,cp))}}),mp=Pe(up,[["__file","ToggleSidebarButton.vue"]]),pp=he({__name:"Navbar",emits:["toggle-sidebar"],setup(e){const t=$e(),l=ke(null),i=ke(null),o=ke(0),n=B(()=>o.value?{maxWidth:o.value+"px"}:{});Yr(Ml.MOBILE,a=>{var c;const r=s(l.value,"paddingLeft")+s(l.value,"paddingRight");window.innerWidth{const c=_t("NavbarSearch");return Y(),te("header",{ref_key:"navbar",ref:l,class:"navbar"},[oe(mp,{onToggle:r[0]||(r[0]=d=>a.$emit("toggle-sidebar"))}),pe("span",{ref_key:"navbarBrand",ref:i},[oe(zm)],512),pe("div",{class:"navbar-items-wrapper",style:Nl(n.value)},[ye(a.$slots,"before"),oe(Kr,{class:"can-hide"}),ye(a.$slots,"after"),le(t).colorModeSwitch?(Y(),Te(ap,{key:0})):Re("v-if",!0),oe(c)],4)],512)}}}),fp=Pe(pp,[["__file","Navbar.vue"]]),gp={class:"page-meta"},vp={key:0,class:"meta-item edit-link"},kp={key:1,class:"meta-item last-updated"},_p={class:"meta-item-label"},bp={class:"meta-item-info"},yp={key:2,class:"meta-item contributors"},xp={class:"meta-item-label"},Ep={class:"meta-item-info"},Lp=["title"],Pp=he({__name:"PageMeta",setup(e){const t=()=>{const r=$e(),c=Kt(),d=vt();return B(()=>{if(!(d.value.editLink??r.value.editLink??!0))return null;const{repo:m,docsRepo:g=m,docsBranch:x="main",docsDir:L="",editLinkText:C}=r.value;if(!g)return null;const I=Jm({docsRepo:g,docsBranch:x,docsDir:L,filePathRelative:c.value.filePathRelative,editLinkPattern:d.value.editLinkPattern??r.value.editLinkPattern});return I?{text:C??"Edit this page",link:I}:null})},l=()=>{const r=$e(),c=Kt(),d=vt();return B(()=>{var g,x;return!(d.value.lastUpdated??r.value.lastUpdated??!0)||!((g=c.value.git)!=null&&g.updatedTime)?null:new Date((x=c.value.git)==null?void 0:x.updatedTime).toLocaleString()})},i=()=>{const r=$e(),c=Kt(),d=vt();return B(()=>{var m;return d.value.contributors??r.value.contributors??!0?((m=c.value.git)==null?void 0:m.contributors)??null:null})},o=$e(),n=t(),s=l(),a=i();return(r,c)=>{const d=_t("ClientOnly");return Y(),te("footer",gp,[le(n)?(Y(),te("div",vp,[oe(kt,{class:"meta-item-label",item:le(n)},null,8,["item"])])):Re("v-if",!0),le(s)?(Y(),te("div",kp,[pe("span",_p,we(le(o).lastUpdatedText)+": ",1),oe(d,null,{default:Se(()=>[pe("span",bp,we(le(s)),1)]),_:1})])):Re("v-if",!0),le(a)&&le(a).length?(Y(),te("div",yp,[pe("span",xp,we(le(o).contributorsText)+": ",1),pe("span",Ep,[(Y(!0),te(xe,null,Dt(le(a),(u,m)=>(Y(),te(xe,{key:m},[pe("span",{class:"contributor",title:`email: ${u.email}`},we(u.name),9,Lp),m!==le(a).length-1?(Y(),te(xe,{key:0},[zt(", ")],64)):Re("v-if",!0)],64))),128))])])):Re("v-if",!0)])}}}),Rp=Pe(Pp,[["__file","PageMeta.vue"]]),Cp={key:0,class:"page-nav"},Ap={class:"inner"},Tp={key:0,class:"prev"},Ip={key:1,class:"next"},wp=he({__name:"PageNav",setup(e){const t=r=>r===!1?null:ge(r)?Xo(r):Mo(r)?r:!1,l=(r,c,d)=>{const u=r.findIndex(m=>m.link===c);if(u!==-1){const m=r[u+d];return m!=null&&m.link?m:null}for(const m of r)if(m.children){const g=l(m.children,c,d);if(g)return g}return null},i=vt(),o=Ko(),n=Zt(),s=B(()=>{const r=t(i.value.prev);return r!==!1?r:l(o.value,n.path,-1)}),a=B(()=>{const r=t(i.value.next);return r!==!1?r:l(o.value,n.path,1)});return(r,c)=>s.value||a.value?(Y(),te("nav",Cp,[pe("p",Ap,[s.value?(Y(),te("span",Tp,[oe(kt,{item:s.value},null,8,["item"])])):Re("v-if",!0),a.value?(Y(),te("span",Ip,[oe(kt,{item:a.value},null,8,["item"])])):Re("v-if",!0)])])):Re("v-if",!0)}}),Op=Pe(wp,[["__file","PageNav.vue"]]),Dp={class:"page"},Fp={class:"theme-default-content"},zp=he({__name:"Page",setup(e){return(t,l)=>{const i=_t("Content");return Y(),te("main",Dp,[ye(t.$slots,"top"),pe("div",Fp,[ye(t.$slots,"content-top"),oe(i),ye(t.$slots,"content-bottom")]),oe(Rp),oe(Op),ye(t.$slots,"bottom")])}}}),Sp=Pe(zp,[["__file","Page.vue"]]),Hp={class:"sidebar-item-children"},Mp=he({__name:"SidebarItem",props:{item:{type:Object,required:!0},depth:{type:Number,required:!1,default:0}},setup(e){const t=e,{item:l,depth:i}=Ti(t),o=Zt(),n=Jt(),s=B(()=>Wr(l.value,o)),a=B(()=>({"sidebar-item":!0,"sidebar-heading":i.value===0,active:s.value,collapsible:l.value.collapsible})),r=B(()=>l.value.collapsible?s.value:!0),[c,d]=Hu(r.value),u=g=>{l.value.collapsible&&(g.preventDefault(),d())},m=n.afterEach(g=>{Yl(()=>{c.value=r.value})});return Wl(()=>{m()}),(g,x)=>{var C;const L=_t("SidebarItem",!0);return Y(),te("li",null,[le(l).link?(Y(),Te(kt,{key:0,class:We(a.value),item:le(l)},null,8,["class","item"])):(Y(),te("p",{key:1,tabindex:"0",class:We(a.value),onClick:u,onKeydown:kd(u,["enter"])},[zt(we(le(l).text)+" ",1),le(l).collapsible?(Y(),te("span",{key:0,class:We(["arrow",le(c)?"down":"right"])},null,2)):Re("v-if",!0)],34)),(C=le(l).children)!=null&&C.length?(Y(),Te(Ur,{key:2},{default:Se(()=>[vi(pe("ul",Hp,[(Y(!0),te(xe,null,Dt(le(l).children,I=>(Y(),Te(L,{key:`${le(i)}${I.text}${I.link}`,item:I,depth:le(i)+1},null,8,["item","depth"]))),128))],512),[[xi,le(c)]])]),_:1})):Re("v-if",!0)])}}}),Vp=Pe(Mp,[["__file","SidebarItem.vue"]]),Np={key:0,class:"sidebar-items"},jp=he({__name:"SidebarItems",setup(e){const t=Zt(),l=Ko();return Be(()=>{Ge(()=>t.hash,i=>{const o=document.querySelector(".sidebar");if(!o)return;const n=document.querySelector(`.sidebar a.sidebar-item[href="${t.path}${i}"]`);if(!n)return;const{top:s,height:a}=o.getBoundingClientRect(),{top:r,height:c}=n.getBoundingClientRect();r s+a&&n.scrollIntoView(!1)})}),(i,o)=>le(l).length?(Y(),te("ul",Np,[(Y(!0),te(xe,null,Dt(le(l),n=>(Y(),Te(Vp,{key:`${n.text}${n.link}`,item:n},null,8,["item"]))),128))])):Re("v-if",!0)}}),$p=Pe(jp,[["__file","SidebarItems.vue"]]),Bp={class:"sidebar"},Yp=he({__name:"Sidebar",setup(e){return(t,l)=>(Y(),te("aside",Bp,[oe(Kr),ye(t.$slots,"top"),oe($p),ye(t.$slots,"bottom")]))}}),Up=Pe(Yp,[["__file","Sidebar.vue"]]),Wp=he({__name:"Layout",setup(e){const t=Kt(),l=vt(),i=$e(),o=B(()=>l.value.navbar!==!1&&i.value.navbar!==!1),n=Ko(),s=ke(!1),a=C=>{s.value=typeof C=="boolean"?C:!s.value},r={x:0,y:0},c=C=>{r.x=C.changedTouches[0].clientX,r.y=C.changedTouches[0].clientY},d=C=>{const I=C.changedTouches[0].clientX-r.x,T=C.changedTouches[0].clientY-r.y;Math.abs(I)>Math.abs(T)&&Math.abs(I)>40&&(I>0&&r.x<=80?a(!0):a(!1))},u=B(()=>[{"no-navbar":!o.value,"no-sidebar":!n.value.length,"sidebar-open":s.value},l.value.pageClass]);let m;Be(()=>{m=Jt().afterEach(()=>{a(!1)})}),Di(()=>{m()});const g=jr(),x=g.resolve,L=g.pending;return(C,I)=>(Y(),te("div",{class:We(["theme-container",u.value]),onTouchstart:c,onTouchend:d},[ye(C.$slots,"navbar",{},()=>[o.value?(Y(),Te(fp,{key:0,onToggleSidebar:a},{before:Se(()=>[ye(C.$slots,"navbar-before")]),after:Se(()=>[ye(C.$slots,"navbar-after")]),_:3})):Re("v-if",!0)]),pe("div",{class:"sidebar-mask",onClick:I[0]||(I[0]=T=>a(!1))}),ye(C.$slots,"sidebar",{},()=>[oe(Up,null,{top:Se(()=>[ye(C.$slots,"sidebar-top")]),bottom:Se(()=>[ye(C.$slots,"sidebar-bottom")]),_:3})]),ye(C.$slots,"page",{},()=>[le(l).home?(Y(),Te(Dm,{key:0})):(Y(),Te(Xl,{key:1,name:"fade-slide-y",mode:"out-in",onBeforeEnter:le(x),onBeforeLeave:le(L)},{default:Se(()=>[(Y(),Te(Sp,{key:le(t).path},{top:Se(()=>[ye(C.$slots,"page-top")]),"content-top":Se(()=>[ye(C.$slots,"page-content-top")]),"content-bottom":Se(()=>[ye(C.$slots,"page-content-bottom")]),bottom:Se(()=>[ye(C.$slots,"page-bottom")]),_:3}))]),_:3},8,["onBeforeEnter","onBeforeLeave"]))])],34))}}),Xp=Pe(Wp,[["__file","Layout.vue"]]),Kp={class:"theme-container"},qp={class:"page"},Gp={class:"theme-default-content"},Jp=pe("h1",null,"404",-1),Zp=he({__name:"NotFound",setup(e){const t=ql(),l=$e(),i=l.value.notFound??["Not Found"],o=()=>i[Math.floor(Math.random()*i.length)],n=l.value.home??t.value,s=l.value.backToHome??"Back to home";return(a,r)=>{const c=_t("RouterLink");return Y(),te("div",Kp,[pe("main",qp,[pe("div",Gp,[Jp,pe("blockquote",null,we(o()),1),oe(c,{to:le(n)},{default:Se(()=>[zt(we(le(s)),1)]),_:1},8,["to"])])])])}}}),Qp=Pe(Zp,[["__file","NotFound.vue"]]),ef=St({enhance({app:e,router:t}){e.component("Badge",Pu),e.component("CodeGroup",Ku),e.component("CodeGroupItem",Zu),e.component("AutoLinkExternalIcon",()=>{const i=e.component("ExternalLinkIcon");return i?ce(i):null}),e.component("NavbarSearch",()=>{const i=e.component("Docsearch")||e.component("SearchBox");return i?ce(i):null});const l=t.options.scrollBehavior;t.options.scrollBehavior=async(...i)=>(await jr().wait(),l(...i))},setup(){em(),im()},layouts:{Layout:Xp,NotFound:Qp}}),tf=e=>e instanceof Element?document.activeElement===e&&(["TEXTAREA","SELECT","INPUT"].includes(e.tagName)||e.hasAttribute("contenteditable")):!1,lf=(e,t)=>t.some(l=>{if(ge(l))return l===e.key;const{key:i,ctrl:o=!1,shift:n=!1,alt:s=!1}=l;return i===e.key&&o===e.ctrlKey&&n===e.shiftKey&&s===e.altKey}),of=/[^\x00-\x7F]/,nf=e=>e.split(/\s+/g).map(t=>t.trim()).filter(t=>!!t),hs=e=>e.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"),us=(e,t)=>{const l=t.join(" "),i=nf(e);if(of.test(e))return i.some(s=>l.toLowerCase().indexOf(s)>-1);const o=e.endsWith(" ");return new RegExp(i.map((s,a)=>i.length===a+1&&!o?`(?=.*\\b${hs(s)})`:`(?=.*\\b${hs(s)}\\b)`).join("")+".+","gi").test(l)},sf=({input:e,hotKeys:t})=>{if(t.value.length===0)return;const l=i=>{e.value&&lf(i,t.value)&&!tf(i.target)&&(i.preventDefault(),e.value.focus())};Be(()=>{document.addEventListener("keydown",l)}),Wl(()=>{document.removeEventListener("keydown",l)})},rf=[{title:"Home",headers:[{level:3,title:"All Hook process in one step, everything is simplified",slug:"all-hook-process-in-one-step-everything-is-simplified",link:"#all-hook-process-in-one-step-everything-is-simplified",children:[]}],path:"/en/",pathLocale:"/en/",extraFields:[]},{title:"首页",headers:[{level:3,title:"所有 Hook 流程一步到位,拒绝繁琐",slug:"所有-hook-流程一步到位-拒绝繁琐",link:"#所有-hook-流程一步到位-拒绝繁琐",children:[]}],path:"/zh-cn/",pathLocale:"/zh-cn/",extraFields:[]},{title:"About This Document",headers:[{level:2,title:"License",slug:"license",link:"#license",children:[]}],path:"/en/about/about.html",pathLocale:"/en/",extraFields:[]},{title:"Changelog",headers:[{level:3,title:"1.3.0 | 2024.06.25",slug:"_1-3-0-2024-06-25",link:"#_1-3-0-2024-06-25",children:[]},{level:3,title:"1.2.1 | 2024.06.20",slug:"_1-2-1-2024-06-20",link:"#_1-2-1-2024-06-20",children:[]},{level:3,title:"1.2.0 | 2023.10.07",slug:"_1-2-0-2023-10-07",link:"#_1-2-0-2023-10-07",children:[]},{level:3,title:"1.1.11 | 2023.04.25",slug:"_1-1-11-2023-04-25",link:"#_1-1-11-2023-04-25",children:[]},{level:3,title:"1.1.10 | 2023.04.21",slug:"_1-1-10-2023-04-21",link:"#_1-1-10-2023-04-21",children:[]},{level:3,title:"1.1.9 | 2023.04.17",slug:"_1-1-9-2023-04-17",link:"#_1-1-9-2023-04-17",children:[]},{level:3,title:"1.1.8 | 2023.02.01",slug:"_1-1-8-2023-02-01",link:"#_1-1-8-2023-02-01",children:[]},{level:3,title:"1.1.6 | 2023.01.21",slug:"_1-1-6-2023-01-21",link:"#_1-1-6-2023-01-21",children:[]},{level:3,title:"1.1.5 | 2023.01.13",slug:"_1-1-5-2023-01-13",link:"#_1-1-5-2023-01-13",children:[]},{level:3,title:"1.1.4 | 2022.10.04",slug:"_1-1-4-2022-10-04",link:"#_1-1-4-2022-10-04",children:[]},{level:3,title:"1.1.3 | 2022.09.30",slug:"_1-1-3-2022-09-30",link:"#_1-1-3-2022-09-30",children:[]},{level:3,title:"1.1.2 | 2022.09.30",slug:"_1-1-2-2022-09-30",link:"#_1-1-2-2022-09-30",children:[]},{level:3,title:"1.1.1 | 2022.09.28",slug:"_1-1-1-2022-09-28",link:"#_1-1-1-2022-09-28",children:[]},{level:3,title:"1.1.0 | 2022.09.28",slug:"_1-1-0-2022-09-28",link:"#_1-1-0-2022-09-28",children:[]},{level:3,title:"1.0.92 | 2022.05.31",slug:"_1-0-92-2022-05-31",link:"#_1-0-92-2022-05-31",children:[]},{level:3,title:"1.0.91 | 2022.05.29",slug:"_1-0-91-2022-05-29",link:"#_1-0-91-2022-05-29",children:[]},{level:3,title:"1.0.90 | 2022.05.27",slug:"_1-0-90-2022-05-27",link:"#_1-0-90-2022-05-27",children:[]},{level:3,title:"1.0.89 | 2022.05.26",slug:"_1-0-89-2022-05-26",link:"#_1-0-89-2022-05-26",children:[]},{level:3,title:"1.0.88 | 2022.05.25",slug:"_1-0-88-2022-05-25",link:"#_1-0-88-2022-05-25",children:[]},{level:3,title:"1.0.87 | 2022.05.10",slug:"_1-0-87-2022-05-10",link:"#_1-0-87-2022-05-10",children:[]},{level:3,title:"1.0.86 | 2022.05.06",slug:"_1-0-86-2022-05-06",link:"#_1-0-86-2022-05-06",children:[]},{level:3,title:"1.0.85 | 2022.05.04",slug:"_1-0-85-2022-05-04",link:"#_1-0-85-2022-05-04",children:[]},{level:3,title:"1.0.83 | 2022.05.04",slug:"_1-0-83-2022-05-04",link:"#_1-0-83-2022-05-04",children:[]},{level:3,title:"1.0.82 | 2022.05.04",slug:"_1-0-82-2022-05-04",link:"#_1-0-82-2022-05-04",children:[]},{level:3,title:"1.0.81 | 2022.05.04",slug:"_1-0-81-2022-05-04",link:"#_1-0-81-2022-05-04",children:[]},{level:3,title:"1.0.80 | 2022.05.01",slug:"_1-0-80-2022-05-01",link:"#_1-0-80-2022-05-01",children:[]},{level:3,title:"1.0.78 | 2022.04.18",slug:"_1-0-78-2022-04-18",link:"#_1-0-78-2022-04-18",children:[]},{level:3,title:"1.0.77 | 2022.04.15",slug:"_1-0-77-2022-04-15",link:"#_1-0-77-2022-04-15",children:[]},{level:3,title:"1.0.75 | 2022.04.13",slug:"_1-0-75-2022-04-13",link:"#_1-0-75-2022-04-13",children:[]},{level:3,title:"1.0.73 | 2022.04.10",slug:"_1-0-73-2022-04-10",link:"#_1-0-73-2022-04-10",children:[]},{level:3,title:"1.0.72 | 2022.04.09",slug:"_1-0-72-2022-04-09",link:"#_1-0-72-2022-04-09",children:[]},{level:3,title:"1.0.71 | 2022.04.04",slug:"_1-0-71-2022-04-04",link:"#_1-0-71-2022-04-04",children:[]},{level:3,title:"1.0.70 | 2022.04.04",slug:"_1-0-70-2022-04-04",link:"#_1-0-70-2022-04-04",children:[]},{level:3,title:"1.0.69 | 2022.03.30",slug:"_1-0-69-2022-03-30",link:"#_1-0-69-2022-03-30",children:[]},{level:3,title:"1.0.68 | 2022.03.29",slug:"_1-0-68-2022-03-29",link:"#_1-0-68-2022-03-29",children:[]},{level:3,title:"1.0.67 | 2022.03.27",slug:"_1-0-67-2022-03-27",link:"#_1-0-67-2022-03-27",children:[]},{level:3,title:"1.0.66 | 2022.03.25",slug:"_1-0-66-2022-03-25",link:"#_1-0-66-2022-03-25",children:[]},{level:3,title:"1.0.65 | 2022.03.25",slug:"_1-0-65-2022-03-25",link:"#_1-0-65-2022-03-25",children:[]},{level:3,title:"1.0.6 | 2022.03.20",slug:"_1-0-6-2022-03-20",link:"#_1-0-6-2022-03-20",children:[]},{level:3,title:"1.0.55 | 2022.03.18",slug:"_1-0-55-2022-03-18",link:"#_1-0-55-2022-03-18",children:[]},{level:3,title:"1.0.5 | 2022.03.18",slug:"_1-0-5-2022-03-18",link:"#_1-0-5-2022-03-18",children:[]},{level:3,title:"1.0.4 | 2022.03.06",slug:"_1-0-4-2022-03-06",link:"#_1-0-4-2022-03-06",children:[]},{level:3,title:"1.0.3 | 2022.03.02",slug:"_1-0-3-2022-03-02",link:"#_1-0-3-2022-03-02",children:[]},{level:3,title:"1.0.2 | 2022.02.18",slug:"_1-0-2-2022-02-18",link:"#_1-0-2-2022-02-18",children:[]},{level:3,title:"1.0.1 | 2022.02.15",slug:"_1-0-1-2022-02-15",link:"#_1-0-1-2022-02-15",children:[]},{level:3,title:"1.0 | 2022.02.14",slug:"_1-0-2022-02-14",link:"#_1-0-2022-02-14",children:[]}],path:"/en/about/changelog.html",pathLocale:"/en/",extraFields:[]},{title:"Contact Us",headers:[{level:2,title:"Help with Maintenance",slug:"help-with-maintenance",link:"#help-with-maintenance",children:[]}],path:"/en/about/contacts.html",pathLocale:"/en/",extraFields:[]},{title:"Looking Toward the Future",headers:[{level:2,title:"Unresolved Issues",slug:"unresolved-issues",link:"#unresolved-issues",children:[{level:3,title:"YukiHookPrefsBridge",slug:"yukihookprefsbridge",link:"#yukihookprefsbridge",children:[]}]},{level:2,title:"Future Plans",slug:"future-plans",link:"#future-plans",children:[{level:3,title:"Lite Version Supported for Standalone Use",slug:"lite-version-supported-for-standalone-use",link:"#lite-version-supported-for-standalone-use",children:[]},{level:3,title:"Milestone Plan",slug:"milestone-plan",link:"#milestone-plan",children:[]}]}],path:"/en/about/future.html",pathLocale:"/en/",extraFields:[]},{title:"Document Introduce",headers:[{level:2,title:"Function Description",slug:"function-description",link:"#function-description",children:[]},{level:2,title:"Function Example Description",slug:"function-example-description",link:"#function-example-description",children:[]},{level:2,title:"Change Record Description",slug:"change-record-description",link:"#change-record-description",children:[]},{level:2,title:"Related Symbols Description",slug:"related-symbols-description",link:"#related-symbols-description",children:[]}],path:"/en/api/home.html",pathLocale:"/en/",extraFields:[]},{title:"API Basic Configs",headers:[{level:2,title:"Function Configs",slug:"function-configs",link:"#function-configs",children:[{level:3,title:"configs Method",slug:"configs-method",link:"#configs-method",children:[]}]},{level:2,title:"Hooker Configs",slug:"hooker-configs",link:"#hooker-configs",children:[{level:3,title:"Created by lambda",slug:"created-by-lambda",link:"#created-by-lambda",children:[]},{level:3,title:"Created by Custom Hooker",slug:"created-by-custom-hooker",link:"#created-by-custom-hooker",children:[]},{level:3,title:"Expansion Features",slug:"expansion-features",link:"#expansion-features",children:[]},{level:3,title:"Precautions",slug:"precautions",link:"#precautions",children:[]}]},{level:2,title:"Precautions when using as Hook API",slug:"precautions-when-using-as-hook-api",link:"#precautions-when-using-as-hook-api",children:[]}],path:"/en/config/api-example.html",pathLocale:"/en/",extraFields:[]},{title:"API Exception Handling",headers:[{level:2,title:"Non-Blocking Exceptions",slug:"non-blocking-exceptions",link:"#non-blocking-exceptions",children:[]},{level:2,title:"Blocking Exceptions",slug:"blocking-exceptions",link:"#blocking-exceptions",children:[]}],path:"/en/config/api-exception.html",pathLocale:"/en/",extraFields:[]},{title:"Use as Hook API Configs",headers:[{level:2,title:"Dependency Configs",slug:"dependency-configs",link:"#dependency-configs",children:[]},{level:2,title:"Entry Configs",slug:"entry-configs",link:"#entry-configs",children:[]},{level:2,title:"Hook Framework",slug:"hook-framework",link:"#hook-framework",children:[{level:3,title:"Pine",slug:"pine",link:"#pine",children:[]},{level:3,title:"SandHook",slug:"sandhook",link:"#sandhook",children:[]},{level:3,title:"Whale",slug:"whale",link:"#whale",children:[]}]}],path:"/en/config/api-using.html",pathLocale:"/en/",extraFields:[]},{title:"Migrate to YukiHookAPI 1.2.x",headers:[{level:2,title:"Default Behavior Changes",slug:"default-behavior-changes",link:"#default-behavior-changes",children:[]},{level:2,title:"New API",slug:"new-api",link:"#new-api",children:[]},{level:2,title:"Differential Functions",slug:"differential-functions",link:"#differential-functions",children:[{level:3,title:"New Multi-Hook Usage",slug:"new-multi-hook-usage",link:"#new-multi-hook-usage",children:[]},{level:3,title:"New allMembers(...) Usage",slug:"new-allmembers-usage",link:"#new-allmembers-usage",children:[]}]}],path:"/en/config/move-to-api-1-2-x.html",pathLocale:"/en/",extraFields:[]},{title:"Migrate to YukiHookAPI 1.3.x",headers:[{level:2,title:"Self-reflection API Deprecated",slug:"self-reflection-api-deprecated",link:"#self-reflection-api-deprecated",children:[]},{level:2,title:"FreeReflection Deprecated",slug:"freereflection-deprecated",link:"#freereflection-deprecated",children:[]},{level:2,title:"Original Method Call",slug:"original-method-call",link:"#original-method-call",children:[]},{level:2,title:"Repeat Hook Restricted Deprecated",slug:"repeat-hook-restricted-deprecated",link:"#repeat-hook-restricted-deprecated",children:[]},{level:2,title:"Register Module App's Activity Behavior Change",slug:"register-module-app-s-activity-behavior-change",link:"#register-module-app-s-activity-behavior-change",children:[]},{level:2,title:"YLog Behavior Change",slug:"ylog-behavior-change",link:"#ylog-behavior-change",children:[]}],path:"/en/config/move-to-api-1-3-x.html",pathLocale:"/en/",extraFields:[]},{title:"R8 & Proguard Obfuscate",headers:[{level:2,title:"R8",slug:"r8",link:"#r8",children:[]},{level:2,title:"Proguard",slug:"proguard",link:"#proguard",children:[]}],path:"/en/config/r8-proguard.html",pathLocale:"/en/",extraFields:[]},{title:"Use as Xposed Module Configs",headers:[{level:2,title:"Dependency Configs",slug:"dependency-configs",link:"#dependency-configs",children:[]},{level:2,title:"Custom Automatic Builder",slug:"custom-automatic-builder",link:"#custom-automatic-builder",children:[{level:3,title:"InjectYukiHookWithXposed Annotation",slug:"injectyukihookwithxposed-annotation",link:"#injectyukihookwithxposed-annotation",children:[]},{level:3,title:"IYukiHookXposedInit Interface",slug:"iyukihookxposedinit-interface",link:"#iyukihookxposedinit-interface",children:[]}]},{level:2,title:"Native Xposed API Events",slug:"native-xposed-api-events",link:"#native-xposed-api-events",children:[]}],path:"/en/config/xposed-using.html",pathLocale:"/en/",extraFields:[]},{title:"Usage Example",headers:[{level:2,title:"Structure Diagram",slug:"structure-diagram",link:"#structure-diagram",children:[]},{level:2,title:"Demo",slug:"demo",link:"#demo",children:[]},{level:2,title:"A Simple Hook Example",slug:"a-simple-hook-example",link:"#a-simple-hook-example",children:[{level:3,title:"Hook App",slug:"hook-app",link:"#hook-app",children:[]},{level:3,title:"Hook Zygote",slug:"hook-zygote",link:"#hook-zygote",children:[]},{level:3,title:"Hook System Framework",slug:"hook-system-framework",link:"#hook-system-framework",children:[]},{level:3,title:"Hook Resources",slug:"hook-resources",link:"#hook-resources",children:[]},{level:3,title:"Remove Hook",slug:"remove-hook",link:"#remove-hook",children:[]}]},{level:2,title:"Exception Handling",slug:"exception-handling",link:"#exception-handling",children:[{level:3,title:"Listen for Exceptions",slug:"listen-for-exceptions",link:"#listen-for-exceptions",children:[]},{level:3,title:"Throw an Exception",slug:"throw-an-exception",link:"#throw-an-exception",children:[]}]},{level:2,title:"Expansion Usage",slug:"expansion-usage",link:"#expansion-usage",children:[{level:3,title:"Multiple Hosts",slug:"multiple-hosts",link:"#multiple-hosts",children:[]},{level:3,title:"Multiple Processes",slug:"multiple-processes",link:"#multiple-processes",children:[]}]},{level:2,title:"Writing Optimization",slug:"writing-optimization",link:"#writing-optimization",children:[]},{level:2,title:"Xposed Module Status",slug:"xposed-module-status",link:"#xposed-module-status",children:[{level:3,title:"Determine Self-activation Status",slug:"determine-self-activation-status",link:"#determine-self-activation-status",children:[]},{level:3,title:"Get Hook Framework Information",slug:"get-hook-framework-information",link:"#get-hook-framework-information",children:[]}]}],path:"/en/guide/example.html",pathLocale:"/en/",extraFields:[]},{title:"Introduction",headers:[{level:2,title:"Background",slug:"background",link:"#background",children:[]},{level:2,title:"Usage",slug:"usage",link:"#usage",children:[]},{level:2,title:"Language Requirement",slug:"language-requirement",link:"#language-requirement",children:[]},{level:2,title:"Source of Inspiration",slug:"source-of-inspiration",link:"#source-of-inspiration",children:[]}],path:"/en/guide/home.html",pathLocale:"/en/",extraFields:[]},{title:"Basic Knowledge",headers:[{level:2,title:"Related Introduction",slug:"related-introduction",link:"#related-introduction",children:[{level:3,title:"What is Xposed",slug:"what-is-xposed",link:"#what-is-xposed",children:[]},{level:3,title:"What can Xposed do",slug:"what-can-xposed-do",link:"#what-can-xposed-do",children:[]},{level:3,title:"Development Process",slug:"development-process",link:"#development-process",children:[]},{level:3,title:"Derivatives",slug:"derivatives",link:"#derivatives",children:[]},{level:3,title:"What YukiHookAPI does",slug:"what-yukihookapi-does",link:"#what-yukihookapi-does",children:[]}]},{level:2,title:"Let's Started",slug:"let-s-started",link:"#let-s-started",children:[]}],path:"/en/guide/knowledge.html",pathLocale:"/en/",extraFields:[]},{title:"Migrate from Other Hook APIs",headers:[{level:2,title:"Rovo89 Xposed API",slug:"rovo89-xposed-api",link:"#rovo89-xposed-api",children:[{level:3,title:"Migrate Hook Entry Point",slug:"migrate-hook-entry-point",link:"#migrate-hook-entry-point",children:[]},{level:3,title:"Migrate Hook Method Body",slug:"migrate-hook-method-body",link:"#migrate-hook-method-body",children:[]},{level:3,title:"Notes on Migrating XposedHelpers",slug:"notes-on-migrating-xposedhelpers",link:"#notes-on-migrating-xposedhelpers",children:[]}]},{level:2,title:"Migrate More Functions Related to Hook API",slug:"migrate-more-functions-related-to-hook-api",link:"#migrate-more-functions-related-to-hook-api",children:[]}],path:"/en/guide/move-to-new-api.html",pathLocale:"/en/",extraFields:[]},{title:"Quick Start",headers:[{level:2,title:"Project Requirements",slug:"project-requirements",link:"#project-requirements",children:[]},{level:2,title:"Automatically Build Project",slug:"automatically-build-project",link:"#automatically-build-project",children:[]},{level:2,title:"Manually Configure Project",slug:"manually-configure-project",link:"#manually-configure-project",children:[{level:3,title:"Create Project",slug:"create-project",link:"#create-project",children:[]},{level:3,title:"Integration Dependencies",slug:"integration-dependencies",link:"#integration-dependencies",children:[]},{level:3,title:"Use as Xposed Module",slug:"use-as-xposed-module",link:"#use-as-xposed-module",children:[]},{level:3,title:"Use as Hook API",slug:"use-as-hook-api",link:"#use-as-hook-api",children:[]}]}],path:"/en/guide/quick-start.html",pathLocale:"/en/",extraFields:[]},{title:"Supportive",headers:[],path:"/en/guide/supportive.html",pathLocale:"/en/",extraFields:[]},{title:"YukiHookAPI Project Builder",headers:[{level:2,title:"Get Project",slug:"get-project",link:"#get-project",children:[]},{level:2,title:"Usage",slug:"usage",link:"#usage",children:[{level:3,title:"Basic Usage",slug:"basic-usage",link:"#basic-usage",children:[]},{level:3,title:"Config Template",slug:"config-template",link:"#config-template",children:[]},{level:3,title:"Multilingual Support",slug:"multilingual-support",link:"#multilingual-support",children:[]}]}],path:"/en/tools/yukihookapi-projectbuilder.html",pathLocale:"/en/",extraFields:[]},{title:"关于此文档",headers:[{level:2,title:"许可证",slug:"许可证",link:"#许可证",children:[]}],path:"/zh-cn/about/about.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"更新日志",headers:[{level:3,title:"1.3.0 | 2025.06.25",slug:"_1-3-0-2025-06-25",link:"#_1-3-0-2025-06-25",children:[]},{level:3,title:"1.2.1 | 2024.06.20",slug:"_1-2-1-2024-06-20",link:"#_1-2-1-2024-06-20",children:[]},{level:3,title:"1.2.0 | 2023.10.07",slug:"_1-2-0-2023-10-07",link:"#_1-2-0-2023-10-07",children:[]},{level:3,title:"1.1.11 | 2023.04.25",slug:"_1-1-11-2023-04-25",link:"#_1-1-11-2023-04-25",children:[]},{level:3,title:"1.1.10 | 2023.04.21",slug:"_1-1-10-2023-04-21",link:"#_1-1-10-2023-04-21",children:[]},{level:3,title:"1.1.9 | 2023.04.17",slug:"_1-1-9-2023-04-17",link:"#_1-1-9-2023-04-17",children:[]},{level:3,title:"1.1.8 | 2023.02.01",slug:"_1-1-8-2023-02-01",link:"#_1-1-8-2023-02-01",children:[]},{level:3,title:"1.1.6 | 2023.01.21",slug:"_1-1-6-2023-01-21",link:"#_1-1-6-2023-01-21",children:[]},{level:3,title:"1.1.5 | 2023.01.13",slug:"_1-1-5-2023-01-13",link:"#_1-1-5-2023-01-13",children:[]},{level:3,title:"1.1.4 | 2022.10.04",slug:"_1-1-4-2022-10-04",link:"#_1-1-4-2022-10-04",children:[]},{level:3,title:"1.1.3 | 2022.09.30",slug:"_1-1-3-2022-09-30",link:"#_1-1-3-2022-09-30",children:[]},{level:3,title:"1.1.2 | 2022.09.30",slug:"_1-1-2-2022-09-30",link:"#_1-1-2-2022-09-30",children:[]},{level:3,title:"1.1.1 | 2022.09.28",slug:"_1-1-1-2022-09-28",link:"#_1-1-1-2022-09-28",children:[]},{level:3,title:"1.1.0 | 2022.09.28",slug:"_1-1-0-2022-09-28",link:"#_1-1-0-2022-09-28",children:[]},{level:3,title:"1.0.92 | 2022.05.31",slug:"_1-0-92-2022-05-31",link:"#_1-0-92-2022-05-31",children:[]},{level:3,title:"1.0.91 | 2022.05.29",slug:"_1-0-91-2022-05-29",link:"#_1-0-91-2022-05-29",children:[]},{level:3,title:"1.0.90 | 2022.05.27",slug:"_1-0-90-2022-05-27",link:"#_1-0-90-2022-05-27",children:[]},{level:3,title:"1.0.89 | 2022.05.26",slug:"_1-0-89-2022-05-26",link:"#_1-0-89-2022-05-26",children:[]},{level:3,title:"1.0.88 | 2022.05.25",slug:"_1-0-88-2022-05-25",link:"#_1-0-88-2022-05-25",children:[]},{level:3,title:"1.0.87 | 2022.05.10",slug:"_1-0-87-2022-05-10",link:"#_1-0-87-2022-05-10",children:[]},{level:3,title:"1.0.86 | 2022.05.06",slug:"_1-0-86-2022-05-06",link:"#_1-0-86-2022-05-06",children:[]},{level:3,title:"1.0.85 | 2022.05.04",slug:"_1-0-85-2022-05-04",link:"#_1-0-85-2022-05-04",children:[]},{level:3,title:"1.0.83 | 2022.05.04",slug:"_1-0-83-2022-05-04",link:"#_1-0-83-2022-05-04",children:[]},{level:3,title:"1.0.82 | 2022.05.04",slug:"_1-0-82-2022-05-04",link:"#_1-0-82-2022-05-04",children:[]},{level:3,title:"1.0.81 | 2022.05.04",slug:"_1-0-81-2022-05-04",link:"#_1-0-81-2022-05-04",children:[]},{level:3,title:"1.0.80 | 2022.05.01",slug:"_1-0-80-2022-05-01",link:"#_1-0-80-2022-05-01",children:[]},{level:3,title:"1.0.78 | 2022.04.18",slug:"_1-0-78-2022-04-18",link:"#_1-0-78-2022-04-18",children:[]},{level:3,title:"1.0.77 | 2022.04.15",slug:"_1-0-77-2022-04-15",link:"#_1-0-77-2022-04-15",children:[]},{level:3,title:"1.0.75 | 2022.04.13",slug:"_1-0-75-2022-04-13",link:"#_1-0-75-2022-04-13",children:[]},{level:3,title:"1.0.73 | 2022.04.10",slug:"_1-0-73-2022-04-10",link:"#_1-0-73-2022-04-10",children:[]},{level:3,title:"1.0.72 | 2022.04.09",slug:"_1-0-72-2022-04-09",link:"#_1-0-72-2022-04-09",children:[]},{level:3,title:"1.0.71 | 2022.04.04",slug:"_1-0-71-2022-04-04",link:"#_1-0-71-2022-04-04",children:[]},{level:3,title:"1.0.70 | 2022.04.04",slug:"_1-0-70-2022-04-04",link:"#_1-0-70-2022-04-04",children:[]},{level:3,title:"1.0.69 | 2022.03.30",slug:"_1-0-69-2022-03-30",link:"#_1-0-69-2022-03-30",children:[]},{level:3,title:"1.0.68 | 2022.03.29",slug:"_1-0-68-2022-03-29",link:"#_1-0-68-2022-03-29",children:[]},{level:3,title:"1.0.67 | 2022.03.27",slug:"_1-0-67-2022-03-27",link:"#_1-0-67-2022-03-27",children:[]},{level:3,title:"1.0.66 | 2022.03.25",slug:"_1-0-66-2022-03-25",link:"#_1-0-66-2022-03-25",children:[]},{level:3,title:"1.0.65 | 2022.03.25",slug:"_1-0-65-2022-03-25",link:"#_1-0-65-2022-03-25",children:[]},{level:3,title:"1.0.6 | 2022.03.20",slug:"_1-0-6-2022-03-20",link:"#_1-0-6-2022-03-20",children:[]},{level:3,title:"1.0.55 | 2022.03.18",slug:"_1-0-55-2022-03-18",link:"#_1-0-55-2022-03-18",children:[]},{level:3,title:"1.0.5 | 2022.03.18",slug:"_1-0-5-2022-03-18",link:"#_1-0-5-2022-03-18",children:[]},{level:3,title:"1.0.4 | 2022.03.06",slug:"_1-0-4-2022-03-06",link:"#_1-0-4-2022-03-06",children:[]},{level:3,title:"1.0.3 | 2022.03.02",slug:"_1-0-3-2022-03-02",link:"#_1-0-3-2022-03-02",children:[]},{level:3,title:"1.0.2 | 2022.02.18",slug:"_1-0-2-2022-02-18",link:"#_1-0-2-2022-02-18",children:[]},{level:3,title:"1.0.1 | 2022.02.15",slug:"_1-0-1-2022-02-15",link:"#_1-0-1-2022-02-15",children:[]},{level:3,title:"1.0 | 2022.02.14",slug:"_1-0-2022-02-14",link:"#_1-0-2022-02-14",children:[]}],path:"/zh-cn/about/changelog.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"联系我们",headers:[{level:2,title:"助力维护",slug:"助力维护",link:"#助力维护",children:[]}],path:"/zh-cn/about/contacts.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"展望未来",headers:[{level:2,title:"未解决的问题",slug:"未解决的问题",link:"#未解决的问题",children:[{level:3,title:"YukiHookPrefsBridge",slug:"yukihookprefsbridge",link:"#yukihookprefsbridge",children:[]}]},{level:2,title:"未来的计划",slug:"未来的计划",link:"#未来的计划",children:[{level:3,title:"支持独立使用的 Lite 版本",slug:"支持独立使用的-lite-版本",link:"#支持独立使用的-lite-版本",children:[]},{level:3,title:"里程碑计划",slug:"里程碑计划",link:"#里程碑计划",children:[]}]}],path:"/zh-cn/about/future.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"文档介绍",headers:[{level:2,title:"功能描述说明",slug:"功能描述说明",link:"#功能描述说明",children:[]},{level:2,title:"功能示例说明",slug:"功能示例说明",link:"#功能示例说明",children:[]},{level:2,title:"变更记录说明",slug:"变更记录说明",link:"#变更记录说明",children:[]},{level:2,title:"相关符号说明",slug:"相关符号说明",link:"#相关符号说明",children:[]}],path:"/zh-cn/api/home.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"API 基本配置",headers:[{level:2,title:"功能配置",slug:"功能配置",link:"#功能配置",children:[{level:3,title:"configs 方法",slug:"configs-方法",link:"#configs-方法",children:[]}]},{level:2,title:"Hooker 配置",slug:"hooker-配置",link:"#hooker-配置",children:[{level:3,title:"通过 lambda 创建",slug:"通过-lambda-创建",link:"#通过-lambda-创建",children:[]},{level:3,title:"通过自定义 Hooker 创建",slug:"通过自定义-hooker-创建",link:"#通过自定义-hooker-创建",children:[]},{level:3,title:"扩展特性",slug:"扩展特性",link:"#扩展特性",children:[]},{level:3,title:"注意事项",slug:"注意事项",link:"#注意事项",children:[]}]},{level:2,title:"作为 Hook API 使用需要注意的地方",slug:"作为-hook-api-使用需要注意的地方",link:"#作为-hook-api-使用需要注意的地方",children:[]}],path:"/zh-cn/config/api-example.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"API 异常处理",headers:[{level:2,title:"非阻断异常",slug:"非阻断异常",link:"#非阻断异常",children:[]},{level:2,title:"阻断异常",slug:"阻断异常",link:"#阻断异常",children:[]}],path:"/zh-cn/config/api-exception.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"作为 Hook API 使用的相关配置",headers:[{level:2,title:"依赖配置",slug:"依赖配置",link:"#依赖配置",children:[]},{level:2,title:"入口配置",slug:"入口配置",link:"#入口配置",children:[]},{level:2,title:"Hook Framework",slug:"hook-framework",link:"#hook-framework",children:[{level:3,title:"Pine",slug:"pine",link:"#pine",children:[]},{level:3,title:"SandHook",slug:"sandhook",link:"#sandhook",children:[]},{level:3,title:"Whale",slug:"whale",link:"#whale",children:[]}]}],path:"/zh-cn/config/api-using.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"迁移至 YukiHookAPI 1.2.x",headers:[{level:2,title:"默认行为变更",slug:"默认行为变更",link:"#默认行为变更",children:[]},{level:2,title:"新版 API",slug:"新版-api",link:"#新版-api",children:[]},{level:2,title:"差异性功能",slug:"差异性功能",link:"#差异性功能",children:[{level:3,title:"新的多重 Hook 用法",slug:"新的多重-hook-用法",link:"#新的多重-hook-用法",children:[]},{level:3,title:"新的 allMembers(...) 用法",slug:"新的-allmembers-用法",link:"#新的-allmembers-用法",children:[]}]}],path:"/zh-cn/config/move-to-api-1-2-x.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"迁移至 YukiHookAPI 1.3.x",headers:[{level:2,title:"自身反射 API 弃用",slug:"自身反射-api-弃用",link:"#自身反射-api-弃用",children:[]},{level:2,title:"FreeReflection 弃用",slug:"freereflection-弃用",link:"#freereflection-弃用",children:[]},{level:2,title:"方法原始调用",slug:"方法原始调用",link:"#方法原始调用",children:[]},{level:2,title:"重复 Hook 限制弃用",slug:"重复-hook-限制弃用",link:"#重复-hook-限制弃用",children:[]},{level:2,title:"注册模块 Activity 行为变更",slug:"注册模块-activity-行为变更",link:"#注册模块-activity-行为变更",children:[]},{level:2,title:"YLog 行为变更",slug:"ylog-行为变更",link:"#ylog-行为变更",children:[]}],path:"/zh-cn/config/move-to-api-1-3-x.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"R8 与 Proguard 混淆",headers:[{level:2,title:"R8",slug:"r8",link:"#r8",children:[]},{level:2,title:"Proguard",slug:"proguard",link:"#proguard",children:[]}],path:"/zh-cn/config/r8-proguard.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"作为 Xposed 模块使用的相关配置",headers:[{level:2,title:"依赖配置",slug:"依赖配置",link:"#依赖配置",children:[]},{level:2,title:"自定义处理程序",slug:"自定义处理程序",link:"#自定义处理程序",children:[{level:3,title:"InjectYukiHookWithXposed 注解",slug:"injectyukihookwithxposed-注解",link:"#injectyukihookwithxposed-注解",children:[]},{level:3,title:"IYukiHookXposedInit 接口",slug:"iyukihookxposedinit-接口",link:"#iyukihookxposedinit-接口",children:[]}]},{level:2,title:"原生 Xposed API 事件",slug:"原生-xposed-api-事件",link:"#原生-xposed-api-事件",children:[]}],path:"/zh-cn/config/xposed-using.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"用法示例",headers:[{level:2,title:"结构图解",slug:"结构图解",link:"#结构图解",children:[]},{level:2,title:"Demo",slug:"demo",link:"#demo",children:[]},{level:2,title:"一个简单的 Hook 例子",slug:"一个简单的-hook-例子",link:"#一个简单的-hook-例子",children:[{level:3,title:"Hook APP",slug:"hook-app",link:"#hook-app",children:[]},{level:3,title:"Hook Zygote",slug:"hook-zygote",link:"#hook-zygote",children:[]},{level:3,title:"Hook 系统框架",slug:"hook-系统框架",link:"#hook-系统框架",children:[]},{level:3,title:"Hook Resources",slug:"hook-resources",link:"#hook-resources",children:[]},{level:3,title:"解除 Hook",slug:"解除-hook",link:"#解除-hook",children:[]}]},{level:2,title:"异常处理",slug:"异常处理",link:"#异常处理",children:[{level:3,title:"监听异常",slug:"监听异常",link:"#监听异常",children:[]},{level:3,title:"抛出异常",slug:"抛出异常",link:"#抛出异常",children:[]}]},{level:2,title:"扩展用法",slug:"扩展用法",link:"#扩展用法",children:[{level:3,title:"多个宿主",slug:"多个宿主",link:"#多个宿主",children:[]},{level:3,title:"多个进程",slug:"多个进程",link:"#多个进程",children:[]}]},{level:2,title:"写法优化",slug:"写法优化",link:"#写法优化",children:[]},{level:2,title:"Xposed 模块状态",slug:"xposed-模块状态",link:"#xposed-模块状态",children:[{level:3,title:"判断自身激活状态",slug:"判断自身激活状态",link:"#判断自身激活状态",children:[]},{level:3,title:"获取 Hook Framework 信息",slug:"获取-hook-framework-信息",link:"#获取-hook-framework-信息",children:[]}]}],path:"/zh-cn/guide/example.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"介绍",headers:[{level:2,title:"背景",slug:"背景",link:"#背景",children:[]},{level:2,title:"用途",slug:"用途",link:"#用途",children:[]},{level:2,title:"语言要求",slug:"语言要求",link:"#语言要求",children:[]},{level:2,title:"灵感来源",slug:"灵感来源",link:"#灵感来源",children:[]}],path:"/zh-cn/guide/home.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"基础知识",headers:[{level:2,title:"相关介绍",slug:"相关介绍",link:"#相关介绍",children:[{level:3,title:"Xposed 是什么",slug:"xposed-是什么",link:"#xposed-是什么",children:[]},{level:3,title:"Xposed 能做什么",slug:"xposed-能做什么",link:"#xposed-能做什么",children:[]},{level:3,title:"发展过程",slug:"发展过程",link:"#发展过程",children:[]},{level:3,title:"衍生产品",slug:"衍生产品",link:"#衍生产品",children:[]},{level:3,title:"YukiHookAPI 做了什么",slug:"yukihookapi-做了什么",link:"#yukihookapi-做了什么",children:[]}]},{level:2,title:"让我们开始吧",slug:"让我们开始吧",link:"#让我们开始吧",children:[]}],path:"/zh-cn/guide/knowledge.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"从其它 Hook API 迁移",headers:[{level:2,title:"Rovo89 Xposed API",slug:"rovo89-xposed-api",link:"#rovo89-xposed-api",children:[{level:3,title:"迁移 Hook 入口点",slug:"迁移-hook-入口点",link:"#迁移-hook-入口点",children:[]},{level:3,title:"迁移 Hook 方法体",slug:"迁移-hook-方法体",link:"#迁移-hook-方法体",children:[]},{level:3,title:"迁移 XposedHelpers 注意事项",slug:"迁移-xposedhelpers-注意事项",link:"#迁移-xposedhelpers-注意事项",children:[]}]},{level:2,title:"迁移更多有关 Hook API 的功能",slug:"迁移更多有关-hook-api-的功能",link:"#迁移更多有关-hook-api-的功能",children:[]}],path:"/zh-cn/guide/move-to-new-api.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"快速开始",headers:[{level:2,title:"项目要求",slug:"项目要求",link:"#项目要求",children:[]},{level:2,title:"自动构建项目",slug:"自动构建项目",link:"#自动构建项目",children:[]},{level:2,title:"手动配置项目",slug:"手动配置项目",link:"#手动配置项目",children:[{level:3,title:"创建项目",slug:"创建项目",link:"#创建项目",children:[]},{level:3,title:"集成依赖",slug:"集成依赖",link:"#集成依赖",children:[]},{level:3,title:"作为 Xposed 模块使用",slug:"作为-xposed-模块使用",link:"#作为-xposed-模块使用",children:[]},{level:3,title:"作为 Hook API 使用",slug:"作为-hook-api-使用",link:"#作为-hook-api-使用",children:[]}]}],path:"/zh-cn/guide/quick-start.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"支持性",headers:[],path:"/zh-cn/guide/supportive.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"YukiHookAPI 构建工具",headers:[{level:2,title:"获取项目",slug:"获取项目",link:"#获取项目",children:[]},{level:2,title:"使用方法",slug:"使用方法",link:"#使用方法",children:[{level:3,title:"基本用法",slug:"基本用法",link:"#基本用法",children:[]},{level:3,title:"配置模板",slug:"配置模板",link:"#配置模板",children:[]},{level:3,title:"多语言支持",slug:"多语言支持",link:"#多语言支持",children:[]}]}],path:"/zh-cn/tools/yukihookapi-projectbuilder.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"Host Resource Injection Extension",headers:[{level:2,title:"Inject Module App's Resources",slug:"inject-module-app-s-resources",link:"#inject-module-app-s-resources",children:[]},{level:2,title:"Register Module App's Activity",slug:"register-module-app-s-activity",link:"#register-module-app-s-activity",children:[]},{level:2,title:"Create ContextThemeWrapper Proxy",slug:"create-contextthemewrapper-proxy",link:"#create-contextthemewrapper-proxy",children:[]},{level:2,title:"ClassLoader Conflict Problem",slug:"classloader-conflict-problem",link:"#classloader-conflict-problem",children:[]}],path:"/en/api/special-features/host-inject.html",pathLocale:"/en/",extraFields:[]},{title:"Host Lifecycle Extension",headers:[{level:2,title:"Listener Lifecycle",slug:"listener-lifecycle",link:"#listener-lifecycle",children:[]},{level:2,title:"Register System Broadcast",slug:"register-system-broadcast",link:"#register-system-broadcast",children:[]}],path:"/en/api/special-features/host-lifecycle.html",pathLocale:"/en/",extraFields:[]},{title:"Debug Logs",headers:[{level:2,title:"Normal Logs",slug:"normal-logs",link:"#normal-logs",children:[]},{level:2,title:"Error Logs",slug:"error-logs",link:"#error-logs",children:[]},{level:2,title:"Save Logs and Custom Elements",slug:"save-logs-and-custom-elements",link:"#save-logs-and-custom-elements",children:[]}],path:"/en/api/special-features/logger.html",pathLocale:"/en/",extraFields:[]},{title:"Reflection Extensions (Migrated)",headers:[{level:2,title:"Class Extensions",slug:"class-extensions",link:"#class-extensions",children:[{level:3,title:"Object Conversion",slug:"object-conversion",link:"#object-conversion",children:[]},{level:3,title:"Lazy Loading",slug:"lazy-loading",link:"#lazy-loading",children:[]},{level:3,title:"Existential Judgment",slug:"existential-judgment",link:"#existential-judgment",children:[]},{level:3,title:"Vague Search",slug:"vague-search",link:"#vague-search",children:[]}]},{level:2,title:"Member Extensions",slug:"member-extensions",link:"#member-extensions",children:[{level:3,title:"Find and Reflection",slug:"find-and-reflection",link:"#find-and-reflection",children:[]},{level:3,title:"Optional Find Conditions",slug:"optional-find-conditions",link:"#optional-find-conditions",children:[]},{level:3,title:"Find in Super Class",slug:"find-in-super-class",link:"#find-in-super-class",children:[]},{level:3,title:"Vague Find",slug:"vague-find",link:"#vague-find",children:[]},{level:3,title:"Multiple Find",slug:"multiple-find",link:"#multiple-find",children:[]},{level:3,title:"Static Bytecode",slug:"static-bytecode",link:"#static-bytecode",children:[]},{level:3,title:"Obfuscated Bytecode",slug:"obfuscated-bytecode",link:"#obfuscated-bytecode",children:[]},{level:3,title:"Directly Called",slug:"directly-called",link:"#directly-called",children:[]},{level:3,title:"Original Called",slug:"original-called",link:"#original-called",children:[]},{level:3,title:"Find Again",slug:"find-again",link:"#find-again",children:[]},{level:3,title:"Relative Matching",slug:"relative-matching",link:"#relative-matching",children:[]},{level:3,title:"Calling Generics",slug:"calling-generics",link:"#calling-generics",children:[]},{level:3,title:"Pay Attention of Trap",slug:"pay-attention-of-trap",link:"#pay-attention-of-trap",children:[]}]},{level:2,title:"Common Type Extensions",slug:"common-type-extensions",link:"#common-type-extensions",children:[]}],path:"/en/api/special-features/reflection.html",pathLocale:"/en/",extraFields:[]},{title:"Xposed Module and Host Channel",headers:[{level:2,title:"Basic Usage",slug:"basic-usage",link:"#basic-usage",children:[]},{level:2,title:"Determine Module App and Host App Version Match",slug:"determine-module-app-and-host-app-version-match",link:"#determine-module-app-and-host-app-version-match",children:[]},{level:2,title:"Rules for Callback Event Response",slug:"rules-for-callback-event-response",link:"#rules-for-callback-event-response",children:[]},{level:2,title:"Security Instructions",slug:"security-instructions",link:"#security-instructions",children:[]}],path:"/en/api/special-features/xposed-channel.html",pathLocale:"/en/",extraFields:[]},{title:"Xposed Module Data Storage",headers:[{level:2,title:"Use in Activity",slug:"use-in-activity",link:"#use-in-activity",children:[]},{level:2,title:"Use in PreferenceFragment",slug:"use-in-preferencefragment",link:"#use-in-preferencefragment",children:[]},{level:2,title:"Use Native Storage",slug:"use-native-storage",link:"#use-native-storage",children:[]}],path:"/en/api/special-features/xposed-storage.html",pathLocale:"/en/",extraFields:[]},{title:"宿主资源注入扩展",headers:[{level:2,title:"注入模块资源 (Resources)",slug:"注入模块资源-resources",link:"#注入模块资源-resources",children:[]},{level:2,title:"注册模块 Activity",slug:"注册模块-activity",link:"#注册模块-activity",children:[]},{level:2,title:"创建 ContextThemeWrapper 代理",slug:"创建-contextthemewrapper-代理",link:"#创建-contextthemewrapper-代理",children:[]},{level:2,title:"ClassLoader 冲突问题",slug:"classloader-冲突问题",link:"#classloader-冲突问题",children:[]}],path:"/zh-cn/api/special-features/host-inject.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"宿主生命周期扩展",headers:[{level:2,title:"监听生命周期",slug:"监听生命周期",link:"#监听生命周期",children:[]},{level:2,title:"注册系统广播",slug:"注册系统广播",link:"#注册系统广播",children:[]}],path:"/zh-cn/api/special-features/host-lifecycle.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"调试日志",headers:[{level:2,title:"普通日志",slug:"普通日志",link:"#普通日志",children:[]},{level:2,title:"错误日志",slug:"错误日志",link:"#错误日志",children:[]},{level:2,title:"保存日志与自定义元素",slug:"保存日志与自定义元素",link:"#保存日志与自定义元素",children:[]}],path:"/zh-cn/api/special-features/logger.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"字节码与反射扩展 (已迁移)",headers:[{level:2,title:"Class 扩展",slug:"class-扩展",link:"#class-扩展",children:[{level:3,title:"对象转换",slug:"对象转换",link:"#对象转换",children:[]},{level:3,title:"延迟装载",slug:"延迟装载",link:"#延迟装载",children:[]},{level:3,title:"存在判断",slug:"存在判断",link:"#存在判断",children:[]},{level:3,title:"模糊查找",slug:"模糊查找",link:"#模糊查找",children:[]}]},{level:2,title:"Member 扩展",slug:"member-扩展",link:"#member-扩展",children:[{level:3,title:"查找与反射调用",slug:"查找与反射调用",link:"#查找与反射调用",children:[]},{level:3,title:"可选的查找条件",slug:"可选的查找条件",link:"#可选的查找条件",children:[]},{level:3,title:"在父类查找",slug:"在父类查找",link:"#在父类查找",children:[]},{level:3,title:"模糊查找",slug:"模糊查找-1",link:"#模糊查找-1",children:[]},{level:3,title:"多重查找",slug:"多重查找-1",link:"#多重查找-1",children:[]},{level:3,title:"静态字节码",slug:"静态字节码",link:"#静态字节码",children:[]},{level:3,title:"混淆的字节码",slug:"混淆的字节码",link:"#混淆的字节码",children:[]},{level:3,title:"直接调用",slug:"直接调用",link:"#直接调用",children:[]},{level:3,title:"原始调用",slug:"原始调用",link:"#原始调用",children:[]},{level:3,title:"再次查找",slug:"再次查找",link:"#再次查找",children:[]},{level:3,title:"相对匹配",slug:"相对匹配",link:"#相对匹配",children:[]},{level:3,title:"调用泛型",slug:"调用泛型",link:"#调用泛型",children:[]},{level:3,title:"注意误区",slug:"注意误区",link:"#注意误区",children:[]}]},{level:2,title:"常用类型扩展",slug:"常用类型扩展",link:"#常用类型扩展",children:[]}],path:"/zh-cn/api/special-features/reflection.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"Xposed 模块与宿主通讯桥",headers:[{level:2,title:"基本用法",slug:"基本用法",link:"#基本用法",children:[]},{level:2,title:"判断模块与宿主版本是否匹配",slug:"判断模块与宿主版本是否匹配",link:"#判断模块与宿主版本是否匹配",children:[]},{level:2,title:"回调事件响应的规则",slug:"回调事件响应的规则",link:"#回调事件响应的规则",children:[]},{level:2,title:"安全性说明",slug:"安全性说明",link:"#安全性说明",children:[]}],path:"/zh-cn/api/special-features/xposed-channel.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"Xposed 模块数据存储",headers:[{level:2,title:"在 Activity 中使用",slug:"在-activity-中使用",link:"#在-activity-中使用",children:[]},{level:2,title:"在 PreferenceFragment 中使用",slug:"在-preferencefragment-中使用",link:"#在-preferencefragment-中使用",children:[]},{level:2,title:"使用原生方式存储",slug:"使用原生方式存储",link:"#使用原生方式存储",children:[]}],path:"/zh-cn/api/special-features/xposed-storage.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"YukiHookAPI - object",headers:[{level:2,title:"TAG - field",slug:"tag-field",link:"#tag-field",children:[]},{level:2,title:"VERSION - field",slug:"version-field",link:"#version-field",children:[]},{level:2,title:"Status - object",slug:"status-object",link:"#status-object",children:[{level:3,title:"compiledTimestamp - field",slug:"compiledtimestamp-field",link:"#compiledtimestamp-field",children:[]},{level:3,title:"isXposedEnvironment - field",slug:"isxposedenvironment-field",link:"#isxposedenvironment-field",children:[]},{level:3,title:"isModuleActive - field",slug:"ismoduleactive-field",link:"#ismoduleactive-field",children:[]},{level:3,title:"isXposedModuleActive - field",slug:"isxposedmoduleactive-field",link:"#isxposedmoduleactive-field",children:[]},{level:3,title:"isTaiChiModuleActive - field",slug:"istaichimoduleactive-field",link:"#istaichimoduleactive-field",children:[]},{level:3,title:"isSupportResourcesHook - field",slug:"issupportresourceshook-field",link:"#issupportresourceshook-field",children:[]},{level:3,title:"Executor - object",slug:"executor-object",link:"#executor-object",children:[]}]},{level:2,title:"Configs - object",slug:"configs-object",link:"#configs-object",children:[{level:3,title:"debugLog - method",slug:"debuglog-method",link:"#debuglog-method",children:[]},{level:3,title:"isDebug - field",slug:"isdebug-field",link:"#isdebug-field",children:[]},{level:3,title:"isEnableModuleAppResourcesCache - field",slug:"isenablemoduleappresourcescache-field",link:"#isenablemoduleappresourcescache-field",children:[]},{level:3,title:"isEnableHookSharedPreferences - field",slug:"isenablehooksharedpreferences-field",link:"#isenablehooksharedpreferences-field",children:[]},{level:3,title:"isEnableDataChannel - field",slug:"isenabledatachannel-field",link:"#isenabledatachannel-field",children:[]}]},{level:2,title:"configs - method",slug:"configs-method",link:"#configs-method",children:[]},{level:2,title:"encase - method",slug:"encase-method",link:"#encase-method",children:[]}],path:"/en/api/public/com/highcapable/yukihookapi/YukiHookAPI.html",pathLocale:"/en/",extraFields:[]},{title:"YukiHookAPI - object",headers:[{level:2,title:"TAG - field",slug:"tag-field",link:"#tag-field",children:[]},{level:2,title:"VERSION - field",slug:"version-field",link:"#version-field",children:[]},{level:2,title:"Status - object",slug:"status-object",link:"#status-object",children:[{level:3,title:"compiledTimestamp - field",slug:"compiledtimestamp-field",link:"#compiledtimestamp-field",children:[]},{level:3,title:"isXposedEnvironment - field",slug:"isxposedenvironment-field",link:"#isxposedenvironment-field",children:[]},{level:3,title:"isModuleActive - field",slug:"ismoduleactive-field",link:"#ismoduleactive-field",children:[]},{level:3,title:"isXposedModuleActive - field",slug:"isxposedmoduleactive-field",link:"#isxposedmoduleactive-field",children:[]},{level:3,title:"isTaiChiModuleActive - field",slug:"istaichimoduleactive-field",link:"#istaichimoduleactive-field",children:[]},{level:3,title:"isSupportResourcesHook - field",slug:"issupportresourceshook-field",link:"#issupportresourceshook-field",children:[]},{level:3,title:"Executor - object",slug:"executor-object",link:"#executor-object",children:[]}]},{level:2,title:"Configs - object",slug:"configs-object",link:"#configs-object",children:[{level:3,title:"debugLog - method",slug:"debuglog-method",link:"#debuglog-method",children:[]},{level:3,title:"isDebug - field",slug:"isdebug-field",link:"#isdebug-field",children:[]},{level:3,title:"isEnableModuleAppResourcesCache - field",slug:"isenablemoduleappresourcescache-field",link:"#isenablemoduleappresourcescache-field",children:[]},{level:3,title:"isEnableHookSharedPreferences - field",slug:"isenablehooksharedpreferences-field",link:"#isenablehooksharedpreferences-field",children:[]},{level:3,title:"isEnableDataChannel - field",slug:"isenabledatachannel-field",link:"#isenabledatachannel-field",children:[]}]},{level:2,title:"configs - method",slug:"configs-method",link:"#configs-method",children:[]},{level:2,title:"encase - method",slug:"encase-method",link:"#encase-method",children:[]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/YukiHookAPI.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"InjectYukiHookWithXposed - annotation",headers:[],path:"/en/api/public/com/highcapable/yukihookapi/annotation/xposed/InjectYukiHookWithXposed.html",pathLocale:"/en/",extraFields:[]},{title:"CurrentClass - class",headers:[{level:2,title:"name - field",slug:"name-field",link:"#name-field",children:[]},{level:2,title:"simpleName - field",slug:"simplename-field",link:"#simplename-field",children:[]},{level:2,title:"generic - method",slug:"generic-method",link:"#generic-method",children:[]},{level:2,title:"generic - method",slug:"generic-method-1",link:"#generic-method-1",children:[]},{level:2,title:"superClass - method",slug:"superclass-method",link:"#superclass-method",children:[]},{level:2,title:"field - method",slug:"field-method",link:"#field-method",children:[]},{level:2,title:"method - method",slug:"method-method",link:"#method-method",children:[]},{level:2,title:"SuperClass - class",slug:"superclass-class",link:"#superclass-class",children:[{level:3,title:"name - field",slug:"name-field-1",link:"#name-field-1",children:[]},{level:3,title:"simpleName - field",slug:"simplename-field-1",link:"#simplename-field-1",children:[]},{level:3,title:"generic - method",slug:"generic-method-2",link:"#generic-method-2",children:[]},{level:3,title:"generic - method",slug:"generic-method-3",link:"#generic-method-3",children:[]},{level:3,title:"field - method",slug:"field-method-1",link:"#field-method-1",children:[]},{level:3,title:"method - method",slug:"method-method-1",link:"#method-method-1",children:[]}]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/bean/CurrentClass.html",pathLocale:"/en/",extraFields:[]},{title:"GenericClass - class",headers:[{level:2,title:"argument - method",slug:"argument-method",link:"#argument-method",children:[]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/bean/GenericClass.html",pathLocale:"/en/",extraFields:[]},{title:"HookClass - class",headers:[],path:"/en/api/public/com/highcapable/yukihookapi/hook/bean/HookClass.html",pathLocale:"/en/",extraFields:[]},{title:"HookResources - class",headers:[],path:"/en/api/public/com/highcapable/yukihookapi/hook/bean/HookResources.html",pathLocale:"/en/",extraFields:[]},{title:"VariousClass - class",headers:[{level:2,title:"get - method",slug:"get-method",link:"#get-method",children:[]},{level:2,title:"getOrNull - method",slug:"getornull-method",link:"#getornull-method",children:[]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/bean/VariousClass.html",pathLocale:"/en/",extraFields:[]},{title:"YukiMemberHookCreator - class",headers:[{level:2,title:"injectMember - method",slug:"injectmember-method",link:"#injectmember-method",children:[]},{level:2,title:"MemberHookCreator - class",slug:"memberhookcreator-class",link:"#memberhookcreator-class",children:[{level:3,title:"before - method",slug:"before-method",link:"#before-method",children:[]},{level:3,title:"after - method",slug:"after-method",link:"#after-method",children:[]},{level:3,title:"replaceAny - method",slug:"replaceany-method",link:"#replaceany-method",children:[]},{level:3,title:"replaceUnit - method",slug:"replaceunit-method",link:"#replaceunit-method",children:[]},{level:3,title:"replaceTo - method",slug:"replaceto-method",link:"#replaceto-method",children:[]},{level:3,title:"replaceToTrue - method",slug:"replacetotrue-method",link:"#replacetotrue-method",children:[]},{level:3,title:"replaceToFalse - method",slug:"replacetofalse-method",link:"#replacetofalse-method",children:[]},{level:3,title:"intercept - method",slug:"intercept-method",link:"#intercept-method",children:[]},{level:3,title:"removeSelf - method",slug:"removeself-method",link:"#removeself-method",children:[]},{level:3,title:"LegacyCreator - class",slug:"legacycreator-class",link:"#legacycreator-class",children:[]},{level:3,title:"HookCallback - class",slug:"hookcallback-class",link:"#hookcallback-class",children:[]},{level:3,title:"Result - class",slug:"result-class",link:"#result-class",children:[]}]},{level:2,title:"Result - class",slug:"result-class-1",link:"#result-class-1",children:[{level:3,title:"result - method",slug:"result-method-1",link:"#result-method-1",children:[]},{level:3,title:"by - method",slug:"by-method-1",link:"#by-method-1",children:[]},{level:3,title:"onPrepareHook - method",slug:"onpreparehook-method",link:"#onpreparehook-method",children:[]},{level:3,title:"onHookClassNotFoundFailure - method",slug:"onhookclassnotfoundfailure-method",link:"#onhookclassnotfoundfailure-method",children:[]},{level:3,title:"ignoredHookClassNotFoundFailure - method",slug:"ignoredhookclassnotfoundfailure-method",link:"#ignoredhookclassnotfoundfailure-method",children:[]}]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/core/YukiMemberHookCreator.html",pathLocale:"/en/",extraFields:[]},{title:"YukiResourcesHookCreator - class",headers:[{level:2,title:"injectResource - method",slug:"injectresource-method",link:"#injectresource-method",children:[]},{level:2,title:"ResourcesHookCreator - class",slug:"resourceshookcreator-class",link:"#resourceshookcreator-class",children:[{level:3,title:"resourceId - field",slug:"resourceid-field",link:"#resourceid-field",children:[]},{level:3,title:"conditions - method",slug:"conditions-method",link:"#conditions-method",children:[]},{level:3,title:"replaceTo - method",slug:"replaceto-method",link:"#replaceto-method",children:[]},{level:3,title:"replaceToTrue - method",slug:"replacetotrue-method",link:"#replacetotrue-method",children:[]},{level:3,title:"replaceToFalse - method",slug:"replacetofalse-method",link:"#replacetofalse-method",children:[]},{level:3,title:"replaceToModuleResource - method",slug:"replacetomoduleresource-method",link:"#replacetomoduleresource-method",children:[]},{level:3,title:"replaceTo - method",slug:"replaceto-method-1",link:"#replaceto-method-1",children:[]},{level:3,title:"replaceToModuleResource - method",slug:"replacetomoduleresource-method-1",link:"#replacetomoduleresource-method-1",children:[]},{level:3,title:"injectAsLayout - method",slug:"injectaslayout-method",link:"#injectaslayout-method",children:[]},{level:3,title:"ConditionFinder - class",slug:"conditionfinder-class",link:"#conditionfinder-class",children:[]},{level:3,title:"Result - class",slug:"result-class",link:"#result-class",children:[]},{level:3,title:"onHookingFailure - method",slug:"onhookingfailure-method",link:"#onhookingfailure-method",children:[]},{level:3,title:"ignoredHookingFailure - method",slug:"ignoredhookingfailure-method",link:"#ignoredhookingfailure-method",children:[]}]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/core/YukiResourcesHookCreator.html",pathLocale:"/en/",extraFields:[]},{title:"YukiBaseHooker - class",headers:[{level:2,title:"onHook - method",slug:"onhook-method",link:"#onhook-method",children:[]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/entity/YukiBaseHooker.html",pathLocale:"/en/",extraFields:[]},{title:"ReflectionFactory - kt",headers:[{level:2,title:"MembersType - class",slug:"memberstype-class",link:"#memberstype-class",children:[{level:3,title:"ALL - enum",slug:"all-enum",link:"#all-enum",children:[]},{level:3,title:"METHOD - enum",slug:"method-enum",link:"#method-enum",children:[]},{level:3,title:"CONSTRUCTOR - enum",slug:"constructor-enum",link:"#constructor-enum",children:[]}]},{level:2,title:"LazyClass - class",slug:"lazyclass-class",link:"#lazyclass-class",children:[]},{level:2,title:"ClassLoader.listOfClasses - ext-method",slug:"classloader-listofclasses-ext-method",link:"#classloader-listofclasses-ext-method",children:[]},{level:2,title:"ClassLoader.searchClass - ext-method",slug:"classloader-searchclass-ext-method",link:"#classloader-searchclass-ext-method",children:[]},{level:2,title:"ClassLoader.onLoadClass - ext-method",slug:"classloader-onloadclass-ext-method",link:"#classloader-onloadclass-ext-method",children:[]},{level:2,title:"Class.hasExtends - ext-field",slug:"class-hasextends-ext-field",link:"#class-hasextends-ext-field",children:[]},{level:2,title:"Class?.extends - ext-method",slug:"class-extends-ext-method",link:"#class-extends-ext-method",children:[]},{level:2,title:"Class?.notExtends - ext-method",slug:"class-notextends-ext-method",link:"#class-notextends-ext-method",children:[]},{level:2,title:"Class?.implements - ext-method",slug:"class-implements-ext-method",link:"#class-implements-ext-method",children:[]},{level:2,title:"Class?.notImplements - ext-method",slug:"class-notimplements-ext-method",link:"#class-notimplements-ext-method",children:[]},{level:2,title:"Class.toJavaPrimitiveType - ext-method",slug:"class-tojavaprimitivetype-ext-method",link:"#class-tojavaprimitivetype-ext-method",children:[]},{level:2,title:"String.toClass - ext-method",slug:"string-toclass-ext-method",link:"#string-toclass-ext-method",children:[]},{level:2,title:"String.toClassOrNull - ext-method",slug:"string-toclassornull-ext-method",link:"#string-toclassornull-ext-method",children:[]},{level:2,title:"classOf - method",slug:"classof-method",link:"#classof-method",children:[]},{level:2,title:"lazyClass - method",slug:"lazyclass-method",link:"#lazyclass-method",children:[]},{level:2,title:"lazyClassOrNull - method",slug:"lazyclassornull-method",link:"#lazyclassornull-method",children:[]},{level:2,title:"String.hasClass - ext-method",slug:"string-hasclass-ext-method",link:"#string-hasclass-ext-method",children:[]},{level:2,title:"Class.hasField - ext-method",slug:"class-hasfield-ext-method",link:"#class-hasfield-ext-method",children:[]},{level:2,title:"Class.hasMethod - ext-method",slug:"class-hasmethod-ext-method",link:"#class-hasmethod-ext-method",children:[]},{level:2,title:"Class.hasConstructor - ext-method",slug:"class-hasconstructor-ext-method",link:"#class-hasconstructor-ext-method",children:[]},{level:2,title:"Member.hasModifiers - ext-method",slug:"member-hasmodifiers-ext-method",link:"#member-hasmodifiers-ext-method",children:[]},{level:2,title:"Class.hasModifiers - ext-method",slug:"class-hasmodifiers-ext-method",link:"#class-hasmodifiers-ext-method",children:[]},{level:2,title:"Class.field - ext-method",slug:"class-field-ext-method",link:"#class-field-ext-method",children:[]},{level:2,title:"Class.method - ext-method",slug:"class-method-ext-method",link:"#class-method-ext-method",children:[]},{level:2,title:"Class.constructor - ext-method",slug:"class-constructor-ext-method",link:"#class-constructor-ext-method",children:[]},{level:2,title:"Class.generic - ext-method",slug:"class-generic-ext-method",link:"#class-generic-ext-method",children:[]},{level:2,title:"Class.generic - ext-method",slug:"class-generic-ext-method-1",link:"#class-generic-ext-method-1",children:[]},{level:2,title:"Any.current - ext-method",slug:"any-current-ext-method",link:"#any-current-ext-method",children:[]},{level:2,title:"Class.buildOf - ext-method",slug:"class-buildof-ext-method",link:"#class-buildof-ext-method",children:[]},{level:2,title:"Class.allMethods - ext-method",slug:"class-allmethods-ext-method",link:"#class-allmethods-ext-method",children:[]},{level:2,title:"Class.allConstructors - ext-method",slug:"class-allconstructors-ext-method",link:"#class-allconstructors-ext-method",children:[]},{level:2,title:"Class.allFields - ext-method",slug:"class-allfields-ext-method",link:"#class-allfields-ext-method",children:[]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.html",pathLocale:"/en/",extraFields:[]},{title:"YukiHookFactory - kt",headers:[{level:2,title:"IYukiHookXposedInit.configs - ext-method",slug:"iyukihookxposedinit-configs-ext-method",link:"#iyukihookxposedinit-configs-ext-method",children:[]},{level:2,title:"IYukiHookXposedInit.encase - ext-method",slug:"iyukihookxposedinit-encase-ext-method",link:"#iyukihookxposedinit-encase-ext-method",children:[]},{level:2,title:"Context.prefs - ext-method",slug:"context-prefs-ext-method",link:"#context-prefs-ext-method",children:[]},{level:2,title:"Context.dataChannel - ext-method",slug:"context-datachannel-ext-method",link:"#context-datachannel-ext-method",children:[]},{level:2,title:"Context.processName - ext-field",slug:"context-processname-ext-field",link:"#context-processname-ext-field",children:[]},{level:2,title:"Context+Resources.injectModuleAppResources - ext-method",slug:"context-resources-injectmoduleappresources-ext-method",link:"#context-resources-injectmoduleappresources-ext-method",children:[]},{level:2,title:"Context.registerModuleAppActivities - ext-method",slug:"context-registermoduleappactivities-ext-method",link:"#context-registermoduleappactivities-ext-method",children:[]},{level:2,title:"Context.applyModuleTheme - ext-method",slug:"context-applymoduletheme-ext-method",link:"#context-applymoduletheme-ext-method",children:[]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/factory/YukiHookFactory.html",pathLocale:"/en/",extraFields:[]},{title:"YLog - object",headers:[{level:2,title:"inMemoryData - field",slug:"inmemorydata-field",link:"#inmemorydata-field",children:[]},{level:2,title:"contents - field",slug:"contents-field",link:"#contents-field",children:[]},{level:2,title:"contents - method",slug:"contents-method",link:"#contents-method",children:[]},{level:2,title:"clear - method",slug:"clear-method",link:"#clear-method",children:[]},{level:2,title:"saveToFile - method",slug:"savetofile-method",link:"#savetofile-method",children:[]},{level:2,title:"Configs - object",slug:"configs-object",link:"#configs-object",children:[{level:3,title:"TAG - field",slug:"tag-field",link:"#tag-field",children:[]},{level:3,title:"PRIORITY - field",slug:"priority-field",link:"#priority-field",children:[]},{level:3,title:"PACKAGE_NAME - field",slug:"package-name-field",link:"#package-name-field",children:[]},{level:3,title:"USER_ID - field",slug:"user-id-field",link:"#user-id-field",children:[]},{level:3,title:"tag - field",slug:"tag-field-1",link:"#tag-field-1",children:[]},{level:3,title:"isEnable - field",slug:"isenable-field",link:"#isenable-field",children:[]},{level:3,title:"isRecord - field",slug:"isrecord-field",link:"#isrecord-field",children:[]},{level:3,title:"elements - method",slug:"elements-method",link:"#elements-method",children:[]}]},{level:2,title:"debug - method",slug:"debug-method",link:"#debug-method",children:[]},{level:2,title:"info - method",slug:"info-method",link:"#info-method",children:[]},{level:2,title:"warn - method",slug:"warn-method",link:"#warn-method",children:[]},{level:2,title:"error - method",slug:"error-method",link:"#error-method",children:[]},{level:2,title:"EnvType - class",slug:"envtype-class",link:"#envtype-class",children:[{level:3,title:"LOGD - enum",slug:"logd-enum",link:"#logd-enum",children:[]},{level:3,title:"XPOSED_ENVIRONMENT - enum",slug:"xposed-environment-enum",link:"#xposed-environment-enum",children:[]},{level:3,title:"SCOPE - enum",slug:"scope-enum",link:"#scope-enum",children:[]},{level:3,title:"BOTH - enum",slug:"both-enum",link:"#both-enum",children:[]}]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/log/YLog.html",pathLocale:"/en/",extraFields:[]},{title:"HookParam - class",headers:[{level:2,title:"args - field",slug:"args-field",link:"#args-field",children:[]},{level:2,title:"instance - field",slug:"instance-field",link:"#instance-field",children:[]},{level:2,title:"instanceOrNull - field",slug:"instanceornull-field",link:"#instanceornull-field",children:[]},{level:2,title:"instanceClass - field",slug:"instanceclass-field",link:"#instanceclass-field",children:[]},{level:2,title:"member - field",slug:"member-field",link:"#member-field",children:[]},{level:2,title:"method - field",slug:"method-field",link:"#method-field",children:[]},{level:2,title:"constructor - field",slug:"constructor-field",link:"#constructor-field",children:[]},{level:2,title:"result - field",slug:"result-field",link:"#result-field",children:[]},{level:2,title:"dataExtra - field",slug:"dataextra-field",link:"#dataextra-field",children:[]},{level:2,title:"hasThrowable - field",slug:"hasthrowable-field",link:"#hasthrowable-field",children:[]},{level:2,title:"throwable - field",slug:"throwable-field",link:"#throwable-field",children:[]},{level:2,title:"Throwable.throwToApp - i-ext-method",slug:"throwable-throwtoapp-i-ext-method",link:"#throwable-throwtoapp-i-ext-method",children:[]},{level:2,title:"result - method",slug:"result-method",link:"#result-method",children:[]},{level:2,title:"instance - method",slug:"instance-method",link:"#instance-method",children:[]},{level:2,title:"instanceOrNull - method",slug:"instanceornull-method",link:"#instanceornull-method",children:[]},{level:2,title:"args - method",slug:"args-method",link:"#args-method",children:[]},{level:2,title:"args - method",slug:"args-method-1",link:"#args-method-1",children:[]},{level:2,title:"callOriginal - method",slug:"calloriginal-method",link:"#calloriginal-method",children:[]},{level:2,title:"invokeOriginal - method",slug:"invokeoriginal-method",link:"#invokeoriginal-method",children:[]},{level:2,title:"resultTrue - method",slug:"resulttrue-method",link:"#resulttrue-method",children:[]},{level:2,title:"resultFalse - method",slug:"resultfalse-method",link:"#resultfalse-method",children:[]},{level:2,title:"resultNull - method",slug:"resultnull-method",link:"#resultnull-method",children:[]},{level:2,title:"ArgsIndexCondition - class",slug:"argsindexcondition-class",link:"#argsindexcondition-class",children:[{level:3,title:"first - method",slug:"first-method",link:"#first-method",children:[]},{level:3,title:"last - method",slug:"last-method",link:"#last-method",children:[]}]},{level:2,title:"ArgsModifyer - class",slug:"argsmodifyer-class",link:"#argsmodifyer-class",children:[{level:3,title:"cast - method",slug:"cast-method",link:"#cast-method",children:[]},{level:3,title:"byte - method",slug:"byte-method",link:"#byte-method",children:[]},{level:3,title:"int - method",slug:"int-method",link:"#int-method",children:[]},{level:3,title:"long - method",slug:"long-method",link:"#long-method",children:[]},{level:3,title:"short - method",slug:"short-method",link:"#short-method",children:[]},{level:3,title:"double - method",slug:"double-method",link:"#double-method",children:[]},{level:3,title:"float - method",slug:"float-method",link:"#float-method",children:[]},{level:3,title:"string - method",slug:"string-method",link:"#string-method",children:[]},{level:3,title:"char - method",slug:"char-method",link:"#char-method",children:[]},{level:3,title:"boolean - method",slug:"boolean-method",link:"#boolean-method",children:[]},{level:3,title:"any - method",slug:"any-method",link:"#any-method",children:[]},{level:3,title:"array - method",slug:"array-method",link:"#array-method",children:[]},{level:3,title:"list - method",slug:"list-method",link:"#list-method",children:[]},{level:3,title:"set - method",slug:"set-method",link:"#set-method",children:[]},{level:3,title:"setNull - method",slug:"setnull-method",link:"#setnull-method",children:[]},{level:3,title:"setTrue - method",slug:"settrue-method",link:"#settrue-method",children:[]},{level:3,title:"setFalse - method",slug:"setfalse-method",link:"#setfalse-method",children:[]}]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/param/HookParam.html",pathLocale:"/en/",extraFields:[]},{title:"PackageParam - class",headers:[{level:2,title:"pageClass: code-page",slug:"pageclass-code-page",link:"#pageclass-code-page",children:[]},{level:2,title:"appClassLoader - field",slug:"appclassloader-field",link:"#appclassloader-field",children:[]},{level:2,title:"appInfo - field",slug:"appinfo-field",link:"#appinfo-field",children:[]},{level:2,title:"appUserId - field",slug:"appuserid-field",link:"#appuserid-field",children:[]},{level:2,title:"appContext - field",slug:"appcontext-field",link:"#appcontext-field",children:[]},{level:2,title:"appResources - field",slug:"appresources-field",link:"#appresources-field",children:[]},{level:2,title:"systemContext - field",slug:"systemcontext-field",link:"#systemcontext-field",children:[]},{level:2,title:"processName - field",slug:"processname-field",link:"#processname-field",children:[]},{level:2,title:"packageName - field",slug:"packagename-field",link:"#packagename-field",children:[]},{level:2,title:"isFirstApplication - field",slug:"isfirstapplication-field",link:"#isfirstapplication-field",children:[]},{level:2,title:"mainProcessName - field",slug:"mainprocessname-field",link:"#mainprocessname-field",children:[]},{level:2,title:"moduleAppFilePath - field",slug:"moduleappfilepath-field",link:"#moduleappfilepath-field",children:[]},{level:2,title:"moduleAppResources - field",slug:"moduleappresources-field",link:"#moduleappresources-field",children:[]},{level:2,title:"prefs - field",slug:"prefs-field",link:"#prefs-field",children:[]},{level:2,title:"prefs - method",slug:"prefs-method",link:"#prefs-method",children:[]},{level:2,title:"dataChannel - field",slug:"datachannel-field",link:"#datachannel-field",children:[]},{level:2,title:"resources - method",slug:"resources-method",link:"#resources-method",children:[]},{level:2,title:"refreshModuleAppResources - method",slug:"refreshmoduleappresources-method",link:"#refreshmoduleappresources-method",children:[]},{level:2,title:"onAppLifecycle - method",slug:"onapplifecycle-method",link:"#onapplifecycle-method",children:[]},{level:2,title:"loadApp - method",slug:"loadapp-method",link:"#loadapp-method",children:[]},{level:2,title:"loadZygote - method",slug:"loadzygote-method",link:"#loadzygote-method",children:[]},{level:2,title:"loadSystem - method",slug:"loadsystem-method",link:"#loadsystem-method",children:[]},{level:2,title:"withProcess - method",slug:"withprocess-method",link:"#withprocess-method",children:[]},{level:2,title:"loadHooker - method",slug:"loadhooker-method",link:"#loadhooker-method",children:[]},{level:2,title:"searchClass - method",slug:"searchclass-method",link:"#searchclass-method",children:[]},{level:2,title:"String+VariousClass.toClass - i-ext-method",slug:"string-variousclass-toclass-i-ext-method",link:"#string-variousclass-toclass-i-ext-method",children:[]},{level:2,title:"String+VariousClass.toClassOrNull - i-ext-method",slug:"string-variousclass-toclassornull-i-ext-method",link:"#string-variousclass-toclassornull-i-ext-method",children:[]},{level:2,title:"lazyClass - method",slug:"lazyclass-method",link:"#lazyclass-method",children:[]},{level:2,title:"lazyClassOrNull - method",slug:"lazyclassornull-method",link:"#lazyclassornull-method",children:[]},{level:2,title:"String.hasClass - i-ext-method",slug:"string-hasclass-i-ext-method",link:"#string-hasclass-i-ext-method",children:[]},{level:2,title:"Class+VariousClass+HookClass.hook - i-ext-method",slug:"class-variousclass-hookclass-hook-i-ext-method",link:"#class-variousclass-hookclass-hook-i-ext-method",children:[]},{level:2,title:"Member+BaseFinder.BaseResult.hook - i-ext-method",slug:"member-basefinder-baseresult-hook-i-ext-method",link:"#member-basefinder-baseresult-hook-i-ext-method",children:[]},{level:2,title:"Array+List +BaseFinder.BaseResult.hookAll - i-ext-method",slug:"array-member-list-member-basefinder-baseresult-hookall-i-ext-method",link:"#array-member-list-member-basefinder-baseresult-hookall-i-ext-method",children:[]},{level:2,title:"HookResources.hook - i-ext-method",slug:"hookresources-hook-i-ext-method",link:"#hookresources-hook-i-ext-method",children:[]},{level:2,title:"AppLifecycle - class",slug:"applifecycle-class",link:"#applifecycle-class",children:[{level:3,title:"attachBaseContext - method",slug:"attachbasecontext-method",link:"#attachbasecontext-method",children:[]},{level:3,title:"onCreate - method",slug:"oncreate-method",link:"#oncreate-method",children:[]},{level:3,title:"onTerminate - method",slug:"onterminate-method",link:"#onterminate-method",children:[]},{level:3,title:"onLowMemory - method",slug:"onlowmemory-method",link:"#onlowmemory-method",children:[]},{level:3,title:"onTrimMemory - method",slug:"ontrimmemory-method",link:"#ontrimmemory-method",children:[]},{level:3,title:"onConfigurationChanged - method",slug:"onconfigurationchanged-method",link:"#onconfigurationchanged-method",children:[]},{level:3,title:"registerReceiver - method",slug:"registerreceiver-method",link:"#registerreceiver-method",children:[]}]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/param/PackageParam.html",pathLocale:"/en/",extraFields:[]},{title:"InjectYukiHookWithXposed - annotation",headers:[],path:"/zh-cn/api/public/com/highcapable/yukihookapi/annotation/xposed/InjectYukiHookWithXposed.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"CurrentClass - class",headers:[{level:2,title:"name - field",slug:"name-field",link:"#name-field",children:[]},{level:2,title:"simpleName - field",slug:"simplename-field",link:"#simplename-field",children:[]},{level:2,title:"generic - method",slug:"generic-method",link:"#generic-method",children:[]},{level:2,title:"generic - method",slug:"generic-method-1",link:"#generic-method-1",children:[]},{level:2,title:"superClass - method",slug:"superclass-method",link:"#superclass-method",children:[]},{level:2,title:"field - method",slug:"field-method",link:"#field-method",children:[]},{level:2,title:"method - method",slug:"method-method",link:"#method-method",children:[]},{level:2,title:"SuperClass - class",slug:"superclass-class",link:"#superclass-class",children:[{level:3,title:"name - field",slug:"name-field-1",link:"#name-field-1",children:[]},{level:3,title:"simpleName - field",slug:"simplename-field-1",link:"#simplename-field-1",children:[]},{level:3,title:"generic - method",slug:"generic-method-2",link:"#generic-method-2",children:[]},{level:3,title:"generic - method",slug:"generic-method-3",link:"#generic-method-3",children:[]},{level:3,title:"field - method",slug:"field-method-1",link:"#field-method-1",children:[]},{level:3,title:"method - method",slug:"method-method-1",link:"#method-method-1",children:[]}]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/bean/CurrentClass.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"GenericClass - class",headers:[{level:2,title:"argument - method",slug:"argument-method",link:"#argument-method",children:[]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/bean/GenericClass.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"HookClass - class",headers:[],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/bean/HookClass.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"HookResources - class",headers:[],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/bean/HookResources.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"VariousClass - class",headers:[{level:2,title:"get - method",slug:"get-method",link:"#get-method",children:[]},{level:2,title:"getOrNull - method",slug:"getornull-method",link:"#getornull-method",children:[]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/bean/VariousClass.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"YukiMemberHookCreator - class",headers:[{level:2,title:"injectMember - method",slug:"injectmember-method",link:"#injectmember-method",children:[]},{level:2,title:"MemberHookCreator - class",slug:"memberhookcreator-class",link:"#memberhookcreator-class",children:[{level:3,title:"before - method",slug:"before-method",link:"#before-method",children:[]},{level:3,title:"after - method",slug:"after-method",link:"#after-method",children:[]},{level:3,title:"replaceAny - method",slug:"replaceany-method",link:"#replaceany-method",children:[]},{level:3,title:"replaceUnit - method",slug:"replaceunit-method",link:"#replaceunit-method",children:[]},{level:3,title:"replaceTo - method",slug:"replaceto-method",link:"#replaceto-method",children:[]},{level:3,title:"replaceToTrue - method",slug:"replacetotrue-method",link:"#replacetotrue-method",children:[]},{level:3,title:"replaceToFalse - method",slug:"replacetofalse-method",link:"#replacetofalse-method",children:[]},{level:3,title:"intercept - method",slug:"intercept-method",link:"#intercept-method",children:[]},{level:3,title:"removeSelf - method",slug:"removeself-method",link:"#removeself-method",children:[]},{level:3,title:"LegacyCreator - class",slug:"legacycreator-class",link:"#legacycreator-class",children:[]},{level:3,title:"HookCallback - class",slug:"hookcallback-class",link:"#hookcallback-class",children:[]},{level:3,title:"Result - class",slug:"result-class",link:"#result-class",children:[]}]},{level:2,title:"Result - class",slug:"result-class-1",link:"#result-class-1",children:[{level:3,title:"result - method",slug:"result-method-1",link:"#result-method-1",children:[]},{level:3,title:"by - method",slug:"by-method-1",link:"#by-method-1",children:[]},{level:3,title:"onPrepareHook - method",slug:"onpreparehook-method",link:"#onpreparehook-method",children:[]},{level:3,title:"onHookClassNotFoundFailure - method",slug:"onhookclassnotfoundfailure-method",link:"#onhookclassnotfoundfailure-method",children:[]},{level:3,title:"ignoredHookClassNotFoundFailure - method",slug:"ignoredhookclassnotfoundfailure-method",link:"#ignoredhookclassnotfoundfailure-method",children:[]}]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/YukiMemberHookCreator.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"YukiResourcesHookCreator - class",headers:[{level:2,title:"injectResource - method",slug:"injectresource-method",link:"#injectresource-method",children:[]},{level:2,title:"ResourcesHookCreator - class",slug:"resourceshookcreator-class",link:"#resourceshookcreator-class",children:[{level:3,title:"resourceId - field",slug:"resourceid-field",link:"#resourceid-field",children:[]},{level:3,title:"conditions - method",slug:"conditions-method",link:"#conditions-method",children:[]},{level:3,title:"replaceTo - method",slug:"replaceto-method",link:"#replaceto-method",children:[]},{level:3,title:"replaceToTrue - method",slug:"replacetotrue-method",link:"#replacetotrue-method",children:[]},{level:3,title:"replaceToFalse - method",slug:"replacetofalse-method",link:"#replacetofalse-method",children:[]},{level:3,title:"replaceToModuleResource - method",slug:"replacetomoduleresource-method",link:"#replacetomoduleresource-method",children:[]},{level:3,title:"replaceTo - method",slug:"replaceto-method-1",link:"#replaceto-method-1",children:[]},{level:3,title:"replaceToModuleResource - method",slug:"replacetomoduleresource-method-1",link:"#replacetomoduleresource-method-1",children:[]},{level:3,title:"injectAsLayout - method",slug:"injectaslayout-method",link:"#injectaslayout-method",children:[]},{level:3,title:"ConditionFinder - class",slug:"conditionfinder-class",link:"#conditionfinder-class",children:[]},{level:3,title:"Result - class",slug:"result-class",link:"#result-class",children:[]},{level:3,title:"onHookingFailure - method",slug:"onhookingfailure-method",link:"#onhookingfailure-method",children:[]},{level:3,title:"ignoredHookingFailure - method",slug:"ignoredhookingfailure-method",link:"#ignoredhookingfailure-method",children:[]}]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/YukiResourcesHookCreator.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"YukiBaseHooker - class",headers:[{level:2,title:"onHook - method",slug:"onhook-method",link:"#onhook-method",children:[]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/entity/YukiBaseHooker.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"ReflectionFactory - kt",headers:[{level:2,title:"MembersType - class",slug:"memberstype-class",link:"#memberstype-class",children:[{level:3,title:"ALL - enum",slug:"all-enum",link:"#all-enum",children:[]},{level:3,title:"METHOD - enum",slug:"method-enum",link:"#method-enum",children:[]},{level:3,title:"CONSTRUCTOR - enum",slug:"constructor-enum",link:"#constructor-enum",children:[]}]},{level:2,title:"LazyClass - class",slug:"lazyclass-class",link:"#lazyclass-class",children:[]},{level:2,title:"ClassLoader.listOfClasses - ext-method",slug:"classloader-listofclasses-ext-method",link:"#classloader-listofclasses-ext-method",children:[]},{level:2,title:"ClassLoader.searchClass - ext-method",slug:"classloader-searchclass-ext-method",link:"#classloader-searchclass-ext-method",children:[]},{level:2,title:"ClassLoader.onLoadClass - ext-method",slug:"classloader-onloadclass-ext-method",link:"#classloader-onloadclass-ext-method",children:[]},{level:2,title:"Class.hasExtends - ext-field",slug:"class-hasextends-ext-field",link:"#class-hasextends-ext-field",children:[]},{level:2,title:"Class?.extends - ext-method",slug:"class-extends-ext-method",link:"#class-extends-ext-method",children:[]},{level:2,title:"Class?.notExtends - ext-method",slug:"class-notextends-ext-method",link:"#class-notextends-ext-method",children:[]},{level:2,title:"Class?.implements - ext-method",slug:"class-implements-ext-method",link:"#class-implements-ext-method",children:[]},{level:2,title:"Class?.notImplements - ext-method",slug:"class-notimplements-ext-method",link:"#class-notimplements-ext-method",children:[]},{level:2,title:"Class.toJavaPrimitiveType - ext-method",slug:"class-tojavaprimitivetype-ext-method",link:"#class-tojavaprimitivetype-ext-method",children:[]},{level:2,title:"String.toClass - ext-method",slug:"string-toclass-ext-method",link:"#string-toclass-ext-method",children:[]},{level:2,title:"String.toClassOrNull - ext-method",slug:"string-toclassornull-ext-method",link:"#string-toclassornull-ext-method",children:[]},{level:2,title:"classOf - method",slug:"classof-method",link:"#classof-method",children:[]},{level:2,title:"lazyClass - method",slug:"lazyclass-method",link:"#lazyclass-method",children:[]},{level:2,title:"lazyClassOrNull - method",slug:"lazyclassornull-method",link:"#lazyclassornull-method",children:[]},{level:2,title:"String.hasClass - ext-method",slug:"string-hasclass-ext-method",link:"#string-hasclass-ext-method",children:[]},{level:2,title:"Class.hasField - ext-method",slug:"class-hasfield-ext-method",link:"#class-hasfield-ext-method",children:[]},{level:2,title:"Class.hasMethod - ext-method",slug:"class-hasmethod-ext-method",link:"#class-hasmethod-ext-method",children:[]},{level:2,title:"Class.hasConstructor - ext-method",slug:"class-hasconstructor-ext-method",link:"#class-hasconstructor-ext-method",children:[]},{level:2,title:"Member.hasModifiers - ext-method",slug:"member-hasmodifiers-ext-method",link:"#member-hasmodifiers-ext-method",children:[]},{level:2,title:"Class.hasModifiers - ext-method",slug:"class-hasmodifiers-ext-method",link:"#class-hasmodifiers-ext-method",children:[]},{level:2,title:"Class.field - ext-method",slug:"class-field-ext-method",link:"#class-field-ext-method",children:[]},{level:2,title:"Class.method - ext-method",slug:"class-method-ext-method",link:"#class-method-ext-method",children:[]},{level:2,title:"Class.constructor - ext-method",slug:"class-constructor-ext-method",link:"#class-constructor-ext-method",children:[]},{level:2,title:"Class.generic - ext-method",slug:"class-generic-ext-method",link:"#class-generic-ext-method",children:[]},{level:2,title:"Class.generic - ext-method",slug:"class-generic-ext-method-1",link:"#class-generic-ext-method-1",children:[]},{level:2,title:"Any.current - ext-method",slug:"any-current-ext-method",link:"#any-current-ext-method",children:[]},{level:2,title:"Class.buildOf - ext-method",slug:"class-buildof-ext-method",link:"#class-buildof-ext-method",children:[]},{level:2,title:"Class.allMethods - ext-method",slug:"class-allmethods-ext-method",link:"#class-allmethods-ext-method",children:[]},{level:2,title:"Class.allConstructors - ext-method",slug:"class-allconstructors-ext-method",link:"#class-allconstructors-ext-method",children:[]},{level:2,title:"Class.allFields - ext-method",slug:"class-allfields-ext-method",link:"#class-allfields-ext-method",children:[]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"YukiHookFactory - kt",headers:[{level:2,title:"IYukiHookXposedInit.configs - ext-method",slug:"iyukihookxposedinit-configs-ext-method",link:"#iyukihookxposedinit-configs-ext-method",children:[]},{level:2,title:"IYukiHookXposedInit.encase - ext-method",slug:"iyukihookxposedinit-encase-ext-method",link:"#iyukihookxposedinit-encase-ext-method",children:[]},{level:2,title:"Context.prefs - ext-method",slug:"context-prefs-ext-method",link:"#context-prefs-ext-method",children:[]},{level:2,title:"Context.dataChannel - ext-method",slug:"context-datachannel-ext-method",link:"#context-datachannel-ext-method",children:[]},{level:2,title:"Context.processName - ext-field",slug:"context-processname-ext-field",link:"#context-processname-ext-field",children:[]},{level:2,title:"Context+Resources.injectModuleAppResources - ext-method",slug:"context-resources-injectmoduleappresources-ext-method",link:"#context-resources-injectmoduleappresources-ext-method",children:[]},{level:2,title:"Context.registerModuleAppActivities - ext-method",slug:"context-registermoduleappactivities-ext-method",link:"#context-registermoduleappactivities-ext-method",children:[]},{level:2,title:"Context.applyModuleTheme - ext-method",slug:"context-applymoduletheme-ext-method",link:"#context-applymoduletheme-ext-method",children:[]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/factory/YukiHookFactory.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"YLog - object",headers:[{level:2,title:"inMemoryData - field",slug:"inmemorydata-field",link:"#inmemorydata-field",children:[]},{level:2,title:"contents - field",slug:"contents-field",link:"#contents-field",children:[]},{level:2,title:"contents - method",slug:"contents-method",link:"#contents-method",children:[]},{level:2,title:"clear - method",slug:"clear-method",link:"#clear-method",children:[]},{level:2,title:"saveToFile - method",slug:"savetofile-method",link:"#savetofile-method",children:[]},{level:2,title:"Configs - object",slug:"configs-object",link:"#configs-object",children:[{level:3,title:"TAG - field",slug:"tag-field",link:"#tag-field",children:[]},{level:3,title:"PRIORITY - field",slug:"priority-field",link:"#priority-field",children:[]},{level:3,title:"PACKAGE_NAME - field",slug:"package-name-field",link:"#package-name-field",children:[]},{level:3,title:"USER_ID - field",slug:"user-id-field",link:"#user-id-field",children:[]},{level:3,title:"tag - field",slug:"tag-field-1",link:"#tag-field-1",children:[]},{level:3,title:"isEnable - field",slug:"isenable-field",link:"#isenable-field",children:[]},{level:3,title:"isRecord - field",slug:"isrecord-field",link:"#isrecord-field",children:[]},{level:3,title:"elements - method",slug:"elements-method",link:"#elements-method",children:[]}]},{level:2,title:"debug - method",slug:"debug-method",link:"#debug-method",children:[]},{level:2,title:"info - method",slug:"info-method",link:"#info-method",children:[]},{level:2,title:"warn - method",slug:"warn-method",link:"#warn-method",children:[]},{level:2,title:"error - method",slug:"error-method",link:"#error-method",children:[]},{level:2,title:"EnvType - class",slug:"envtype-class",link:"#envtype-class",children:[{level:3,title:"LOGD - enum",slug:"logd-enum",link:"#logd-enum",children:[]},{level:3,title:"XPOSED_ENVIRONMENT - enum",slug:"xposed-environment-enum",link:"#xposed-environment-enum",children:[]},{level:3,title:"SCOPE - enum",slug:"scope-enum",link:"#scope-enum",children:[]},{level:3,title:"BOTH - enum",slug:"both-enum",link:"#both-enum",children:[]}]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/log/YLog.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"HookParam - class",headers:[{level:2,title:"args - field",slug:"args-field",link:"#args-field",children:[]},{level:2,title:"instance - field",slug:"instance-field",link:"#instance-field",children:[]},{level:2,title:"instanceOrNull - field",slug:"instanceornull-field",link:"#instanceornull-field",children:[]},{level:2,title:"instanceClass - field",slug:"instanceclass-field",link:"#instanceclass-field",children:[]},{level:2,title:"member - field",slug:"member-field",link:"#member-field",children:[]},{level:2,title:"method - field",slug:"method-field",link:"#method-field",children:[]},{level:2,title:"constructor - field",slug:"constructor-field",link:"#constructor-field",children:[]},{level:2,title:"result - field",slug:"result-field",link:"#result-field",children:[]},{level:2,title:"dataExtra - field",slug:"dataextra-field",link:"#dataextra-field",children:[]},{level:2,title:"hasThrowable - field",slug:"hasthrowable-field",link:"#hasthrowable-field",children:[]},{level:2,title:"throwable - field",slug:"throwable-field",link:"#throwable-field",children:[]},{level:2,title:"Throwable.throwToApp - i-ext-method",slug:"throwable-throwtoapp-i-ext-method",link:"#throwable-throwtoapp-i-ext-method",children:[]},{level:2,title:"result - method",slug:"result-method",link:"#result-method",children:[]},{level:2,title:"instance - method",slug:"instance-method",link:"#instance-method",children:[]},{level:2,title:"instanceOrNull - method",slug:"instanceornull-method",link:"#instanceornull-method",children:[]},{level:2,title:"args - method",slug:"args-method",link:"#args-method",children:[]},{level:2,title:"args - method",slug:"args-method-1",link:"#args-method-1",children:[]},{level:2,title:"callOriginal - method",slug:"calloriginal-method",link:"#calloriginal-method",children:[]},{level:2,title:"invokeOriginal - method",slug:"invokeoriginal-method",link:"#invokeoriginal-method",children:[]},{level:2,title:"resultTrue - method",slug:"resulttrue-method",link:"#resulttrue-method",children:[]},{level:2,title:"resultFalse - method",slug:"resultfalse-method",link:"#resultfalse-method",children:[]},{level:2,title:"resultNull - method",slug:"resultnull-method",link:"#resultnull-method",children:[]},{level:2,title:"ArgsIndexCondition - class",slug:"argsindexcondition-class",link:"#argsindexcondition-class",children:[{level:3,title:"first - method",slug:"first-method",link:"#first-method",children:[]},{level:3,title:"last - method",slug:"last-method",link:"#last-method",children:[]}]},{level:2,title:"ArgsModifyer - class",slug:"argsmodifyer-class",link:"#argsmodifyer-class",children:[{level:3,title:"cast - method",slug:"cast-method",link:"#cast-method",children:[]},{level:3,title:"byte - method",slug:"byte-method",link:"#byte-method",children:[]},{level:3,title:"int - method",slug:"int-method",link:"#int-method",children:[]},{level:3,title:"long - method",slug:"long-method",link:"#long-method",children:[]},{level:3,title:"short - method",slug:"short-method",link:"#short-method",children:[]},{level:3,title:"double - method",slug:"double-method",link:"#double-method",children:[]},{level:3,title:"float - method",slug:"float-method",link:"#float-method",children:[]},{level:3,title:"string - method",slug:"string-method",link:"#string-method",children:[]},{level:3,title:"char - method",slug:"char-method",link:"#char-method",children:[]},{level:3,title:"boolean - method",slug:"boolean-method",link:"#boolean-method",children:[]},{level:3,title:"any - method",slug:"any-method",link:"#any-method",children:[]},{level:3,title:"array - method",slug:"array-method",link:"#array-method",children:[]},{level:3,title:"list - method",slug:"list-method",link:"#list-method",children:[]},{level:3,title:"set - method",slug:"set-method",link:"#set-method",children:[]},{level:3,title:"setNull - method",slug:"setnull-method",link:"#setnull-method",children:[]},{level:3,title:"setTrue - method",slug:"settrue-method",link:"#settrue-method",children:[]},{level:3,title:"setFalse - method",slug:"setfalse-method",link:"#setfalse-method",children:[]}]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/param/HookParam.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"PackageParam - class",headers:[{level:2,title:"appClassLoader - field",slug:"appclassloader-field",link:"#appclassloader-field",children:[]},{level:2,title:"appInfo - field",slug:"appinfo-field",link:"#appinfo-field",children:[]},{level:2,title:"appUserId - field",slug:"appuserid-field",link:"#appuserid-field",children:[]},{level:2,title:"appContext - field",slug:"appcontext-field",link:"#appcontext-field",children:[]},{level:2,title:"appResources - field",slug:"appresources-field",link:"#appresources-field",children:[]},{level:2,title:"systemContext - field",slug:"systemcontext-field",link:"#systemcontext-field",children:[]},{level:2,title:"processName - field",slug:"processname-field",link:"#processname-field",children:[]},{level:2,title:"packageName - field",slug:"packagename-field",link:"#packagename-field",children:[]},{level:2,title:"isFirstApplication - field",slug:"isfirstapplication-field",link:"#isfirstapplication-field",children:[]},{level:2,title:"mainProcessName - field",slug:"mainprocessname-field",link:"#mainprocessname-field",children:[]},{level:2,title:"moduleAppFilePath - field",slug:"moduleappfilepath-field",link:"#moduleappfilepath-field",children:[]},{level:2,title:"moduleAppResources - field",slug:"moduleappresources-field",link:"#moduleappresources-field",children:[]},{level:2,title:"prefs - field",slug:"prefs-field",link:"#prefs-field",children:[]},{level:2,title:"prefs - method",slug:"prefs-method",link:"#prefs-method",children:[]},{level:2,title:"dataChannel - field",slug:"datachannel-field",link:"#datachannel-field",children:[]},{level:2,title:"resources - method",slug:"resources-method",link:"#resources-method",children:[]},{level:2,title:"refreshModuleAppResources - method",slug:"refreshmoduleappresources-method",link:"#refreshmoduleappresources-method",children:[]},{level:2,title:"onAppLifecycle - method",slug:"onapplifecycle-method",link:"#onapplifecycle-method",children:[]},{level:2,title:"loadApp - method",slug:"loadapp-method",link:"#loadapp-method",children:[]},{level:2,title:"loadZygote - method",slug:"loadzygote-method",link:"#loadzygote-method",children:[]},{level:2,title:"loadSystem - method",slug:"loadsystem-method",link:"#loadsystem-method",children:[]},{level:2,title:"withProcess - method",slug:"withprocess-method",link:"#withprocess-method",children:[]},{level:2,title:"loadHooker - method",slug:"loadhooker-method",link:"#loadhooker-method",children:[]},{level:2,title:"searchClass - method",slug:"searchclass-method",link:"#searchclass-method",children:[]},{level:2,title:"String+VariousClass.toClass - i-ext-method",slug:"string-variousclass-toclass-i-ext-method",link:"#string-variousclass-toclass-i-ext-method",children:[]},{level:2,title:"String+VariousClass.toClassOrNull - i-ext-method",slug:"string-variousclass-toclassornull-i-ext-method",link:"#string-variousclass-toclassornull-i-ext-method",children:[]},{level:2,title:"lazyClass - method",slug:"lazyclass-method",link:"#lazyclass-method",children:[]},{level:2,title:"lazyClassOrNull - method",slug:"lazyclassornull-method",link:"#lazyclassornull-method",children:[]},{level:2,title:"String.hasClass - i-ext-method",slug:"string-hasclass-i-ext-method",link:"#string-hasclass-i-ext-method",children:[]},{level:2,title:"Class+VariousClass+HookClass.hook - i-ext-method",slug:"class-variousclass-hookclass-hook-i-ext-method",link:"#class-variousclass-hookclass-hook-i-ext-method",children:[]},{level:2,title:"Member+BaseFinder.BaseResult.hook - i-ext-method",slug:"member-basefinder-baseresult-hook-i-ext-method",link:"#member-basefinder-baseresult-hook-i-ext-method",children:[]},{level:2,title:"Array +List +BaseFinder.BaseResult.hookAll - i-ext-method",slug:"array-member-list-member-basefinder-baseresult-hookall-i-ext-method",link:"#array-member-list-member-basefinder-baseresult-hookall-i-ext-method",children:[]},{level:2,title:"HookResources.hook - i-ext-method",slug:"hookresources-hook-i-ext-method",link:"#hookresources-hook-i-ext-method",children:[]},{level:2,title:"AppLifecycle - class",slug:"applifecycle-class",link:"#applifecycle-class",children:[{level:3,title:"attachBaseContext - method",slug:"attachbasecontext-method",link:"#attachbasecontext-method",children:[]},{level:3,title:"onCreate - method",slug:"oncreate-method",link:"#oncreate-method",children:[]},{level:3,title:"onTerminate - method",slug:"onterminate-method",link:"#onterminate-method",children:[]},{level:3,title:"onLowMemory - method",slug:"onlowmemory-method",link:"#onlowmemory-method",children:[]},{level:3,title:"onTrimMemory - method",slug:"ontrimmemory-method",link:"#ontrimmemory-method",children:[]},{level:3,title:"onConfigurationChanged - method",slug:"onconfigurationchanged-method",link:"#onconfigurationchanged-method",children:[]},{level:3,title:"registerReceiver - method",slug:"registerreceiver-method",link:"#registerreceiver-method",children:[]}]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/param/PackageParam.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"YLogData - class",headers:[],path:"/en/api/public/com/highcapable/yukihookapi/hook/log/data/YLogData.html",pathLocale:"/en/",extraFields:[]},{title:"ComponentTypeFactory - kt",headers:[],path:"/en/api/public/com/highcapable/yukihookapi/hook/type/android/ComponentTypeFactory.html",pathLocale:"/en/",extraFields:[]},{title:"GraphicsTypeFactory - kt",headers:[],path:"/en/api/public/com/highcapable/yukihookapi/hook/type/android/GraphicsTypeFactory.html",pathLocale:"/en/",extraFields:[]},{title:"ViewTypeFactory - kt",headers:[],path:"/en/api/public/com/highcapable/yukihookapi/hook/type/android/ViewTypeFactory.html",pathLocale:"/en/",extraFields:[]},{title:"DefinedTypeFactory - kt",headers:[{level:2,title:"VagueType - field",slug:"vaguetype-field",link:"#vaguetype-field",children:[]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/type/defined/DefinedTypeFactory.html",pathLocale:"/en/",extraFields:[]},{title:"VariableTypeFactory - kt",headers:[],path:"/en/api/public/com/highcapable/yukihookapi/hook/type/java/VariableTypeFactory.html",pathLocale:"/en/",extraFields:[]},{title:"ModuleApplication - class",headers:[{level:2,title:"appContext - field",slug:"appcontext-field",link:"#appcontext-field",children:[]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/xposed/application/ModuleApplication.html",pathLocale:"/en/",extraFields:[]},{title:"YukiHookDataChannel - class",headers:[{level:2,title:"NameSpace - class",slug:"namespace-class",link:"#namespace-class",children:[{level:3,title:"with - method",slug:"with-method",link:"#with-method",children:[]},{level:3,title:"dataMaxByteSize - field",slug:"datamaxbytesize-field",link:"#datamaxbytesize-field",children:[]},{level:3,title:"dataMaxByteCompressionFactor - field",slug:"datamaxbytecompressionfactor-field",link:"#datamaxbytecompressionfactor-field",children:[]},{level:3,title:"allowSendTooLargeData - method",slug:"allowsendtoolargedata-method",link:"#allowsendtoolargedata-method",children:[]},{level:3,title:"put - method",slug:"put-method",link:"#put-method",children:[]},{level:3,title:"put - method",slug:"put-method-1",link:"#put-method-1",children:[]},{level:3,title:"wait - method",slug:"wait-method",link:"#wait-method",children:[]},{level:3,title:"wait - method",slug:"wait-method-1",link:"#wait-method-1",children:[]},{level:3,title:"checkingVersionEquals - method",slug:"checkingversionequals-method",link:"#checkingversionequals-method",children:[]},{level:3,title:"obtainLoggerInMemoryData - method",slug:"obtainloggerinmemorydata-method",link:"#obtainloggerinmemorydata-method",children:[]}]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/xposed/channel/YukiHookDataChannel.html",pathLocale:"/en/",extraFields:[]},{title:"YukiHookPrefsBridge - class",headers:[{level:2,title:"isPreferencesAvailable - field",slug:"ispreferencesavailable-field",link:"#ispreferencesavailable-field",children:[]},{level:2,title:"name - method",slug:"name-method",link:"#name-method",children:[]},{level:2,title:"native - method",slug:"native-method",link:"#native-method",children:[]},{level:2,title:"getString - method",slug:"getstring-method",link:"#getstring-method",children:[]},{level:2,title:"getStringSet - method",slug:"getstringset-method",link:"#getstringset-method",children:[]},{level:2,title:"getBoolean - method",slug:"getboolean-method",link:"#getboolean-method",children:[]},{level:2,title:"getInt - method",slug:"getint-method",link:"#getint-method",children:[]},{level:2,title:"getLong - method",slug:"getlong-method",link:"#getlong-method",children:[]},{level:2,title:"getFloat - method",slug:"getfloat-method",link:"#getfloat-method",children:[]},{level:2,title:"contains - method",slug:"contains-method",link:"#contains-method",children:[]},{level:2,title:"all - method",slug:"all-method",link:"#all-method",children:[]},{level:2,title:"get - method",slug:"get-method",link:"#get-method",children:[]},{level:2,title:"edit - method",slug:"edit-method",link:"#edit-method",children:[]},{level:2,title:"edit - method",slug:"edit-method-1",link:"#edit-method-1",children:[]},{level:2,title:"Editor - class",slug:"editor-class",link:"#editor-class",children:[{level:3,title:"remove - method",slug:"remove-method",link:"#remove-method",children:[]},{level:3,title:"remove - method",slug:"remove-method-1",link:"#remove-method-1",children:[]},{level:3,title:"clear - method",slug:"clear-method",link:"#clear-method",children:[]},{level:3,title:"putString - method",slug:"putstring-method",link:"#putstring-method",children:[]},{level:3,title:"putStringSet - method",slug:"putstringset-method",link:"#putstringset-method",children:[]},{level:3,title:"putBoolean - method",slug:"putboolean-method",link:"#putboolean-method",children:[]},{level:3,title:"putInt - method",slug:"putint-method",link:"#putint-method",children:[]},{level:3,title:"putLong - method",slug:"putlong-method",link:"#putlong-method",children:[]},{level:3,title:"putFloat - method",slug:"putfloat-method",link:"#putfloat-method",children:[]},{level:3,title:"put - method",slug:"put-method",link:"#put-method",children:[]},{level:3,title:"commit - method",slug:"commit-method",link:"#commit-method",children:[]},{level:3,title:"apply - method",slug:"apply-method",link:"#apply-method",children:[]}]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookPrefsBridge.html",pathLocale:"/en/",extraFields:[]},{title:"IYukiHookXposedInit - interface",headers:[{level:2,title:"onInit - method",slug:"oninit-method",link:"#oninit-method",children:[]},{level:2,title:"onHook - method",slug:"onhook-method",link:"#onhook-method",children:[]},{level:2,title:"onXposedEvent - method",slug:"onxposedevent-method",link:"#onxposedevent-method",children:[]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/xposed/proxy/IYukiHookXposedInit.html",pathLocale:"/en/",extraFields:[]},{title:"YLogData - class",headers:[],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/log/data/YLogData.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"ComponentTypeFactory - kt",headers:[],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/type/android/ComponentTypeFactory.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"GraphicsTypeFactory - kt",headers:[],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/type/android/GraphicsTypeFactory.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"ViewTypeFactory - kt",headers:[],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/type/android/ViewTypeFactory.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"DefinedTypeFactory - kt",headers:[{level:2,title:"VagueType - field",slug:"vaguetype-field",link:"#vaguetype-field",children:[]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/type/defined/DefinedTypeFactory.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"VariableTypeFactory - kt",headers:[],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/type/java/VariableTypeFactory.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"ModuleApplication - class",headers:[{level:2,title:"appContext - field",slug:"appcontext-field",link:"#appcontext-field",children:[]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/application/ModuleApplication.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"YukiHookDataChannel - class",headers:[{level:2,title:"NameSpace - class",slug:"namespace-class",link:"#namespace-class",children:[{level:3,title:"with - method",slug:"with-method",link:"#with-method",children:[]},{level:3,title:"dataMaxByteSize - field",slug:"datamaxbytesize-field",link:"#datamaxbytesize-field",children:[]},{level:3,title:"dataMaxByteCompressionFactor - field",slug:"datamaxbytecompressionfactor-field",link:"#datamaxbytecompressionfactor-field",children:[]},{level:3,title:"allowSendTooLargeData - method",slug:"allowsendtoolargedata-method",link:"#allowsendtoolargedata-method",children:[]},{level:3,title:"put - method",slug:"put-method",link:"#put-method",children:[]},{level:3,title:"put - method",slug:"put-method-1",link:"#put-method-1",children:[]},{level:3,title:"wait - method",slug:"wait-method",link:"#wait-method",children:[]},{level:3,title:"wait - method",slug:"wait-method-1",link:"#wait-method-1",children:[]},{level:3,title:"checkingVersionEquals - method",slug:"checkingversionequals-method",link:"#checkingversionequals-method",children:[]},{level:3,title:"obtainLoggerInMemoryData - method",slug:"obtainloggerinmemorydata-method",link:"#obtainloggerinmemorydata-method",children:[]}]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/channel/YukiHookDataChannel.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"YukiHookPrefsBridge - class",headers:[{level:2,title:"isPreferencesAvailable - field",slug:"ispreferencesavailable-field",link:"#ispreferencesavailable-field",children:[]},{level:2,title:"name - method",slug:"name-method",link:"#name-method",children:[]},{level:2,title:"native - method",slug:"native-method",link:"#native-method",children:[]},{level:2,title:"getString - method",slug:"getstring-method",link:"#getstring-method",children:[]},{level:2,title:"getStringSet - method",slug:"getstringset-method",link:"#getstringset-method",children:[]},{level:2,title:"getBoolean - method",slug:"getboolean-method",link:"#getboolean-method",children:[]},{level:2,title:"getInt - method",slug:"getint-method",link:"#getint-method",children:[]},{level:2,title:"getLong - method",slug:"getlong-method",link:"#getlong-method",children:[]},{level:2,title:"getFloat - method",slug:"getfloat-method",link:"#getfloat-method",children:[]},{level:2,title:"contains - method",slug:"contains-method",link:"#contains-method",children:[]},{level:2,title:"all - method",slug:"all-method",link:"#all-method",children:[]},{level:2,title:"get - method",slug:"get-method",link:"#get-method",children:[]},{level:2,title:"edit - method",slug:"edit-method",link:"#edit-method",children:[]},{level:2,title:"edit - method",slug:"edit-method-1",link:"#edit-method-1",children:[]},{level:2,title:"Editor - class",slug:"editor-class",link:"#editor-class",children:[{level:3,title:"remove - method",slug:"remove-method",link:"#remove-method",children:[]},{level:3,title:"remove - method",slug:"remove-method-1",link:"#remove-method-1",children:[]},{level:3,title:"clear - method",slug:"clear-method",link:"#clear-method",children:[]},{level:3,title:"putString - method",slug:"putstring-method",link:"#putstring-method",children:[]},{level:3,title:"putStringSet - method",slug:"putstringset-method",link:"#putstringset-method",children:[]},{level:3,title:"putBoolean - method",slug:"putboolean-method",link:"#putboolean-method",children:[]},{level:3,title:"putInt - method",slug:"putint-method",link:"#putint-method",children:[]},{level:3,title:"putLong - method",slug:"putlong-method",link:"#putlong-method",children:[]},{level:3,title:"putFloat - method",slug:"putfloat-method",link:"#putfloat-method",children:[]},{level:3,title:"put - method",slug:"put-method",link:"#put-method",children:[]},{level:3,title:"commit - method",slug:"commit-method",link:"#commit-method",children:[]},{level:3,title:"apply - method",slug:"apply-method",link:"#apply-method",children:[]}]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookPrefsBridge.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"IYukiHookXposedInit - interface",headers:[{level:2,title:"onInit - method",slug:"oninit-method",link:"#oninit-method",children:[]},{level:2,title:"onHook - method",slug:"onhook-method",link:"#onhook-method",children:[]},{level:2,title:"onXposedEvent - method",slug:"onxposedevent-method",link:"#onxposedevent-method",children:[]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/proxy/IYukiHookXposedInit.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"YukiHookPriority - class",headers:[{level:2,title:"DEFAULT - enum",slug:"default-enum",link:"#default-enum",children:[]},{level:2,title:"LOWEST - enum",slug:"lowest-enum",link:"#lowest-enum",children:[]},{level:2,title:"HIGHEST - enum",slug:"highest-enum",link:"#highest-enum",children:[]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/core/api/priority/YukiHookPriority.html",pathLocale:"/en/",extraFields:[]},{title:"BaseFinder - class",headers:[{level:2,title:"BaseFinder.IndexTypeCondition - class",slug:"basefinder-indextypecondition-class",link:"#basefinder-indextypecondition-class",children:[{level:3,title:"index - method",slug:"index-method",link:"#index-method",children:[]},{level:3,title:"index - method",slug:"index-method-1",link:"#index-method-1",children:[]},{level:3,title:"IndexTypeConditionSort - class",slug:"indextypeconditionsort-class",link:"#indextypeconditionsort-class",children:[]}]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/BaseFinder.html",pathLocale:"/en/",extraFields:[]},{title:"DexClassFinder - class",headers:[{level:2,title:"companion object - object",slug:"companion-object-object",link:"#companion-object-object",children:[{level:3,title:"clearCache - method",slug:"clearcache-method",link:"#clearcache-method",children:[]}]},{level:2,title:"fullName - field",slug:"fullname-field",link:"#fullname-field",children:[]},{level:2,title:"simpleName - field",slug:"simplename-field",link:"#simplename-field",children:[]},{level:2,title:"singleName - field",slug:"singlename-field",link:"#singlename-field",children:[]},{level:2,title:"from - method",slug:"from-method",link:"#from-method",children:[]},{level:2,title:"modifiers - method",slug:"modifiers-method",link:"#modifiers-method",children:[]},{level:2,title:"fullName - method",slug:"fullname-method",link:"#fullname-method",children:[]},{level:2,title:"simpleName - method",slug:"simplename-method",link:"#simplename-method",children:[]},{level:2,title:"singleName - method",slug:"singlename-method",link:"#singlename-method",children:[]},{level:2,title:"fullName - method",slug:"fullname-method-1",link:"#fullname-method-1",children:[]},{level:2,title:"simpleName - method",slug:"simplename-method-1",link:"#simplename-method-1",children:[]},{level:2,title:"singleName - method",slug:"singlename-method-1",link:"#singlename-method-1",children:[]},{level:2,title:"extends - method",slug:"extends-method",link:"#extends-method",children:[]},{level:2,title:"extends - method",slug:"extends-method-1",link:"#extends-method-1",children:[]},{level:2,title:"implements - method",slug:"implements-method",link:"#implements-method",children:[]},{level:2,title:"implements - method",slug:"implements-method-1",link:"#implements-method-1",children:[]},{level:2,title:"anonymous - method",slug:"anonymous-method",link:"#anonymous-method",children:[]},{level:2,title:"noExtends - method",slug:"noextends-method",link:"#noextends-method",children:[]},{level:2,title:"noImplements - method",slug:"noimplements-method",link:"#noimplements-method",children:[]},{level:2,title:"noSuper - method",slug:"nosuper-method",link:"#nosuper-method",children:[]},{level:2,title:"enclosing - method",slug:"enclosing-method",link:"#enclosing-method",children:[]},{level:2,title:"enclosing - method",slug:"enclosing-method-1",link:"#enclosing-method-1",children:[]},{level:2,title:"FromPackageRules - class",slug:"frompackagerules-class",link:"#frompackagerules-class",children:[{level:3,title:"absolute - method",slug:"absolute-method",link:"#absolute-method",children:[]}]},{level:2,title:"ClassNameRules - class",slug:"classnamerules-class",link:"#classnamerules-class",children:[{level:3,title:"optional - method",slug:"optional-method",link:"#optional-method",children:[]}]},{level:2,title:"member - method",slug:"member-method",link:"#member-method",children:[]},{level:2,title:"field - method",slug:"field-method",link:"#field-method",children:[]},{level:2,title:"method - method",slug:"method-method",link:"#method-method",children:[]},{level:2,title:"constructor - method",slug:"constructor-method",link:"#constructor-method",children:[]},{level:2,title:"Result - class",slug:"result-class",link:"#result-class",children:[{level:3,title:"result - method",slug:"result-method",link:"#result-method",children:[]},{level:3,title:"get - method",slug:"get-method",link:"#get-method",children:[]},{level:3,title:"all - method",slug:"all-method",link:"#all-method",children:[]},{level:3,title:"all - method",slug:"all-method-1",link:"#all-method-1",children:[]},{level:3,title:"wait - method",slug:"wait-method",link:"#wait-method",children:[]},{level:3,title:"waitAll - method",slug:"waitall-method",link:"#waitall-method",children:[]},{level:3,title:"onNoClassDefFoundError - method",slug:"onnoclassdeffounderror-method",link:"#onnoclassdeffounderror-method",children:[]},{level:3,title:"ignored - method",slug:"ignored-method",link:"#ignored-method",children:[]}]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/DexClassFinder.html",pathLocale:"/en/",extraFields:[]},{title:"ConstructorFinder - class",headers:[{level:2,title:"paramCount - field",slug:"paramcount-field",link:"#paramcount-field",children:[]},{level:2,title:"modifiers - method",slug:"modifiers-method",link:"#modifiers-method",children:[]},{level:2,title:"emptyParam - method",slug:"emptyparam-method",link:"#emptyparam-method",children:[]},{level:2,title:"param - method",slug:"param-method",link:"#param-method",children:[]},{level:2,title:"param - method",slug:"param-method-1",link:"#param-method-1",children:[]},{level:2,title:"paramCount - method",slug:"paramcount-method",link:"#paramcount-method",children:[]},{level:2,title:"paramCount - method",slug:"paramcount-method-1",link:"#paramcount-method-1",children:[]},{level:2,title:"paramCount - method",slug:"paramcount-method-2",link:"#paramcount-method-2",children:[]},{level:2,title:"superClass - method",slug:"superclass-method",link:"#superclass-method",children:[]},{level:2,title:"RemedyPlan - class",slug:"remedyplan-class",link:"#remedyplan-class",children:[{level:3,title:"constructor - method",slug:"constructor-method",link:"#constructor-method",children:[]},{level:3,title:"Result - class",slug:"result-class",link:"#result-class",children:[]}]},{level:2,title:"Process - class",slug:"process-class",link:"#process-class",children:[{level:3,title:"result - method",slug:"result-method",link:"#result-method",children:[]},{level:3,title:"all - method",slug:"all-method",link:"#all-method",children:[]},{level:3,title:"remedys - method",slug:"remedys-method",link:"#remedys-method",children:[]},{level:3,title:"onNoSuchConstructor - method",slug:"onnosuchconstructor-method",link:"#onnosuchconstructor-method",children:[]}]},{level:2,title:"Result - class",slug:"result-class-1",link:"#result-class-1",children:[{level:3,title:"result - method",slug:"result-method-1",link:"#result-method-1",children:[]},{level:3,title:"get - method",slug:"get-method",link:"#get-method",children:[]},{level:3,title:"all - method",slug:"all-method-1",link:"#all-method-1",children:[]},{level:3,title:"give - method",slug:"give-method",link:"#give-method",children:[]},{level:3,title:"giveAll - method",slug:"giveall-method",link:"#giveall-method",children:[]},{level:3,title:"wait - method",slug:"wait-method",link:"#wait-method",children:[]},{level:3,title:"waitAll - method",slug:"waitall-method",link:"#waitall-method",children:[]},{level:3,title:"remedys - method",slug:"remedys-method-1",link:"#remedys-method-1",children:[]},{level:3,title:"onNoSuchConstructor - method",slug:"onnosuchconstructor-method-1",link:"#onnosuchconstructor-method-1",children:[]},{level:3,title:"ignored - method",slug:"ignored-method",link:"#ignored-method",children:[]},{level:3,title:"Instance - class",slug:"instance-class",link:"#instance-class",children:[]}]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/core/finder/members/ConstructorFinder.html",pathLocale:"/en/",extraFields:[]},{title:"FieldFinder - class",headers:[{level:2,title:"name - field",slug:"name-field",link:"#name-field",children:[]},{level:2,title:"type - field",slug:"type-field",link:"#type-field",children:[]},{level:2,title:"modifiers - method",slug:"modifiers-method",link:"#modifiers-method",children:[]},{level:2,title:"order - method",slug:"order-method",link:"#order-method",children:[]},{level:2,title:"name - method",slug:"name-method",link:"#name-method",children:[]},{level:2,title:"name - method",slug:"name-method-1",link:"#name-method-1",children:[]},{level:2,title:"type - method",slug:"type-method",link:"#type-method",children:[]},{level:2,title:"type - method",slug:"type-method-1",link:"#type-method-1",children:[]},{level:2,title:"superClass - method",slug:"superclass-method",link:"#superclass-method",children:[]},{level:2,title:"RemedyPlan - class",slug:"remedyplan-class",link:"#remedyplan-class",children:[{level:3,title:"field - method",slug:"field-method",link:"#field-method",children:[]},{level:3,title:"Result - class",slug:"result-class",link:"#result-class",children:[]}]},{level:2,title:"Result - class",slug:"result-class-1",link:"#result-class-1",children:[{level:3,title:"result - method",slug:"result-method",link:"#result-method",children:[]},{level:3,title:"get - method",slug:"get-method",link:"#get-method",children:[]},{level:3,title:"all - method",slug:"all-method",link:"#all-method",children:[]},{level:3,title:"give - method",slug:"give-method",link:"#give-method",children:[]},{level:3,title:"giveAll - method",slug:"giveall-method",link:"#giveall-method",children:[]},{level:3,title:"wait - method",slug:"wait-method",link:"#wait-method",children:[]},{level:3,title:"waitAll - method",slug:"waitall-method",link:"#waitall-method",children:[]},{level:3,title:"remedys - method",slug:"remedys-method",link:"#remedys-method",children:[]},{level:3,title:"onNoSuchField - method",slug:"onnosuchfield-method",link:"#onnosuchfield-method",children:[]},{level:3,title:"ignored - method",slug:"ignored-method",link:"#ignored-method",children:[]},{level:3,title:"Instance - class",slug:"instance-class",link:"#instance-class",children:[]}]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/core/finder/members/FieldFinder.html",pathLocale:"/en/",extraFields:[]},{title:"MethodFinder - class",headers:[{level:2,title:"name - field",slug:"name-field",link:"#name-field",children:[]},{level:2,title:"paramCount - field",slug:"paramcount-field",link:"#paramcount-field",children:[]},{level:2,title:"returnType - field",slug:"returntype-field",link:"#returntype-field",children:[]},{level:2,title:"modifiers - method",slug:"modifiers-method",link:"#modifiers-method",children:[]},{level:2,title:"emptyParam - method",slug:"emptyparam-method",link:"#emptyparam-method",children:[]},{level:2,title:"param - method",slug:"param-method",link:"#param-method",children:[]},{level:2,title:"param - method",slug:"param-method-1",link:"#param-method-1",children:[]},{level:2,title:"order - method",slug:"order-method",link:"#order-method",children:[]},{level:2,title:"name - method",slug:"name-method",link:"#name-method",children:[]},{level:2,title:"name - method",slug:"name-method-1",link:"#name-method-1",children:[]},{level:2,title:"paramCount - method",slug:"paramcount-method",link:"#paramcount-method",children:[]},{level:2,title:"paramCount - method",slug:"paramcount-method-1",link:"#paramcount-method-1",children:[]},{level:2,title:"paramCount - method",slug:"paramcount-method-2",link:"#paramcount-method-2",children:[]},{level:2,title:"returnType - method",slug:"returntype-method",link:"#returntype-method",children:[]},{level:2,title:"returnType - method",slug:"returntype-method-1",link:"#returntype-method-1",children:[]},{level:2,title:"superClass - method",slug:"superclass-method",link:"#superclass-method",children:[]},{level:2,title:"RemedyPlan - class",slug:"remedyplan-class",link:"#remedyplan-class",children:[{level:3,title:"method - method",slug:"method-method",link:"#method-method",children:[]},{level:3,title:"Result - class",slug:"result-class",link:"#result-class",children:[]}]},{level:2,title:"Process - class",slug:"process-class",link:"#process-class",children:[{level:3,title:"result - method",slug:"result-method",link:"#result-method",children:[]},{level:3,title:"all - method",slug:"all-method",link:"#all-method",children:[]},{level:3,title:"remedys - method",slug:"remedys-method",link:"#remedys-method",children:[]},{level:3,title:"onNoSuchMethod - method",slug:"onnosuchmethod-method",link:"#onnosuchmethod-method",children:[]}]},{level:2,title:"Result - class",slug:"result-class-1",link:"#result-class-1",children:[{level:3,title:"result - method",slug:"result-method-1",link:"#result-method-1",children:[]},{level:3,title:"get - method",slug:"get-method",link:"#get-method",children:[]},{level:3,title:"all - method",slug:"all-method-1",link:"#all-method-1",children:[]},{level:3,title:"give - method",slug:"give-method",link:"#give-method",children:[]},{level:3,title:"giveAll - method",slug:"giveall-method",link:"#giveall-method",children:[]},{level:3,title:"wait - method",slug:"wait-method",link:"#wait-method",children:[]},{level:3,title:"waitAll - method",slug:"waitall-method",link:"#waitall-method",children:[]},{level:3,title:"remedys - method",slug:"remedys-method-1",link:"#remedys-method-1",children:[]},{level:3,title:"onNoSuchMethod - method",slug:"onnosuchmethod-method-1",link:"#onnosuchmethod-method-1",children:[]},{level:3,title:"ignored - method",slug:"ignored-method",link:"#ignored-method",children:[]},{level:3,title:"Instance - class",slug:"instance-class",link:"#instance-class",children:[]},{level:3,title:"array - method",slug:"array-method",link:"#array-method",children:[]},{level:3,title:"list - method",slug:"list-method",link:"#list-method",children:[]}]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/core/finder/members/MethodFinder.html",pathLocale:"/en/",extraFields:[]},{title:"YukiXposedEvent - object",headers:[{level:2,title:"events - method",slug:"events-method",link:"#events-method",children:[]},{level:2,title:"onInitZygote - method",slug:"oninitzygote-method",link:"#oninitzygote-method",children:[]},{level:2,title:"onHandleLoadPackage - method",slug:"onhandleloadpackage-method",link:"#onhandleloadpackage-method",children:[]},{level:2,title:"onHandleInitPackageResources - method",slug:"onhandleinitpackageresources-method",link:"#onhandleinitpackageresources-method",children:[]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/event/YukiXposedEvent.html",pathLocale:"/en/",extraFields:[]},{title:"YukiModuleResources - class",headers:[{level:2,title:"fwd - method",slug:"fwd-method",link:"#fwd-method",children:[]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiModuleResources.html",pathLocale:"/en/",extraFields:[]},{title:"YukiResForwarder - class",headers:[{level:2,title:"id - field",slug:"id-field",link:"#id-field",children:[]},{level:2,title:"resources - field",slug:"resources-field",link:"#resources-field",children:[]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResForwarder.html",pathLocale:"/en/",extraFields:[]},{title:"YukiResources - class",headers:[{level:2,title:"LayoutInflatedParam - class",slug:"layoutinflatedparam-class",link:"#layoutinflatedparam-class",children:[{level:3,title:"variantName - field",slug:"variantname-field",link:"#variantname-field",children:[]},{level:3,title:"currentView - field",slug:"currentview-field",link:"#currentview-field",children:[]},{level:3,title:"findViewByIdentifier - method",slug:"findviewbyidentifier-method",link:"#findviewbyidentifier-method",children:[]}]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResources.html",pathLocale:"/en/",extraFields:[]},{title:"ChannelData - class",headers:[],path:"/en/api/public/com/highcapable/yukihookapi/hook/xposed/channel/data/ChannelData.html",pathLocale:"/en/",extraFields:[]},{title:"ChannelPriority - class",headers:[],path:"/en/api/public/com/highcapable/yukihookapi/hook/xposed/channel/priority/ChannelPriority.html",pathLocale:"/en/",extraFields:[]},{title:"ModuleClassLoader - class",headers:[{level:2,title:"companion object - object",slug:"companion-object-object",link:"#companion-object-object",children:[{level:3,title:"excludeHostClasses - method",slug:"excludehostclasses-method",link:"#excludehostclasses-method",children:[]},{level:3,title:"excludeModuleClasses - method",slug:"excludemoduleclasses-method",link:"#excludemoduleclasses-method",children:[]}]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/reference/ModuleClassLoader.html",pathLocale:"/en/",extraFields:[]},{title:"PrefsData - class",headers:[],path:"/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData.html",pathLocale:"/en/",extraFields:[]},{title:"ModulePreferenceFragment - class",headers:[{level:2,title:"onCreatePreferencesInModuleApp - method",slug:"oncreatepreferencesinmoduleapp-method",link:"#oncreatepreferencesinmoduleapp-method",children:[]},{level:2,title:"onSharedPreferenceChanged - method",slug:"onsharedpreferencechanged-method",link:"#onsharedpreferencechanged-method",children:[]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/ui/ModulePreferenceFragment.html",pathLocale:"/en/",extraFields:[]},{title:"YukiHookPriority - class",headers:[{level:2,title:"DEFAULT - enum",slug:"default-enum",link:"#default-enum",children:[]},{level:2,title:"LOWEST - enum",slug:"lowest-enum",link:"#lowest-enum",children:[]},{level:2,title:"HIGHEST - enum",slug:"highest-enum",link:"#highest-enum",children:[]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/api/priority/YukiHookPriority.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"BaseFinder - class",headers:[{level:2,title:"BaseFinder.IndexTypeCondition - class",slug:"basefinder-indextypecondition-class",link:"#basefinder-indextypecondition-class",children:[{level:3,title:"index - method",slug:"index-method",link:"#index-method",children:[]},{level:3,title:"index - method",slug:"index-method-1",link:"#index-method-1",children:[]},{level:3,title:"IndexTypeConditionSort - class",slug:"indextypeconditionsort-class",link:"#indextypeconditionsort-class",children:[]}]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/base/BaseFinder.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"DexClassFinder - class",headers:[{level:2,title:"companion object - object",slug:"companion-object-object",link:"#companion-object-object",children:[{level:3,title:"clearCache - method",slug:"clearcache-method",link:"#clearcache-method",children:[]}]},{level:2,title:"fullName - field",slug:"fullname-field",link:"#fullname-field",children:[]},{level:2,title:"simpleName - field",slug:"simplename-field",link:"#simplename-field",children:[]},{level:2,title:"singleName - field",slug:"singlename-field",link:"#singlename-field",children:[]},{level:2,title:"from - method",slug:"from-method",link:"#from-method",children:[]},{level:2,title:"modifiers - method",slug:"modifiers-method",link:"#modifiers-method",children:[]},{level:2,title:"fullName - method",slug:"fullname-method",link:"#fullname-method",children:[]},{level:2,title:"simpleName - method",slug:"simplename-method",link:"#simplename-method",children:[]},{level:2,title:"singleName - method",slug:"singlename-method",link:"#singlename-method",children:[]},{level:2,title:"fullName - method",slug:"fullname-method-1",link:"#fullname-method-1",children:[]},{level:2,title:"simpleName - method",slug:"simplename-method-1",link:"#simplename-method-1",children:[]},{level:2,title:"singleName - method",slug:"singlename-method-1",link:"#singlename-method-1",children:[]},{level:2,title:"extends - method",slug:"extends-method",link:"#extends-method",children:[]},{level:2,title:"extends - method",slug:"extends-method-1",link:"#extends-method-1",children:[]},{level:2,title:"implements - method",slug:"implements-method",link:"#implements-method",children:[]},{level:2,title:"implements - method",slug:"implements-method-1",link:"#implements-method-1",children:[]},{level:2,title:"anonymous - method",slug:"anonymous-method",link:"#anonymous-method",children:[]},{level:2,title:"noExtends - method",slug:"noextends-method",link:"#noextends-method",children:[]},{level:2,title:"noImplements - method",slug:"noimplements-method",link:"#noimplements-method",children:[]},{level:2,title:"noSuper - method",slug:"nosuper-method",link:"#nosuper-method",children:[]},{level:2,title:"enclosing - method",slug:"enclosing-method",link:"#enclosing-method",children:[]},{level:2,title:"enclosing - method",slug:"enclosing-method-1",link:"#enclosing-method-1",children:[]},{level:2,title:"FromPackageRules - class",slug:"frompackagerules-class",link:"#frompackagerules-class",children:[{level:3,title:"absolute - method",slug:"absolute-method",link:"#absolute-method",children:[]}]},{level:2,title:"ClassNameRules - class",slug:"classnamerules-class",link:"#classnamerules-class",children:[{level:3,title:"optional - method",slug:"optional-method",link:"#optional-method",children:[]}]},{level:2,title:"member - method",slug:"member-method",link:"#member-method",children:[]},{level:2,title:"field - method",slug:"field-method",link:"#field-method",children:[]},{level:2,title:"method - method",slug:"method-method",link:"#method-method",children:[]},{level:2,title:"constructor - method",slug:"constructor-method",link:"#constructor-method",children:[]},{level:2,title:"Result - class",slug:"result-class",link:"#result-class",children:[{level:3,title:"result - method",slug:"result-method",link:"#result-method",children:[]},{level:3,title:"get - method",slug:"get-method",link:"#get-method",children:[]},{level:3,title:"all - method",slug:"all-method",link:"#all-method",children:[]},{level:3,title:"all - method",slug:"all-method-1",link:"#all-method-1",children:[]},{level:3,title:"wait - method",slug:"wait-method",link:"#wait-method",children:[]},{level:3,title:"waitAll - method",slug:"waitall-method",link:"#waitall-method",children:[]},{level:3,title:"onNoClassDefFoundError - method",slug:"onnoclassdeffounderror-method",link:"#onnoclassdeffounderror-method",children:[]},{level:3,title:"ignored - method",slug:"ignored-method",link:"#ignored-method",children:[]}]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/DexClassFinder.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"ConstructorFinder - class",headers:[{level:2,title:"paramCount - field",slug:"paramcount-field",link:"#paramcount-field",children:[]},{level:2,title:"modifiers - method",slug:"modifiers-method",link:"#modifiers-method",children:[]},{level:2,title:"emptyParam - method",slug:"emptyparam-method",link:"#emptyparam-method",children:[]},{level:2,title:"param - method",slug:"param-method",link:"#param-method",children:[]},{level:2,title:"param - method",slug:"param-method-1",link:"#param-method-1",children:[]},{level:2,title:"paramCount - method",slug:"paramcount-method",link:"#paramcount-method",children:[]},{level:2,title:"paramCount - method",slug:"paramcount-method-1",link:"#paramcount-method-1",children:[]},{level:2,title:"paramCount - method",slug:"paramcount-method-2",link:"#paramcount-method-2",children:[]},{level:2,title:"superClass - method",slug:"superclass-method",link:"#superclass-method",children:[]},{level:2,title:"RemedyPlan - class",slug:"remedyplan-class",link:"#remedyplan-class",children:[{level:3,title:"constructor - method",slug:"constructor-method",link:"#constructor-method",children:[]},{level:3,title:"Result - class",slug:"result-class",link:"#result-class",children:[]}]},{level:2,title:"Process - class",slug:"process-class",link:"#process-class",children:[{level:3,title:"result - method",slug:"result-method",link:"#result-method",children:[]},{level:3,title:"all - method",slug:"all-method",link:"#all-method",children:[]},{level:3,title:"remedys - method",slug:"remedys-method",link:"#remedys-method",children:[]},{level:3,title:"onNoSuchConstructor - method",slug:"onnosuchconstructor-method",link:"#onnosuchconstructor-method",children:[]}]},{level:2,title:"Result - class",slug:"result-class-1",link:"#result-class-1",children:[{level:3,title:"result - method",slug:"result-method-1",link:"#result-method-1",children:[]},{level:3,title:"get - method",slug:"get-method",link:"#get-method",children:[]},{level:3,title:"all - method",slug:"all-method-1",link:"#all-method-1",children:[]},{level:3,title:"give - method",slug:"give-method",link:"#give-method",children:[]},{level:3,title:"giveAll - method",slug:"giveall-method",link:"#giveall-method",children:[]},{level:3,title:"wait - method",slug:"wait-method",link:"#wait-method",children:[]},{level:3,title:"waitAll - method",slug:"waitall-method",link:"#waitall-method",children:[]},{level:3,title:"remedys - method",slug:"remedys-method-1",link:"#remedys-method-1",children:[]},{level:3,title:"onNoSuchConstructor - method",slug:"onnosuchconstructor-method-1",link:"#onnosuchconstructor-method-1",children:[]},{level:3,title:"ignored - method",slug:"ignored-method",link:"#ignored-method",children:[]},{level:3,title:"Instance - class",slug:"instance-class",link:"#instance-class",children:[]}]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/members/ConstructorFinder.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"FieldFinder - class",headers:[{level:2,title:"name - field",slug:"name-field",link:"#name-field",children:[]},{level:2,title:"type - field",slug:"type-field",link:"#type-field",children:[]},{level:2,title:"modifiers - method",slug:"modifiers-method",link:"#modifiers-method",children:[]},{level:2,title:"order - method",slug:"order-method",link:"#order-method",children:[]},{level:2,title:"name - method",slug:"name-method",link:"#name-method",children:[]},{level:2,title:"name - method",slug:"name-method-1",link:"#name-method-1",children:[]},{level:2,title:"type - method",slug:"type-method",link:"#type-method",children:[]},{level:2,title:"type - method",slug:"type-method-1",link:"#type-method-1",children:[]},{level:2,title:"superClass - method",slug:"superclass-method",link:"#superclass-method",children:[]},{level:2,title:"RemedyPlan - class",slug:"remedyplan-class",link:"#remedyplan-class",children:[{level:3,title:"field - method",slug:"field-method",link:"#field-method",children:[]},{level:3,title:"Result - class",slug:"result-class",link:"#result-class",children:[]}]},{level:2,title:"Result - class",slug:"result-class-1",link:"#result-class-1",children:[{level:3,title:"result - method",slug:"result-method",link:"#result-method",children:[]},{level:3,title:"get - method",slug:"get-method",link:"#get-method",children:[]},{level:3,title:"all - method",slug:"all-method",link:"#all-method",children:[]},{level:3,title:"give - method",slug:"give-method",link:"#give-method",children:[]},{level:3,title:"giveAll - method",slug:"giveall-method",link:"#giveall-method",children:[]},{level:3,title:"wait - method",slug:"wait-method",link:"#wait-method",children:[]},{level:3,title:"waitAll - method",slug:"waitall-method",link:"#waitall-method",children:[]},{level:3,title:"remedys - method",slug:"remedys-method",link:"#remedys-method",children:[]},{level:3,title:"onNoSuchField - method",slug:"onnosuchfield-method",link:"#onnosuchfield-method",children:[]},{level:3,title:"ignored - method",slug:"ignored-method",link:"#ignored-method",children:[]},{level:3,title:"Instance - class",slug:"instance-class",link:"#instance-class",children:[]}]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/members/FieldFinder.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"MethodFinder - class",headers:[{level:2,title:"name - field",slug:"name-field",link:"#name-field",children:[]},{level:2,title:"paramCount - field",slug:"paramcount-field",link:"#paramcount-field",children:[]},{level:2,title:"returnType - field",slug:"returntype-field",link:"#returntype-field",children:[]},{level:2,title:"modifiers - method",slug:"modifiers-method",link:"#modifiers-method",children:[]},{level:2,title:"emptyParam - method",slug:"emptyparam-method",link:"#emptyparam-method",children:[]},{level:2,title:"param - method",slug:"param-method",link:"#param-method",children:[]},{level:2,title:"param - method",slug:"param-method-1",link:"#param-method-1",children:[]},{level:2,title:"order - method",slug:"order-method",link:"#order-method",children:[]},{level:2,title:"name - method",slug:"name-method",link:"#name-method",children:[]},{level:2,title:"name - method",slug:"name-method-1",link:"#name-method-1",children:[]},{level:2,title:"paramCount - method",slug:"paramcount-method",link:"#paramcount-method",children:[]},{level:2,title:"paramCount - method",slug:"paramcount-method-1",link:"#paramcount-method-1",children:[]},{level:2,title:"paramCount - method",slug:"paramcount-method-2",link:"#paramcount-method-2",children:[]},{level:2,title:"returnType - method",slug:"returntype-method",link:"#returntype-method",children:[]},{level:2,title:"returnType - method",slug:"returntype-method-1",link:"#returntype-method-1",children:[]},{level:2,title:"superClass - method",slug:"superclass-method",link:"#superclass-method",children:[]},{level:2,title:"RemedyPlan - class",slug:"remedyplan-class",link:"#remedyplan-class",children:[{level:3,title:"method - method",slug:"method-method",link:"#method-method",children:[]},{level:3,title:"Result - class",slug:"result-class",link:"#result-class",children:[]}]},{level:2,title:"Process - class",slug:"process-class",link:"#process-class",children:[{level:3,title:"result - method",slug:"result-method",link:"#result-method",children:[]},{level:3,title:"all - method",slug:"all-method",link:"#all-method",children:[]},{level:3,title:"remedys - method",slug:"remedys-method",link:"#remedys-method",children:[]},{level:3,title:"onNoSuchMethod - method",slug:"onnosuchmethod-method",link:"#onnosuchmethod-method",children:[]}]},{level:2,title:"Result - class",slug:"result-class-1",link:"#result-class-1",children:[{level:3,title:"result - method",slug:"result-method-1",link:"#result-method-1",children:[]},{level:3,title:"get - method",slug:"get-method",link:"#get-method",children:[]},{level:3,title:"all - method",slug:"all-method-1",link:"#all-method-1",children:[]},{level:3,title:"give - method",slug:"give-method",link:"#give-method",children:[]},{level:3,title:"giveAll - method",slug:"giveall-method",link:"#giveall-method",children:[]},{level:3,title:"wait - method",slug:"wait-method",link:"#wait-method",children:[]},{level:3,title:"waitAll - method",slug:"waitall-method",link:"#waitall-method",children:[]},{level:3,title:"remedys - method",slug:"remedys-method-1",link:"#remedys-method-1",children:[]},{level:3,title:"onNoSuchMethod - method",slug:"onnosuchmethod-method-1",link:"#onnosuchmethod-method-1",children:[]},{level:3,title:"ignored - method",slug:"ignored-method",link:"#ignored-method",children:[]},{level:3,title:"Instance - class",slug:"instance-class",link:"#instance-class",children:[]},{level:3,title:"array - method",slug:"array-method",link:"#array-method",children:[]},{level:3,title:"list - method",slug:"list-method",link:"#list-method",children:[]}]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/members/MethodFinder.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"YukiXposedEvent - object",headers:[{level:2,title:"events - method",slug:"events-method",link:"#events-method",children:[]},{level:2,title:"onInitZygote - method",slug:"oninitzygote-method",link:"#oninitzygote-method",children:[]},{level:2,title:"onHandleLoadPackage - method",slug:"onhandleloadpackage-method",link:"#onhandleloadpackage-method",children:[]},{level:2,title:"onHandleInitPackageResources - method",slug:"onhandleinitpackageresources-method",link:"#onhandleinitpackageresources-method",children:[]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/event/YukiXposedEvent.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"YukiModuleResources - class",headers:[{level:2,title:"fwd - method",slug:"fwd-method",link:"#fwd-method",children:[]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiModuleResources.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"YukiResForwarder - class",headers:[{level:2,title:"id - field",slug:"id-field",link:"#id-field",children:[]},{level:2,title:"resources - field",slug:"resources-field",link:"#resources-field",children:[]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResForwarder.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"YukiResources - class",headers:[{level:2,title:"LayoutInflatedParam - class",slug:"layoutinflatedparam-class",link:"#layoutinflatedparam-class",children:[{level:3,title:"variantName - field",slug:"variantname-field",link:"#variantname-field",children:[]},{level:3,title:"currentView - field",slug:"currentview-field",link:"#currentview-field",children:[]},{level:3,title:"findViewByIdentifier - method",slug:"findviewbyidentifier-method",link:"#findviewbyidentifier-method",children:[]}]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResources.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"ChannelData - class",headers:[],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/channel/data/ChannelData.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"ChannelPriority - class",headers:[],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/channel/priority/ChannelPriority.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"ModuleClassLoader - class",headers:[{level:2,title:"companion object - object",slug:"companion-object-object",link:"#companion-object-object",children:[{level:3,title:"excludeHostClasses - method",slug:"excludehostclasses-method",link:"#excludehostclasses-method",children:[]},{level:3,title:"excludeModuleClasses - method",slug:"excludemoduleclasses-method",link:"#excludemoduleclasses-method",children:[]}]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/reference/ModuleClassLoader.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"PrefsData - class",headers:[],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"ModulePreferenceFragment - class",headers:[{level:2,title:"onCreatePreferencesInModuleApp - method",slug:"oncreatepreferencesinmoduleapp-method",link:"#oncreatepreferencesinmoduleapp-method",children:[]},{level:2,title:"onSharedPreferenceChanged - method",slug:"onsharedpreferencechanged-method",link:"#onsharedpreferencechanged-method",children:[]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/ui/ModulePreferenceFragment.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"ExecutorType - class",headers:[{level:2,title:"UNKNOWN - enum",slug:"unknown-enum",link:"#unknown-enum",children:[]},{level:2,title:"XPOSED - enum",slug:"xposed-enum",link:"#xposed-enum",children:[]},{level:2,title:"LSPOSED_LSPATCH - enum",slug:"lsposed-lspatch-enum",link:"#lsposed-lspatch-enum",children:[]},{level:2,title:"ED_XPOSED - enum",slug:"ed-xposed-enum",link:"#ed-xposed-enum",children:[]},{level:2,title:"TAICHI_XPOSED - enum",slug:"taichi-xposed-enum",link:"#taichi-xposed-enum",children:[]},{level:2,title:"BUG_XPOSED - enum",slug:"bug-xposed-enum",link:"#bug-xposed-enum",children:[]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/core/api/compat/type/ExecutorType.html",pathLocale:"/en/",extraFields:[]},{title:"CountRules - class",headers:[{level:2,title:"Int.isZero - i-ext-method",slug:"int-iszero-i-ext-method",link:"#int-iszero-i-ext-method",children:[]},{level:2,title:"Int.moreThan - i-ext-method",slug:"int-morethan-i-ext-method",link:"#int-morethan-i-ext-method",children:[]},{level:2,title:"Int.lessThan - i-ext-method",slug:"int-lessthan-i-ext-method",link:"#int-lessthan-i-ext-method",children:[]},{level:2,title:"Int.inInterval - i-ext-method",slug:"int-ininterval-i-ext-method",link:"#int-ininterval-i-ext-method",children:[]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/CountRules.html",pathLocale:"/en/",extraFields:[]},{title:"ModifierRules - class",headers:[{level:2,title:"isPublic - i-ext-field",slug:"ispublic-i-ext-field",link:"#ispublic-i-ext-field",children:[]},{level:2,title:"isPrivate - i-ext-field",slug:"isprivate-i-ext-field",link:"#isprivate-i-ext-field",children:[]},{level:2,title:"isProtected - i-ext-field",slug:"isprotected-i-ext-field",link:"#isprotected-i-ext-field",children:[]},{level:2,title:"isStatic - i-ext-field",slug:"isstatic-i-ext-field",link:"#isstatic-i-ext-field",children:[]},{level:2,title:"isFinal - i-ext-field",slug:"isfinal-i-ext-field",link:"#isfinal-i-ext-field",children:[]},{level:2,title:"isSynchronized - i-ext-field",slug:"issynchronized-i-ext-field",link:"#issynchronized-i-ext-field",children:[]},{level:2,title:"isVolatile - i-ext-field",slug:"isvolatile-i-ext-field",link:"#isvolatile-i-ext-field",children:[]},{level:2,title:"isTransient - i-ext-field",slug:"istransient-i-ext-field",link:"#istransient-i-ext-field",children:[]},{level:2,title:"isNative - i-ext-field",slug:"isnative-i-ext-field",link:"#isnative-i-ext-field",children:[]},{level:2,title:"isInterface - i-ext-field",slug:"isinterface-i-ext-field",link:"#isinterface-i-ext-field",children:[]},{level:2,title:"isAbstract - i-ext-field",slug:"isabstract-i-ext-field",link:"#isabstract-i-ext-field",children:[]},{level:2,title:"isStrict - i-ext-field",slug:"isstrict-i-ext-field",link:"#isstrict-i-ext-field",children:[]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/ModifierRules.html",pathLocale:"/en/",extraFields:[]},{title:"NameRules - class",headers:[{level:2,title:"String.isSynthetic - i-ext-method",slug:"string-issynthetic-i-ext-method",link:"#string-issynthetic-i-ext-method",children:[]},{level:2,title:"String.isOnlySymbols - i-ext-method",slug:"string-isonlysymbols-i-ext-method",link:"#string-isonlysymbols-i-ext-method",children:[]},{level:2,title:"String.isOnlyLetters - i-ext-method",slug:"string-isonlyletters-i-ext-method",link:"#string-isonlyletters-i-ext-method",children:[]},{level:2,title:"String.isOnlyNumbers - i-ext-method",slug:"string-isonlynumbers-i-ext-method",link:"#string-isonlynumbers-i-ext-method",children:[]},{level:2,title:"String.isOnlyLettersNumbers - i-ext-method",slug:"string-isonlylettersnumbers-i-ext-method",link:"#string-isonlylettersnumbers-i-ext-method",children:[]},{level:2,title:"String.isOnlyLowercase - i-ext-method",slug:"string-isonlylowercase-i-ext-method",link:"#string-isonlylowercase-i-ext-method",children:[]},{level:2,title:"String.isOnlyUppercase - i-ext-method",slug:"string-isonlyuppercase-i-ext-method",link:"#string-isonlyuppercase-i-ext-method",children:[]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/NameRules.html",pathLocale:"/en/",extraFields:[]},{title:"ObjectRules - class",headers:[],path:"/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/ObjectRules.html",pathLocale:"/en/",extraFields:[]},{title:"ConstructorRules - class",headers:[{level:2,title:"paramCount - field",slug:"paramcount-field",link:"#paramcount-field",children:[]},{level:2,title:"modifiers - method",slug:"modifiers-method",link:"#modifiers-method",children:[]},{level:2,title:"emptyParam - method",slug:"emptyparam-method",link:"#emptyparam-method",children:[]},{level:2,title:"param - method",slug:"param-method",link:"#param-method",children:[]},{level:2,title:"param - method",slug:"param-method-1",link:"#param-method-1",children:[]},{level:2,title:"paramCount - method",slug:"paramcount-method",link:"#paramcount-method",children:[]},{level:2,title:"paramCount - method",slug:"paramcount-method-1",link:"#paramcount-method-1",children:[]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/ConstructorRules.html",pathLocale:"/en/",extraFields:[]},{title:"FieldRules - class",headers:[{level:2,title:"name - field",slug:"name-field",link:"#name-field",children:[]},{level:2,title:"type - field",slug:"type-field",link:"#type-field",children:[]},{level:2,title:"modifiers - method",slug:"modifiers-method",link:"#modifiers-method",children:[]},{level:2,title:"name - method",slug:"name-method",link:"#name-method",children:[]},{level:2,title:"type - method",slug:"type-method",link:"#type-method",children:[]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/FieldRules.html",pathLocale:"/en/",extraFields:[]},{title:"MemberRules - class",headers:[{level:2,title:"modifiers - method",slug:"modifiers-method",link:"#modifiers-method",children:[]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/MemberRules.html",pathLocale:"/en/",extraFields:[]},{title:"MethodRules - class",headers:[{level:2,title:"name - field",slug:"name-field",link:"#name-field",children:[]},{level:2,title:"paramCount - field",slug:"paramcount-field",link:"#paramcount-field",children:[]},{level:2,title:"returnType - field",slug:"returntype-field",link:"#returntype-field",children:[]},{level:2,title:"modifiers - method",slug:"modifiers-method",link:"#modifiers-method",children:[]},{level:2,title:"emptyParam - method",slug:"emptyparam-method",link:"#emptyparam-method",children:[]},{level:2,title:"param - method",slug:"param-method",link:"#param-method",children:[]},{level:2,title:"param - method",slug:"param-method-1",link:"#param-method-1",children:[]},{level:2,title:"name - method",slug:"name-method",link:"#name-method",children:[]},{level:2,title:"paramCount - method",slug:"paramcount-method",link:"#paramcount-method",children:[]},{level:2,title:"paramCount - method",slug:"paramcount-method-1",link:"#paramcount-method-1",children:[]},{level:2,title:"returnType - method",slug:"returntype-method",link:"#returntype-method",children:[]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/MethodRules.html",pathLocale:"/en/",extraFields:[]},{title:"ModuleAppActivity - class",headers:[{level:2,title:"proxyClassName - field",slug:"proxyclassname-field",link:"#proxyclassname-field",children:[]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/base/ModuleAppActivity.html",pathLocale:"/en/",extraFields:[]},{title:"ModuleAppCompatActivity - class",headers:[{level:2,title:"moduleTheme - field",slug:"moduletheme-field",link:"#moduletheme-field",children:[]},{level:2,title:"proxyClassName - field",slug:"proxyclassname-field",link:"#proxyclassname-field",children:[]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/base/ModuleAppCompatActivity.html",pathLocale:"/en/",extraFields:[]},{title:"ModuleContextThemeWrapper - class",headers:[{level:2,title:"applyConfiguration - method",slug:"applyconfiguration-method",link:"#applyconfiguration-method",children:[]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/context/wrapper/ModuleContextThemeWrapper.html",pathLocale:"/en/",extraFields:[]},{title:"ExecutorType - class",headers:[{level:2,title:"UNKNOWN - enum",slug:"unknown-enum",link:"#unknown-enum",children:[]},{level:2,title:"XPOSED - enum",slug:"xposed-enum",link:"#xposed-enum",children:[]},{level:2,title:"LSPOSED_LSPATCH - enum",slug:"lsposed-lspatch-enum",link:"#lsposed-lspatch-enum",children:[]},{level:2,title:"ED_XPOSED - enum",slug:"ed-xposed-enum",link:"#ed-xposed-enum",children:[]},{level:2,title:"TAICHI_XPOSED - enum",slug:"taichi-xposed-enum",link:"#taichi-xposed-enum",children:[]},{level:2,title:"BUG_XPOSED - enum",slug:"bug-xposed-enum",link:"#bug-xposed-enum",children:[]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/api/compat/type/ExecutorType.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"CountRules - class",headers:[{level:2,title:"Int.isZero - i-ext-method",slug:"int-iszero-i-ext-method",link:"#int-iszero-i-ext-method",children:[]},{level:2,title:"Int.moreThan - i-ext-method",slug:"int-morethan-i-ext-method",link:"#int-morethan-i-ext-method",children:[]},{level:2,title:"Int.lessThan - i-ext-method",slug:"int-lessthan-i-ext-method",link:"#int-lessthan-i-ext-method",children:[]},{level:2,title:"Int.inInterval - i-ext-method",slug:"int-ininterval-i-ext-method",link:"#int-ininterval-i-ext-method",children:[]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/CountRules.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"ModifierRules - class",headers:[{level:2,title:"isPublic - i-ext-field",slug:"ispublic-i-ext-field",link:"#ispublic-i-ext-field",children:[]},{level:2,title:"isPrivate - i-ext-field",slug:"isprivate-i-ext-field",link:"#isprivate-i-ext-field",children:[]},{level:2,title:"isProtected - i-ext-field",slug:"isprotected-i-ext-field",link:"#isprotected-i-ext-field",children:[]},{level:2,title:"isStatic - i-ext-field",slug:"isstatic-i-ext-field",link:"#isstatic-i-ext-field",children:[]},{level:2,title:"isFinal - i-ext-field",slug:"isfinal-i-ext-field",link:"#isfinal-i-ext-field",children:[]},{level:2,title:"isSynchronized - i-ext-field",slug:"issynchronized-i-ext-field",link:"#issynchronized-i-ext-field",children:[]},{level:2,title:"isVolatile - i-ext-field",slug:"isvolatile-i-ext-field",link:"#isvolatile-i-ext-field",children:[]},{level:2,title:"isTransient - i-ext-field",slug:"istransient-i-ext-field",link:"#istransient-i-ext-field",children:[]},{level:2,title:"isNative - i-ext-field",slug:"isnative-i-ext-field",link:"#isnative-i-ext-field",children:[]},{level:2,title:"isInterface - i-ext-field",slug:"isinterface-i-ext-field",link:"#isinterface-i-ext-field",children:[]},{level:2,title:"isAbstract - i-ext-field",slug:"isabstract-i-ext-field",link:"#isabstract-i-ext-field",children:[]},{level:2,title:"isStrict - i-ext-field",slug:"isstrict-i-ext-field",link:"#isstrict-i-ext-field",children:[]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/ModifierRules.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"NameRules - class",headers:[{level:2,title:"String.isSynthetic - i-ext-method",slug:"string-issynthetic-i-ext-method",link:"#string-issynthetic-i-ext-method",children:[]},{level:2,title:"String.isOnlySymbols - i-ext-method",slug:"string-isonlysymbols-i-ext-method",link:"#string-isonlysymbols-i-ext-method",children:[]},{level:2,title:"String.isOnlyLetters - i-ext-method",slug:"string-isonlyletters-i-ext-method",link:"#string-isonlyletters-i-ext-method",children:[]},{level:2,title:"String.isOnlyNumbers - i-ext-method",slug:"string-isonlynumbers-i-ext-method",link:"#string-isonlynumbers-i-ext-method",children:[]},{level:2,title:"String.isOnlyLettersNumbers - i-ext-method",slug:"string-isonlylettersnumbers-i-ext-method",link:"#string-isonlylettersnumbers-i-ext-method",children:[]},{level:2,title:"String.isOnlyLowercase - i-ext-method",slug:"string-isonlylowercase-i-ext-method",link:"#string-isonlylowercase-i-ext-method",children:[]},{level:2,title:"String.isOnlyUppercase - i-ext-method",slug:"string-isonlyuppercase-i-ext-method",link:"#string-isonlyuppercase-i-ext-method",children:[]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/NameRules.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"ObjectRules - class",headers:[],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/ObjectRules.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"ConstructorRules - class",headers:[{level:2,title:"paramCount - field",slug:"paramcount-field",link:"#paramcount-field",children:[]},{level:2,title:"modifiers - method",slug:"modifiers-method",link:"#modifiers-method",children:[]},{level:2,title:"emptyParam - method",slug:"emptyparam-method",link:"#emptyparam-method",children:[]},{level:2,title:"param - method",slug:"param-method",link:"#param-method",children:[]},{level:2,title:"param - method",slug:"param-method-1",link:"#param-method-1",children:[]},{level:2,title:"paramCount - method",slug:"paramcount-method",link:"#paramcount-method",children:[]},{level:2,title:"paramCount - method",slug:"paramcount-method-1",link:"#paramcount-method-1",children:[]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/ConstructorRules.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"FieldRules - class",headers:[{level:2,title:"name - field",slug:"name-field",link:"#name-field",children:[]},{level:2,title:"type - field",slug:"type-field",link:"#type-field",children:[]},{level:2,title:"modifiers - method",slug:"modifiers-method",link:"#modifiers-method",children:[]},{level:2,title:"name - method",slug:"name-method",link:"#name-method",children:[]},{level:2,title:"type - method",slug:"type-method",link:"#type-method",children:[]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/FieldRules.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"MemberRules - class",headers:[{level:2,title:"modifiers - method",slug:"modifiers-method",link:"#modifiers-method",children:[]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/MemberRules.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"MethodRules - class",headers:[{level:2,title:"name - field",slug:"name-field",link:"#name-field",children:[]},{level:2,title:"paramCount - field",slug:"paramcount-field",link:"#paramcount-field",children:[]},{level:2,title:"returnType - field",slug:"returntype-field",link:"#returntype-field",children:[]},{level:2,title:"modifiers - method",slug:"modifiers-method",link:"#modifiers-method",children:[]},{level:2,title:"emptyParam - method",slug:"emptyparam-method",link:"#emptyparam-method",children:[]},{level:2,title:"param - method",slug:"param-method",link:"#param-method",children:[]},{level:2,title:"param - method",slug:"param-method-1",link:"#param-method-1",children:[]},{level:2,title:"name - method",slug:"name-method",link:"#name-method",children:[]},{level:2,title:"paramCount - method",slug:"paramcount-method",link:"#paramcount-method",children:[]},{level:2,title:"paramCount - method",slug:"paramcount-method-1",link:"#paramcount-method-1",children:[]},{level:2,title:"returnType - method",slug:"returntype-method",link:"#returntype-method",children:[]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/MethodRules.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"ModuleAppActivity - class",headers:[{level:2,title:"proxyClassName - field",slug:"proxyclassname-field",link:"#proxyclassname-field",children:[]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/base/ModuleAppActivity.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"ModuleAppCompatActivity - class",headers:[{level:2,title:"moduleTheme - field",slug:"moduletheme-field",link:"#moduletheme-field",children:[]},{level:2,title:"proxyClassName - field",slug:"proxyclassname-field",link:"#proxyclassname-field",children:[]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/base/ModuleAppCompatActivity.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"ModuleContextThemeWrapper - class",headers:[{level:2,title:"applyConfiguration - method",slug:"applyconfiguration-method",link:"#applyconfiguration-method",children:[]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/context/wrapper/ModuleContextThemeWrapper.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"MemberRulesResult - class",headers:[{level:2,title:"none - method",slug:"none-method",link:"#none-method",children:[]},{level:2,title:"count - method",slug:"count-method",link:"#count-method",children:[]},{level:2,title:"count - method",slug:"count-method-1",link:"#count-method-1",children:[]},{level:2,title:"count - method",slug:"count-method-2",link:"#count-method-2",children:[]}],path:"/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/result/MemberRulesResult.html",pathLocale:"/en/",extraFields:[]},{title:"MemberRulesResult - class",headers:[{level:2,title:"none - method",slug:"none-method",link:"#none-method",children:[]},{level:2,title:"count - method",slug:"count-method",link:"#count-method",children:[]},{level:2,title:"count - method",slug:"count-method-1",link:"#count-method-1",children:[]},{level:2,title:"count - method",slug:"count-method-2",link:"#count-method-2",children:[]}],path:"/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/result/MemberRulesResult.html",pathLocale:"/zh-cn/",extraFields:[]},{title:"",headers:[],path:"/404.html",pathLocale:"/",extraFields:[]}],af=ke(rf),cf=()=>af,df=({searchIndex:e,routeLocale:t,query:l,maxSuggestions:i})=>{const o=B(()=>e.value.filter(n=>n.pathLocale===t.value));return B(()=>{const n=l.value.trim().toLowerCase();if(!n)return[];const s=[],a=(r,c)=>{us(n,[c.title])&&s.push({link:`${r.path}#${c.slug}`,title:r.title,header:c.title});for(const d of c.children){if(s.length>=i.value)return;a(r,d)}};for(const r of o.value){if(s.length>=i.value)break;if(us(n,[r.title,...r.extraFields])){s.push({link:r.path,title:r.title});continue}for(const c of r.headers){if(s.length>=i.value)break;a(r,c)}}return s})},hf=e=>{const t=ke(0);return{focusIndex:t,focusNext:()=>{t.value {t.value>0?t.value-=1:t.value=e.value.length-1}}},uf=he({name:"SearchBox",props:{locales:{type:Object,required:!1,default:()=>({})},hotKeys:{type:Array,required:!1,default:()=>[]},maxSuggestions:{type:Number,required:!1,default:5}},setup(e){const{locales:t,hotKeys:l,maxSuggestions:i}=Ti(e),o=Jt(),n=ql(),s=cf(),a=ke(null),r=ke(!1),c=ke(""),d=B(()=>t.value[n.value]??{}),u=df({searchIndex:s,routeLocale:n,query:c,maxSuggestions:i}),{focusIndex:m,focusNext:g,focusPrev:x}=hf(u);sf({input:a,hotKeys:l});const L=B(()=>r.value&&!!u.value.length),C=()=>{L.value&&x()},I=()=>{L.value&&g()},T=_=>{if(!L.value)return;const y=u.value[_];y&&o.push(y.link).then(()=>{c.value="",m.value=0})};return()=>ce("form",{class:"search-box",role:"search"},[ce("input",{ref:a,type:"search",placeholder:d.value.placeholder,autocomplete:"off",spellcheck:!1,value:c.value,onFocus:()=>r.value=!0,onBlur:()=>r.value=!1,onInput:_=>c.value=_.target.value,onKeydown:_=>{switch(_.key){case"ArrowUp":{C();break}case"ArrowDown":{I();break}case"Enter":{_.preventDefault(),T(m.value);break}}}}),L.value&&ce("ul",{class:"suggestions",onMouseleave:()=>m.value=-1},u.value.map(({link:_,title:y,header:j},K)=>ce("li",{class:["suggestion",{focus:m.value===K}],onMouseenter:()=>m.value=K,onMousedown:()=>T(K)},ce("a",{href:_,onClick:M=>M.preventDefault()},[ce("span",{class:"page-title"},y),j&&ce("span",{class:"page-header"},`> ${j}`)]))))])}});var mf=["s","/"],pf={"/en/":{placeholder:"Search"},"/zh-cn/":{placeholder:"搜索"}};const ff=pf,gf=mf,vf=5,kf=St({enhance({app:e}){e.component("SearchBox",t=>ce(uf,{locales:ff,hotKeys:gf,maxSuggestions:vf,...t}))}}),ci=[Kh,Jh,lu,pu,ku,Eu,ef,kf],_f=[["v-8daa1a0e","/",{title:""},["/index.md"]],["v-2d0a870d","/en/",{title:"Home"},["/en/index.md"]],["v-c0c85b84","/zh-cn/",{title:"首页"},["/zh-cn/index.md"]],["v-7a15fe3b","/en/about/about.html",{title:"About This Document"},[":md"]],["v-3f851d14","/en/about/changelog.html",{title:"Changelog"},[":md"]],["v-193cf592","/en/about/contacts.html",{title:"Contact Us"},[":md"]],["v-ae7b83f2","/en/about/future.html",{title:"Looking Toward the Future"},[":md"]],["v-64fc7bb8","/en/api/home.html",{title:"Document Introduce"},[":md"]],["v-9cfea7fc","/en/config/api-example.html",{title:"API Basic Configs"},[":md"]],["v-72c12b7d","/en/config/api-exception.html",{title:"API Exception Handling"},[":md"]],["v-793879e8","/en/config/api-using.html",{title:"Use as Hook API Configs"},[":md"]],["v-de1c6dbe","/en/config/move-to-api-1-2-x.html",{title:"Migrate to YukiHookAPI 1.2.x"},[":md"]],["v-0e5a1400","/en/config/move-to-api-1-3-x.html",{title:"Migrate to YukiHookAPI 1.3.x"},[":md"]],["v-29d6c1ba","/en/config/r8-proguard.html",{title:"R8 & Proguard Obfuscate"},[":md"]],["v-24e71de7","/en/config/xposed-using.html",{title:"Use as Xposed Module Configs"},[":md"]],["v-7b22efaf","/en/guide/example.html",{title:"Usage Example"},[":md"]],["v-efb45d4c","/en/guide/home.html",{title:"Introduction"},[":md"]],["v-277b35ca","/en/guide/knowledge.html",{title:"Basic Knowledge"},[":md"]],["v-77d752a2","/en/guide/move-to-new-api.html",{title:"Migrate from Other Hook APIs"},[":md"]],["v-72889797","/en/guide/quick-start.html",{title:"Quick Start"},[":md"]],["v-68fd81d0","/en/guide/supportive.html",{title:"Supportive"},[":md"]],["v-55c11626","/en/tools/yukihookapi-projectbuilder.html",{title:"YukiHookAPI Project Builder"},[":md"]],["v-41967128","/zh-cn/about/about.html",{title:"关于此文档"},[":md"]],["v-0e6c3476","/zh-cn/about/changelog.html",{title:"更新日志"},[":md"]],["v-6cf86266","/zh-cn/about/contacts.html",{title:"联系我们"},[":md"]],["v-3106ca14","/zh-cn/about/future.html",{title:"展望未来"},[":md"]],["v-c8deafb2","/zh-cn/api/home.html",{title:"文档介绍"},[":md"]],["v-c6114c9e","/zh-cn/config/api-example.html",{title:"API 基本配置"},[":md"]],["v-5b43296c","/zh-cn/config/api-exception.html",{title:"API 异常处理"},[":md"]],["v-2ee67152","/zh-cn/config/api-using.html",{title:"作为 Hook API 使用的相关配置"},[":md"]],["v-4b553790","/zh-cn/config/move-to-api-1-2-x.html",{title:"迁移至 YukiHookAPI 1.2.x"},[":md"]],["v-99933722","/zh-cn/config/move-to-api-1-3-x.html",{title:"迁移至 YukiHookAPI 1.3.x"},[":md"]],["v-154d6f69","/zh-cn/config/r8-proguard.html",{title:"R8 与 Proguard 混淆"},[":md"]],["v-af73b3d0","/zh-cn/config/xposed-using.html",{title:"作为 Xposed 模块使用的相关配置"},[":md"]],["v-13b430a0","/zh-cn/guide/example.html",{title:"用法示例"},[":md"]],["v-6a609e09","/zh-cn/guide/home.html",{title:"介绍"},[":md"]],["v-b4f1a468","/zh-cn/guide/knowledge.html",{title:"基础知识"},[":md"]],["v-c0d5dada","/zh-cn/guide/move-to-new-api.html",{title:"从其它 Hook API 迁移"},[":md"]],["v-24840ff0","/zh-cn/guide/quick-start.html",{title:"快速开始"},[":md"]],["v-4f5c6182","/zh-cn/guide/supportive.html",{title:"支持性"},[":md"]],["v-a2fab4d6","/zh-cn/tools/yukihookapi-projectbuilder.html",{title:"YukiHookAPI 构建工具"},[":md"]],["v-12042f1f","/en/api/special-features/host-inject.html",{title:"Host Resource Injection Extension"},[":md"]],["v-deaff1d0","/en/api/special-features/host-lifecycle.html",{title:"Host Lifecycle Extension"},[":md"]],["v-33c1dc26","/en/api/special-features/logger.html",{title:"Debug Logs"},[":md"]],["v-581ddb9c","/en/api/special-features/reflection.html",{title:"Reflection Extensions (Migrated)"},[":md"]],["v-2e6ad66c","/en/api/special-features/xposed-channel.html",{title:"Xposed Module and Host Channel"},[":md"]],["v-68bebbf4","/en/api/special-features/xposed-storage.html",{title:"Xposed Module Data Storage"},[":md"]],["v-6ac5be8e","/zh-cn/api/special-features/host-inject.html",{title:"宿主资源注入扩展"},[":md"]],["v-357a8d49","/zh-cn/api/special-features/host-lifecycle.html",{title:"宿主生命周期扩展"},[":md"]],["v-1f0f591e","/zh-cn/api/special-features/logger.html",{title:"调试日志"},[":md"]],["v-001858e3","/zh-cn/api/special-features/reflection.html",{title:"字节码与反射扩展 (已迁移)"},[":md"]],["v-598546c6","/zh-cn/api/special-features/xposed-channel.html",{title:"Xposed 模块与宿主通讯桥"},[":md"]],["v-0d914225","/zh-cn/api/special-features/xposed-storage.html",{title:"Xposed 模块数据存储"},[":md"]],["v-053599a5","/en/api/public/com/highcapable/yukihookapi/YukiHookAPI.html",{title:"YukiHookAPI - object"},[":md"]],["v-6931cb54","/zh-cn/api/public/com/highcapable/yukihookapi/YukiHookAPI.html",{title:"YukiHookAPI - object"},[":md"]],["v-818b3ca6","/en/api/public/com/highcapable/yukihookapi/annotation/xposed/InjectYukiHookWithXposed.html",{title:"InjectYukiHookWithXposed - annotation"},[":md"]],["v-b6a815c4","/en/api/public/com/highcapable/yukihookapi/hook/bean/CurrentClass.html",{title:"CurrentClass - class"},[":md"]],["v-0183e3fc","/en/api/public/com/highcapable/yukihookapi/hook/bean/GenericClass.html",{title:"GenericClass - class"},[":md"]],["v-57506200","/en/api/public/com/highcapable/yukihookapi/hook/bean/HookClass.html",{title:"HookClass - class"},[":md"]],["v-9af56c1a","/en/api/public/com/highcapable/yukihookapi/hook/bean/HookResources.html",{title:"HookResources - class"},[":md"]],["v-032b1710","/en/api/public/com/highcapable/yukihookapi/hook/bean/VariousClass.html",{title:"VariousClass - class"},[":md"]],["v-71147891","/en/api/public/com/highcapable/yukihookapi/hook/core/YukiMemberHookCreator.html",{title:"YukiMemberHookCreator - class"},[":md"]],["v-5ed1ceee","/en/api/public/com/highcapable/yukihookapi/hook/core/YukiResourcesHookCreator.html",{title:"YukiResourcesHookCreator - class"},[":md"]],["v-e288ce96","/en/api/public/com/highcapable/yukihookapi/hook/entity/YukiBaseHooker.html",{title:"YukiBaseHooker - class"},[":md"]],["v-0d0fcec2","/en/api/public/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.html",{title:"ReflectionFactory - kt"},[":md"]],["v-65091354","/en/api/public/com/highcapable/yukihookapi/hook/factory/YukiHookFactory.html",{title:"YukiHookFactory - kt"},[":md"]],["v-36749c00","/en/api/public/com/highcapable/yukihookapi/hook/log/YLog.html",{title:"YLog - object"},[":md"]],["v-60cbe1b4","/en/api/public/com/highcapable/yukihookapi/hook/param/HookParam.html",{title:"HookParam - class"},[":md"]],["v-b381a126","/en/api/public/com/highcapable/yukihookapi/hook/param/PackageParam.html",{title:"PackageParam - class"},[":md"]],["v-30f3ba1e","/zh-cn/api/public/com/highcapable/yukihookapi/annotation/xposed/InjectYukiHookWithXposed.html",{title:"InjectYukiHookWithXposed - annotation"},[":md"]],["v-6e47300f","/zh-cn/api/public/com/highcapable/yukihookapi/hook/bean/CurrentClass.html",{title:"CurrentClass - class"},[":md"]],["v-69c1c226","/zh-cn/api/public/com/highcapable/yukihookapi/hook/bean/GenericClass.html",{title:"GenericClass - class"},[":md"]],["v-735374af","/zh-cn/api/public/com/highcapable/yukihookapi/hook/bean/HookClass.html",{title:"HookClass - class"},[":md"]],["v-1c516d22","/zh-cn/api/public/com/highcapable/yukihookapi/hook/bean/HookResources.html",{title:"HookResources - class"},[":md"]],["v-66735bfe","/zh-cn/api/public/com/highcapable/yukihookapi/hook/bean/VariousClass.html",{title:"VariousClass - class"},[":md"]],["v-3ac40680","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/YukiMemberHookCreator.html",{title:"YukiMemberHookCreator - class"},[":md"]],["v-5e81af42","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/YukiResourcesHookCreator.html",{title:"YukiResourcesHookCreator - class"},[":md"]],["v-516df326","/zh-cn/api/public/com/highcapable/yukihookapi/hook/entity/YukiBaseHooker.html",{title:"YukiBaseHooker - class"},[":md"]],["v-213d88b3","/zh-cn/api/public/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.html",{title:"ReflectionFactory - kt"},[":md"]],["v-448e9585","/zh-cn/api/public/com/highcapable/yukihookapi/hook/factory/YukiHookFactory.html",{title:"YukiHookFactory - kt"},[":md"]],["v-3a7c33ef","/zh-cn/api/public/com/highcapable/yukihookapi/hook/log/YLog.html",{title:"YLog - object"},[":md"]],["v-75a9b636","/zh-cn/api/public/com/highcapable/yukihookapi/hook/param/HookParam.html",{title:"HookParam - class"},[":md"]],["v-100b529c","/zh-cn/api/public/com/highcapable/yukihookapi/hook/param/PackageParam.html",{title:"PackageParam - class"},[":md"]],["v-e37480a6","/en/api/public/com/highcapable/yukihookapi/hook/log/data/YLogData.html",{title:"YLogData - class"},[":md"]],["v-8293d958","/en/api/public/com/highcapable/yukihookapi/hook/type/android/ComponentTypeFactory.html",{title:"ComponentTypeFactory - kt"},[":md"]],["v-7b0abf86","/en/api/public/com/highcapable/yukihookapi/hook/type/android/GraphicsTypeFactory.html",{title:"GraphicsTypeFactory - kt"},[":md"]],["v-5309e4a0","/en/api/public/com/highcapable/yukihookapi/hook/type/android/ViewTypeFactory.html",{title:"ViewTypeFactory - kt"},[":md"]],["v-a2615d0c","/en/api/public/com/highcapable/yukihookapi/hook/type/defined/DefinedTypeFactory.html",{title:"DefinedTypeFactory - kt"},[":md"]],["v-ba01a600","/en/api/public/com/highcapable/yukihookapi/hook/type/java/VariableTypeFactory.html",{title:"VariableTypeFactory - kt"},[":md"]],["v-7fec5836","/en/api/public/com/highcapable/yukihookapi/hook/xposed/application/ModuleApplication.html",{title:"ModuleApplication - class"},[":md"]],["v-7414265a","/en/api/public/com/highcapable/yukihookapi/hook/xposed/channel/YukiHookDataChannel.html",{title:"YukiHookDataChannel - class"},[":md"]],["v-65c20d2d","/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookPrefsBridge.html",{title:"YukiHookPrefsBridge - class"},[":md"]],["v-1d680acc","/en/api/public/com/highcapable/yukihookapi/hook/xposed/proxy/IYukiHookXposedInit.html",{title:"IYukiHookXposedInit - interface"},[":md"]],["v-57e0fa9e","/zh-cn/api/public/com/highcapable/yukihookapi/hook/log/data/YLogData.html",{title:"YLogData - class"},[":md"]],["v-5e874c45","/zh-cn/api/public/com/highcapable/yukihookapi/hook/type/android/ComponentTypeFactory.html",{title:"ComponentTypeFactory - kt"},[":md"]],["v-4ea62475","/zh-cn/api/public/com/highcapable/yukihookapi/hook/type/android/GraphicsTypeFactory.html",{title:"GraphicsTypeFactory - kt"},[":md"]],["v-ef79cde2","/zh-cn/api/public/com/highcapable/yukihookapi/hook/type/android/ViewTypeFactory.html",{title:"ViewTypeFactory - kt"},[":md"]],["v-5acc12ab","/zh-cn/api/public/com/highcapable/yukihookapi/hook/type/defined/DefinedTypeFactory.html",{title:"DefinedTypeFactory - kt"},[":md"]],["v-14ec8671","/zh-cn/api/public/com/highcapable/yukihookapi/hook/type/java/VariableTypeFactory.html",{title:"VariableTypeFactory - kt"},[":md"]],["v-4709ad58","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/application/ModuleApplication.html",{title:"ModuleApplication - class"},[":md"]],["v-632be8ee","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/channel/YukiHookDataChannel.html",{title:"YukiHookDataChannel - class"},[":md"]],["v-395d721c","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookPrefsBridge.html",{title:"YukiHookPrefsBridge - class"},[":md"]],["v-763140ee","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/proxy/IYukiHookXposedInit.html",{title:"IYukiHookXposedInit - interface"},[":md"]],["v-3895ce22","/en/api/public/com/highcapable/yukihookapi/hook/core/api/priority/YukiHookPriority.html",{title:"YukiHookPriority - class"},[":md"]],["v-4fca92c0","/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/BaseFinder.html",{title:"BaseFinder - class"},[":md"]],["v-2a898c66","/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/DexClassFinder.html",{title:"DexClassFinder - class"},[":md"]],["v-a71937aa","/en/api/public/com/highcapable/yukihookapi/hook/core/finder/members/ConstructorFinder.html",{title:"ConstructorFinder - class"},[":md"]],["v-42e0f0ab","/en/api/public/com/highcapable/yukihookapi/hook/core/finder/members/FieldFinder.html",{title:"FieldFinder - class"},[":md"]],["v-a4aa4d00","/en/api/public/com/highcapable/yukihookapi/hook/core/finder/members/MethodFinder.html",{title:"MethodFinder - class"},[":md"]],["v-19e7277e","/en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/event/YukiXposedEvent.html",{title:"YukiXposedEvent - object"},[":md"]],["v-8455e04e","/en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiModuleResources.html",{title:"YukiModuleResources - class"},[":md"]],["v-7b087cce","/en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResForwarder.html",{title:"YukiResForwarder - class"},[":md"]],["v-a00b4de6","/en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResources.html",{title:"YukiResources - class"},[":md"]],["v-2f64a2d4","/en/api/public/com/highcapable/yukihookapi/hook/xposed/channel/data/ChannelData.html",{title:"ChannelData - class"},[":md"]],["v-87027140","/en/api/public/com/highcapable/yukihookapi/hook/xposed/channel/priority/ChannelPriority.html",{title:"ChannelPriority - class"},[":md"]],["v-2d4e0da6","/en/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/reference/ModuleClassLoader.html",{title:"ModuleClassLoader - class"},[":md"]],["v-58ed8298","/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData.html",{title:"PrefsData - class"},[":md"]],["v-23e1a817","/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/ui/ModulePreferenceFragment.html",{title:"ModulePreferenceFragment - class"},[":md"]],["v-3e0afe1e","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/api/priority/YukiHookPriority.html",{title:"YukiHookPriority - class"},[":md"]],["v-0f719471","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/base/BaseFinder.html",{title:"BaseFinder - class"},[":md"]],["v-45111efc","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/DexClassFinder.html",{title:"DexClassFinder - class"},[":md"]],["v-1e2cbc9c","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/members/ConstructorFinder.html",{title:"ConstructorFinder - class"},[":md"]],["v-22449c48","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/members/FieldFinder.html",{title:"FieldFinder - class"},[":md"]],["v-fd738322","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/members/MethodFinder.html",{title:"MethodFinder - class"},[":md"]],["v-0a4de82f","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/event/YukiXposedEvent.html",{title:"YukiXposedEvent - object"},[":md"]],["v-8266e0ec","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiModuleResources.html",{title:"YukiModuleResources - class"},[":md"]],["v-aa38fa86","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResForwarder.html",{title:"YukiResForwarder - class"},[":md"]],["v-21b3b17e","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResources.html",{title:"YukiResources - class"},[":md"]],["v-493d37f6","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/channel/data/ChannelData.html",{title:"ChannelData - class"},[":md"]],["v-b57870de","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/channel/priority/ChannelPriority.html",{title:"ChannelPriority - class"},[":md"]],["v-4b468415","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/reference/ModuleClassLoader.html",{title:"ModuleClassLoader - class"},[":md"]],["v-d99f7f36","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData.html",{title:"PrefsData - class"},[":md"]],["v-53bcae06","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/ui/ModulePreferenceFragment.html",{title:"ModulePreferenceFragment - class"},[":md"]],["v-f150b17c","/en/api/public/com/highcapable/yukihookapi/hook/core/api/compat/type/ExecutorType.html",{title:"ExecutorType - class"},[":md"]],["v-52995ef7","/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/CountRules.html",{title:"CountRules - class"},[":md"]],["v-8d5ce71a","/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/ModifierRules.html",{title:"ModifierRules - class"},[":md"]],["v-f5b1ffb2","/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/NameRules.html",{title:"NameRules - class"},[":md"]],["v-652b815b","/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/ObjectRules.html",{title:"ObjectRules - class"},[":md"]],["v-08b70f7f","/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/ConstructorRules.html",{title:"ConstructorRules - class"},[":md"]],["v-21f64ebf","/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/FieldRules.html",{title:"FieldRules - class"},[":md"]],["v-77f11cf9","/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/MemberRules.html",{title:"MemberRules - class"},[":md"]],["v-64827680","/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/MethodRules.html",{title:"MethodRules - class"},[":md"]],["v-2d5d16db","/en/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/base/ModuleAppActivity.html",{title:"ModuleAppActivity - class"},[":md"]],["v-cadbe48e","/en/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/base/ModuleAppCompatActivity.html",{title:"ModuleAppCompatActivity - class"},[":md"]],["v-78731c50","/en/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/context/wrapper/ModuleContextThemeWrapper.html",{title:"ModuleContextThemeWrapper - class"},[":md"]],["v-2728e033","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/api/compat/type/ExecutorType.html",{title:"ExecutorType - class"},[":md"]],["v-1b2ad030","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/CountRules.html",{title:"CountRules - class"},[":md"]],["v-547a3c3c","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/ModifierRules.html",{title:"ModifierRules - class"},[":md"]],["v-58c26516","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/NameRules.html",{title:"NameRules - class"},[":md"]],["v-80fd32ec","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/ObjectRules.html",{title:"ObjectRules - class"},[":md"]],["v-a42f54a4","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/ConstructorRules.html",{title:"ConstructorRules - class"},[":md"]],["v-3e67a42e","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/FieldRules.html",{title:"FieldRules - class"},[":md"]],["v-2cab152c","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/MemberRules.html",{title:"MemberRules - class"},[":md"]],["v-5388621e","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/MethodRules.html",{title:"MethodRules - class"},[":md"]],["v-1446bdca","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/base/ModuleAppActivity.html",{title:"ModuleAppActivity - class"},[":md"]],["v-c7cef530","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/base/ModuleAppCompatActivity.html",{title:"ModuleAppCompatActivity - class"},[":md"]],["v-44efb702","/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/context/wrapper/ModuleContextThemeWrapper.html",{title:"ModuleContextThemeWrapper - class"},[":md"]],["v-5e375d98","/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/result/MemberRulesResult.html",{title:"MemberRulesResult - class"},[":md"]],["v-b8000f3a","/zh-cn/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/result/MemberRulesResult.html",{title:"MemberRulesResult - class"},[":md"]],["v-3706649a","/404.html",{title:""},[]]];var ms=he({name:"Vuepress",setup(){const e=zd();return()=>ce(e.value)}}),bf=()=>_f.reduce((e,[t,l,i,o])=>(e.push({name:t,path:l,component:ms,meta:i},{path:l.endsWith("/")?l+"index.html":l.substring(0,l.length-5),redirect:l},...o.map(n=>({path:n===":md"?l.substring(0,l.length-5)+".md":n,redirect:l}))),e),[{name:"404",path:"/:catchAll(.*)",component:ms}]),yf=oh,xf=()=>{const e=jh({history:yf(dr("/YukiHookAPI/")),routes:bf(),scrollBehavior:(t,l,i)=>i||(t.hash?{el:t.hash}:{top:0})});return e.beforeResolve(async(t,l)=>{var i;(t.path!==l.path||l===pt)&&([t.meta._data]=await Promise.all([mt.resolvePageData(t.name),(i=mr[t.name])==null?void 0:i.__asyncLoader()]))}),e},Ef=e=>{e.component("ClientOnly",jo),e.component("Content",Nd)},Lf=(e,t,l)=>{const i=rs(()=>t.currentRoute.value.path),o=rs(()=>mt.resolveRouteLocale(il.value.locales,i.value)),n=Ru(i,()=>t.currentRoute.value.meta._data),s=B(()=>mt.resolveLayouts(l)),a=B(()=>mt.resolveSiteLocaleData(il.value,o.value)),r=B(()=>mt.resolvePageFrontmatter(n.value)),c=B(()=>mt.resolvePageHeadTitle(n.value,a.value)),d=B(()=>mt.resolvePageHead(c.value,r.value,a.value)),u=B(()=>mt.resolvePageLang(n.value,a.value)),m=B(()=>mt.resolvePageLayout(n.value,s.value));return e.provide(Id,s),e.provide(pr,n),e.provide(fr,r),e.provide(Dd,c),e.provide(gr,d),e.provide(vr,u),e.provide(kr,m),e.provide(Vo,o),e.provide(br,a),Object.defineProperties(e.config.globalProperties,{$frontmatter:{get:()=>r.value},$head:{get:()=>d.value},$headTitle:{get:()=>c.value},$lang:{get:()=>u.value},$page:{get:()=>n.value},$routeLocale:{get:()=>o.value},$site:{get:()=>il.value},$siteLocale:{get:()=>a.value},$withBase:{get:()=>$o}}),{layouts:s,pageData:n,pageFrontmatter:r,pageHead:d,pageHeadTitle:c,pageLang:u,pageLayout:m,routeLocale:o,siteData:il,siteLocaleData:a}},Pf=()=>{const e=Od(),t=Fd(),l=ke([]),i=()=>{e.value.forEach(n=>{const s=Rf(n);s&&l.value.push(s)})},o=()=>{document.documentElement.lang=t.value,l.value.forEach(n=>{n.parentNode===document.head&&document.head.removeChild(n)}),l.value.splice(0,l.value.length),e.value.forEach(n=>{const s=Cf(n);s!==null&&(document.head.appendChild(s),l.value.push(s))})};Wt(Hd,o),Be(()=>{i(),o(),Ge(()=>e.value,o)})},Rf=([e,t,l=""])=>{const i=Object.entries(t).map(([a,r])=>ge(r)?`[${a}=${JSON.stringify(r)}]`:r===!0?`[${a}]`:"").join(""),o=`head > ${e}${i}`;return Array.from(document.querySelectorAll(o)).find(a=>a.innerText===l)||null},Cf=([e,t,l])=>{if(!ge(e))return null;const i=document.createElement(e);return Mo(t)&&Object.entries(t).forEach(([o,n])=>{ge(n)?i.setAttribute(o,n):n===!0&&i.setAttribute(o,"")}),ge(l)&&i.appendChild(document.createTextNode(l)),i},Af=yd,Tf=async()=>{var l;const e=Af({name:"VuepressApp",setup(){var i;Pf();for(const o of ci)(i=o.setup)==null||i.call(o);return()=>[ce(Or),...ci.flatMap(({rootComponents:o=[]})=>o.map(n=>ce(n)))]}}),t=xf();Ef(e),Lf(e,t,ci);for(const i of ci)await((l=i.enhance)==null?void 0:l.call(i,{app:e,router:t,siteData:il}));return e.use(t),{app:e,router:t}};Tf().then(({app:e,router:t})=>{t.isReady().then(()=>{e.mount("#app")})});export{Pe as _,zc as a,pe as b,te as c,Tf as createVueApp,zt as d,oe as e,Y as o,_t as r,Se as w}; +function __vite__mapDeps(indexes) { + if (!__vite__mapDeps.viteFileDeps) { + __vite__mapDeps.viteFileDeps = [] + } + return indexes.map((i) => __vite__mapDeps.viteFileDeps[i]) +} \ No newline at end of file diff --git a/assets/changelog.html-B8UfyBpi.js b/assets/changelog.html-B8UfyBpi.js new file mode 100644 index 00000000..936c5266 --- /dev/null +++ b/assets/changelog.html-B8UfyBpi.js @@ -0,0 +1 @@ +const l=JSON.parse('{"key":"v-0e6c3476","path":"/zh-cn/about/changelog.html","title":"更新日志","lang":"zh-CN","frontmatter":{},"headers":[{"level":3,"title":"1.3.0 | 2025.06.25","slug":"_1-3-0-2025-06-25","link":"#_1-3-0-2025-06-25","children":[]},{"level":3,"title":"1.2.1 | 2024.06.20","slug":"_1-2-1-2024-06-20","link":"#_1-2-1-2024-06-20","children":[]},{"level":3,"title":"1.2.0 | 2023.10.07","slug":"_1-2-0-2023-10-07","link":"#_1-2-0-2023-10-07","children":[]},{"level":3,"title":"1.1.11 | 2023.04.25","slug":"_1-1-11-2023-04-25","link":"#_1-1-11-2023-04-25","children":[]},{"level":3,"title":"1.1.10 | 2023.04.21","slug":"_1-1-10-2023-04-21","link":"#_1-1-10-2023-04-21","children":[]},{"level":3,"title":"1.1.9 | 2023.04.17","slug":"_1-1-9-2023-04-17","link":"#_1-1-9-2023-04-17","children":[]},{"level":3,"title":"1.1.8 | 2023.02.01","slug":"_1-1-8-2023-02-01","link":"#_1-1-8-2023-02-01","children":[]},{"level":3,"title":"1.1.6 | 2023.01.21","slug":"_1-1-6-2023-01-21","link":"#_1-1-6-2023-01-21","children":[]},{"level":3,"title":"1.1.5 | 2023.01.13","slug":"_1-1-5-2023-01-13","link":"#_1-1-5-2023-01-13","children":[]},{"level":3,"title":"1.1.4 | 2022.10.04","slug":"_1-1-4-2022-10-04","link":"#_1-1-4-2022-10-04","children":[]},{"level":3,"title":"1.1.3 | 2022.09.30","slug":"_1-1-3-2022-09-30","link":"#_1-1-3-2022-09-30","children":[]},{"level":3,"title":"1.1.2 | 2022.09.30","slug":"_1-1-2-2022-09-30","link":"#_1-1-2-2022-09-30","children":[]},{"level":3,"title":"1.1.1 | 2022.09.28","slug":"_1-1-1-2022-09-28","link":"#_1-1-1-2022-09-28","children":[]},{"level":3,"title":"1.1.0 | 2022.09.28","slug":"_1-1-0-2022-09-28","link":"#_1-1-0-2022-09-28","children":[]},{"level":3,"title":"1.0.92 | 2022.05.31","slug":"_1-0-92-2022-05-31","link":"#_1-0-92-2022-05-31","children":[]},{"level":3,"title":"1.0.91 | 2022.05.29","slug":"_1-0-91-2022-05-29","link":"#_1-0-91-2022-05-29","children":[]},{"level":3,"title":"1.0.90 | 2022.05.27","slug":"_1-0-90-2022-05-27","link":"#_1-0-90-2022-05-27","children":[]},{"level":3,"title":"1.0.89 | 2022.05.26","slug":"_1-0-89-2022-05-26","link":"#_1-0-89-2022-05-26","children":[]},{"level":3,"title":"1.0.88 | 2022.05.25","slug":"_1-0-88-2022-05-25","link":"#_1-0-88-2022-05-25","children":[]},{"level":3,"title":"1.0.87 | 2022.05.10","slug":"_1-0-87-2022-05-10","link":"#_1-0-87-2022-05-10","children":[]},{"level":3,"title":"1.0.86 | 2022.05.06","slug":"_1-0-86-2022-05-06","link":"#_1-0-86-2022-05-06","children":[]},{"level":3,"title":"1.0.85 | 2022.05.04","slug":"_1-0-85-2022-05-04","link":"#_1-0-85-2022-05-04","children":[]},{"level":3,"title":"1.0.83 | 2022.05.04","slug":"_1-0-83-2022-05-04","link":"#_1-0-83-2022-05-04","children":[]},{"level":3,"title":"1.0.82 | 2022.05.04","slug":"_1-0-82-2022-05-04","link":"#_1-0-82-2022-05-04","children":[]},{"level":3,"title":"1.0.81 | 2022.05.04","slug":"_1-0-81-2022-05-04","link":"#_1-0-81-2022-05-04","children":[]},{"level":3,"title":"1.0.80 | 2022.05.01","slug":"_1-0-80-2022-05-01","link":"#_1-0-80-2022-05-01","children":[]},{"level":3,"title":"1.0.78 | 2022.04.18","slug":"_1-0-78-2022-04-18","link":"#_1-0-78-2022-04-18","children":[]},{"level":3,"title":"1.0.77 | 2022.04.15","slug":"_1-0-77-2022-04-15","link":"#_1-0-77-2022-04-15","children":[]},{"level":3,"title":"1.0.75 | 2022.04.13","slug":"_1-0-75-2022-04-13","link":"#_1-0-75-2022-04-13","children":[]},{"level":3,"title":"1.0.73 | 2022.04.10","slug":"_1-0-73-2022-04-10","link":"#_1-0-73-2022-04-10","children":[]},{"level":3,"title":"1.0.72 | 2022.04.09","slug":"_1-0-72-2022-04-09","link":"#_1-0-72-2022-04-09","children":[]},{"level":3,"title":"1.0.71 | 2022.04.04","slug":"_1-0-71-2022-04-04","link":"#_1-0-71-2022-04-04","children":[]},{"level":3,"title":"1.0.70 | 2022.04.04","slug":"_1-0-70-2022-04-04","link":"#_1-0-70-2022-04-04","children":[]},{"level":3,"title":"1.0.69 | 2022.03.30","slug":"_1-0-69-2022-03-30","link":"#_1-0-69-2022-03-30","children":[]},{"level":3,"title":"1.0.68 | 2022.03.29","slug":"_1-0-68-2022-03-29","link":"#_1-0-68-2022-03-29","children":[]},{"level":3,"title":"1.0.67 | 2022.03.27","slug":"_1-0-67-2022-03-27","link":"#_1-0-67-2022-03-27","children":[]},{"level":3,"title":"1.0.66 | 2022.03.25","slug":"_1-0-66-2022-03-25","link":"#_1-0-66-2022-03-25","children":[]},{"level":3,"title":"1.0.65 | 2022.03.25","slug":"_1-0-65-2022-03-25","link":"#_1-0-65-2022-03-25","children":[]},{"level":3,"title":"1.0.6 | 2022.03.20","slug":"_1-0-6-2022-03-20","link":"#_1-0-6-2022-03-20","children":[]},{"level":3,"title":"1.0.55 | 2022.03.18","slug":"_1-0-55-2022-03-18","link":"#_1-0-55-2022-03-18","children":[]},{"level":3,"title":"1.0.5 | 2022.03.18","slug":"_1-0-5-2022-03-18","link":"#_1-0-5-2022-03-18","children":[]},{"level":3,"title":"1.0.4 | 2022.03.06","slug":"_1-0-4-2022-03-06","link":"#_1-0-4-2022-03-06","children":[]},{"level":3,"title":"1.0.3 | 2022.03.02","slug":"_1-0-3-2022-03-02","link":"#_1-0-3-2022-03-02","children":[]},{"level":3,"title":"1.0.2 | 2022.02.18","slug":"_1-0-2-2022-02-18","link":"#_1-0-2-2022-02-18","children":[]},{"level":3,"title":"1.0.1 | 2022.02.15","slug":"_1-0-1-2022-02-15","link":"#_1-0-1-2022-02-15","children":[]},{"level":3,"title":"1.0 | 2022.02.14","slug":"_1-0-2022-02-14","link":"#_1-0-2022-02-14","children":[]}],"git":{"updatedTime":1750853460000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":22}]},"filePathRelative":"zh-cn/about/changelog.md"}');export{l as data}; diff --git a/assets/changelog.html-BQ5AB5_x.js b/assets/changelog.html-BQ5AB5_x.js new file mode 100644 index 00000000..4e8a3808 --- /dev/null +++ b/assets/changelog.html-BQ5AB5_x.js @@ -0,0 +1 @@ +import{_ as c,r as a,o as l,c as s,b as e,d as o,e as t,a as n}from"./app-BpUB8-Q8.js";const r={},h=n(' # Changelog
The version update history of
YukiHookAPI
is recorded here.Pay Attention
We will only maintain the latest API version, if you are using an outdate API version, you voluntarily renounce any possibility of maintenance.
',4),u={id:"_1-3-0-2024-06-25",tabindex:"-1"},m=e("a",{class:"header-anchor",href:"#_1-3-0-2024-06-25","aria-hidden":"true"},"#",-1),p={href:"https://highcapable.github.io/YukiHookAPI/zh-cn/config/move-to-api-1-3-x",target:"_blank",rel:"noopener noreferrer"},f=e("code",null,"YukiHookAPI",-1),g={href:"https://github.com/HighCapable/KavaRef",target:"_blank",rel:"noopener noreferrer"},_=n("Notice
To avoid translation time consumption, Changelog will use Google Translation from Chinese to English, please refer to the original text for actual reference.
Time zone of version release date: UTC+8
The limitation of duplicate Hooks has been deprecated, now you can repeat the same method of the Hook Deprecated ,ModuleAppActivity
, please useModuleAppCompatActivity
ModuleActivity
to create your own proxyActivity
",3),k=e("code",null,"FreeReflection",-1),b={href:"https://github.com/LSPosed/AndroidHiddenApiBypass",target:"_blank",rel:"noopener noreferrer"},y={id:"_1-2-1-2024-06-20",tabindex:"-1"},x=e("a",{class:"header-anchor",href:"#_1-2-1-2024-06-20","aria-hidden":"true"},"#",-1),v=e("li",null,"Catch exceptions in singleton Hooker to prevent it from blocking the entire process",-1),w={href:"https://github.com/zhufengning",target:"_blank",rel:"noopener noreferrer"},A={href:"https://github.com/HighCapable/YukiHookAPI/pull/70",target:"_blank",rel:"noopener noreferrer"},H={href:"https://github.com/xihan123",target:"_blank",rel:"noopener noreferrer"},P={href:"https://github.com/HighCapable/YukiHookAPI/pull/76",target:"_blank",rel:"noopener noreferrer"},C={id:"_1-2-0-2023-10-07",tabindex:"-1"},F=e("a",{class:"header-anchor",href:"#_1-2-0-2023-10-07","aria-hidden":"true"},"#",-1),M=e("li",null,[o("The license agreement has been changed from "),e("code",null,"MIT"),o(" to "),e("code",null,"Apache-2.0"),o(", subsequent versions will be distributed under this license agreement, you should change the relevant license agreement after using this version")],-1),Y={href:"https://highcapable.github.io/YukiHookAPI/en/config/move-to-api-1-2-x",target:"_blank",rel:"noopener noreferrer"},I={href:"https://github.com/BlueCat300",target:"_blank",rel:"noopener noreferrer"},R={href:"https://github.com/HighCapable/YukiHookAPI/pull/44",target:"_blank",rel:"noopener noreferrer"},S=e("code",null,"findAllInterfaces",-1),D={href:"https://github.com/buffcow",target:"_blank",rel:"noopener noreferrer"},T={href:"https://github.com/HighCapable/YukiHookAPI/pull/38",target:"_blank",rel:"noopener noreferrer"},L={href:"https://github.com/cesaryuan",target:"_blank",rel:"noopener noreferrer"},z={href:"https://github.com/HighCapable/YukiHookAPI/issues/47",target:"_blank",rel:"noopener noreferrer"},X={href:"https://github.com/HighCapable/YukiHookAPI/issues/36",target:"_blank",rel:"noopener noreferrer"},j=n(" YLog
is now allowed to passmsg
into any object and will be automatically converted to a string for printingAdded YukiHookAPI.TAG
Deprecated ,YukiHookAPI.API_VERSION_NAME
, merged intoYukiHookAPI.API_VERSION_CODE
YukiHookAPI.VERSION
Added YukiHookAPI.TAG
Deprecated ,YukiHookAPI.API_VERSION_NAME
, merged intoYukiHookAPI.API_VERSION_CODE
YukiHookAPI.VERSION
Deprecated method inuseDangerousOperation
YukiMemberHookCreator
Deprecated function ininstanceClass
YukiMemberHookCreator
, it is no longer recommendedModify instanceClass
inHookParam
to be a null safe return value typeDetach all Hook objects created using injectMember
toLegacyCreator
Modify appClassLoader
inPackageParam
to be a null safe return value typeRefactor all logger...
methods to new usageYLog
Removed the -->
style behind the print log functionFixed and improved the problem that the module package name cannot be obtained through KSP after using namespace
Functions such as whether to enable module activation status have now been moved to the ",13),O={href:"https://github.com/tiann/FreeReflection",target:"_blank",rel:"noopener noreferrer"},B=n("InjectYukiHookWithXposed
annotationAdded a warning log that will be automatically printed when the same Hook method is repeated The findClass(...)
method inPackageParam
is obsolete, please migrate to the"...".toClass()
methodThe String.hook { ... }
method inPackageParam
is obsolete, and it is recommended to use a new method for HookAppLifecycle
can now be created repeatedly in different HookersThe old version of Hook priority writing is obsolete and migrated to YukiHookPriority
Removed the tag
function in the Hook processRefactored remendy
functionality in find methods, which now prints exceptions in stepsThe multi-method find result type is changed from HashSet
toMutableList
Added method()
,constructor()
,field()
to directly obtain all object functions in the classconstructor()
no longer behaves likeconstructor { emptyParam() }
Added ",11),E={id:"_1-1-11-2023-04-25",tabindex:"-1"},N=e("a",{class:"header-anchor",href:"#_1-1-11-2023-04-25","aria-hidden":"true"},"#",-1),W=e("code",null,"1.1.5",-1),q=e("code",null,"Member",-1),V={href:"https://github.com/Art-Chen",target:"_blank",rel:"noopener noreferrer"},K=n("lazyClass
andlazyClassOrNull
methods to lazily loadClass
Remove the direct cache function of Member
and deprecated, keep the cache function ofYukiReflection.Configs.isEnableMemberCache
Class
Modified finder to Sequence
, optimize the finding speed and performance ofMember
Remove the YukiHookPrefsBridge
's direct key-value cache function and removedLruCache
related functionsDeprecated YukiHookAPI.Configs.isEnablePrefsBridgeCache
Deprecated ",5),U={id:"_1-1-10-2023-04-21",tabindex:"-1"},Z=e("a",{class:"header-anchor",href:"#_1-1-10-2023-04-21","aria-hidden":"true"},"#",-1),G=n(",direct
functions inclearCache
YukiHookPrefsBridge
",1),J={id:"_1-1-9-2023-04-17",tabindex:"-1"},Q=e("a",{class:"header-anchor",href:"#_1-1-9-2023-04-17","aria-hidden":"true"},"#",-1),$=n("
- The
Activity
proxy function adds the function of specifying a separate proxyActivity
for each proxiedActivity
- Fixed problem that the
contains
andall
methods inYukiHookPrefsBridge
did not judge thenative
function- Integrate the cache function in
YukiHookPrefsBridge
intoPreferencesCacheManager
and useLruCache
as a key-value pair cache- Modify
YukiHookPrefsBridge
key-value pair caching function to take effect in all environments (Module Apps, Host Apps)- Modify part of
HashMap
used for caching toArrayMap
to reduce memory consumption- Fix some other possible problems
",1),ee={id:"_1-1-8-2023-02-01",tabindex:"-1"},oe=e("a",{class:"header-anchor",href:"#_1-1-8-2023-02-01","aria-hidden":"true"},"#",-1),te=e("code",null,"result",-1),de={href:"https://github.com/HighCapable/YukiHookAPI/issues/23",target:"_blank",rel:"noopener noreferrer"},ie={href:"https://github.com/elvizlai",target:"_blank",rel:"noopener noreferrer"},ne=n("
- Change the type of dependent library from Java Library (jar) to Android Library (aar)
- Remove the inspection function of internal methods and parameters through Hook or reflection API
- Fixed the problem that
YukiHookDataChannel
automatically segmented data sending function could not work normally (exception would still be thrown)- Added the ability to manually modify the maximum data byte size allowed by
YukiHookDataChannel
to be sent at one time according to the limitations of the target device- Remove the restriction that
YukiHookDataChannel
can only be used in moduleActivity
, now you can use it anywhere- Modify and standardize the broadcast Action name used by
YukiHookDataChannel
- Fix the problem that
BadParcelableException
occurs whenYukiHookDataChannel
has different modules with the same host- Added
ExecutorType
, you can get the type of known Hook Framework throughYukiHookAPI.Status.Executor.type
renamed toYukiHookModulePrefs
YukiHookPrefsBridge
- Modify
YukiHookPrefsBridge
to be implemented as a non-singleton, as a singleton may cause data confusion- Deprecated
method, please move toContext.modulePrefs(...)
Context.prefs(...)
YukiHookPrefsBridge
addsnative
method, which supports storing private data in modules and hosts directly as native storage- Integrate the storage method in
YukiHookPrefsBridge
toYukiHookPrefsBridge.Editor
, please useedit
method to store dataYukiHookPrefsBridge
addscontains
method- Cache dynamically created proxy objects in
YukiHookPrefsBridge
, try to fix problems that may cause OOM in the host and modules- Modify the proxy class of the
Activity
proxy function to be dynamically generated to prevent conflicts caused by injecting different modules into the host- Fixed some other possible problems
Move the entry class name file automatically generated by YukiHookAPI
fromassets/yukihookapi_init
toresources/META-INF/yukihookapi_init
When only printing the exception stack, the msg
parameter is allowed to be empty and themsg
parameter can not be set, and the log with themsg
parameter left blank will not be logged unless the exception stack is not emptyFixed the bug that the log printed by the exception that occurs in the body of the Hook callback method has no specific method information HookParam
addsinstanceOrNull
variable and method, which can be used on the premise that the Hook instance is not sure whether it is empty to prevent the Hook instance from being empty and throw an exceptionDecoupled all hookers in Member
lookup functionality toMemberBaseFinder.MemberHookerManager
Modified the usage of by
condition inYukiMemberHookCreator
, now you can reuseby
method to set multiple conditionsRemoved wrong Class
object declaration in Androidtype
The registerReceiver
method inPackageParam.AppLifecycle
adds the function of directly usingIntentFilter
to create a system broadcast listenerFixed the problem that there may be multiple registration lifecycles in PackageParam.AppLifecycle
Revert: The 1.1.7 version has been withdrawn due to a serious problem, please update to this version directly (the update log is the same as version 1.1.7) ",10),ae={id:"_1-1-6-2023-01-21",tabindex:"-1"},ce=e("a",{class:"header-anchor",href:"#_1-1-6-2023-01-21","aria-hidden":"true"},"#",-1),le=n("",1),se={id:"_1-1-5-2023-01-13",tabindex:"-1"},re=e("a",{class:"header-anchor",href:"#_1-1-5-2023-01-13","aria-hidden":"true"},"#",-1),he=n('
- Fixed the serious problem that
ClassLoader
does not match afterPackageParam
keeps a single instance when there may be multiple package names in the same process when Xposed Module is loaded- When the package name is not distinguished when there are multiple package names in the same process, stop loading the singleton child Hooker and print a warning message
- Fixed the problem that the number of parameters is incorrect when methods such as
HookParam.callOriginal
,HookParam.invokeOriginal
call the original method- Modify the method parameter name
param
of reflection calls inMethodFinder
,ConstructorFinder
,ReflectionFactory
toargs
- Added the function of judging the parameters of the entry class constructor in the automatic processing program of the Xposed Module, the entry class needs to ensure that it does not have any constructor parameters
',1),ue={id:"_1-1-4-2022-10-04",tabindex:"-1"},me=e("a",{class:"header-anchor",href:"#_1-1-4-2022-10-04","aria-hidden":"true"},"#",-1),pe=n("
- Standardize and optimize the overall code style
- Privatized some APIs called internally
- The underlying API interface is decoupled as a whole to prepare for compatibility with more Hook Frameworks
- Move some of the functions integrated in the API to
ksp-xposed
dependencies (decoupling), and the separate introduction ofapi
dependencies will no longer contain references to functions such as third-party libraries- Documentation Quick Start page added instructions on when
YukiHookAPI.Configs.isDebug
needs to be closed- Standardize Java Primitive Types in type definitions and sync update to docs
- Java
type
addsNumberClass
type- Improved (Xposed) Host environment recognition
- Take over all exceptions after loading the Xposed Module, if an exception occurs, it will automatically intercept and print the error log
- Modify the
Class
that does not exist in the lower Android system version (Android 5.0) in the type definition to be an empty safe type- Adapt and support native Xposed, the minimum recommended version is Android 7.0
- Added support for Hook entry class declared as
object
type (singleton)- Fixed the problem that the system below Android 8 does not support the
Executable
type, causing the Hook to fail- Fixed the problem of reporting an error when using the
Activity
proxy function for systems below Android 9 and limit the minimum supported version of this function to Android 7.0- Added the prohibition of resource injection and
Activity
proxy function injection into the current module's own instance process to prevent problems- Fixed a serious error that the return value of a method in the Hook process is not consistent with the target's inherited class and interface.
- Fixed the problem that the object is empty when calling
HookParam.callOriginal
andHookParam.invokeOriginal
when the current Hook instance object is static- Optimize the function of judging the Tai Chi activation method and update the relevant instructions of the document synchronously
- Obsolete
,YukiHookAPI.Status.executorName
, please move toYukiHookAPI.Status.executorVersion
YukiHookAPI.Status.Executor
- Adapted the
YukiHookAPI.Status.Executor.name
name display function of some third-party Hook Frameworks- Added
Class.extends
,Class.implements
and other methods, which can more conveniently judge the inheritance and interface relationship of the currentClass
- Added generic methods of the same name as
Class.toClass
,Class.toClassOrNull
and other related methods, you can use generics to constrain the instance object type of knownClass
- Modify the return value of the
classOf<T>
method to the generic typeT
to constrain the instance object type of the knownClass
- Added
initialize
parameter ofClass
related extension method, which can control whether to initialize its static method block at the same time when gettingClass
object- Added
param { ... }
,type { ... }
and other usages in the variable, method, and construction method search functions, which can add more specific conditional judgments to the searched objects- The
loadApp
method ofPackageParam
adds theisExcludeSelf
parameter, which can be used to exclude Hook-related functions from injecting into the module's own instance process- The
onAppLifecycle
method ofPackageParam
adds theisOnFailureThrowToApp
parameter, which can directly throw the exception that occurs in the lifecycle method body to the host- Modify
appClassLoader
inPackageParam
to be a modifiable variable, which can dynamically set theClassLoader
used by the host in the Hook process- Added
dataExtra
function inHookParam
, which can be used to temporarily store the data in the Hook method body- Obsolete
,isRunInNewXShareMode
inisXSharePrefsReadable
YukiHookModulePrefs
, merged intoisPreferencesAvailable
Class.allFields
,Class.allMethods
and other related methods add theisAccessible
parameter, which can control when the member object can be set as an accessible type- Fixed the problem that only the last method body will be called back when receiving the same key-value data in an Activity when there are multiple hosts in
YukiHookDataChannel
- Added
priority
parameter inwait
and other related methods ofYukiHookDataChannel
, you can pass inChannelPriority
to customize the conditions for callback data resultsYukiHookDataChannel
adds the function of automatically usingChannelDataWrapper
type wrapper when sending data, which improves the user experience and enhances data protectionYukiHookDataChannel
has added the function of limiting the maximum byte size of data sent at one time to prevent the app from crashing due to excessive dataYukiHookDataChannel
has added the function of automatically segmenting when the sent data is too large, only supportsList
,Map
,Set
,String
typesYukiHookLogger
adds thecontents
method and thedata
parameter ofsaveToFile
, which can be passed in custom debug log data for formatting or saving to a file- Fixed the problem that the debug log data package name processed by
YukiHookLogger
may be incorrect in the (Xposed) Host environment- Fixed the problem that the package name may be incorrect on some systems (in some system apps) when the Xposed Module loads the Resource Hook event
",1),fe={id:"_1-1-3-2022-09-30",tabindex:"-1"},ge=e("a",{class:"header-anchor",href:"#_1-1-3-2022-09-30","aria-hidden":"true"},"#",-1),_e=e("ul",null,[e("li",null,"Fixed a fatal bug where the Hook entry class name could not be customized"),e("li",null,[o("Added some code notes in "),e("code",null,"LoggerFactory"),o(" and updated special features documentation")])],-1),ke={id:"_1-1-2-2022-09-30",tabindex:"-1"},be=e("a",{class:"header-anchor",href:"#_1-1-2-2022-09-30","aria-hidden":"true"},"#",-1),ye=n('
- Fixed the issue that
YukiHookDataChannel
may not respond to broadcast events in the system framework, reproduced in A13- Fixed the issue that
YukiHookDataChannel
could not communicate with Module App in Host App for multiple versions- Added
obtainLoggerInMemoryData
method inYukiHookDataChannel
to share debug log data between module and host- Modify the type of
YukiHookLogger.inMemoryData
toArrayList
and changeYukiLoggerData
todata class
- Fixed
YukiLoggerData
printing blank when the package name is empty in the module- Added
loadApp
,loadZygote
,loadSystem
,withProcess
multi-parameter methods of the same name inPackageParam
- Fixed some possible bugs
',1),xe={id:"_1-1-1-2022-09-28",tabindex:"-1"},ve=e("a",{class:"header-anchor",href:"#_1-1-1-2022-09-28","aria-hidden":"true"},"#",-1),we=e("ul",null,[e("li",null,[o("Fixed the problem of wrong document friend links in "),e("a",{href:"../guide/knowledge"},"Basic Knowledge"),o(" page")]),e("li",null,[o("Fixed document "),e("code",null,"favicon"),o(" not showing up")]),e("li",null,[o("Fixed bug in "),e("code",null,"DexClassFinder"),o(" search conditions")])],-1),Ae={id:"_1-1-0-2022-09-28",tabindex:"-1"},He=e("a",{class:"header-anchor",href:"#_1-1-0-2022-09-28","aria-hidden":"true"},"#",-1),Pe=e("li",null,[o("This is a major version update, please refer to "),e("a",{href:"../api/home"},"API Document"),o(" and "),e("a",{href:"../api/special-features/reflection"},"Special Features"),o(" for the changes and usage mentioned in the changelog")],-1),Ce={href:"https://v2.vuepress.vuejs.org",target:"_blank",rel:"noopener noreferrer"},Fe=n('
- Documentation Basic Knowledge page add a friend link to the English version
- Fixed
YukiBaseHooker
comments in English code note link errors- Fixed
ClassCastException
inModuleClassLoader
- Fixed and standardize some code notes
- Added
ModuleClassLoader
exclusion list function, you can useexcludeHostClasses
andexcludeModuleClasses
methods to customize the exclusion list- Added
YukiLoggerData
real-time log data class, you can get the log array in real time throughYukiHookLogger.inMemoryData
- Added
ClassLoader.listOfClasses
method, which can directly get allClass
in the currentDex
Unify and standardize the terms and nouns in the document, for example, "query" is always changed to "find", XposedHelper
is misspelled and changed toXposedHelpers
Documentation Basic Knowledge page to add friend links, Simplified Chinese only Convert Class
andMethod
of Hook App Demo to Java to provide better demo effectFixed code comment naming in Hook Module Demo Refactored a lot of low-level Hook logic and the docking method of Xposed API Removed HookParamWrapper
, it now interfaces directly withYukiBridgeFactory
Moved methods in section YukiHookBridge
toAppParasitics
Removed HookParam.args
and the underlying direct connection methodsetArgs
, directly get and set the object of the current arrayOptimized automatic handler to merge referenced ',9),Me={href:"https://github.com/5ec1cff",target:"_blank",rel:"noopener noreferrer"},Ye=n("jar
intostub
projectInternal closure processing for the methods of API private tool classes to avoid polluting the top-level namespace Fixed Creater
naming toCreator
for all reflection and Hook classesAdded YukiHookAPI.Status.compiledTimestamp
function, which can get the compilation completion timestamp when used as an Xposed moduleAdded YukiHookAPI.Status.isXposedEnvironment
function, which can determine whether the current (Xposed) host environment or module environment isThe debug logging function has been overhauled, and functions such as YukiHookAPI.Configs.debugTag
have been merged intoYukiHookLogger.Configs
The debug log can be added to specify the printing method as XposedBridge.log
orLogd
The package name of the current host and the current user ID are added to the debug log by default for debugging, you can change it yourself in the debugLog
configurationAdded generic
function to reflect and call generics, you can use it inClass
orCurrentClass
obsolete the buildOfAny
method, now use thebuildOf
method directly (without generics) to use the constructor to create a new object and get the resultAny
Fixed the issue of null pointer exception when using hasExtends
CurrentClass
added non-lambda method of callingCurrentClass
addsname
andsimpleName
functionsCompletely rewrite the core method of ReflectionTool
, sorting and classifying different search conditionsFixed the problem that Member
obtained by directly callingdeclared
inReflectionTool
throws an exceptionFixed UndefinedType
inReflectionTool
is not correctly judged inMethod
andConstructor
conditionsAdded a friendly prompt method when the reflection search result is abnormal, which can specifically locate the problem that Member
cannot be found under specified conditionsAdded VagueType
condition inMethod
andConstructor
for reflection search, which can be used inparam
condition to ignore parameters you don't want to fill inAdded paramCount { ... }
condition inMethod
andConstructor
of reflection search, now you can directly getit
in it to customize your judgment conditionThe current
method is added to theFieldFinder
result, which can directly create a call space for the result instanceModified the ",20),Ie=e("code",null,"as*",-1),Re=e("code",null,"ModifierRules",-1),Se=e("code",null,"is*",-1),De={href:"https://github.com/KyuubiRan",target:"_blank",rel:"noopener noreferrer"},Te=n("modifiers
condition andname
condition in the reflection lookup function, now you need to return aBoolean
at the end of the method body to make the condition trueAdded RemedyPlan
feature inFieldFinder
Added ",2),Le=e("strong",null,"AA",-1),ze={href:"https://github.com/KyuubiRan",target:"_blank",rel:"noopener noreferrer"},Xe=e("code",null,"appClassLoader",-1),je={href:"https://github.com/luckyzyx",target:"_blank",rel:"noopener noreferrer"},Oe=e("li",null,[o("Modified the calling method of "),e("code",null,"XposedBridge.invokeOriginalMethod"),o(" and added "),e("code",null,"original"),o(" function in "),e("code",null,"MethodFinder.Result.Instance")],-1),Be=e("code",null,"getStringSet",-1),Ee=e("code",null,"YukiHookModulePrefs",-1),Ne={href:"https://github.com/Teddy-Zhu",target:"_blank",rel:"noopener noreferrer"},We={href:"https://github.com/HighCapable/YukiHookAPI/pull/19",target:"_blank",rel:"noopener noreferrer"},qe=e("li",null,[o("Modify "),e("code",null,"YukiHookModulePrefs"),o(" to intercept exceptions that may not exist in "),e("code",null,"XSharePreference")],-1),Ve=e("li",null,[o("Fixed the problem that "),e("code",null,"YukiHookDataChannel"),o(" could not be successfully registered in some third-party ROM system frameworks")],-1),Ke=e("li",null,[o("Secured "),e("code",null,"YukiHookDataChannel"),o(", now it can only communicate between modules from the specified package name and the host")],-1),Ue=e("code",null,"SharedPreferences",-1),Ze=e("code",null,"0664",-1),Ge={href:"https://github.com/5ec1cff",target:"_blank",rel:"noopener noreferrer"},Je=n("Class
fuzzy search function (Beta) inDex
, you can now directly usesearchClass
function to fuzzy searchClass
with specified conditionsAdded YukiHookAPI.Configs.isEnableHookSharedPreferences
function, which is disabled by default and can be enabled if the permission ofSharedPreferences
is incorrectFixed the bug that the no-parameter construction method cannot be found when searching for Constructor
without filling in the search conditions, thanks B5 KAKA for the feedbackDetach Result
instances located inmethod
,constructor
ininjectMember
toProcess
Added the useDangerousOperation
method in the Hook process, which will automatically stop the Hook and print an error after the function in the Hook Dangerous List is not declaredAdded module resource injection and Activity
proxy functions, you can callinjectModuleAppResources
andregisterModuleAppActivities
to useAdded ModuleContextThemeWrapper
function, you can callapplyModuleTheme
to create theContext
of a module in anyActivity
Added ClassLoader.onLoadClass
function, which can be used to listen for events when theloadClass
method ofClassLoader
is calledobsolete classOf
andclazz
extension methods, addtoClass
andtoClassOrNull
usage, please move to the new method nowVariousClass
adds agetOrNull
method, which can returnnull
instead of throwing an exception when it can't matchClass
Removed isUseAppClassLoader
parameter inPackageParam.hook
, changed it toisForceUseAbsolute
and automatically matched the targetClass
PackageParam
addssystemContext
function, you can call this function at any time to get a persistentContext
no longer expose any methods in HookClass
Added throwToApp
function inHookParam
, which can throw exceptions directly to the hostThe onFailureThrowToApp
function is added to the Hook callback, which can be directly thrown to the host when an exception occursModified the printing logic of the debug log, the time-consuming records in the reflection search function will only be printed during the Hook process Added the function of removing Hook in the Hook process, you can use the remove
andremoveSelf
methods to remove the hookFixed the issue that caused the host to throw an exception when ReplaceHook failed, and now it is modified to call the original method to ensure the normal operation of the host function Added the function of checking the return value of the method in the Hook process. If the return value does not match, it will automatically throw an exception or print an error according to the situation ",18),Qe=e("code",null,"array",-1),$e={href:"https://github.com/HighCapable/YukiHookAPI/pull/12",target:"_blank",rel:"noopener noreferrer"},eo={href:"https://github.com/GSWXXN",target:"_blank",rel:"noopener noreferrer"},oo=e("li",null,[o("Moved "),e("code",null,"me.weishu.reflection"),o(" to "),e("code",null,"thirdparty"),o(" to prevent conflicting dependencies of the same name introduced at the same time")],-1),to=e("li",null,"Remove the exception thrown when the Hook method body is empty, and modify it to print the warning log",-1),io=e("li",null,[o("Modify the exception handling logic of "),e("code",null,"AppLifecycle"),o(" and throw it directly to the host when an exception occurs")],-1),no=e("li",null,"Updated Demo API version to 33",-1),ao={id:"_1-0-92-2022-05-31",tabindex:"-1"},co=e("a",{class:"header-anchor",href:"#_1-0-92-2022-05-31","aria-hidden":"true"},"#",-1),lo=n("",1),so={id:"_1-0-91-2022-05-29",tabindex:"-1"},ro=e("a",{class:"header-anchor",href:"#_1-0-91-2022-05-29","aria-hidden":"true"},"#",-1),ho=e("code",null,"ClassLoader",-1),uo={href:"https://github.com/luckyzyx",target:"_blank",rel:"noopener noreferrer"},mo=n("
- Fixed the naming method of callback in a large number of methods
- Changed the solution to fix the problem that
YukiHookDataChannel
cannot call back the currentActivity
broadcast on devices lower than Android 12- The
InjectYukiHookWithXposed
annotation adds theisUsingResourcesHook
function, now you can selectively disable the dependency interface that automatically generatesIXposedHookInitPackageResources
Fixed YukiHookDataChannel
not being able to call back the currentActivity
broadcast on ZUI and systems below Android 12Integrate the ",2),po={id:"_1-0-90-2022-05-27",tabindex:"-1"},fo=e("a",{class:"header-anchor",href:"#_1-0-90-2022-05-27","aria-hidden":"true"},"#",-1),go=n("YukiHookModuleStatus
function intoYukiHookAPI.Status
, rewrite a lot of methods, now you can judge the status information such as module activation in the module and the host in both directions",1),_o={id:"_1-0-89-2022-05-26",tabindex:"-1"},ko=e("a",{class:"header-anchor",href:"#_1-0-89-2022-05-26","aria-hidden":"true"},"#",-1),bo=n("
- Fixed
YukiHookDataChannel
crashing when the module sets the listener callback- Fixed
YukiHookDataChannel
still calling back when not in currentActivity
- Remove the default value of
YukiHookDataChannel
callback event, no callback- Removed
YukiHookModulePrefs
warning printed if XShare is unreadable- Added the
isXSharePrefsReadable
method inYukiHookModulePrefs
to determine whether the current XShare is available",1),yo={id:"_1-0-88-2022-05-25",tabindex:"-1"},xo=e("a",{class:"header-anchor",href:"#_1-0-88-2022-05-25","aria-hidden":"true"},"#",-1),vo=n("
- Fixed the problem that
YukiHookDataChannel
cannot be repeatedly set to monitor, and added the function of repeating response in differentActivity
modules and automatically followingActivity
to destroy the monitor function- Added
YukiHookDataChannel
repeated listening use case description document- Add the
onAlreadyHooked
method to determine whether the current method is repeated Hook- Modify part of the logic of repeatedly adding HashMap, remove the
putIfAbsent
method, allow to override the addition- Fixed several possible bugs
",1),wo={id:"_1-0-87-2022-05-10",tabindex:"-1"},Ao=e("a",{class:"header-anchor",href:"#_1-0-87-2022-05-10","aria-hidden":"true"},"#",-1),Ho=e("ul",null,[e("li",null,[o("Added "),e("code",null,"refreshModuleAppResources"),o(" function to adapt Resources refresh when the language region, font size, resolution changes, etc.")]),e("li",null,[o("Added "),e("code",null,"isEnableModuleAppResourcesCache"),o(" function, you can set whether to automatically cache the resources of the current module")])],-1),Po={id:"_1-0-86-2022-05-06",tabindex:"-1"},Co=e("a",{class:"header-anchor",href:"#_1-0-86-2022-05-06","aria-hidden":"true"},"#",-1),Fo=e("ul",null,[e("li",null,[o("Fixed the problem of continuous error reporting during "),e("code",null,"initZygote"),o(" when Resources Hook is not supported, reproduced in "),e("strong",null,"ZUI"),o("/"),e("strong",null,"LSPosed CI(1.8.3-6550)")]),e("li",null,"Optimize and handle exceptions for Resources Hook, only print errors and warnings if they are used and not supported")],-1),Mo={id:"_1-0-85-2022-05-04",tabindex:"-1"},Yo=e("a",{class:"header-anchor",href:"#_1-0-85-2022-05-04","aria-hidden":"true"},"#",-1),Io=e("ul",null,[e("li",null,[o("Fixed a serious problem of not being able to hook the system framework, since "),e("code",null,"1.0.80")]),e("li",null,[o("Added in the debug log to distinguish the package name loaded by "),e("code",null,"initZygote"),o(" as "),e("code",null,"android-zygote"),o(", "),e("code",null,"packageName"),o(" keeps "),e("code",null,"android"),o(" unchanged")])],-1),Ro={id:"_1-0-83-2022-05-04",tabindex:"-1"},So=e("a",{class:"header-anchor",href:"#_1-0-83-2022-05-04","aria-hidden":"true"},"#",-1),Do=e("ul",null,[e("li",null,[o("Fixed "),e("code",null,"YukiHookModuleStatus"),o(" reporting a lot of errors after "),e("code",null,"loadSystem")]),e("li",null,[o("Added "),e("code",null,"android"),o(" type in "),e("code",null,"type")]),e("li",null,"Updated example descriptions in help documentation")],-1),To={id:"_1-0-82-2022-05-04",tabindex:"-1"},Lo=e("a",{class:"header-anchor",href:"#_1-0-82-2022-05-04","aria-hidden":"true"},"#",-1),zo=e("ul",null,[e("li",null,[o("Fixed a concept confusion error, distinguishing the relationship between "),e("code",null,"initZygote"),o(" and the system framework, there are problems with the previous comments and documentation, I am very sorry")]),e("li",null,[e("code",null,"PackageParam"),o(" adds "),e("code",null,"loadSystem"),o(" method, no need to write "),e("code",null,'loadApp(name = "android")'),o(" to hook the system framework")])],-1),Xo={id:"_1-0-81-2022-05-04",tabindex:"-1"},jo=e("a",{class:"header-anchor",href:"#_1-0-81-2022-05-04","aria-hidden":"true"},"#",-1),Oo=e("ul",null,[e("li",null,[o("Fixed the problem that the method and constructor that cannot be found in the Hook method body still output the error log after setting the condition using the "),e("code",null,"by"),o(" method")]),e("li",null,"Added a global log to display the package name of the current Hook APP during the execution of the Hook, and fixed a problem with the printing style of the error log")],-1),Bo={id:"_1-0-80-2022-05-01",tabindex:"-1"},Eo=e("a",{class:"header-anchor",href:"#_1-0-80-2022-05-01","aria-hidden":"true"},"#",-1),No=n("
- Fully decoupled from Xposed API
- Added
android
type intype
- Separate
YukiHookModuleStatus
from auto-generated code and addisEnableHookModuleStatus
switch, it is up to you to enable or not- Internal closure processing for the constructors of a large number of classes in the API
- Set
YukiHookModulePrefs
to run as a singleton to prevent repeated creation and waste of system resources- Fixed the bug that Hook cannot be nested since version
1.0.80
, and optimize the related functions of nested Hook- Modify the Hooker storage scheme from HashSet to HashMap to prevent the problem of repeatedly adding Hookers
- Modify the core implementation method of Hook, add duplicate checking to avoid repeating the Hook multiple callbacks to the
HookParam
methodMethodFinder
andFieldFinder
add the function of finding fuzzy methods and variable names, you can callname { ... }
to set search conditions, and support regular expressions- Optimize and modify the way to get
appContext
to reduce the possibility of getting empty- Modify the print
TAG
oflogger
in the automatically generated code to default to your custom name, which is convenient for debugging- Optimize the
Hooker
implementation ofYukiHookBridge
to improve Hook performancePackageParam
adds theonAppLifecycle
method, which can natively monitor the life cycle of the host and implement the registration system broadcast function- Added
YukiHookDataChannel
function to communicate using system out-of-order broadcast while the module and the host remain aliveYukiHookDataChannel
adds thecheckingVersionEquals
method, which can be monitored to verify that the host has not updated the version mismatch problem after the module is updated- Added Java version example in the example code of
demo-module
for reference onlyThe InjectYukiHookWithXposed
annotation adds theentryClassName
function, which can customize the generatedxposed_init
entry class namerenamed toYukiHookXposedInitProxy
IYukiHookXposedInit
, the original interface name has been invalidated and will be deleted directly in subsequent versionsAdded initZygote
and Resources Hook functions to support Hook LayoutAdded onXposedEvent
method to listen to all events of native Xposed APIPerform inline
processing on the lambda of the Hook function to avoid generating excessively broken anonymous classes and improve the running performance after compilationFixed PrefsData
compiled method body copy is too largeAdded XSharePreference
readability test, which will automatically print a warning log if it failsPackageParam
addsappResources
,moduleAppResources
,moduleAppFilePath
functionsloadApp
ofPackageParam
adds the function of not writingname
, and all APPs are filtered by defaultPackageParam
adds theloadZygote
method, which can directly hook the system frameworkPackageParam
addedresources().hook
functionOptimization method, construction method, variable search function, the error log that cannot be found will display the set query conditions first Added hasExtends
extension method to determine whether the currentClass
has an inheritance relationshipAdded isSupportResourcesHook
function to determine whether resource hooks are currently supported (Resources Hook)current
function addssuperClass
method to call superclassNew superClass
query conditions for search methods, construction methods and variables, you can continue to search in the parent classYukiHookAPI
lots of methods are decoupled from Xposed APIAdded native Hook priority function of Xposed API Fixed the problem that isFirstApplication
may be inaccurateBlock the problem that MiuiCatcherPatch repeatedly calls the Hook entry method on the MIUI system Optimize Hook entry calling method to avoid multiple calls due to Hook Framework issues ",21),Wo=e("code",null,"ClassLoader",-1),qo={href:"https://github.com/WankkoRee",target:"_blank",rel:"noopener noreferrer"},Vo=e("li",null,[o("Improve the performance after the "),e("code",null,"XC_Callback"),o(" interface is connected")],-1),Ko=e("li",null,[o("Java "),e("code",null,"type"),o(" added "),e("code",null,"ClassLoader"),o(" type")],-1),Uo=e("li",null,"Optimize the API help documentation, fix the problem that the page may be continuously cached",-1),Zo={id:"_1-0-78-2022-04-18",tabindex:"-1"},Go=e("a",{class:"header-anchor",href:"#_1-0-78-2022-04-18","aria-hidden":"true"},"#",-1),Jo=n("YukiHookModulePrefs
addsisRunInNewXShareMode
method, which can be used to determine whether the module is currently inNew XSharePreference
modeFixed YukiHookModulePrefs
working inNew XSharePreference
modeAdded ",3),Qo=e("code",null,"PreferenceFragmentCompat",-1),$o={href:"https://github.com/mahoshojoHCG",target:"_blank",rel:"noopener noreferrer"},et=e("li",null,"Update autohandlers and Kotlin dependencies to the latest version",-1),ot=e("li",null,"Fixed some bugs in documentation and code comments",-1),tt={id:"_1-0-77-2022-04-15",tabindex:"-1"},dt=e("a",{class:"header-anchor",href:"#_1-0-77-2022-04-15","aria-hidden":"true"},"#",-1),it=e("code",null,"YukiHookModulePrefs",-1),nt=e("code",null,"clear",-1),at={href:"https://github.com/WankkoRee",target:"_blank",rel:"noopener noreferrer"},ct=n("ModulePreferenceFragment
, now you can completely replacePreferenceFragmentCompat
and start using the new functionalityYukiHookModulePrefs
addedgetStringSet
,putStringSet
,all
methodsAdded any
method toargs
ofHookParam
Added ModuleApplication
, which can be inherited in modules to achieve more functionsConnect all findClass
functions to the Xposed API, and continue to use nativeClassLoader
in non-hosted environmentsFixed some possible bugs ",5),lt={id:"_1-0-75-2022-04-13",tabindex:"-1"},st=e("a",{class:"header-anchor",href:"#_1-0-75-2022-04-13","aria-hidden":"true"},"#",-1),rt={href:"https://github.com/ApeaSuperz",target:"_blank",rel:"noopener noreferrer"},ht=n("Fixed an issue where the reference to a doc comment was not changed firstArgs
andlastArgs
methods have been removed fromHookParam
, now you can useargs().first()
andargs().last()
instead of itRemoved default parameter index = 0
inargs()
inHookParam
, now you can useargs().first()
orargs(index = 0)
to replace itThe result
function inHookParam
adds generic matching, now you can useresult<T>
to match the known return value type of your target methodThe emptyParam
condition is added to the method and constructor query function, and the misunderstanding of the query condition that needs to be paid attention to in the document has been improvedAdded ",6),ut={id:"_1-0-73-2022-04-10",tabindex:"-1"},mt=e("a",{class:"header-anchor",href:"#_1-0-73-2022-04-10","aria-hidden":"true"},"#",-1),pt={href:"https://github.com/WankkoRee",target:"_blank",rel:"noopener noreferrer"},ft=e("code",null,"XC_LoadPackage.LoadPackageParam",-1),gt={href:"https://github.com/luckyzyx",target:"_blank",rel:"noopener noreferrer"},_t=e("li",null,"Fixed some known bugs and improve Hook stability",-1),kt={id:"_1-0-72-2022-04-09",tabindex:"-1"},bt=e("a",{class:"header-anchor",href:"#_1-0-72-2022-04-09","aria-hidden":"true"},"#",-1),yt=e("ul",null,[e("li",null,"Update API documentation to new address"),e("li",null,[o("Add "),e("code",null,"appContext"),o(" function to "),e("code",null,"PackageParam")]),e("li",null,"Fixed some known bugs and improve Hook stability")],-1),xt={id:"_1-0-71-2022-04-04",tabindex:"-1"},vt=e("a",{class:"header-anchor",href:"#_1-0-71-2022-04-04","aria-hidden":"true"},"#",-1),wt=e("ul",null,[e("li",null,"Fixed a serious issue that would stop the Hook from throwing an exception when VariousClass could not be matched")],-1),At={id:"_1-0-70-2022-04-04",tabindex:"-1"},Ht=e("a",{class:"header-anchor",href:"#_1-0-70-2022-04-04","aria-hidden":"true"},"#",-1),Pt=e("li",null,[o("Fixed "),e("code",null,"instanceClass"),o(" reporting an error after being called in a static instance")],-1),Ct=e("code",null,"isUseAppClassLoader",-1),Ft={href:"https://github.com/WankkoRee",target:"_blank",rel:"noopener noreferrer"},Mt=e("li",null,[o("Added the "),e("code",null,"withProcess"),o(" function, which can be hooked according to the currently specified process of the APP")],-1),Yt=e("li",null,"Fixed critical logic errors in lookup methods, constructor classes and variables",-1),It=e("li",null,"Fixed the problem that the abnormal output cannot be ignored when the Hook target class does not exist",-1),Rt=e("li",null,"Fixed the problem that the Hook could not take effect due to the fast loading of the APP startup method in some cases",-1),St=e("code",null,"allMethods",-1),Dt={href:"https://github.com/WankkoRee",target:"_blank",rel:"noopener noreferrer"},Tt={href:"https://github.com/WankkoRee",target:"_blank",rel:"noopener noreferrer"},Lt=e("li",null,"Modify the way the Xposed entry is injected into the class, and redefine the definition domain of the API",-1),zt=e("code",null,"index",-1),Xt={href:"https://github.com/WankkoRee",target:"_blank",rel:"noopener noreferrer"},jt=e("li",null,[o("When looking for methods and variables, multiple types are allowed, such as the class name declared by "),e("code",null,"String"),o(" and "),e("code",null,"VariousClass")],-1),Ot=e("li",null,[o("Add a new "),e("code",null,"current"),o(" function, which can build a reflection method operation space for any class, and easily call and modify the methods and variables in it")],-1),Bt={href:"https://github.com/WankkoRee",target:"_blank",rel:"noopener noreferrer"},Et={id:"_1-0-69-2022-03-30",tabindex:"-1"},Nt=e("a",{class:"header-anchor",href:"#_1-0-69-2022-03-30","aria-hidden":"true"},"#",-1),Wt=e("li",null,"Added and improved annotations for some method functions",-1),qt=e("li",null,"Added more example Hook content in Demo",-1),Vt=e("code",null,"allMethods",-1),Kt={href:"https://github.com/WankkoRee",target:"_blank",rel:"noopener noreferrer"},Ut={id:"_1-0-68-2022-03-29",tabindex:"-1"},Zt=e("a",{class:"header-anchor",href:"#_1-0-68-2022-03-29","aria-hidden":"true"},"#",-1),Gt=n("android
type intype
",1),Jt={id:"_1-0-67-2022-03-27",tabindex:"-1"},Qt=e("a",{class:"header-anchor",href:"#_1-0-67-2022-03-27","aria-hidden":"true"},"#",-1),$t=n("
- Added new use case and LSPosed scope in Demo
- Added
Member
lookup cache and lookup cache configuration switches- Removed and modified
MethodFinder
,FieldFinder
andHookParam
related method calls- Add more
cast
types inFinder
and supportcast
as array- Overall performance and stability improvements
- Fixed bugs that may exist in the previous version
",1),ed={id:"_1-0-66-2022-03-25",tabindex:"-1"},od=e("a",{class:"header-anchor",href:"#_1-0-66-2022-03-25","aria-hidden":"true"},"#",-1),td=e("ul",null,[e("li",null,[o("Fixed a serious bug in "),e("code",null,"MethodFinder")]),e("li",null,[o("Added "),e("code",null,"args"),o(" call method in "),e("code",null,"hookParam")]),e("li",null,"Fixed other possible problems and fix some class annotation problems")],-1),dd={id:"_1-0-65-2022-03-25",tabindex:"-1"},id=e("a",{class:"header-anchor",href:"#_1-0-65-2022-03-25","aria-hidden":"true"},"#",-1),nd=n("
- Added three
modifiers
functions inFinder
, which can filterstatic
,native
,public
,abstract
and many other description types- When searching for methods and constructors, the method parameter type can be blurred to a specified number for searching
- Added
hasModifiers
extension forMember
- Added
give
method inMethodFinder
andConstructorFinder
to get primitive types- Added
PrefsData
template function inYukiHookModulePrefs
- Completely refactored method, constructor and variable lookup scheme
- Optimized code comments and fixed possible bugs
",1),ad={id:"_1-0-6-2022-03-20",tabindex:"-1"},cd=e("a",{class:"header-anchor",href:"#_1-0-6-2022-03-20","aria-hidden":"true"},"#",-1),ld=n("
- Republished version to fix the incorrect new version of the Maven repository due to cache issues
- Added
MethodFinder
andFieldFinder
new return value calling methods- Fixed possible problems and fix possible problems during the use of Tai Chi
- Fixed possible problems with auto-generated Xposed entry classes
- Added
android
type and Java type intype
",1),sd={id:"_1-0-55-2022-03-18",tabindex:"-1"},rd=e("a",{class:"header-anchor",href:"#_1-0-55-2022-03-18","aria-hidden":"true"},"#",-1),hd=e("ul",null,[e("li",null,"Fixed an annotation error"),e("li",null,"Temporarily fix a bug"),e("li",null,[o("Added a large number of "),e("code",null,"android"),o(" types in "),e("code",null,"type"),o(" and a small number of Java types")]),e("li",null,"Fixed compatibility issues between new and old Kotlin APIs")],-1),ud={id:"_1-0-5-2022-03-18",tabindex:"-1"},md=e("a",{class:"header-anchor",href:"#_1-0-5-2022-03-18","aria-hidden":"true"},"#",-1),pd=n("
- Fixed
YukiHookModulePrefs
being ignored every time after usingdirect
once to ignore cache- Added new API, abolished the traditional usage of
isActive
to judge module activation- Fixed the issue of printing debug logs when using the API in a non-Xposed environment
- Fixed log output issue and unintercepted exception issue when looking for
Field
- Decoupling Xposed API in
ReflectionUtils
- Added
YukiHookModuleStatus
method name confusion to reduce the size of module generation- The welcome message will no longer be printed when loading the module's own Hook
- Fixed some bugs that still exist in the previous version
",1),fd={id:"_1-0-4-2022-03-06",tabindex:"-1"},gd=e("a",{class:"header-anchor",href:"#_1-0-4-2022-03-06","aria-hidden":"true"},"#",-1),_d=n("
- Fixed the problem that the welcome message was printed multiple times in the case of the old version of the LSPosed framework
- Added
onInit
method to configureYukiHookAPI
- Added
executorName
andexecutorVersion
to get the name and version number of the current hook framework- Added
by
method to set the timing and condition of HookYukiHookModulePrefs
adds a controllable key-value cache, which can dynamically update data when the host is running- Fixed some possible bugs
",1),kd={id:"_1-0-3-2022-03-02",tabindex:"-1"},bd=e("a",{class:"header-anchor",href:"#_1-0-3-2022-03-02","aria-hidden":"true"},"#",-1),yd=n("
- Fixed LSPosed cannot find
XposedBridge
after enabling "Only module classloader can use Xposed API" option in latest version- Added constant version name and version number for
YukiHookAPI
- Added
hasField
method andisAllowPrintingLogs
configuration parameter- Added
isDebug
to enable the API to automatically print the welcome message to test whether the module is valid",1),xd={id:"_1-0-2-2022-02-18",tabindex:"-1"},vd=e("a",{class:"header-anchor",href:"#_1-0-2-2022-02-18","aria-hidden":"true"},"#",-1),wd=e("ul",null,[e("li",null,"Fixed the problem that the project path cannot be found under Windows"),e("li",null,[o("Remove part of reflection API, merge into "),e("code",null,"BaseFinder"),o(" for integration")]),e("li",null,"Add a method to create Hook directly using string")],-1),Ad={id:"_1-0-1-2022-02-15",tabindex:"-1"},Hd=e("a",{class:"header-anchor",href:"#_1-0-1-2022-02-15","aria-hidden":"true"},"#",-1),Pd=e("ul",null,[e("li",null,[e("code",null,"RemedyPlan"),o(" adds "),e("code",null,"onFind"),o(" function")]),e("li",null,"Integrate and modify some reflection API code"),e("li",null,[o("Added Java type in "),e("code",null,"type")]),e("li",null,"Fixed the issue that ignored errors still output in the console")],-1),Cd={id:"_1-0-2022-02-14",tabindex:"-1"},Fd=e("a",{class:"header-anchor",href:"#_1-0-2022-02-14","aria-hidden":"true"},"#",-1),Md=e("ul",null,[e("li",null,"The first version is submitted to Maven")],-1);function Yd(Id,Rd){const d=a("Badge"),i=a("ExternalLinkIcon");return l(),s("div",null,[h,e("h3",u,[m,o(" 1.3.0 | 2024.06.25 "),t(d,{type:"tip",text:"latest",vertical:"middle"})]),e("ul",null,[e("li",null,[o("This is a major update, please refer to "),e("a",p,[o("Migrate to YukiHookAPI 1.3.x"),t(i)])]),e("li",null,[o("The reflection API of "),f,o(" is deprecated, please move to the brand new "),e("a",g,[o("KavaRef"),t(i)])]),_,e("li",null,[k,o(" has been deprecated and has now switched to "),e("a",b,[o("AndroidHiddenApiBypass"),t(i)])])]),e("h3",y,[x,o(" 1.2.1 | 2024.06.20 "),t(d,{type:"warning",text:"stale",vertical:"middle"})]),e("ul",null,[v,e("li",null,[o('Add automatic use of "`" in the automatic handler to fix the situation where Kotlin keywords are package names, thanks to '),e("a",w,[o("Fengning Zhu"),t(i)]),o(" for "),e("a",A,[o("PR"),t(i)])]),e("li",null,[o("Adapt to Kotlin 2.0.0+, fix the problem that it cannot be compiled during automatic processing, thanks to "),e("a",H,[o("xihan123"),t(i)]),o(" for "),e("a",P,[o("PR"),t(i)])])]),e("h3",C,[F,o(" 1.2.0 | 2023.10.07 "),t(d,{type:"warning",text:"stale",vertical:"middle"})]),e("ul",null,[M,e("li",null,[o("This is a breaking update, please refer to "),e("a",Y,[o("Migrate to YukiHookAPI 1.2.x"),t(i)]),o(" for details")]),e("li",null,[o("Adapted to Android 14, thanks to "),e("a",I,[o("BlueCat300"),t(i)]),o(" for "),e("a",R,[o("PR"),t(i)])]),e("li",null,[o("Fixed "),S,o(" related issues, thanks to "),e("a",D,[o("buffcow"),t(i)]),o(" for "),e("a",T,[o("PR"),t(i)])]),e("li",null,[o("Fixed the delayed callback problem in the Hook process, thanks to "),e("a",L,[o("cesaryuan"),t(i)]),o(" for his "),e("a",z,[o("Issue"),t(i)])]),e("li",null,[o("Added support for Resources Hook related functions, please refer to this "),e("a",X,[o("Issue"),t(i)]),o(" for details")]),j,e("li",null,[o("Detached "),e("a",O,[o("FreeReflection"),t(i)]),o(" will no longer be automatically generated and will be automatically imported as a dependency")]),B]),e("h3",E,[N,o(" 1.1.11 | 2023.04.25 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),e("ul",null,[e("li",null,[o("Fixed a critical issue since "),W,o(" version where the "),q,o(" cache did not take effect and persistent storage eventually caused app out of memory (OOM), thanks to "),e("a",V,[o("Art-Chen"),t(i)])]),K]),e("h3",U,[Z,o(" 1.1.10 | 2023.04.21 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),G,e("h3",J,[Q,o(" 1.1.9 | 2023.04.17 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),$,e("h3",ee,[oe,o(" 1.1.8 | 2023.02.01 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),e("ul",null,[e("li",null,[o("Fixed the problem that the underlying Hook method cannot update the modified state synchronously when modifying parameters such as "),te,o(" during callback, thanks to the "),e("a",de,[o("Issue"),t(i)]),o(" of "),e("a",ie,[o("Yongzheng Lai"),t(i)])]),ne]),e("h3",ae,[ce,o(" 1.1.6 | 2023.01.21 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),le,e("h3",se,[re,o(" 1.1.5 | 2023.01.13 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),he,e("h3",ue,[me,o(" 1.1.4 | 2022.10.04 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),pe,e("h3",fe,[ge,o(" 1.1.3 | 2022.09.30 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),_e,e("h3",ke,[be,o(" 1.1.2 | 2022.09.30 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),ye,e("h3",xe,[ve,o(" 1.1.1 | 2022.09.28 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),we,e("h3",Ae,[He,o(" 1.1.0 | 2022.09.28 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),e("ul",null,[Pe,e("li",null,[o("Change the help documentation framework to "),e("a",Ce,[o("VuePress"),t(i)])]),Fe,e("li",null,[o("Fixed the problem that the module package name cannot be correctly matched when multi-project packaging, and modify the module package name matching logic of the automatic handler, thanks to "),e("a",Me,[o("5ec1cff"),t(i)]),o(" for the feedback and solutions provided")]),Ye,e("li",null,[Ie,o(" function in "),Re,o(" renamed to "),Se,o(", thanks to "),e("a",De,[o("Kitsune"),t(i)]),o(" suggestion")]),Te,e("li",null,[o("Added multiple search function in reflection search, you can use relative search conditions to obtain multiple search results at the same time, thanks to "),Le,o(" and "),e("a",ze,[o("Kitsune"),t(i)]),o(" for suggestions")]),e("li",null,[o("Fixed the problem that the object obtained by "),Xe,o(" is incorrect in system applications in some systems, thanks to "),e("a",je,[o("Luckyzyx"),t(i)]),o(" for the feedback")]),Oe,e("li",null,[o("Fixed the problem of wrong value of "),Be,o(" method in "),Ee,o(" and optimize the code style, thanks to "),e("a",Ne,[o("Teddy_Zhu"),t(i)]),o(),e("a",We,[o("PR"),t(i)])]),qe,Ve,Ke,e("li",null,[o("Added automatic hook "),Ue,o(" to fix the problem that file permissions are not "),Ze,o(" in some systems, thanks to "),e("a",Ge,[o("5ec1cff"),t(i)]),o(" for the feedback and implementation code provided")]),Je,e("li",null,[o("Added "),Qe,o(" type to Resources Hook, thanks to "),e("a",$e,[o("PR"),t(i)]),o(" of "),e("a",eo,[o("GSWXXN"),t(i)])]),oo,to,io,no]),e("h3",ao,[co,o(" 1.0.92 | 2022.05.31 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),lo,e("h3",so,[ro,o(" 1.0.91 | 2022.05.29 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),e("ul",null,[e("li",null,[o("Fixed the "),ho,o(" error when the customized system of some devices is booted in the LSPosed environment, thanks to "),e("a",uo,[o("Luckyzyx"),t(i)]),o(" for the feedback")]),mo]),e("h3",po,[fo,o(" 1.0.90 | 2022.05.27 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),go,e("h3",_o,[ko,o(" 1.0.89 | 2022.05.26 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),bo,e("h3",yo,[xo,o(" 1.0.88 | 2022.05.25 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),vo,e("h3",wo,[Ao,o(" 1.0.87 | 2022.05.10 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),Ho,e("h3",Po,[Co,o(" 1.0.86 | 2022.05.06 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),Fo,e("h3",Mo,[Yo,o(" 1.0.85 | 2022.05.04 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),Io,e("h3",Ro,[So,o(" 1.0.83 | 2022.05.04 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),Do,e("h3",To,[Lo,o(" 1.0.82 | 2022.05.04 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),zo,e("h3",Xo,[jo,o(" 1.0.81 | 2022.05.04 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),Oo,e("h3",Bo,[Eo,o(" 1.0.80 | 2022.05.01 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),e("ul",null,[No,e("li",null,[o("Fixed the problem that Hook "),Wo,o(" causes Hook to freeze, thanks to "),e("a",qo,[o("WankkoRee"),t(i)]),o(" for the feedback")]),Vo,Ko,Uo]),e("h3",Zo,[Go,o(" 1.0.78 | 2022.04.18 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),e("ul",null,[Jo,e("li",null,[o("Adapt the Sp data storage solution of "),Qo,o(", thanks to "),e("a",$o,[o("mahoshojoHCG"),t(i)]),o(" for feedback")]),et,ot]),e("h3",tt,[dt,o(" 1.0.77 | 2022.04.15 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),e("ul",null,[e("li",null,[it,o(" added "),nt,o(" method, thanks to "),e("a",at,[o("WankkoRee"),t(i)]),o(" for the suggestion")]),ct]),e("h3",lt,[st,o(" 1.0.75 | 2022.04.13 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),e("ul",null,[e("li",null,[o("Corrected the logic recognition part of the automatic handler, thanks to "),e("a",rt,[o("ApeaSuperz"),t(i)]),o(" contribution")]),ht]),e("h3",ut,[mt,o(" 1.0.73 | 2022.04.10 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),e("ul",null,[e("li",null,[o("Fixed some Chinese translation errors in documents, thanks to "),e("a",pt,[o("WankkoRee"),t(i)]),o(" for their contributions")]),e("li",null,[o("Fixed the problem that "),ft,o(" throws an exception when the content is empty in some cases, thanks to "),e("a",gt,[o("Luckyzyx"),t(i)]),o(" for the feedback")]),_t]),e("h3",kt,[bt,o(" 1.0.72 | 2022.04.09 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),yt,e("h3",xt,[vt,o(" 1.0.71 | 2022.04.04 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),wt,e("h3",At,[Ht,o(" 1.0.70 | 2022.04.04 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),e("ul",null,[Pt,e("li",null,[o("Add "),Ct,o(" function in Hook process, thanks to "),e("a",Ft,[o("WankkoRee"),t(i)]),o(" for feedback")]),Mt,Yt,It,Rt,e("li",null,[o("Fixed "),St,o(" not throwing an exception when it is not hooked to a method, thanks to "),e("a",Dt,[o("WankkoRee"),t(i)]),o(" for the feedback")]),e("li",null,[o("Added Hook status monitoring function, thanks to "),e("a",Tt,[o("WankkoRee"),t(i)]),o(" for the suggestion")]),Lt,e("li",null,[o("Added obfuscated method and variable lookup function, you can use different types of filter "),zt,o(" to locate the specified method and variable, thanks to "),e("a",Xt,[o("WankkoRee"),t(i)]),o(" for the ideas provided")]),jt,Ot,e("li",null,[o("Fixed a lot of bugs in the hook process, thanks to "),e("a",Bt,[o("WankkoRee"),t(i)]),o(" for contributing to this project")])]),e("h3",Et,[Nt,o(" 1.0.69 | 2022.03.30 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),e("ul",null,[Wt,qt,e("li",null,[o("Fixed the issue that only the last one takes effect when "),Vt,o(" is used multiple times in a Hook instance, thanks to "),e("a",Kt,[o("WankkoRee"),t(i)]),o(" for the feedback")])]),e("h3",Ut,[Zt,o(" 1.0.68 | 2022.03.29 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),Gt,e("h3",Jt,[Qt,o(" 1.0.67 | 2022.03.27 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),$t,e("h3",ed,[od,o(" 1.0.66 | 2022.03.25 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),td,e("h3",dd,[id,o(" 1.0.65 | 2022.03.25 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),nd,e("h3",ad,[cd,o(" 1.0.6 | 2022.03.20 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),ld,e("h3",sd,[rd,o(" 1.0.55 | 2022.03.18 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),hd,e("h3",ud,[md,o(" 1.0.5 | 2022.03.18 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),pd,e("h3",fd,[gd,o(" 1.0.4 | 2022.03.06 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),_d,e("h3",kd,[bd,o(" 1.0.3 | 2022.03.02 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),yd,e("h3",xd,[vd,o(" 1.0.2 | 2022.02.18 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),wd,e("h3",Ad,[Hd,o(" 1.0.1 | 2022.02.15 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),Pd,e("h3",Cd,[Fd,o(" 1.0 | 2022.02.14 "),t(d,{type:"danger",text:"outdate",vertical:"middle"})]),Md])}const Dd=c(r,[["render",Yd],["__file","changelog.html.vue"]]);export{Dd as default}; diff --git a/assets/changelog.html-Bti1NzlA.js b/assets/changelog.html-Bti1NzlA.js new file mode 100644 index 00000000..0525dc3c --- /dev/null +++ b/assets/changelog.html-Bti1NzlA.js @@ -0,0 +1 @@ +const l=JSON.parse('{"key":"v-3f851d14","path":"/en/about/changelog.html","title":"Changelog","lang":"en-US","frontmatter":{},"headers":[{"level":3,"title":"1.3.0 | 2024.06.25","slug":"_1-3-0-2024-06-25","link":"#_1-3-0-2024-06-25","children":[]},{"level":3,"title":"1.2.1 | 2024.06.20","slug":"_1-2-1-2024-06-20","link":"#_1-2-1-2024-06-20","children":[]},{"level":3,"title":"1.2.0 | 2023.10.07","slug":"_1-2-0-2023-10-07","link":"#_1-2-0-2023-10-07","children":[]},{"level":3,"title":"1.1.11 | 2023.04.25","slug":"_1-1-11-2023-04-25","link":"#_1-1-11-2023-04-25","children":[]},{"level":3,"title":"1.1.10 | 2023.04.21","slug":"_1-1-10-2023-04-21","link":"#_1-1-10-2023-04-21","children":[]},{"level":3,"title":"1.1.9 | 2023.04.17","slug":"_1-1-9-2023-04-17","link":"#_1-1-9-2023-04-17","children":[]},{"level":3,"title":"1.1.8 | 2023.02.01","slug":"_1-1-8-2023-02-01","link":"#_1-1-8-2023-02-01","children":[]},{"level":3,"title":"1.1.6 | 2023.01.21","slug":"_1-1-6-2023-01-21","link":"#_1-1-6-2023-01-21","children":[]},{"level":3,"title":"1.1.5 | 2023.01.13","slug":"_1-1-5-2023-01-13","link":"#_1-1-5-2023-01-13","children":[]},{"level":3,"title":"1.1.4 | 2022.10.04","slug":"_1-1-4-2022-10-04","link":"#_1-1-4-2022-10-04","children":[]},{"level":3,"title":"1.1.3 | 2022.09.30","slug":"_1-1-3-2022-09-30","link":"#_1-1-3-2022-09-30","children":[]},{"level":3,"title":"1.1.2 | 2022.09.30","slug":"_1-1-2-2022-09-30","link":"#_1-1-2-2022-09-30","children":[]},{"level":3,"title":"1.1.1 | 2022.09.28","slug":"_1-1-1-2022-09-28","link":"#_1-1-1-2022-09-28","children":[]},{"level":3,"title":"1.1.0 | 2022.09.28","slug":"_1-1-0-2022-09-28","link":"#_1-1-0-2022-09-28","children":[]},{"level":3,"title":"1.0.92 | 2022.05.31","slug":"_1-0-92-2022-05-31","link":"#_1-0-92-2022-05-31","children":[]},{"level":3,"title":"1.0.91 | 2022.05.29","slug":"_1-0-91-2022-05-29","link":"#_1-0-91-2022-05-29","children":[]},{"level":3,"title":"1.0.90 | 2022.05.27","slug":"_1-0-90-2022-05-27","link":"#_1-0-90-2022-05-27","children":[]},{"level":3,"title":"1.0.89 | 2022.05.26","slug":"_1-0-89-2022-05-26","link":"#_1-0-89-2022-05-26","children":[]},{"level":3,"title":"1.0.88 | 2022.05.25","slug":"_1-0-88-2022-05-25","link":"#_1-0-88-2022-05-25","children":[]},{"level":3,"title":"1.0.87 | 2022.05.10","slug":"_1-0-87-2022-05-10","link":"#_1-0-87-2022-05-10","children":[]},{"level":3,"title":"1.0.86 | 2022.05.06","slug":"_1-0-86-2022-05-06","link":"#_1-0-86-2022-05-06","children":[]},{"level":3,"title":"1.0.85 | 2022.05.04","slug":"_1-0-85-2022-05-04","link":"#_1-0-85-2022-05-04","children":[]},{"level":3,"title":"1.0.83 | 2022.05.04","slug":"_1-0-83-2022-05-04","link":"#_1-0-83-2022-05-04","children":[]},{"level":3,"title":"1.0.82 | 2022.05.04","slug":"_1-0-82-2022-05-04","link":"#_1-0-82-2022-05-04","children":[]},{"level":3,"title":"1.0.81 | 2022.05.04","slug":"_1-0-81-2022-05-04","link":"#_1-0-81-2022-05-04","children":[]},{"level":3,"title":"1.0.80 | 2022.05.01","slug":"_1-0-80-2022-05-01","link":"#_1-0-80-2022-05-01","children":[]},{"level":3,"title":"1.0.78 | 2022.04.18","slug":"_1-0-78-2022-04-18","link":"#_1-0-78-2022-04-18","children":[]},{"level":3,"title":"1.0.77 | 2022.04.15","slug":"_1-0-77-2022-04-15","link":"#_1-0-77-2022-04-15","children":[]},{"level":3,"title":"1.0.75 | 2022.04.13","slug":"_1-0-75-2022-04-13","link":"#_1-0-75-2022-04-13","children":[]},{"level":3,"title":"1.0.73 | 2022.04.10","slug":"_1-0-73-2022-04-10","link":"#_1-0-73-2022-04-10","children":[]},{"level":3,"title":"1.0.72 | 2022.04.09","slug":"_1-0-72-2022-04-09","link":"#_1-0-72-2022-04-09","children":[]},{"level":3,"title":"1.0.71 | 2022.04.04","slug":"_1-0-71-2022-04-04","link":"#_1-0-71-2022-04-04","children":[]},{"level":3,"title":"1.0.70 | 2022.04.04","slug":"_1-0-70-2022-04-04","link":"#_1-0-70-2022-04-04","children":[]},{"level":3,"title":"1.0.69 | 2022.03.30","slug":"_1-0-69-2022-03-30","link":"#_1-0-69-2022-03-30","children":[]},{"level":3,"title":"1.0.68 | 2022.03.29","slug":"_1-0-68-2022-03-29","link":"#_1-0-68-2022-03-29","children":[]},{"level":3,"title":"1.0.67 | 2022.03.27","slug":"_1-0-67-2022-03-27","link":"#_1-0-67-2022-03-27","children":[]},{"level":3,"title":"1.0.66 | 2022.03.25","slug":"_1-0-66-2022-03-25","link":"#_1-0-66-2022-03-25","children":[]},{"level":3,"title":"1.0.65 | 2022.03.25","slug":"_1-0-65-2022-03-25","link":"#_1-0-65-2022-03-25","children":[]},{"level":3,"title":"1.0.6 | 2022.03.20","slug":"_1-0-6-2022-03-20","link":"#_1-0-6-2022-03-20","children":[]},{"level":3,"title":"1.0.55 | 2022.03.18","slug":"_1-0-55-2022-03-18","link":"#_1-0-55-2022-03-18","children":[]},{"level":3,"title":"1.0.5 | 2022.03.18","slug":"_1-0-5-2022-03-18","link":"#_1-0-5-2022-03-18","children":[]},{"level":3,"title":"1.0.4 | 2022.03.06","slug":"_1-0-4-2022-03-06","link":"#_1-0-4-2022-03-06","children":[]},{"level":3,"title":"1.0.3 | 2022.03.02","slug":"_1-0-3-2022-03-02","link":"#_1-0-3-2022-03-02","children":[]},{"level":3,"title":"1.0.2 | 2022.02.18","slug":"_1-0-2-2022-02-18","link":"#_1-0-2-2022-02-18","children":[]},{"level":3,"title":"1.0.1 | 2022.02.15","slug":"_1-0-1-2022-02-15","link":"#_1-0-1-2022-02-15","children":[]},{"level":3,"title":"1.0 | 2022.02.14","slug":"_1-0-2022-02-14","link":"#_1-0-2022-02-14","children":[]}],"git":{"updatedTime":1750853460000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":19}]},"filePathRelative":"en/about/changelog.md"}');export{l as data}; diff --git a/assets/changelog.html-D0nYCScY.js b/assets/changelog.html-D0nYCScY.js new file mode 100644 index 00000000..565e8a10 --- /dev/null +++ b/assets/changelog.html-D0nYCScY.js @@ -0,0 +1 @@ +import{_ as a,r as t,o as n,c as r,b as e,d as o,e as d,a as c}from"./app-BpUB8-Q8.js";const s={},h=e("h1",{id:"更新日志",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#更新日志","aria-hidden":"true"},"#"),o(" 更新日志")],-1),u=e("blockquote",null,[e("p",null,[o("这里记录了 "),e("code",null,"YukiHookAPI"),o(" 的版本更新历史。")])],-1),_=e("div",{class:"custom-container danger"},[e("p",{class:"custom-container-title"},"特别注意"),e("p",null,"我们只会对最新的 API 版本进行维护,若你正在使用过时的 API 版本则代表你自愿放弃一切维护的可能性。")],-1),k={id:"_1-3-0-2025-06-25",tabindex:"-1"},p=e("a",{class:"header-anchor",href:"#_1-3-0-2025-06-25","aria-hidden":"true"},"#",-1),g={href:"https://highcapable.github.io/YukiHookAPI/zh-cn/config/move-to-api-1-3-x",target:"_blank",rel:"noopener noreferrer"},f=e("code",null,"YukiHookAPI",-1),H={href:"https://github.com/HighCapable/KavaRef",target:"_blank",rel:"noopener noreferrer"},m=c("
- Fixed a potential exception not intercepted BUG
- Added
ignoredError
function- Added
android
type intype
- Added
ClassNotFound
function after listening tohook
弃用了重复 Hook 的限制,现在你可以重复 Hook 同一个方法 弃用了 、ModuleAppActivity
,现在请使用ModuleAppCompatActivity
ModuleActivity
创建自己的代理Activity
",3),P=e("code",null,"FreeReflection",-1),b={href:"https://github.com/LSPosed/AndroidHiddenApiBypass",target:"_blank",rel:"noopener noreferrer"},A={id:"_1-2-1-2024-06-20",tabindex:"-1"},C=e("a",{class:"header-anchor",href:"#_1-2-1-2024-06-20","aria-hidden":"true"},"#",-1),y=e("li",null,"捕获单例 Hooker 中的异常,防止其阻断整个进程",-1),x={href:"https://github.com/zhufengning",target:"_blank",rel:"noopener noreferrer"},Y={href:"https://github.com/HighCapable/YukiHookAPI/pull/70",target:"_blank",rel:"noopener noreferrer"},v={href:"https://github.com/xihan123",target:"_blank",rel:"noopener noreferrer"},I={href:"https://github.com/HighCapable/YukiHookAPI/pull/76",target:"_blank",rel:"noopener noreferrer"},M={id:"_1-2-0-2023-10-07",tabindex:"-1"},R=e("a",{class:"header-anchor",href:"#_1-2-0-2023-10-07","aria-hidden":"true"},"#",-1),L=e("li",null,[o("许可协议由 "),e("code",null,"MIT"),o(" 变更为 "),e("code",null,"Apache-2.0"),o(",在此之后的版本将由此许可协议进行分发,您在使用此版本后应变更相关许可协议")],-1),S={href:"https://highcapable.github.io/YukiHookAPI/zh-cn/config/move-to-api-1-2-x",target:"_blank",rel:"noopener noreferrer"},B={href:"https://github.com/BlueCat300",target:"_blank",rel:"noopener noreferrer"},F={href:"https://github.com/HighCapable/YukiHookAPI/pull/44",target:"_blank",rel:"noopener noreferrer"},X=e("code",null,"findAllInterfaces",-1),D={href:"https://github.com/buffcow",target:"_blank",rel:"noopener noreferrer"},E={href:"https://github.com/HighCapable/YukiHookAPI/pull/38",target:"_blank",rel:"noopener noreferrer"},N={href:"https://github.com/cesaryuan",target:"_blank",rel:"noopener noreferrer"},O={href:"https://github.com/HighCapable/YukiHookAPI/issues/47",target:"_blank",rel:"noopener noreferrer"},T={href:"https://github.com/HighCapable/YukiHookAPI/issues/36",target:"_blank",rel:"noopener noreferrer"},W=c(" YLog
现已允许msg
传入任意对象,将自动转换为字符串进行打印新增 YukiHookAPI.TAG
作废了 、YukiHookAPI.API_VERSION_NAME
,统一合并到YukiHookAPI.API_VERSION_CODE
YukiHookAPI.VERSION
作废了 中的YukiMemberHookCreator
方法useDangerousOperation
作废了 中的YukiMemberHookCreator
功能,不再推荐使用instanceClass
修改 HookParam
中的instanceClass
为空安全返回值类型分离全部使用 injectMember
创建的 Hook 对象到LegacyCreator
修改 PackageParam
中的appClassLoader
为空安全返回值类型重构全部 logger...
方法到新用法YLog
移除了打印日志功能后方的 -->
样式修复并改进在使用 namespace
后通过 KSP 无法获取模块包名的问题是否启用模块激活状态等功能现已移动到 ",11),U={href:"https://github.com/tiann/FreeReflection",target:"_blank",rel:"noopener noreferrer"},w=c("InjectYukiHookWithXposed
注解中新增重复 Hook 同一个方法时将自动打印警告日志 作废了 PackageParam
中的findClass(...)
方法,请迁移到"...".toClass()
方法作废了 PackageParam
中的String.hook { ... }
方法,推荐使用新方式进行 HookAppLifecycle
现在可以在不同 Hooker 中重复创建作废了旧版 Hook 优先级写法,统一迁移到 YukiHookPriority
移除了 Hook 过程中的 tag
功能重构方法查找中的 remendy
功能,现在可以对其进行分步打印异常多重方法查找结果类型由 HashSet
改为MutableList
新增使用 method()
、constructor()
、field()
可直接获取到类中的所有对象功能constructor()
的行为不再是constructor { emptyParam() }
新增 ",11),G={id:"_1-1-11-2023-04-25",tabindex:"-1"},z=e("a",{class:"header-anchor",href:"#_1-1-11-2023-04-25","aria-hidden":"true"},"#",-1),V=e("code",null,"1.1.5",-1),K=e("code",null,"Member",-1),j={href:"https://github.com/Art-Chen",target:"_blank",rel:"noopener noreferrer"},Z=c("lazyClass
、lazyClassOrNull
方法,可延迟装载Class
移除 Member
的直接缓存功能并作废,保留YukiHookAPI.Configs.isEnableMemberCache
Class
的缓存功能对接查找功能到 Sequence
,优化Member
的查找速度与性能移除 YukiHookPrefsBridge
的直接键值缓存功能并移除LruCache
相关功能作废了 YukiHookAPI.Configs.isEnablePrefsBridgeCache
作废了 ",5),J={id:"_1-1-10-2023-04-21",tabindex:"-1"},q=e("a",{class:"header-anchor",href:"#_1-1-10-2023-04-21","aria-hidden":"true"},"#",-1),Q=c("YukiHookPrefsBridge
中的、direct
方法clearCache
",1),$={id:"_1-1-9-2023-04-17",tabindex:"-1"},ee=e("a",{class:"header-anchor",href:"#_1-1-9-2023-04-17","aria-hidden":"true"},"#",-1),oe=c("
Activity
代理功能新增每个被代理的Activity
指定单独的代理Activity
功能- 修复
YukiHookPrefsBridge
中的contains
、all
方法未判断native
功能的问题- 整合
YukiHookPrefsBridge
中的缓存功能到PreferencesCacheManager
并使用LruCache
作为键值对前置缓存- 修改
YukiHookPrefsBridge
键值对缓存功能在所有环境中生效 (模块、宿主)- 修改部分用于缓存的
HashMap
到ArrayMap
以减少内存消耗- 修复一些其它可能出现的问题
",1),de={id:"_1-1-8-2023-02-01",tabindex:"-1"},ie=e("a",{class:"header-anchor",href:"#_1-1-8-2023-02-01","aria-hidden":"true"},"#",-1),le=e("code",null,"result",-1),ce={href:"https://github.com/elvizlai",target:"_blank",rel:"noopener noreferrer"},te={href:"https://github.com/HighCapable/YukiHookAPI/issues/23",target:"_blank",rel:"noopener noreferrer"},ae=c("
- 将依赖库的类型由 Java Library (jar) 修改为 Android Library (aar)
- 移除通过 Hook 或反射 API 内部方法、参数的检查功能
- 修复
YukiHookDataChannel
自动分段发送数据功能不能正常生效 (依然会抛出异常) 的问题- 新增可以手动根据目标设备的限制修改
YukiHookDataChannel
允许一次发送的最大数据字节大小- 移除
YukiHookDataChannel
只能在模块Activity
中使用的限制,现在你可以在任何地方使用它- 修改并规范
YukiHookDataChannel
使用的广播 Action 名称- 修复
YukiHookDataChannel
在不同模块同一宿主的情况下出现BadParcelableException
异常的问题- 新增
ExecutorType
,可以通过YukiHookAPI.Status.Executor.type
来获取已知 Hook Framework 的类型更名为YukiHookModulePrefs
YukiHookPrefsBridge
- 修改
YukiHookPrefsBridge
为非单例实现,作为单例可能发生数据混淆的问题- 作废了
方法,请迁移到Context.modulePrefs(...)
Context.prefs(...)
YukiHookPrefsBridge
新增native
方法,支持直接作为原生存储在模块和宿主中存储私有数据- 整合
YukiHookPrefsBridge
中的存储方法到YukiHookPrefsBridge.Editor
,请使用edit
方法来存储数据YukiHookPrefsBridge
新增contains
方法- 缓存
YukiHookPrefsBridge
中动态创建的代理对象,尝试修复可能会导致宿主、模块出现 OOM 的问题- 修改
Activity
代理功能的代理类为动态生成,防止不同模块注入宿主后造成冲突- 修复一些其它可能出现的问题
移动 YukiHookAPI
自动生成的入口类名称文件assets/yukihookapi_init
到resources/META-INF/yukihookapi_init
允许在仅打印异常堆栈时 msg
参数为空并可以不设置msg
参数,留空msg
参数的日志除非异常堆栈不为空否则将不会被记录修复 Hook 回调方法体内发生的异常打印的日志无具体方法信息的 BUG HookParam
新增instanceOrNull
变量与方法,可以在不确定 Hook 实例是否为空的前提下使用以防止 Hook 实例为空抛出异常解耦合所有 Member
查找功能中的 Hooker 到MemberBaseFinder.MemberHookerManager
修改了 YukiMemberHookCreator
中的by
条件用法,现在可以重复使用by
方法设置多个条件移除了 Android type
中的错误Class
对象声明PackageParam.AppLifecycle
中的registerReceiver
方法新增直接使用IntentFilter
创建系统广播监听的功能修复在 PackageParam.AppLifecycle
中可能存在多次注册生命周期的问题Revert: 1.1.7 版本由于有一个严重问题已经撤回,请直接更新到此版本即可 (更新日志同 1.1.7 版本) ",10),ne={id:"_1-1-6-2023-01-21",tabindex:"-1"},re=e("a",{class:"header-anchor",href:"#_1-1-6-2023-01-21","aria-hidden":"true"},"#",-1),se=c("",1),he={id:"_1-1-5-2023-01-13",tabindex:"-1"},ue=e("a",{class:"header-anchor",href:"#_1-1-5-2023-01-13","aria-hidden":"true"},"#",-1),_e=c('
- 修复 Xposed 模块装载时可能存在同一个进程多个包名的情况导致
PackageParam
保持单例后ClassLoader
不符的严重问题- 新增同一个进程多个包名的情况下未区分包名时,停止装载单例化的子 Hooker 并打印警告信息
- 修复
HookParam.callOriginal
、HookParam.invokeOriginal
等方法调用原始方法时参数个数不正确的问题- 修改
MethodFinder
、ConstructorFinder
、ReflectionFactory
中反射调用的方法参数名param
为args
- 新增 Xposed 模块自动处理程序中判断入口类构造方法参数功能,入口类需要保证其不存在任何构造方法参数
',1),ke={id:"_1-1-4-2022-10-04",tabindex:"-1"},pe=e("a",{class:"header-anchor",href:"#_1-1-4-2022-10-04","aria-hidden":"true"},"#",-1),ge=c("
- 规范并优化整体代码风格
- 对部分内部调用的 API 进行了私有化处理
- 底层 API 接口整体解耦合,为兼容更多 Hook Framework 做准备
- 将部分集成于 API 中的功能移动到
ksp-xposed
依赖 (解耦合),单独引入api
依赖将不再包含第三方库等功能的引用- 文档 快速开始 页面加入
YukiHookAPI.Configs.isDebug
何时需要关闭的说明- 规范类型定义中的 Java 原始类型 (Primitive Type) 并同步更新到文档
- Java
type
新增NumberClass
类型- 改进了 (Xposed) 宿主环境的识别能力
- 接管了 Xposed 模块装载后的全部异常,若发生异常将会自动拦截并打印错误日志
- 修改类型定义中较低 Android 系统版本 (Android 5.0) 中不存在的
Class
为空安全类型- 适配并支持原生 Xposed,最低推荐版本为 Android 7.0
- Hook 入口类新增支持声明为
object
类型 (单例)- 修复 Android 8 以下系统不支持
Executable
类型导致 Hook 失效的问题- 修复 Android 9 以下系统在使用
Activity
代理功能时报错问题并限制此功能最低支持版本为 Android 7.0- 新增禁止资源注入与
Activity
代理功能注入当前模块自身实例进程,防止发生问题- 修复一个 Hook 过程中方法返回值的对象是目标的继承类和接口时被识别为返回值不符的严重错误
- 修复在当前 Hook 的实例对象是静态的情况下调用
HookParam.callOriginal
、HookParam.invokeOriginal
出现对象为空问题- 优化对太极激活方法相关判断功能以及同步更新文档相关说明
- 作废了
、YukiHookAPI.Status.executorName
,请迁移到YukiHookAPI.Status.executorVersion
YukiHookAPI.Status.Executor
- 适配了一些第三方 Hook Framework 的
YukiHookAPI.Status.Executor.name
名称显示功能- 新增
Class.extends
、Class.implements
等方法,可更加方便地判断当前Class
的继承与接口关系- 新增
Class.toClass
、Class.toClassOrNull
等相关方法的同名泛型方法,可使用泛型来约束已知Class
的实例对象类型- 修改
classOf<T>
方法的返回值为泛型T
,以约束已知Class
的实例对象类型- 新增
Class
相关扩展方法的initialize
参数,可控制在得到Class
对象时是否同时初始化其静态方法块- 变量、方法、构造方法查找功能中新增
param { ... }
、type { ... }
等用法,可对查找的对象增加更加具体的条件判断PackageParam
的loadApp
方法新增isExcludeSelf
参数,可用于排除 Hook 相关功能注入模块自身实例进程PackageParam
的onAppLifecycle
方法新增isOnFailureThrowToApp
参数,可将生命周期方法体内发生的异常直接抛给宿主- 修改
PackageParam
中的appClassLoader
为可修改变量,可在 Hook 过程中动态设置宿主使用的ClassLoader
HookParam
中新增dataExtra
功能,可用于临时存储 Hook 方法体中的数据- 作废
YukiHookModulePrefs
中的、isRunInNewXShareMode
,统一合并到isXSharePrefsReadable
isPreferencesAvailable
Class.allFields
、Class.allMethods
等相关方法新增isAccessible
参数,可控制成员对象何时可被设置为可访问类型- 修复
YukiHookDataChannel
存在多个宿主时在一个Activity
中接收相同键值数据时仅会回调最后一个方法体的问题YukiHookDataChannel
的wait
等相关方法中新增priority
参数,可传入ChannelPriority
来自定义回调数据结果的条件YukiHookDataChannel
新增发送数据时自动使用ChannelDataWrapper
类型包装功能,提升使用体验并增强数据保护YukiHookDataChannel
新增限制一次性发送数据的最大字节大小功能,防止数据过大造成 APP 崩溃YukiHookDataChannel
新增发送数据过大时自动分段发送功能,仅支持List
、Map
、Set
、String
类型YukiHookLogger
新增contents
方法与saveToFile
的data
参数,可传入自定义的调试日志数据进行格式化或保存到文件- 修复
YukiHookLogger
处理后的调试日志数据包名可能在 (Xposed) 宿主环境不正确的问题- 修复 Xposed 模块装载资源钩子 (Resources Hook) 事件时在部分系统上 (部分系统 APP 中) 包名可能不正确的问题
",1),fe={id:"_1-1-3-2022-09-30",tabindex:"-1"},He=e("a",{class:"header-anchor",href:"#_1-1-3-2022-09-30","aria-hidden":"true"},"#",-1),me=e("ul",null,[e("li",null,"修复一个无法自定义 Hook 入口类名的致命错误"),e("li",null,[o("添加 "),e("code",null,"LoggerFactory"),o(" 中的部分代码注释文案并更新特色功能文档")])],-1),Pe={id:"_1-1-2-2022-09-30",tabindex:"-1"},be=e("a",{class:"header-anchor",href:"#_1-1-2-2022-09-30","aria-hidden":"true"},"#",-1),Ae=c('
- 修复
YukiHookDataChannel
可能不能响应系统框架中响应广播事件的问题,在 Android 13 中复现- 修复
YukiHookDataChannel
长达多个版本在 (Xposed) 宿主环境无法与模块通讯的问题YukiHookDataChannel
中新增obtainLoggerInMemoryData
方法,可在模块与宿主之间共享调试日志数据- 修改
YukiHookLogger.inMemoryData
的类型为ArrayList
并修改YukiLoggerData
为data class
- 修复
YukiLoggerData
在模块中包名为空打印空白的问题PackageParam
中新增loadApp
、loadZygote
、loadSystem
、withProcess
的同名多参数方法- 修复了一些可能存在的 BUG
',1),Ce={id:"_1-1-1-2022-09-28",tabindex:"-1"},ye=e("a",{class:"header-anchor",href:"#_1-1-1-2022-09-28","aria-hidden":"true"},"#",-1),xe=e("ul",null,[e("li",null,[o("修复了文档 "),e("a",{href:"../guide/knowledge"},"基础知识"),o(" 页面友情链接错误的问题")]),e("li",null,[o("修复了文档 "),e("code",null,"favicon"),o(" 不显示的问题")]),e("li",null,[o("修复 "),e("code",null,"DexClassFinder"),o(" 查找条件中的 BUG")])],-1),Ye={id:"_1-1-0-2022-09-28",tabindex:"-1"},ve=e("a",{class:"header-anchor",href:"#_1-1-0-2022-09-28","aria-hidden":"true"},"#",-1),Ie=e("li",null,[o("这是一次大版本更新,有关更新日志中提到的变化及用法请参考 "),e("a",{href:"../api/home"},"API 文档"),o(" 以及 "),e("a",{href:"../api/special-features/reflection"},"特色功能")],-1),Me={href:"https://v2.vuepress.vuejs.org",target:"_blank",rel:"noopener noreferrer"},Re=c('
- 文档 基础知识 页面新增 English 版本友情链接
- 修复
YukiBaseHooker
注释中的 English 文档链接错误问题- 修复
ModuleClassLoader
中的ClassCastException
问题- 修正并规范部分代码注释
- 新增
ModuleClassLoader
排除列表功能,可使用excludeHostClasses
和excludeModuleClasses
方法来自定义排除列表- 新增
YukiLoggerData
实时日志数据类,可实时通过YukiHookLogger.inMemoryData
获取日志数组- 新增
ClassLoader.listOfClasses
方法,可直接获取当前Dex
中的全部Class
统一并规范文档中的术语名词,例如“查询”一律更改为了“查找”, XposedHelper
拼写错误修改为了XposedHelpers
文档 基础知识 页面加入友情链接,仅限简体中文 将 Hook App Demo 的 Class
与Method
转为 Java 以提供更好的演示效果修正了 Hook Module Demo 中的代码注释命名 重构了大量底层 Hook 逻辑及 Xposed API 的对接方式 移除了 HookParamWrapper
,现已将其直接与YukiBridgeFactory
对接移动部分 YukiHookBridge
中的方法到AppParasitics
移除了 HookParam.args
与底层的直接对接方法setArgs
,直接获取并设置当前数组的对象优化自动处理程序,将引用的 ',9),Le={href:"https://github.com/5ec1cff",target:"_blank",rel:"noopener noreferrer"},Se=c("jar
合并到stub
项目对 API 私有工具类的方法进行了 internal 闭包处理,避免污染顶级命名空间 修正了所有反射和 Hook 类的 Creater
命名到Creator
新增 YukiHookAPI.Status.compiledTimestamp
功能,可以在作为 Xposed 模块使用时获取编译完成的时间戳新增 YukiHookAPI.Status.isXposedEnvironment
功能,可以判断当前为 (Xposed) 宿主环境还是模块环境调试日志功能进行了大改版,现已将 YukiHookAPI.Configs.debugTag
等功能合并到YukiHookLogger.Configs
中调试日志新增可指定打印使用的方法为 XposedBridge.log
或Logd
调试日志中默认加入当前宿主的包名以及当前用户 ID,以供调试,你可以在 debugLog
配置中自行更改新增 generic
功能,可对泛型进行反射和调用,你可以在Class
或CurrentClass
中使用它作废 buildOfAny
方法,现在请直接使用buildOf
方法 (不带泛型) 来使用构造方法创建新对象并得到结果Any
修复 hasExtends
使用过程发生空指针异常的问题CurrentClass
新增非 lambda 方式的调用方法CurrentClass
新增name
与simpleName
功能完全重写 ReflectionTool
的核心方法,将不同的查找条件进行了整理分类修复 ReflectionTool
中可能的直接调用declared
获取的Member
抛出异常的问题修复 ReflectionTool
中UndefinedType
未在Method
与Constructor
条件中正确判断的问题新增反射查找结果发生异常时的友好提示方式,可具体定位到指定条件找不到 Member
的问题反射查找 Method
、Constructor
中新增VagueType
条件,可使用在param
条件中用于忽略你不想填写的参数反射查找 Method
、Constructor
中新增paramCount { ... }
条件,现在你可以直接拿到其中的it
来自定义你的判断条件FieldFinder
结果中新增current
方法,可直接对结果实例创建调用空间修改了反射查找功能中的 ",20),Be=e("code",null,"ModifierRules",-1),Fe=e("code",null,"as*",-1),Xe=e("code",null,"is*",-1),De={href:"https://github.com/KyuubiRan",target:"_blank",rel:"noopener noreferrer"},Ee=c("modifiers
条件以及name
条件,现在你需要对此方法体结尾返回一个Boolean
以使条件成立FieldFinder
中新增RemedyPlan
功能新增 ",2),Ne=e("strong",null,"AA",-1),Oe={href:"https://github.com/KyuubiRan",target:"_blank",rel:"noopener noreferrer"},Te=e("code",null,"appClassLoader",-1),We={href:"https://github.com/luckyzyx",target:"_blank",rel:"noopener noreferrer"},Ue=e("li",null,[o("修改了 "),e("code",null,"XposedBridge.invokeOriginalMethod"),o(" 的调用方式并在 "),e("code",null,"MethodFinder.Result.Instance"),o(" 中增加 "),e("code",null,"original"),o(" 功能")],-1),we=e("code",null,"YukiHookModulePrefs",-1),Ge=e("code",null,"getStringSet",-1),ze={href:"https://github.com/Teddy-Zhu",target:"_blank",rel:"noopener noreferrer"},Ve={href:"https://github.com/HighCapable/YukiHookAPI/pull/19",target:"_blank",rel:"noopener noreferrer"},Ke=e("li",null,[o("修改 "),e("code",null,"YukiHookModulePrefs"),o(",拦截 "),e("code",null,"XSharePreference"),o(" 可能不存在的异常")],-1),je=e("li",null,[o("修复 "),e("code",null,"YukiHookDataChannel"),o(" 在某些第三方 ROM 系统框架中无法注册成功的问题")],-1),Ze=e("li",null,[o("安全化 "),e("code",null,"YukiHookDataChannel"),o(",现在它只能在来自指定包名的模块与宿主之间通信")],-1),Je=e("code",null,"SharedPreferences",-1),qe=e("code",null,"0664",-1),Qe={href:"https://github.com/5ec1cff",target:"_blank",rel:"noopener noreferrer"},$e=c("Dex
中的Class
模糊查找功能 (Beta),你现在可以直接使用searchClass
功能来使用指定条件模糊查找Class
新增 YukiHookAPI.Configs.isEnableHookSharedPreferences
功能,默认关闭,若SharedPreferences
的权限错误可进行启用修复查找 Constructor
时无参构造方法在不填写查找条件时无法找到的 BUG,感谢 B5 KAKA 的反馈分离位于 injectMember
中method
、constructor
的Result
实例到Process
在 Hook 过程中新增 useDangerousOperation
方法,未进行声明时在 Hook 危险列表中的功能后会自动停止 Hook 并打印错误新增模块资源注入与 Activity
代理功能,你可以调用injectModuleAppResources
及registerModuleAppActivities
来使用新增 ModuleContextThemeWrapper
功能,你可以调用applyModuleTheme
在任意Activity
中创建模块的Context
新增 ClassLoader.onLoadClass
功能,可用于监听ClassLoader
的loadClass
方法被调用的事件作废了 classOf
与clazz
扩展方法,新增toClass
以及toClassOrNull
用法,请现在迁移到新的方法VariousClass
新增getOrNull
方法,可在匹配不到Class
的时候不抛出异常而是返回null
PackageParam.hook
中移除了isUseAppClassLoader
参数,修改为isForceUseAbsolute
并自动匹配目标Class
PackageParam
新增systemContext
功能,你可以在任意时间调用此功能获取一个持久化的Context
不再对外开放 HookClass
中的任何方法HookParam
中新增throwToApp
功能,可将异常直接抛给宿主Hook 回调中新增 onFailureThrowToApp
功能,可在发生异常时直接抛给宿主修改了调试日志的打印逻辑,反射查找功能中的耗时记录仅会在 Hook 过程中进行打印 Hook 过程中新增解除 Hook 功能,可使用 remove
及removeSelf
方法解除 Hook修复在 ReplaceHook 失败的时候导致宿主抛出异常的问题,现修改为调用原始方法保证宿主功能正常运行 新增 Hook 过程中对方法返回值的检查功能,在返回值不匹配的情况下会根据情景自动抛出异常或打印错误 ",18),eo=e("code",null,"array",-1),oo={href:"https://github.com/GSWXXN",target:"_blank",rel:"noopener noreferrer"},io={href:"https://github.com/HighCapable/YukiHookAPI/pull/12",target:"_blank",rel:"noopener noreferrer"},lo=e("li",null,[o("移动 "),e("code",null,"me.weishu.reflection"),o(" 到 "),e("code",null,"thirdparty"),o(" 防止同时引入的同名依赖冲突")],-1),co=e("li",null,"移除 Hook 方法体为空时抛出的异常,修改为打印警告日志",-1),to=e("li",null,[o("修改 "),e("code",null,"AppLifecycle"),o(" 的异常处理逻辑,当其发生异常时直接抛给宿主")],-1),ao=e("li",null,"更新 Demo 的 API 版本到 33",-1),no={id:"_1-0-92-2022-05-31",tabindex:"-1"},ro=e("a",{class:"header-anchor",href:"#_1-0-92-2022-05-31","aria-hidden":"true"},"#",-1),so=c("",1),ho={id:"_1-0-91-2022-05-29",tabindex:"-1"},uo=e("a",{class:"header-anchor",href:"#_1-0-91-2022-05-29","aria-hidden":"true"},"#",-1),_o=e("code",null,"ClassLoader",-1),ko={href:"https://github.com/luckyzyx",target:"_blank",rel:"noopener noreferrer"},po=c("
- 修正了大量方法中 callback 的命名方法
- 更换方案再次修复
YukiHookDataChannel
在低于 Android 12 的设备上不能回调当前Activity
广播的问题InjectYukiHookWithXposed
注解新增isUsingResourcesHook
功能,现在你可以选择性关闭自动生成IXposedHookInitPackageResources
的依赖接口了修复 YukiHookDataChannel
在 ZUI 以及低于 Android 12 的系统上不能回调当前Activity
广播的问题整合 ",2),go={id:"_1-0-90-2022-05-27",tabindex:"-1"},fo=e("a",{class:"header-anchor",href:"#_1-0-90-2022-05-27","aria-hidden":"true"},"#",-1),Ho=c("YukiHookModuleStatus
功能到YukiHookAPI.Status
,重写了大量方法,现在你可以在模块与宿主中双向判断模块激活等状态信息",1),mo={id:"_1-0-89-2022-05-26",tabindex:"-1"},Po=e("a",{class:"header-anchor",href:"#_1-0-89-2022-05-26","aria-hidden":"true"},"#",-1),bo=c("
- 修复
YukiHookDataChannel
在模块设置监听回调时闪退的问题- 修复
YukiHookDataChannel
在非当前Activity
情况下依然会回调的问题- 移除
YukiHookDataChannel
回调事件的默认值,没有即不回调- 移除
YukiHookModulePrefs
在 XShare 不可读的情况下打印的警告- 新增
YukiHookModulePrefs
中的isXSharePrefsReadable
方法,可判断当前的 XShare 是否可用",1),Ao={id:"_1-0-88-2022-05-25",tabindex:"-1"},Co=e("a",{class:"header-anchor",href:"#_1-0-88-2022-05-25","aria-hidden":"true"},"#",-1),yo=c("
- 修复
YukiHookDataChannel
不能重复设置监听的问题,并加入在模块不同Activity
中重复响应和自动跟随Activity
销毁监听功能- 新增
YukiHookDataChannel
重复监听用例说明文档- 加入
onAlreadyHooked
方法,可判断当前方法是否被重复 Hook- 修改部分重复添加 HashMap 的逻辑,移除
putIfAbsent
方法,允许覆盖添加- 修复了几处可能的 BUG
",1),xo={id:"_1-0-87-2022-05-10",tabindex:"-1"},Yo=e("a",{class:"header-anchor",href:"#_1-0-87-2022-05-10","aria-hidden":"true"},"#",-1),vo=e("ul",null,[e("li",null,[o("新增 "),e("code",null,"refreshModuleAppResources"),o(" 功能,以适配语言区域、字体大小、分辨率改变等情况下的 Resources 刷新")]),e("li",null,[o("新增 "),e("code",null,"isEnableModuleAppResourcesCache"),o(" 功能,可自行设置是否自动缓存当前模块的 Resources")])],-1),Io={id:"_1-0-86-2022-05-06",tabindex:"-1"},Mo=e("a",{class:"header-anchor",href:"#_1-0-86-2022-05-06","aria-hidden":"true"},"#",-1),Ro=e("ul",null,[e("li",null,[o("修复不支持 Resources Hook(资源钩子) 的情况下在 "),e("code",null,"initZygote"),o(" 时持续报错的问题,复现在 "),e("strong",null,"ZUI"),o("/"),e("strong",null,"LSPosed CI(1.8.3-6550)")]),e("li",null,"优化并对 Resources Hook 进行异常处理,只有被使用后不支持才会打印错误和警告")],-1),Lo={id:"_1-0-85-2022-05-04",tabindex:"-1"},So=e("a",{class:"header-anchor",href:"#_1-0-85-2022-05-04","aria-hidden":"true"},"#",-1),Bo=c("
- 对 Xposed API 完全解耦合
- 增加了
type
中的android
类型- 将
YukiHookModuleStatus
从自动生成代码中分离,并加入isEnableHookModuleStatus
的开关,由你决定是否启用- 对 API 大量类的构造方法进行了 internal 闭包处理
- 将
YukiHookModulePrefs
设置为单例运行,防止重复创建浪费系统资源- 修复自
1.0.80
版本后无法嵌套 Hook 的 BUG,并优化嵌套 Hook 相关功能- 修改 Hooker 存储方案由 HashSet 到 HashMap,防止重复添加 Hooker 的问题
- 修改 Hook 核心实现方法,加入查重,避免重复 Hook 多次回调
HookParam
方法MethodFinder
与FieldFinder
加入查找模糊方法、变量名称功能,可调用name { ... }
来设置查找条件,支持正则- 优化并修改
appContext
的获取方式,降低会取到空的问题的可能性- 修改自动生成的代码中
logger
的打印TAG
默认为你自定义的名称,方便进行调试- 优化
YukiHookBridge
的Hooker
实现方式,提升 Hook 性能PackageParam
增加onAppLifecycle
方法,可原生监听宿主的生命周期以及实现注册系统广播功能- 新增
YukiHookDataChannel
功能,可在模块与宿主保持存活的情况下使用系统无序广播进行通讯YukiHookDataChannel
增加checkingVersionEquals
方法,可通过监听来验证模块更新后宿主并未更新版本不匹配问题demo-module
的示例代码中新增 Java 版本的示例,仅供参考",1),Fo={id:"_1-0-83-2022-05-04",tabindex:"-1"},Xo=e("a",{class:"header-anchor",href:"#_1-0-83-2022-05-04","aria-hidden":"true"},"#",-1),Do=e("ul",null,[e("li",null,[o("修复 "),e("code",null,"YukiHookModuleStatus"),o(" 在 "),e("code",null,"loadSystem"),o(" 后大量报错的问题")]),e("li",null,[o("新增 "),e("code",null,"type"),o(" 中的 "),e("code",null,"android"),o(" 类型")]),e("li",null,"更新帮助文档的示例说明")],-1),Eo={id:"_1-0-82-2022-05-04",tabindex:"-1"},No=e("a",{class:"header-anchor",href:"#_1-0-82-2022-05-04","aria-hidden":"true"},"#",-1),Oo=e("ul",null,[e("li",null,[o("修复了一处概念混淆错误,区分 "),e("code",null,"initZygote"),o(" 与系统框架的关系,之前的注释和文档有问题,非常抱歉")]),e("li",null,[e("code",null,"PackageParam"),o(" 新增 "),e("code",null,"loadSystem"),o(" 方法,不需要再写 "),e("code",null,'loadApp(name = "android")'),o(" 即可 Hook 系统框架")])],-1),To={id:"_1-0-81-2022-05-04",tabindex:"-1"},Wo=e("a",{class:"header-anchor",href:"#_1-0-81-2022-05-04","aria-hidden":"true"},"#",-1),Uo=e("ul",null,[e("li",null,[o("修复使用 "),e("code",null,"by"),o(" 方法设置条件后 Hook 方法体内查找不到的方法、构造方法依然输出错误日志的问题")]),e("li",null,"在执行 Hook 过程中加入全局日志显示当前 Hook APP 的包名,并修复一处错误日志打印样式的问题")],-1),wo={id:"_1-0-80-2022-05-01",tabindex:"-1"},Go=e("a",{class:"header-anchor",href:"#_1-0-80-2022-05-01","aria-hidden":"true"},"#",-1),zo=c("
- 修复无法 Hook 系统框架的严重问题,从
1.0.80
开始出现- 调试日志中新增区分
initZygote
装载的包名为android-zygote
,packageName
保持android
不变InjectYukiHookWithXposed
注解新增entryClassName
功能,可自定义生成的xposed_init
入口类名更名为YukiHookXposedInitProxy
IYukiHookXposedInit
,原接口名称已作废,将在后续版本中直接被删除新增 initZygote
与 Resources Hook 功能,支持 Hook Layout新增 onXposedEvent
方法,可监听原生 Xposed API 的全部事件对 Hook 功能的 lambda 进行 inline
处理,避免生成过碎的匿名类,提升编译后的运行性能修复 PrefsData
编译后的方法体复制过大的问题增加 XSharePreference
可读性测试,失败后会自动打印警告日志PackageParam
新增appResources
、moduleAppResources
、moduleAppFilePath
功能PackageParam
的loadApp
新增不写name
功能,默认筛选全部 APPPackageParam
新增loadZygote
方法,可直接 Hook 系统框架PackageParam
新增resources().hook
功能优化方法、构造方法、变量查找功能,找不到的错误日志将优先显示已设置的查找条件 增加 hasExtends
扩展方法,可判断当前Class
是否有继承关系增加 isSupportResourcesHook
功能,判断当前是否支持资源钩子(Resources Hook)current
功能新增superClass
方法调用父类查找方法、构造方法、变量新增 superClass
查找条件,可继续在父类中查找YukiHookAPI
大量方法与 Xposed API 解耦合新增 Xposed API 的原生 Hook 优先级功能 修复 isFirstApplication
可能判断不准确的问题屏蔽 MIUI 系统上 MiuiCatcherPatch 重复调用 Hook 入口方法的问题 优化 Hook 入口调用方法,避免因为 Hook Framework 问题导致多次调用 ",21),Vo=e("code",null,"ClassLoader",-1),Ko={href:"https://github.com/WankkoRee",target:"_blank",rel:"noopener noreferrer"},jo=e("li",null,[o("提升 "),e("code",null,"XC_Callback"),o(" 接口对接后的性能")],-1),Zo=e("li",null,[o("Java "),e("code",null,"type"),o(" 新增 "),e("code",null,"ClassLoader"),o(" 类型")],-1),Jo=e("li",null,"优化 API 帮助文档,修复可能持续缓存页面的问题",-1),qo={id:"_1-0-78-2022-04-18",tabindex:"-1"},Qo=e("a",{class:"header-anchor",href:"#_1-0-78-2022-04-18","aria-hidden":"true"},"#",-1),$o=c("YukiHookModulePrefs
新增isRunInNewXShareMode
方法,可用于判断模块当前是否处于New XSharePreference
模式修复 YukiHookModulePrefs
在New XSharePreference
模式下工作的部分问题新增 ",3),ed=e("code",null,"PreferenceFragmentCompat",-1),od={href:"https://github.com/mahoshojoHCG",target:"_blank",rel:"noopener noreferrer"},dd=e("li",null,"更新自动处理程序以及 Kotlin 依赖到最新版本",-1),id=e("li",null,"修正部分文档和代码注释中的错误",-1),ld={id:"_1-0-77-2022-04-15",tabindex:"-1"},cd=e("a",{class:"header-anchor",href:"#_1-0-77-2022-04-15","aria-hidden":"true"},"#",-1),td=e("code",null,"YukiHookModulePrefs",-1),ad=e("code",null,"clear",-1),nd={href:"https://github.com/WankkoRee",target:"_blank",rel:"noopener noreferrer"},rd=c("ModulePreferenceFragment
,现在,你可以完全替换掉PreferenceFragmentCompat
并开始使用新的功能YukiHookModulePrefs
新增getStringSet
、putStringSet
、all
方法HookParam
的args
增加any
方法新增 ModuleApplication
,可在模块中继承此类实现更多功能对接全部的 findClass
功能到 Xposed API,在非宿主环境继续使用原生ClassLoader
修复了一些可能存在的 BUG ",5),sd={id:"_1-0-75-2022-04-13",tabindex:"-1"},hd=e("a",{class:"header-anchor",href:"#_1-0-75-2022-04-13","aria-hidden":"true"},"#",-1),ud={href:"https://github.com/ApeaSuperz",target:"_blank",rel:"noopener noreferrer"},_d=c("修正一处文档注释的引用未更改的问题 HookParam
中删除了firstArgs
与lastArgs
方法,现在你可以使用args().first()
与args().last()
来取代它HookParam
中删除了args()
中的默认参数index = 0
,现在你可以使用args().first()
或args(index = 0)
来取代它HookParam
中result
功能增加了泛型匹配,现在你可以使用result<T>
来匹配你的目标方法已知返回值类型了方法、构造方法查找功能新增 emptyParam
条件,并完善了文档相关需要注意的查找条件误区增加了 ",6),kd=e("h3",{id:"_1-0-73-2022-04-10",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#_1-0-73-2022-04-10","aria-hidden":"true"},"#"),o(" 1.0.73 | 2022.04.10")],-1),pd={href:"https://github.com/WankkoRee",target:"_blank",rel:"noopener noreferrer"},gd=e("code",null,"XC_LoadPackage.LoadPackageParam",-1),fd={href:"https://github.com/luckyzyx",target:"_blank",rel:"noopener noreferrer"},Hd=e("li",null,"修复一些已知的 BUG,提升 Hook 稳定性",-1),md={id:"_1-0-72-2022-04-09",tabindex:"-1"},Pd=e("a",{class:"header-anchor",href:"#_1-0-72-2022-04-09","aria-hidden":"true"},"#",-1),bd=e("ul",null,[e("li",null,"更新 API 文档到新的地址"),e("li",null,[e("code",null,"PackageParam"),o(" 中加入 "),e("code",null,"appContext"),o(" 功能")]),e("li",null,"修复一些已知的 BUG,提升 Hook 稳定性")],-1),Ad={id:"_1-0-71-2022-04-04",tabindex:"-1"},Cd=e("a",{class:"header-anchor",href:"#_1-0-71-2022-04-04","aria-hidden":"true"},"#",-1),yd=e("ul",null,[e("li",null,"修复 VariousClass 无法匹配时会停止 Hook 抛出异常的严重问题")],-1),xd={id:"_1-0-70-2022-04-04",tabindex:"-1"},Yd=e("a",{class:"header-anchor",href:"#_1-0-70-2022-04-04","aria-hidden":"true"},"#",-1),vd=e("li",null,[o("修复 "),e("code",null,"instanceClass"),o(" 在静态实例中调用后报错问题")],-1),Id=e("code",null,"isUseAppClassLoader",-1),Md={href:"https://github.com/WankkoRee",target:"_blank",rel:"noopener noreferrer"},Rd=e("li",null,[o("加入 "),e("code",null,"withProcess"),o(" 功能,可根据 APP 当前指定进程进行 Hook")],-1),Ld=e("li",null,"修复查找方法、构造类和变量的严重逻辑错误问题",-1),Sd=e("li",null,"修复 Hook 目标类不存在的时候无法忽略异常输出的问题",-1),Bd=e("li",null,"修复部分情况下 APP 启动方法装载过快导致 Hook 不能生效的问题",-1),Fd=e("code",null,"allMethods",-1),Xd={href:"https://github.com/WankkoRee",target:"_blank",rel:"noopener noreferrer"},Dd={href:"https://github.com/WankkoRee",target:"_blank",rel:"noopener noreferrer"},Ed=e("li",null,"修改 Xposed 入口注入类的方式,重新声明 API 的定义域",-1),Nd=e("code",null,"index",-1),Od={href:"https://github.com/WankkoRee",target:"_blank",rel:"noopener noreferrer"},Td=e("li",null,[o("查找方法、变量时允许传入多种类型,例如 "),e("code",null,"String"),o(" 声明的类名和 "),e("code",null,"VariousClass")],-1),Wd=e("li",null,[o("加入全新的 "),e("code",null,"current"),o(" 功能,可对任意的类构建一个反射方法操作空间,方便地调用和修改其中的方法和变量")],-1),Ud={href:"https://github.com/WankkoRee",target:"_blank",rel:"noopener noreferrer"},wd={id:"_1-0-69-2022-03-30",tabindex:"-1"},Gd=e("a",{class:"header-anchor",href:"#_1-0-69-2022-03-30","aria-hidden":"true"},"#",-1),zd=e("li",null,"添加并改进一些方法功能的注释",-1),Vd=e("li",null,"增加 Demo 中的更多示例 Hook 内容",-1),Kd=e("code",null,"allMethods",-1),jd={href:"https://github.com/WankkoRee",target:"_blank",rel:"noopener noreferrer"},Zd={id:"_1-0-68-2022-03-29",tabindex:"-1"},Jd=e("a",{class:"header-anchor",href:"#_1-0-68-2022-03-29","aria-hidden":"true"},"#",-1),qd=c("type
中的android
类型",1),Qd={id:"_1-0-67-2022-03-27",tabindex:"-1"},$d=e("a",{class:"header-anchor",href:"#_1-0-67-2022-03-27","aria-hidden":"true"},"#",-1),ei=c("
- 增加 Demo 中的新用例和 LSPosed 作用域
- 增加
Member
查找缓存和查找缓存配置开关- 移除和修改
MethodFinder
、FieldFinder
以及HookParam
相关方法的调用- 增加更多
Finder
中的cast
类型并支持cast
为数组- 整体的性能和稳定性提升
- 修复上一个版本可能存在的 BUG
",1),oi={id:"_1-0-66-2022-03-25",tabindex:"-1"},di=e("a",{class:"header-anchor",href:"#_1-0-66-2022-03-25","aria-hidden":"true"},"#",-1),ii=e("ul",null,[e("li",null,[o("修复 "),e("code",null,"MethodFinder"),o(" 中的一个严重问题")]),e("li",null,[o("增加 "),e("code",null,"hookParam"),o(" 中的 "),e("code",null,"args"),o(" 调用方法")]),e("li",null,"修复其它可能存在的问题以及修复部分类的注释问题")],-1),li={id:"_1-0-65-2022-03-25",tabindex:"-1"},ci=e("a",{class:"header-anchor",href:"#_1-0-65-2022-03-25","aria-hidden":"true"},"#",-1),ti=c("
- 增加三个
Finder
中的modifiers
功能,可筛选static
、native
、public
、abstract
等诸多描述类型- 增加方法和构造方法查找时可模糊方法参数类型为指定个数进行查找
- 增加
Member
的hasModifiers
扩展功能- 增加
MethodFinder
和ConstructorFinder
中的give
方法,可获得原始类型- 增加
YukiHookModulePrefs
中的PrefsData
模板功能- 彻底对方法、构造方法及变量的查找方案进行重构
- 优化代码注释,修复了可能产生的 BUG
",1),ai={id:"_1-0-6-2022-03-20",tabindex:"-1"},ni=e("a",{class:"header-anchor",href:"#_1-0-6-2022-03-20","aria-hidden":"true"},"#",-1),ri=c("
- 重新发布版本修复 Maven 仓库因为缓存问题新版本不正确的情况
- 增加
MethodFinder
与FieldFinder
新的返回值调用方法- 修复可能存在的问题,并修复太极使用过程中可能存在的问题
- 修复自动生成 Xposed 入口类可能发生的问题
- 增加了
type
中的android
类型以及 Java 类型",1),si={id:"_1-0-55-2022-03-18",tabindex:"-1"},hi=e("a",{class:"header-anchor",href:"#_1-0-55-2022-03-18","aria-hidden":"true"},"#",-1),ui=e("ul",null,[e("li",null,"修正一处注释错误"),e("li",null,"临时修复一个 BUG"),e("li",null,[o("增加了 "),e("code",null,"type"),o(" 中的大量 "),e("code",null,"android"),o(" 类型以及少量 Java 类型")]),e("li",null,"修复新版与旧版 Kotlin APIs 的兼容性问题")],-1),_i={id:"_1-0-5-2022-03-18",tabindex:"-1"},ki=e("a",{class:"header-anchor",href:"#_1-0-5-2022-03-18","aria-hidden":"true"},"#",-1),pi=c("
- 修复
YukiHookModulePrefs
在使用一次direct
忽略缓存后每次都忽略的 BUG- 增加新的 API,作废了
isActive
判断模块激活的传统用法- 修复非 Xposed 环境使用 API 时打印调试日志的问题
- 修复查找
Field
时的日志输出问题和未拦截的异常问题- 解耦合
ReflectionUtils
中的 Xposed API- 增加
YukiHookModuleStatus
方法名称的混淆,以精简模块生成的体积- 装载模块自身 Hook 时将不再打印欢迎信息
- 修复上一个版本仍然存在的某些 BUG
",1),gi={id:"_1-0-4-2022-03-06",tabindex:"-1"},fi=e("a",{class:"header-anchor",href:"#_1-0-4-2022-03-06","aria-hidden":"true"},"#",-1),Hi=c("
- 修复旧版本 LSPosed 框架情况下欢迎信息多次打印的问题
- 添加
onInit
方法来配置YukiHookAPI
- 新增
executorName
和executorVersion
来获取当前 Hook Framework 的名称和版本号- 新增
by
方法来设置 Hook 的时机和条件YukiHookModulePrefs
新增可控制的键值缓存,可在宿主运行时模块动态更新数据- 修复了一些可能存在的 BUG
",1),mi={id:"_1-0-3-2022-03-02",tabindex:"-1"},Pi=e("a",{class:"header-anchor",href:"#_1-0-3-2022-03-02","aria-hidden":"true"},"#",-1),bi=c("
- 修复 LSPosed 在最新版本中启用“只有模块classloader可以使用Xposed API”选项后找不到
XposedBridge
的问题- 添加
YukiHookAPI
的常量版本名称和版本号- 新增
hasField
方法以及isAllowPrintingLogs
配置参数- 新增
isDebug
开启的情况下 API 将自动打印欢迎信息测试模块是否生效",1),Ai={id:"_1-0-2-2022-02-18",tabindex:"-1"},Ci=e("a",{class:"header-anchor",href:"#_1-0-2-2022-02-18","aria-hidden":"true"},"#",-1),yi=e("ul",null,[e("li",null,"修复 Windows 下无法找到项目路径的问题"),e("li",null,[o("移除部分反射 API,合并至 "),e("code",null,"BaseFinder"),o(" 进行整合")]),e("li",null,"增加直接使用字符串创建 Hook 的方法")],-1),xi={id:"_1-0-1-2022-02-15",tabindex:"-1"},Yi=e("a",{class:"header-anchor",href:"#_1-0-1-2022-02-15","aria-hidden":"true"},"#",-1),vi=e("ul",null,[e("li",null,[e("code",null,"RemedyPlan"),o(" 增加 "),e("code",null,"onFind"),o(" 功能")]),e("li",null,"整合并修改了部分反射 API 代码"),e("li",null,[o("增加了 "),e("code",null,"type"),o(" 中的 Java 类型")]),e("li",null,"修复忽略错误在控制台仍然输出的问题")],-1),Ii={id:"_1-0-2022-02-14",tabindex:"-1"},Mi=e("a",{class:"header-anchor",href:"#_1-0-2022-02-14","aria-hidden":"true"},"#",-1),Ri=e("ul",null,[e("li",null,"首个版本提交至 Maven")],-1);function Li(Si,Bi){const i=t("Badge"),l=t("ExternalLinkIcon");return n(),r("div",null,[h,u,_,e("h3",k,[p,o(" 1.3.0 | 2025.06.25 "),d(i,{type:"tip",text:"最新",vertical:"middle"})]),e("ul",null,[e("li",null,[o("这是一次重大更新,详情请参考 "),e("a",g,[o("迁移到 YukiHookAPI 1.3.x"),d(l)])]),e("li",null,[o("弃用了 "),f,o(" 自身的反射 API,现在请迁移到全新的 "),e("a",H,[o("KavaRef"),d(l)])]),m,e("li",null,[P,o(" 已被弃用,现已切换至 "),e("a",b,[o("AndroidHiddenApiBypass"),d(l)])])]),e("h3",A,[C,o(" 1.2.1 | 2024.06.20 "),d(i,{type:"warning",text:"过旧",vertical:"middle"})]),e("ul",null,[y,e("li",null,[o('在自动处理程序中添加自动使用 "`" 来修复 Kotlin 关键字为包名的情况,感谢 '),e("a",x,[o("Fengning Zhu"),d(l)]),o(" 的 "),e("a",Y,[o("PR"),d(l)])]),e("li",null,[o("适配 Kotlin 2.0.0+,修复在自动处理过程中无法通过编译的问题,感谢 "),e("a",v,[o("xihan123"),d(l)]),o(" 的 "),e("a",I,[o("PR"),d(l)])])]),e("h3",M,[R,o(" 1.2.0 | 2023.10.07 "),d(i,{type:"warning",text:"过旧",vertical:"middle"})]),e("ul",null,[L,e("li",null,[o("这是一次重大更新,详情请参考 "),e("a",S,[o("迁移到 YukiHookAPI 1.2.x"),d(l)])]),e("li",null,[o("适配 Android 14,感谢 "),e("a",B,[o("BlueCat300"),d(l)]),o(" 的 "),e("a",F,[o("PR"),d(l)])]),e("li",null,[o("修复 "),X,o(" 相关问题,感谢 "),e("a",D,[o("buffcow"),d(l)]),o(" 的 "),e("a",E,[o("PR"),d(l)])]),e("li",null,[o("修复 Hook 过程中的延迟回调问题,感谢 "),e("a",N,[o("cesaryuan"),d(l)]),o(" 的 "),e("a",O,[o("Issue"),d(l)])]),e("li",null,[o("新增 Resources Hook 相关功能支持,详情请参考这个 "),e("a",T,[o("Issue"),d(l)])]),W,e("li",null,[o("分离 "),e("a",U,[o("FreeReflection"),d(l)]),o(" 不再自动生成,将作为依赖自动导入")]),w]),e("h3",G,[z,o(" 1.1.11 | 2023.04.25 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),e("ul",null,[e("li",null,[o("修复从 "),V,o(" 版本开始的一个严重问题,"),K,o(" 缓存未生效且持续存储最终引发 APP 内存溢出 (OOM),感谢 "),e("a",j,[o("Art-Chen"),d(l)])]),Z]),e("h3",J,[q,o(" 1.1.10 | 2023.04.21 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),Q,e("h3",$,[ee,o(" 1.1.9 | 2023.04.17 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),oe,e("h3",de,[ie,o(" 1.1.8 | 2023.02.01 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),e("ul",null,[e("li",null,[o("修复底层 Hook 方法在回调时修改 "),le,o(" 等参数时时不能同步更新修改后的状态问题,感谢 "),e("a",ce,[o("Yongzheng Lai"),d(l)]),o(" 的 "),e("a",te,[o("Issue"),d(l)])]),ae]),e("h3",ne,[re,o(" 1.1.6 | 2023.01.21 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),se,e("h3",he,[ue,o(" 1.1.5 | 2023.01.13 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),_e,e("h3",ke,[pe,o(" 1.1.4 | 2022.10.04 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),ge,e("h3",fe,[He,o(" 1.1.3 | 2022.09.30 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),me,e("h3",Pe,[be,o(" 1.1.2 | 2022.09.30 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),Ae,e("h3",Ce,[ye,o(" 1.1.1 | 2022.09.28 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),xe,e("h3",Ye,[ve,o(" 1.1.0 | 2022.09.28 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),e("ul",null,[Ie,e("li",null,[o("更换帮助文档框架到 "),e("a",Me,[o("VuePress"),d(l)])]),Re,e("li",null,[o("修复多项目打包时模块包名无法正确匹配的问题以及修改自动处理程序的模块包名匹配逻辑,感谢 "),e("a",Le,[o("5ec1cff"),d(l)]),o(" 的反馈及提供的解决方案")]),Se,e("li",null,[Be,o(" 中的 "),Fe,o(" 功能改名为 "),Xe,o(",感谢 "),e("a",De,[o("Kitsune"),d(l)]),o(" 的建议")]),Ee,e("li",null,[o("新增反射查找中的多重查找功能,可使用相对查找条件同时获取多个查找结果,感谢 "),Ne,o(" 以及 "),e("a",Oe,[o("Kitsune"),d(l)]),o(" 的建议")]),e("li",null,[o("修复 "),Te,o(" 获取到的对象在某些系统中的系统应用中不正确的问题,感谢 "),e("a",We,[o("Luckyzyx"),d(l)]),o(" 的反馈")]),Ue,e("li",null,[o("修复 "),we,o(" 中 "),Ge,o(" 方法取值错误的问题并优化代码风格,感谢 "),e("a",ze,[o("Teddy_Zhu"),d(l)]),o(" 的 "),e("a",Ve,[o("PR"),d(l)])]),Ke,je,Ze,e("li",null,[o("新增自动 Hook "),Je,o(" 以修复部分系统中文件权限不是 "),qe,o(" 的问题,感谢 "),e("a",Qe,[o("5ec1cff"),d(l)]),o(" 的反馈及提供的实现代码")]),$e,e("li",null,[o("Resources Hook 中新增 "),eo,o(" 类型,感谢 "),e("a",oo,[o("GSWXXN"),d(l)]),o(" 的 "),e("a",io,[o("PR"),d(l)])]),lo,co,to,ao]),e("h3",no,[ro,o(" 1.0.92 | 2022.05.31 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),so,e("h3",ho,[uo,o(" 1.0.91 | 2022.05.29 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),e("ul",null,[e("li",null,[o("修复部分设备的定制系统在 LSPosed 环境下开机启动获取的 "),_o,o(" 错误的问题,感谢 "),e("a",ko,[o("Luckyzyx"),d(l)]),o(" 的反馈")]),po]),e("h3",go,[fo,o(" 1.0.90 | 2022.05.27 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),Ho,e("h3",mo,[Po,o(" 1.0.89 | 2022.05.26 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),bo,e("h3",Ao,[Co,o(" 1.0.88 | 2022.05.25 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),yo,e("h3",xo,[Yo,o(" 1.0.87 | 2022.05.10 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),vo,e("h3",Io,[Mo,o(" 1.0.86 | 2022.05.06 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),Ro,e("h3",Lo,[So,o(" 1.0.85 | 2022.05.04 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),Bo,e("h3",Fo,[Xo,o(" 1.0.83 | 2022.05.04 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),Do,e("h3",Eo,[No,o(" 1.0.82 | 2022.05.04 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),Oo,e("h3",To,[Wo,o(" 1.0.81 | 2022.05.04 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),Uo,e("h3",wo,[Go,o(" 1.0.80 | 2022.05.01 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),e("ul",null,[zo,e("li",null,[o("修复 Hook "),Vo,o(" 导致 Hook 卡死的问题,感谢 "),e("a",Ko,[o("WankkoRee"),d(l)]),o(" 的反馈")]),jo,Zo,Jo]),e("h3",qo,[Qo,o(" 1.0.78 | 2022.04.18 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),e("ul",null,[$o,e("li",null,[o("适配 "),ed,o(" 的 Sp 数据存储解决方案,感谢 "),e("a",od,[o("mahoshojoHCG"),d(l)]),o(" 的反馈")]),dd,id]),e("h3",ld,[cd,o(" 1.0.77 | 2022.04.15 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),e("ul",null,[e("li",null,[td,o(" 新增 "),ad,o(" 方法,感谢 "),e("a",nd,[o("WankkoRee"),d(l)]),o(" 的建议")]),rd]),e("h3",sd,[hd,o(" 1.0.75 | 2022.04.13 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),e("ul",null,[e("li",null,[o("更正了自动处理程序的逻辑识别部分,感谢 "),e("a",ud,[o("ApeaSuperz"),d(l)]),o(" 的贡献")]),_d]),kd,e("ul",null,[e("li",null,[o("修正几处文档的中文翻译错误,感谢 "),e("a",pd,[o("WankkoRee"),d(l)]),o(" 的贡献")]),e("li",null,[o("修复在某些情况下 "),gd,o(" 内容为空抛出异常的问题,感谢 "),e("a",fd,[o("Luckyzyx"),d(l)]),o(" 的反馈")]),Hd]),e("h3",md,[Pd,o(" 1.0.72 | 2022.04.09 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),bd,e("h3",Ad,[Cd,o(" 1.0.71 | 2022.04.04 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),yd,e("h3",xd,[Yd,o(" 1.0.70 | 2022.04.04 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),e("ul",null,[vd,e("li",null,[o("在 Hook 过程中加入 "),Id,o(" 功能,感谢 "),e("a",Md,[o("WankkoRee"),d(l)]),o(" 的反馈")]),Rd,Ld,Sd,Bd,e("li",null,[o("修复 "),Fd,o(" 未 Hook 到方法时不会抛出异常的问题,感谢 "),e("a",Xd,[o("WankkoRee"),d(l)]),o(" 的反馈")]),e("li",null,[o("加入 Hook 状态监听功能,感谢 "),e("a",Dd,[o("WankkoRee"),d(l)]),o(" 的建议")]),Ed,e("li",null,[o("加入混淆的方法以及变量的查找功能,可使用不同类型筛选 "),Nd,o(" 定位指定的方法和变量,感谢 "),e("a",Od,[o("WankkoRee"),d(l)]),o(" 提供的思路")]),Td,Wd,e("li",null,[o("修复了 Hook 过程中的大量 BUG,感谢 "),e("a",Ud,[o("WankkoRee"),d(l)]),o(" 对此项目所做出的贡献")])]),e("h3",wd,[Gd,o(" 1.0.69 | 2022.03.30 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),e("ul",null,[zd,Vd,e("li",null,[o("修复在一个 Hook 实例中,"),Kd,o(" 多次使用时只有最后一个生效的问题,感谢 "),e("a",jd,[o("WankkoRee"),d(l)]),o(" 的反馈")])]),e("h3",Zd,[Jd,o(" 1.0.68 | 2022.03.29 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),qd,e("h3",Qd,[$d,o(" 1.0.67 | 2022.03.27 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),ei,e("h3",oi,[di,o(" 1.0.66 | 2022.03.25 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),ii,e("h3",li,[ci,o(" 1.0.65 | 2022.03.25 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),ti,e("h3",ai,[ni,o(" 1.0.6 | 2022.03.20 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),ri,e("h3",si,[hi,o(" 1.0.55 | 2022.03.18 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),ui,e("h3",_i,[ki,o(" 1.0.5 | 2022.03.18 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),pi,e("h3",gi,[fi,o(" 1.0.4 | 2022.03.06 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),Hi,e("h3",mi,[Pi,o(" 1.0.3 | 2022.03.02 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),bi,e("h3",Ai,[Ci,o(" 1.0.2 | 2022.02.18 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),yi,e("h3",xi,[Yi,o(" 1.0.1 | 2022.02.15 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),vi,e("h3",Ii,[Mi,o(" 1.0 | 2022.02.14 "),d(i,{type:"danger",text:"过期",vertical:"middle"})]),Ri])}const Xi=a(s,[["render",Li],["__file","changelog.html.vue"]]);export{Xi as default}; diff --git a/assets/contacts.html-BSRuPKMe.js b/assets/contacts.html-BSRuPKMe.js new file mode 100644 index 00000000..0af9ffd7 --- /dev/null +++ b/assets/contacts.html-BSRuPKMe.js @@ -0,0 +1 @@ +const t=JSON.parse('{"key":"v-193cf592","path":"/en/about/contacts.html","title":"Contact Us","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"Help with Maintenance","slug":"help-with-maintenance","link":"#help-with-maintenance","children":[]}],"git":{"updatedTime":1754157645000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":6}]},"filePathRelative":"en/about/contacts.md"}');export{t as data}; diff --git a/assets/contacts.html-BfIGgEZ9.js b/assets/contacts.html-BfIGgEZ9.js new file mode 100644 index 00000000..ca9e4f71 --- /dev/null +++ b/assets/contacts.html-BfIGgEZ9.js @@ -0,0 +1 @@ +const t=JSON.parse('{"key":"v-6cf86266","path":"/zh-cn/about/contacts.html","title":"联系我们","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"助力维护","slug":"助力维护","link":"#助力维护","children":[]}],"git":{"updatedTime":1704138350000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":4}]},"filePathRelative":"zh-cn/about/contacts.md"}');export{t as data}; diff --git a/assets/contacts.html-CGQemCaU.js b/assets/contacts.html-CGQemCaU.js new file mode 100644 index 00000000..fdc6418b --- /dev/null +++ b/assets/contacts.html-CGQemCaU.js @@ -0,0 +1 @@ +import{_ as a,r,o as s,c,b as e,d as n,e as t}from"./app-BpUB8-Q8.js";const l={},i=e("h1",{id:"contact-us",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#contact-us","aria-hidden":"true"},"#"),n(" Contact Us")],-1),u=e("blockquote",null,[e("p",null,"If you have any questions during usage, or have any constructive suggestions, you can contact us.")],-1),h=e("p",null,"Join our developers group.",-1),_={href:"https://t.me/YukiHookAPI",target:"_blank",rel:"noopener noreferrer"},d={href:"https://t.me/HighCapable_Dev",target:"_blank",rel:"noopener noreferrer"},p=e("strong",null,"Twitter",-1),f={href:"https://twitter.com/fankesyooni",target:"_blank",rel:"noopener noreferrer"},g=e("h2",{id:"help-with-maintenance",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#help-with-maintenance","aria-hidden":"true"},"#"),n(" Help with Maintenance")],-1),k=e("p",null,[n("Thank you for choosing and using "),e("code",null,"YukiHookAPI"),n(".")],-1),m=e("p",null,"If you have code-related suggestions and requests, you can submit a Pull Request on GitHub.",-1);function b(v,y){const o=r("ExternalLinkIcon");return s(),c("div",null,[i,u,h,e("ul",null,[e("li",null,[e("a",_,[n("Click to join Telegram group"),t(o)])]),e("li",null,[e("a",d,[n("Click to join Telegram group (Developer)"),t(o)])])]),e("p",null,[n("Find me on "),p,n(),e("a",f,[n("@fankesyooni"),t(o)]),n(".")]),g,k,m])}const I=a(l,[["render",b],["__file","contacts.html.vue"]]);export{I as default}; diff --git a/assets/contacts.html-Co35EHVH.js b/assets/contacts.html-Co35EHVH.js new file mode 100644 index 00000000..ddcc330d --- /dev/null +++ b/assets/contacts.html-Co35EHVH.js @@ -0,0 +1 @@ +import{_ as r,r as l,o as a,c as s,b as e,d as t,e as o}from"./app-BpUB8-Q8.js";const c={},_=e("h1",{id:"联系我们",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#联系我们","aria-hidden":"true"},"#"),t(" 联系我们")],-1),i=e("blockquote",null,[e("p",null,"如在使用中有任何问题,或有任何建设性的建议,都可以联系我们。")],-1),h=e("p",null,"加入我们的开发者群组。",-1),d={href:"https://t.me/YukiHookAPI",target:"_blank",rel:"noopener noreferrer"},u={href:"https://t.me/HighCapable_Dev",target:"_blank",rel:"noopener noreferrer"},p={href:"https://qm.qq.com/cgi-bin/qm/qr?k=Pnsc5RY6N2mBKFjOLPiYldbAbprAU3V7&jump_from=webapi&authKey=X5EsOVzLXt1dRunge8ryTxDRrh9/IiW1Pua75eDLh9RE3KXE+bwXIYF5cWri/9lf",target:"_blank",rel:"noopener noreferrer"},f=e("strong",null,"酷安",-1),m={href:"http://www.coolapk.com/u/876977",target:"_blank",rel:"noopener noreferrer"},b=e("h2",{id:"助力维护",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#助力维护","aria-hidden":"true"},"#"),t(" 助力维护")],-1),k=e("p",null,[t("感谢您选择并使用 "),e("code",null,"YukiHookAPI"),t(",如有代码相关的建议和请求,可在 GitHub 提交 Pull Request。")],-1);function g(x,q){const n=l("ExternalLinkIcon");return a(),s("div",null,[_,i,h,e("ul",null,[e("li",null,[e("a",d,[t("点击加入 Telegram 群组"),o(n)])]),e("li",null,[e("a",u,[t("点击加入 Telegram 群组 (开发者)"),o(n)])]),e("li",null,[e("a",p,[t("点击加入 QQ 群 (开发者)"),o(n)])])]),e("p",null,[t("在 "),f,t(" 找到我 "),e("a",m,[t("@星夜不荟"),o(n)]),t("。")]),b,k])}const I=r(c,[["render",g],["__file","contacts.html.vue"]]);export{I as default}; diff --git a/assets/example.html-CnT6OQuI.js b/assets/example.html-CnT6OQuI.js new file mode 100644 index 00000000..67686265 --- /dev/null +++ b/assets/example.html-CnT6OQuI.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-7b22efaf","path":"/en/guide/example.html","title":"Usage Example","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"Structure Diagram","slug":"structure-diagram","link":"#structure-diagram","children":[]},{"level":2,"title":"Demo","slug":"demo","link":"#demo","children":[]},{"level":2,"title":"A Simple Hook Example","slug":"a-simple-hook-example","link":"#a-simple-hook-example","children":[{"level":3,"title":"Hook App","slug":"hook-app","link":"#hook-app","children":[]},{"level":3,"title":"Hook Zygote","slug":"hook-zygote","link":"#hook-zygote","children":[]},{"level":3,"title":"Hook System Framework","slug":"hook-system-framework","link":"#hook-system-framework","children":[]},{"level":3,"title":"Hook Resources","slug":"hook-resources","link":"#hook-resources","children":[]},{"level":3,"title":"Remove Hook","slug":"remove-hook","link":"#remove-hook","children":[]}]},{"level":2,"title":"Exception Handling","slug":"exception-handling","link":"#exception-handling","children":[{"level":3,"title":"Listen for Exceptions","slug":"listen-for-exceptions","link":"#listen-for-exceptions","children":[]},{"level":3,"title":"Throw an Exception","slug":"throw-an-exception","link":"#throw-an-exception","children":[]}]},{"level":2,"title":"Expansion Usage","slug":"expansion-usage","link":"#expansion-usage","children":[{"level":3,"title":"Multiple Hosts","slug":"multiple-hosts","link":"#multiple-hosts","children":[]},{"level":3,"title":"Multiple Processes","slug":"multiple-processes","link":"#multiple-processes","children":[]}]},{"level":2,"title":"Writing Optimization","slug":"writing-optimization","link":"#writing-optimization","children":[]},{"level":2,"title":"Xposed Module Status","slug":"xposed-module-status","link":"#xposed-module-status","children":[{"level":3,"title":"Determine Self-activation Status","slug":"determine-self-activation-status","link":"#determine-self-activation-status","children":[]},{"level":3,"title":"Get Hook Framework Information","slug":"get-hook-framework-information","link":"#get-hook-framework-information","children":[]}]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":15}]},"filePathRelative":"en/guide/example.md"}');export{e as data}; diff --git a/assets/example.html-Cp22GGCP.js b/assets/example.html-Cp22GGCP.js new file mode 100644 index 00000000..d87d7137 --- /dev/null +++ b/assets/example.html-Cp22GGCP.js @@ -0,0 +1,300 @@ +import{_ as l,r as p,o as i,c,b as s,d as n,e,a as o}from"./app-BpUB8-Q8.js";const t={},r=o(`
- 修复一个潜在性的异常未拦截 BUG
- 增加
ignoredError
功能- 增加了
type
中的android
类型- 增加监听
hook
后的ClassNotFound
功能# Usage Example
Here is an introduction to the basic working method of
YukiHookAPI
and a list of simple Hook examples and common functions.# Structure Diagram
The structure below describes the basic working and principle of
YukiHookAPI
.Host Environment +└─ YukiMemberHookCreator + └─ Class + └─ MemberHookCreator + └─ Member + ├─ Before + └─ After + MemberHookCreator + └─ Member + ├─ Before + └─ After + ... + YukiResourcesHookCreator + └─ Resources + └─ ResourcesHookCreator + └─ Drawable + └─ Replace + ResourcesHookCreator + └─ Layout + └─ Inject + ... +
The above structure can be written in the following form in code.
// KavaRef +TargetClass.resolve().firstMethod { + // Your code here. +}.hook { + before { + // Your code here. + } + after { + // Your code here. + } +} +
Click to view the previous writing method
// Old version (1.2.x-1.3.0 (Not included)) +TargetClass.method { + // Your code here. +}.hook { + before { + // Your code here. + } + after { + // Your code here. + } +} +// Old version +TargetClass.hook { + injectMember { + method { + // Your code here. + } + beforeHook { + // Your code here. + } + afterHook { + // Your code here. + } + } +} +
// Resources Hook (2.0.0 will be discontinued) +resources().hook { + injectResource { + conditions { + // Your code here. + } + replaceTo(...) + } +} +
# Demo
`,11),d={href:"https://github.com/HighCapable/YukiHookAPI/tree/master/samples/demo-app",target:"_blank",rel:"noopener noreferrer"},u={href:"https://github.com/HighCapable/YukiHookAPI/tree/master/samples/demo-module",target:"_blank",rel:"noopener noreferrer"},A=s("p",null,"Install the Host App and Module App Demo at the same time, and test the hooked function in the Host App by activating the Module App.",-1),y=s("h2",{id:"a-simple-hook-example",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#a-simple-hook-example","aria-hidden":"true"},"#"),n(" A Simple Hook Example")],-1),m=s("blockquote",null,[s("p",null,"Here are examples of Hook App, Hook System Framework and Hook Resources for reference.")],-1),v={class:"custom-container tip"},D=s("p",{class:"custom-container-title"},"Tips",-1),h=s("code",null,"1.3.0",-1),B={href:"https://github.com/HighCapable/KavaRef",target:"_blank",rel:"noopener noreferrer"},b=s("code",null,"KavaRef",-1),C=s("code",null,"YukiHookAPI",-1),k=o(`You can find the demo provided by the API below to learn how to use
YukiHookAPI
.# Hook App
Suppose, we want to hook the
onCreate
method incom.android.browser
and show a dialog.Add code in the body of the
encase
method.The following example
loadApp(name = "com.android.browser") { + Activity::class.resolve().firstMethod { + name = "onCreate" + parameters(Bundle::class) + }.hook { + after { + AlertDialog.Builder(instance()) + .setTitle("Hooked") + .setMessage("I am hook!") + .setPositiveButton("OK", null) + .show() + } + } +} +
At this point, the
onCreate
method will be successfully hooked and this dialog will show when everyActivity
incom.android.browser
starts.So, what should I do if I want to continue the Hook
onStart
method?We can use Kotlin's
apply
method onActivity::class.resolve()
to create a call space.The following example
loadApp(name = "com.android.browser") { + Activity::class.resolve().apply { + firstMethod { + name = "onCreate" + parameters(Bundle::class) + }.hook { + after { + AlertDialog.Builder(instance()) + .setTitle("Hooked") + .setMessage("I am hook!") + .setPositiveButton("OK", null) + .show() + } + } + firstMethod { + name = "onStart" + emptyParameters() + }.hook { + after { + // Your code here. + } + } + } +} +
For the
Class
that does not exist in the current project, you can use thestub
method or theString.toClass(...)
method to get the class that needs to be hooked.For example, I want to get
com.example.demo.TestClass
.The following example
"com.example.demo.TestClass".toClass() + .resolve() + .firstMethod { + // Your code here. + }.hook { + // Your code here. + } +
If
com.example.demo
is the app you want to hook, then the writing method can be simpler.The following example
"$packageName.TestClass".toClass() + .resolve() + .firstMethod { + // Your code here. + }.hook { + // Your code here. + } +
If this
Class
is not immediately available, you can uselazyClass(...)
to define it.The following example
Define
TestClass
.val TestClass by lazyClass("com.example.demo.TestClass") +
Use it when appropriate.
TestClass.resolve().firstMethod { + // Your code here. +}.hook { + // Your code here. +} +
Tips
For more functions, please refer to MemberHookCreator.
# Hook Zygote
The first event
initZygote
after the new process is forked when the app starts.Suppose we want to globally Hook the
onCreate
event of an appActivity
Add code in the body of the
encase
method.The following example
loadZygote { + Activity::class.resolve().firstMethod { + name = "onCreate" + parameters(Bundle::class) + }.hook { + after { + // Your code here. + } + } +} +
Notice
The functionality performed in loadZygote is very limited, and the loadZygote method is rarely needed.
# Hook System Framework
In
YukiHookAPI
, the implementation of the Hook System Framework is very simple.Suppose, you want to get
ApplicationInfo
andPackageInfo
and do something with them.Add code in the body of the
encase
method.The following example
loadSystem { + ApplicationInfo::class.resolve().firstMethod { + // Your code here. + }.hook { + // Your code here. + } + PackageInfo::class.resolve().firstMethod { + // Your code here. + }.hook { + // Your code here. + } +} +
Pay Attention
loadZygote is directly different from loadSystem, loadZygote will be loaded in initZygote, and the System Framework is regarded as loadApp(name = "android") and exists, To Hook the System Framework, you can use loadSystem directly.
# Hook Resources
Notice
This feature will be discontinued and removed in version 2.0.0.
Suppose, we want to replace the content of
app_name
of typestring
in Hookcom.android.browser
with123
.Add code in the body of the
encase
method.The following example
loadApp(name = "com.android.browser") { + resources().hook { + injectResource { + conditions { + name = "app_name" + string() + } + replaceTo("123") + } + } +} +
If the current app has a title bar text set with
app_name
, it will become our123
.You can also replace the Hook App's Resources with the current Xposed Module's Resources.
Suppose, we want to continue to hook
ic_launcher
of typemipmap
incom.android.browser
.The following example
loadApp(name = "com.android.browser") { + resources().hook { + injectResource { + conditions { + name = "ic_launcher" + mipmap() + } + replaceToModuleResource(R.mipmap.ic_launcher) + } + } +} +
At this point, the icon of the target app will be replaced with the icon we set.
If you want to replace the Resources of the System Framework, you can do the same, just replace
loadApp
withloadZygote
.The following example
loadZygote { + resources().hook { + // Your code here. + } +} +
Tips
For more functions, please refer to ResourcesHookCreator.
# Remove Hook
The native Xposed provides us with a
XC_MethodHook.Unhook
function, which can remove the current Hook from the Hook queue, andYukiHookAPI
can also implement this function.The first way, save the
Result
instance of the current injected object, and callremove
at the appropriate time and place to remove the injected object.The following example
// Set a variable to save the current instance +val hookResult = + resolve().firstMethod { + name = "test" + returnType = Void.TYPE + }.hook { + after { + // ... + } + } +// Call the following method when appropriate +hookResult.remove() +
The second method, call
removeSelf
in the Hook callback method to remove itself.The following example
resolve().firstMethod { + name = "test" + returnType = Void.TYPE +}.hook { + after { + // Just call the following method directly + removeSelf() + } +} +
Tips
For more functions, please refer to MemberHookCreator.
# Exception Handling
YukiHookAPI
has redesigned the monitoring of exceptions, any exception will not be thrown during the hook process, to avoid interrupting the next hook process and causing the hook process to "die".# Listen for Exceptions
You can handle exceptions that occur during the Hook method.
The following example
hook { + // Your code here. +}.result { + // Handle the exception at the start of the hook + onHookingFailure {} + // Handle exceptions in the hook process + onConductFailure { param, throwable -> } + // Handle all exceptions + onAllFailure {} + // ... +} +
This method also works in the Resources Hook.
The following example
injectResource { + // Your code here. +}.result { + // Handle arbitrary exceptions when hooking + onHookingFailure {} + // ... +} +
(Applicable to older versions) You can also handle exceptions that occur when the Hook's
Class
does not exist.The following example
TargetClass.hook { + injectMember { + // Your code here. + } +}.onHookClassNotFoundFailure { + // Your code here. +} +
(Applicable to older versions) You can also handle exceptions when looking up methods.
The following example
method { + // Your code here. +}.onNoSuchMethod { + // Your code here. +} +
Tips
For more functions, please refer to MemberHookCreator.Result, ResourcesHookCreator.Result.
Common exceptions that may occur are described here. For more information, please refer to API Exception Handling.
`,80),g={class:"custom-container warning"},F=s("p",{class:"custom-container-title"},"Notice",-1),f=s("code",null,"KavaRef",-1),x={href:"https://highcapable.github.io/KavaRef/en/library/kavaref-core#exception-handling",target:"_blank",rel:"noopener noreferrer"},w=s("code",null,"KavaRef",-1),q=o(`# Throw an Exception
In some cases, you can manually throw exceptions to alert some functionality that there is a problem.
As mentioned above, the exception thrown in the
hook
method body will be taken over by theYukiHookAPI
to avoid interrupting the next Hook process and causing the Hook process to "die".Here's how these exceptions work when
YukiHookAPI
takes over.The following example
// <Scenario 1> +injectMember { + method { + throw RuntimeException("Exception Test") + } + afterHook { + // ... + } +}.result { + // Can catch RuntimeException + onHookingFailure {} +} +// <Scenario 2> +injectMember { + method { + // ... + } + afterHook { + throw RuntimeException("Exception Test") + } +}.result { + // Can catch RuntimeException + onConductFailure { param, throwable -> } +} +
The above scenarios will only be processed in the (Xposed) Host App environment and will not have any impact on the host itself.
If we want to throw these exceptions directly to the Host App, the native Xposed provides us with the
param.throwable
method, andYukiHookAPI
can also implement this function.If you want to throw an exception directly to the Host App in the Hook callback method body, you can implement the following methods.
The following example
method { + // ... +}.hook { + after { + RuntimeException("Exception Test").throwToApp() + } +} +
You can also throw exceptions directly in the Hook callback method body, and then mark the exception to be thrown to the Host App.
The following example
method { + // ... +}.hook { + after { + throw RuntimeException("Exception Test") + }.onFailureThrowToApp() +} +
The above two methods can receive an exception at the Host App and cause the Host App process to crash.
Notice
In order to ensure that the Hook calling domain and the calling domain within the Host App are isolated from each other, exceptions can only be thrown to the Host App in the before and after callback method bodies.
Tips
For more functions, please refer to Throwable.throwToApp, YukiMemberHookCreator.MemberMookCreator.HookCallback.
# Expansion Usage
You can use the following methods to easily implement various judgments and functions in the Hook process.
# Multiple Hosts
If your Module App needs to handle Hook events of multiple apps at the same time, you can use the
loadApp
method body to distinguish the app you want to hook.The following example
loadApp(name = "com.android.browser") { + // Your code here. +} +loadApp(name = "com.android.phone") { + // Your code here. +} +
Tips
For more functions, please refer to PackageParam.loadApp.
# Multiple Processes
If your Hook's Host App has multiple processes, you can use the
withProcess
method body to hook them separately.The following example
withProcess(mainProcessName) { + // Your code here. +} +withProcess(name = "$packageName:tool") { + // Your code here. +} +
Tips
For more functions, please refer to PackageParam.withProcess.
# Writing Optimization
To make the code more concise, you can omit the name of
YukiHookAPI
and write youronHook
entry as lambda.The following example
override fun onHook() = encase { + // Your code here. +} +
You can also abbreviate the
hook { ... }
method body when you only need a Hook callback event.The following example
Activity::class.resolve().firstMethod { + // Your code here. +}.hook().after { + // Your code here. +} +
# Xposed Module Status
Usually, the developer of the Xposed Module will choose to read the activation information of the current Xposed Module to better show the user the effective status of the current function.
In addition to the basic Hook functions,
YukiHookAPI
also designed a set of Xposed Module status judgment functions for developers, such as activation status and Hook Framework information.# Determine Self-activation Status
Usually, we will choose to write a method to make it return
false
, and then hook this method to make it returntrue
to prove that the Hook has taken effect.In
YukiHookAPI
, you don’t need to do this at all,YukiHookAPI
has already encapsulated this operation for you, and you can use it directly.Now, you can directly use
YukiHookAPI.Status.isXposedModuleActive
to determine whether it is activated in the Module App.The following example
if(YukiHookAPI.Status.isXposedModuleActive) { + // Your code here. +} +
Due to some special reasons, the Xposed Modules in TaiChi and Wuji cannot use the standard method to detect the activation state.
At this point you can use
YukiHookAPI.Status.isTaiChiModuleActive
to determine whether it is activated.The following example
if(YukiHookAPI.Status.isTaiChiModuleActive) { + // Your code here. +} +
If you want to use both judgment schemes,
YukiHookAPI
also encapsulates a convenient way for you.At this point, you can use
YukiHookAPI.Status.isModuleActive
to determine whether you are activated in Xposed or TaiChi and Wuji.The following example
if(YukiHookAPI.Status.isModuleActive) { + // Your code here. +} +
Tips
For more functions, please refer to YukiHookAPI.Status.
Notice
If your Module App's API version is higher than 29 and is running on a system whose target API is 29 or higher, you need to add the following permission statement in AndroidManifest.xml to judge the activation status of the module in TaiChi and Wuji.
The following example
<queries> + <intent> + <action android:name="android.intent.action.MAIN" /> + </intent> +</queries> +
There is another solution, you can directly declare the android.permission.QUERY_ALL_PACKAGES permission, but it is not recommended and will be warned by code inspection.
The following example
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" /> +
If the activation status of TaiChi and Wuji is included in the Module App activation judgment, the Application of the Module App must be extends from ModuleApplication or directly use ModuleApplication.
# Get Hook Framework Information
In addition to judging your own activation status, you can also get information about the current Hook Framework through the
Executor
inYukiHookAPI.Status
.For example, we can use
YukiHookAPI.Status.Executor.name
to get the name of the current Hook Framework.The following example
val frameworkName = YukiHookAPI.Status.Executor.name +
We can also use
YukiHookAPI.Status.Executor.apiLevel
to get the API Level of the current Hook Framework.The following example
val frameworkApiLevel = YukiHookAPI.Status.Executor.apiLevel +
Tips
For more functions, please refer to YukiHookAPI.Status.Executor.
`,65);function H(Y,T){const a=p("ExternalLinkIcon");return i(),c("div",null,[r,s("ul",null,[s("li",null,[s("p",null,[n("Host App Demo "),s("a",d,[n("click here to view"),e(a)])])]),s("li",null,[s("p",null,[n("Module App Demo "),s("a",u,[n("click here to view"),e(a)])])])]),A,y,m,s("div",v,[D,s("p",null,[n("Starting with version "),h,n(", YukiHookAPI has moved its own reflection API partially to "),s("a",B,[n("KavaRef"),e(a)]),n(", the reflection APIs in the demonstration section below use the "),b,n(" writing method. We no longer recommend using the "),C,n("'s own reflection API.")])]),k,s("div",g,[F,s("p",null,[n("The exception of "),f,n(" will be managed separately by itself. For detailed configuration plans, you can refer to "),s("a",x,[n("here"),e(a)]),n(", which will jump to the "),w,n(" document.")])]),q])}const P=l(t,[["render",H],["__file","example.html.vue"]]);export{P as default}; diff --git a/assets/example.html-DBLcpd3T.js b/assets/example.html-DBLcpd3T.js new file mode 100644 index 00000000..c3725de6 --- /dev/null +++ b/assets/example.html-DBLcpd3T.js @@ -0,0 +1 @@ +const l=JSON.parse('{"key":"v-13b430a0","path":"/zh-cn/guide/example.html","title":"用法示例","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"结构图解","slug":"结构图解","link":"#结构图解","children":[]},{"level":2,"title":"Demo","slug":"demo","link":"#demo","children":[]},{"level":2,"title":"一个简单的 Hook 例子","slug":"一个简单的-hook-例子","link":"#一个简单的-hook-例子","children":[{"level":3,"title":"Hook APP","slug":"hook-app","link":"#hook-app","children":[]},{"level":3,"title":"Hook Zygote","slug":"hook-zygote","link":"#hook-zygote","children":[]},{"level":3,"title":"Hook 系统框架","slug":"hook-系统框架","link":"#hook-系统框架","children":[]},{"level":3,"title":"Hook Resources","slug":"hook-resources","link":"#hook-resources","children":[]},{"level":3,"title":"解除 Hook","slug":"解除-hook","link":"#解除-hook","children":[]}]},{"level":2,"title":"异常处理","slug":"异常处理","link":"#异常处理","children":[{"level":3,"title":"监听异常","slug":"监听异常","link":"#监听异常","children":[]},{"level":3,"title":"抛出异常","slug":"抛出异常","link":"#抛出异常","children":[]}]},{"level":2,"title":"扩展用法","slug":"扩展用法","link":"#扩展用法","children":[{"level":3,"title":"多个宿主","slug":"多个宿主","link":"#多个宿主","children":[]},{"level":3,"title":"多个进程","slug":"多个进程","link":"#多个进程","children":[]}]},{"level":2,"title":"写法优化","slug":"写法优化","link":"#写法优化","children":[]},{"level":2,"title":"Xposed 模块状态","slug":"xposed-模块状态","link":"#xposed-模块状态","children":[{"level":3,"title":"判断自身激活状态","slug":"判断自身激活状态","link":"#判断自身激活状态","children":[]},{"level":3,"title":"获取 Hook Framework 信息","slug":"获取-hook-framework-信息","link":"#获取-hook-framework-信息","children":[]}]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":15}]},"filePathRelative":"zh-cn/guide/example.md"}');export{l as data}; diff --git a/assets/example.html-l_t2vpgR.js b/assets/example.html-l_t2vpgR.js new file mode 100644 index 00000000..596c41eb --- /dev/null +++ b/assets/example.html-l_t2vpgR.js @@ -0,0 +1,300 @@ +import{_ as o,r as p,o as c,c as i,b as s,d as n,e as l,a as e}from"./app-BpUB8-Q8.js";const r={},t=e(`Notice
YukiHookAPI after 1.0.91 version modifies the logical judgment method of obtaining the status of the Xposed Module, and now you can use this API in the Module App and Host App at the same time;
Need to make sure InjectYukiHookWithXposed.isUsingXposedModuleStatus is enabled;
YukiHookAPI only connects to the known acquisition methods.
Except for the Hook Framework that provides standard APIs, in other cases, the Xposed Module may not be able to determine whether it is activated or obtain information about the Hook Framework.
# 用法示例
这里介绍了
YukiHookAPI
的基本工作方式以及列举了简单的 Hook 例子和常用功能。# 结构图解
下方的结构描述了
YukiHookAPI
的基本工作方式和原理。Host Environment +└─ YukiMemberHookCreator + └─ Class + └─ MemberHookCreator + └─ Member + ├─ Before + └─ After + MemberHookCreator + └─ Member + ├─ Before + └─ After + ... + YukiResourcesHookCreator + └─ Resources + └─ ResourcesHookCreator + └─ Drawable + └─ Replace + ResourcesHookCreator + └─ Layout + └─ Inject + ... +
上方的结构换做代码将可写为如下形式。
// KavaRef 写法 +TargetClass.resolve().firstMethod { + // Your code here. +}.hook { + before { + // Your code here. + } + after { + // Your code here. + } +} +
点击查看以往写法
// 旧版 (1.2.x-1.3.0 (不含)) 写法 +TargetClass.method { + // Your code here. +}.hook { + before { + // Your code here. + } + after { + // Your code here. + } +} +// 旧版写法 +TargetClass.hook { + injectMember { + method { + // Your code here. + } + beforeHook { + // Your code here. + } + afterHook { + // Your code here. + } + } +} +
// Resources Hook (2.0.0 将停止支持) +resources().hook { + injectResource { + conditions { + // Your code here. + } + replaceTo(...) + } +} +
# Demo
`,11),d={href:"https://github.com/HighCapable/YukiHookAPI/tree/master/samples/demo-app",target:"_blank",rel:"noopener noreferrer"},A={href:"https://github.com/HighCapable/YukiHookAPI/tree/master/samples/demo-module",target:"_blank",rel:"noopener noreferrer"},u=s("p",null,"同时安装宿主和模块 Demo,通过激活模块来测试宿主中被 Hook 的功能。",-1),y=s("h2",{id:"一个简单的-hook-例子",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#一个简单的-hook-例子","aria-hidden":"true"},"#"),n(" 一个简单的 Hook 例子")],-1),D=s("blockquote",null,[s("p",null,"这里给出了 Hook APP、Hook 系统框架与 Hook Resources 等例子,可供参考。")],-1),B={class:"custom-container tip"},v=s("p",{class:"custom-container-title"},"小提示",-1),C=s("code",null,"1.3.0",-1),m=s("code",null,"YukiHookAPI",-1),b={href:"https://github.com/HighCapable/KavaRef",target:"_blank",rel:"noopener noreferrer"},k=s("code",null,"KavaRef",-1),h=s("code",null,"YukiHookAPI",-1),F=e(`你可以在下方找到 API 提供的 Demo 来学习
YukiHookAPI
的使用方法。# Hook APP
假设,我们要 Hook
com.android.browser
中的onCreate
方法并弹出一个对话框。在
encase
方法体中添加代码。示例如下
loadApp(name = "com.android.browser") { + Activity::class.resolve().firstMethod { + name = "onCreate" + parameters(Bundle::class) + }.hook { + after { + AlertDialog.Builder(instance()) + .setTitle("Hooked") + .setMessage("I am hook!") + .setPositiveButton("OK", null) + .show() + } + } +} +
至此,
onCreate
方法将被成功 Hook 并在com.android.browser
中的每个Activity
启动时弹出此对话框。那么,我想继续 Hook
onStart
方法要怎么做呢?我们可以对
Activity::class.resolve()
使用 Kotlin 的apply
方法创建一个调用空间。示例如下
loadApp(name = "com.android.browser") { + Activity::class.resolve().apply { + firstMethod { + name = "onCreate" + parameters(Bundle::class) + }.hook { + after { + AlertDialog.Builder(instance()) + .setTitle("Hooked") + .setMessage("I am hook!") + .setPositiveButton("OK", null) + .show() + } + } + firstMethod { + name = "onStart" + emptyParameters() + }.hook { + after { + // Your code here. + } + } + } +} +
对于当前项目下没有的
Class
,你可以使用stub
方式或String.toClass(...)
方法来得到需要 Hook 的类。比如,我要得到
com.example.demo.TestClass
。示例如下
"com.example.demo.TestClass".toClass() + .resolve() + .firstMethod { + // Your code here. + }.hook { + // Your code here. + } +
若
com.example.demo
是你要 Hook 的 APP,那么写法可以更简单。示例如下
"$packageName.TestClass".toClass() + .resolve() + .firstMethod { + // Your code here. + }.hook { + // Your code here. + } +
若这个
Class
不是马上就能被得到的,你可以使用lazyClass(...)
来定义它。示例如下
定义
TestClass
。val TestClass by lazyClass("com.example.demo.TestClass") +
在适当的时候使用它。
TestClass.resolve().firstMethod { + // Your code here. +}.hook { + // Your code here. +} +
小提示
更多功能请参考 MemberHookCreator。
# Hook Zygote
在 APP 启动时,新的进程被 fork 后的第一个事件
initZygote
。假设我们要全局 Hook 一个 APP
Activity
的onCreate
事件在
encase
方法体中添加代码。示例如下
loadZygote { + Activity::class.resolve().firstMethod { + name = "onCreate" + parameters(Bundle::class) + }.hook { + after { + // Your code here. + } + } +} +
注意
在 loadZygote 中进行的功能十分有限,几乎很少的情况下需要用到 loadZygote 方法。
# Hook 系统框架
在
YukiHookAPI
中,Hook 系统框架的实现非常简单。假设,你要得到
ApplicationInfo
与PackageInfo
并对它们进行一些操作。在
encase
方法体中添加代码。示例如下
loadSystem { + ApplicationInfo::class.resolve().firstMethod { + // Your code here. + }.hook { + // Your code here. + } + PackageInfo::class.resolve().firstMethod { + // Your code here. + }.hook { + // Your code here. + } +} +
特别注意
loadZygote 与 loadSystem 有直接性区别,loadZygote 会在 initZygote 中装载,系统框架被视为 loadApp(name = "android") 而存在,若要 Hook 系统框架,可直接使用 loadSystem。
# Hook Resources
注意
此功能将在 2.0.0 版本停止支持并移除。
假设,我们要 Hook
com.android.browser
中string
类型的app_name
内容替换为123
。在
encase
方法体中添加代码。示例如下
loadApp(name = "com.android.browser") { + resources().hook { + injectResource { + conditions { + name = "app_name" + string() + } + replaceTo("123") + } + } +} +
若当前 APP 使用
app_name
设置了标题栏文本,则它就会变成我们的123
。你还可以使用当前 Xposed 模块的 Resources 替换 Hook APP 的 Resources。
假设,我们要继续 Hook
com.android.browser
中mipmap
类型的ic_launcher
。示例如下
loadApp(name = "com.android.browser") { + resources().hook { + injectResource { + conditions { + name = "ic_launcher" + mipmap() + } + replaceToModuleResource(R.mipmap.ic_launcher) + } + } +} +
至此目标 APP 的图标将会被替换为我们设置的图标。
若你想替换系统框架的资源,同样也可以这样实现,只需要把
loadApp
换成loadZygote
即可。示例如下
loadZygote { + resources().hook { + // Your code here. + } +} +
小提示
更多功能请参考 ResourcesHookCreator。
# 解除 Hook
原生的 Xposed 为我们提供了一个
XC_MethodHook.Unhook
功能,可以从 Hook 队列中将当前 Hook 移除,YukiHookAPI
同样可以实现此功能。第一种方法,保存当前注入对象的
Result
实例,在适当的时候和地方调用remove
即可解除该注入对象。示例如下
// 设置一个变量保存当前实例 +val hookResult = + resolve().firstMethod { + name = "test" + returnType = Void.TYPE + }.hook { + after { + // ... + } + } +// 在适当的时候调用如下方法即可 +hookResult.remove() +
第二种方法,在 Hook 回调方法中调用
removeSelf
移除自身。示例如下
resolve().firstMethod { + name = "test" + returnType = Void.TYPE +}.hook { + after { + // 直接调用如下方法即可 + removeSelf() + } +} +
小提示
更多功能请参考 MemberHookCreator。
# 异常处理
YukiHookAPI
重新设计了对异常的监听,任何异常都不会在 Hook 过程中抛出,避免打断下一个 Hook 流程导致 Hook 进程“死掉”。# 监听异常
你可以处理 Hook 方法过程发生的异常。
示例如下
hook { + // Your code here. +}.result { + // 处理 Hook 开始时的异常 + onHookingFailure {} + // 处理 Hook 过程中的异常 + onConductFailure { param, throwable -> } + // 处理全部异常 + onAllFailure {} + // ... +} +
在 Resources Hook 时此方法同样适用。
示例如下
injectResource { + // Your code here. +}.result { + // 处理 Hook 时的任意异常 + onHookingFailure {} + // ... +} +
(旧版本适用) 你还可以处理 Hook 的
Class
不存在时发生的异常。示例如下
TargetClass.hook { + injectMember { + // Your code here. + } +}.onHookClassNotFoundFailure { + // Your code here. +} +
(旧版本适用) 你还可以处理查找方法时的异常。
示例如下
method { + // Your code here. +}.onNoSuchMethod { + // Your code here. +} +
小提示
更多功能请参考 MemberHookCreator.Result、ResourcesHookCreator.Result。
这里介绍了可能发生的常见异常,若要了解更多请参考 API 异常处理。
`,80),g={class:"custom-container warning"},q=s("p",{class:"custom-container-title"},"注意",-1),x=s("code",null,"KavaRef",-1),H={href:"https://highcapable.github.io/KavaRef/zh-cn/library/kavaref-core#%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86",target:"_blank",rel:"noopener noreferrer"},f=s("code",null,"KavaRef",-1),P=e(`# 抛出异常
在某些情况下,你可以手动抛出异常来达到提醒某些功能存在问题的目的。
上面已经介绍过,在
hook
方法体内抛出的异常会被YukiHookAPI
接管,避免打断下一个 Hook 流程导致 Hook 进程“死掉”。以下是
YukiHookAPI
接管时这些异常的运作方式。示例如下
// <情景1> +injectMember { + method { + throw RuntimeException("Exception Test") + } + afterHook { + // ... + } +}.result { + // 能够捕获到 RuntimeException + onHookingFailure {} +} +// <情景2> +injectMember { + method { + // ... + } + afterHook { + throw RuntimeException("Exception Test") + } +}.result { + // 能够捕获到 RuntimeException + onConductFailure { param, throwable -> } +} +
以上情景只会在 (Xposed) 宿主环境被处理,不会对宿主自身造成任何影响。
若我们想将这些异常直接抛给宿主,原生的 Xposed 为我们提供了
param.throwable
方法,YukiHookAPI
同样可以实现此功能。若想在 Hook 回调方法体中将一个异常直接抛给宿主,可以有如下实现方法。
示例如下
method { + // ... +}.hook { + after { + RuntimeException("Exception Test").throwToApp() + } +} +
你也可以直接在 Hook 回调方法体中抛出异常,然后标识将异常抛给宿主。
示例如下
method { + // ... +}.hook { + after { + throw RuntimeException("Exception Test") + }.onFailureThrowToApp() +} +
以上两种方法均可在宿主接收到异常从而使宿主进程崩溃。
注意
为了保证 Hook 调用域与宿主内调用域相互隔离,异常只有在 before 与 after 回调方法体中才能抛给宿主。
# 扩展用法
你可以在 Hook 过程中使用下面的方法方便地实现各种判断和功能。
# 多个宿主
如果你的模块需要同时处理多个 APP 的 Hook 事件,你可以使用
loadApp
方法体来区分你要 Hook 的 APP。示例如下
loadApp(name = "com.android.browser") { + // Your code here. +} +loadApp(name = "com.android.phone") { + // Your code here. +} +
小提示
更多功能请参考 PackageParam.loadApp。
# 多个进程
如果你 Hook 的宿主 APP 有多个进程,你可以使用
withProcess
方法体来对它们分别进行 Hook。示例如下
withProcess(mainProcessName) { + // Your code here. +} +withProcess(name = "$packageName:tool") { + // Your code here. +} +
小提示
更多功能请参考 PackageParam.withProcess。
# 写法优化
为了使代码更加简洁,你可以删去
YukiHookAPI
的名称,将你的onHook
入口写作 lambda 形式。示例如下
override fun onHook() = encase { + // Your code here. +} +
你还可以在仅需要一个 Hook 回调事件的时候简写
hook { ... }
方法体。示例如下
Activity::class.resolve().firstMethod { + // Your code here. +}.hook().after { + // Your code here. +} +
# Xposed 模块状态
通常情况下,Xposed 模块的开发者都会去选择读取当前 Xposed 模块的激活信息以更好地向用户展示当前功能的生效状态。
除了基本的 Hook 功能,
YukiHookAPI
还为开发者设计了一套 Xposed 模块状态判断的功能,如激活状态、Hook Framework 信息。# 判断自身激活状态
通常情况下,我们会选择写一个方法,使其返回
false
,然后 Hook 掉这个方法使其返回true
来证明 Hook 已经生效。在
YukiHookAPI
中你完全不需要再这么做了,YukiHookAPI
已经帮你封装好了这个操作,你可以直接进行使用。现在,你可以直接使用
YukiHookAPI.Status.isXposedModuleActive
在模块中判断自身是否被激活。示例如下
if(YukiHookAPI.Status.isXposedModuleActive) { + // Your code here. +} +
由于一些特殊原因,在太极、无极中的模块无法使用标准方法检测激活状态。
此时你可以使用
YukiHookAPI.Status.isTaiChiModuleActive
判断自身是否被激活。示例如下
if(YukiHookAPI.Status.isTaiChiModuleActive) { + // Your code here. +} +
若你想使用两者得兼的判断方案,
YukiHookAPI
同样为你封装了便捷的方式。此时你可以使用
YukiHookAPI.Status.isModuleActive
判断自身是否在 Xposed 或太极、无极中被激活。示例如下
if(YukiHookAPI.Status.isModuleActive) { + // Your code here. +} +
小提示
更多功能请参考 YukiHookAPI.Status。
注意
如果你的模块 API 版本高于 29 且正在目标 API 为 29 以上的系统中运行,你需要在 AndroidManifest.xml 中添加如下权限声明才能正常判断模块在太极、无极中的激活状态。
示例如下
<queries> + <intent> + <action android:name="android.intent.action.MAIN" /> + </intent> +</queries> +
还有一种方案,你可以直接声明 android.permission.QUERY_ALL_PACKAGES 权限,但是不推荐且会被代码检查警告。
示例如下
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" /> +
若模块激活判断中包含太极、无极中的激活状态,就必须将模块的 Application 继承于 ModuleApplication 或直接使用 ModuleApplication。
# 获取 Hook Framework 信息
除了判断自身激活状态之外,你还可以通过
YukiHookAPI.Status
中的Executor
来获取当前 Hook Framework 的相关信息。例如我们可以使用
YukiHookAPI.Status.Executor.name
来获取当前 Hook Framework 的名称。示例如下
val frameworkName = YukiHookAPI.Status.Executor.name +
我们还可以使用
YukiHookAPI.Status.Executor.apiLevel
来获取当前 Hook Framework 的 API Level。示例如下
val frameworkApiLevel = YukiHookAPI.Status.Executor.apiLevel +
小提示
更多功能请参考 YukiHookAPI.Status.Executor。
`,65);function Y(_,I){const a=p("ExternalLinkIcon");return c(),i("div",null,[t,s("ul",null,[s("li",null,[s("p",null,[n("宿主 APP Demo "),s("a",d,[n("点击这里查看"),l(a)])])]),s("li",null,[s("p",null,[n("模块 APP Demo "),s("a",A,[n("点击这里查看"),l(a)])])])]),u,y,D,s("div",B,[v,s("p",null,[n("从 "),C,n(" 版本开始,"),m,n(" 已将自身的反射 API 部分迁移至 "),s("a",b,[n("KavaRef"),l(a)]),n(",下方演示部分的反射 API 均使用了 "),k,n(" 的写法,我们不再推荐使用 "),h,n(" 自身的反射 API。")])]),F,s("div",g,[q,s("p",null,[x,n(" 的异常将由其自身单独管理,详细的配置方案你可以参考 "),s("a",H,[n("这里"),l(a)]),n(",这将跳转到 "),f,n(" 的文档。")])]),P])}const w=o(r,[["render",Y],["__file","example.html.vue"]]);export{w as default}; diff --git a/assets/future.html-BJR2WZUb.js b/assets/future.html-BJR2WZUb.js new file mode 100644 index 00000000..c940935a --- /dev/null +++ b/assets/future.html-BJR2WZUb.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-3106ca14","path":"/zh-cn/about/future.html","title":"展望未来","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"未解决的问题","slug":"未解决的问题","link":"#未解决的问题","children":[{"level":3,"title":"YukiHookPrefsBridge","slug":"yukihookprefsbridge","link":"#yukihookprefsbridge","children":[]}]},{"level":2,"title":"未来的计划","slug":"未来的计划","link":"#未来的计划","children":[{"level":3,"title":"支持独立使用的 Lite 版本","slug":"支持独立使用的-lite-版本","link":"#支持独立使用的-lite-版本","children":[]},{"level":3,"title":"里程碑计划","slug":"里程碑计划","link":"#里程碑计划","children":[]}]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":8}]},"filePathRelative":"zh-cn/about/future.md"}');export{e as data}; diff --git a/assets/future.html-BS9bLph2.js b/assets/future.html-BS9bLph2.js new file mode 100644 index 00000000..b786fd84 --- /dev/null +++ b/assets/future.html-BS9bLph2.js @@ -0,0 +1 @@ +import{_ as n,r as s,o as i,c,b as e,d as o,e as r,a}from"./app-BpUB8-Q8.js";const d={},l=a('注意
1.0.91 版本后的 YukiHookAPI 修改了获取 Xposed 模块状态的逻辑判断方式,现在你可以在模块与 Hook APP (宿主) 中同时使用此 API;
需要确保 InjectYukiHookWithXposed.isUsingXposedModuleStatus 是启用状态;
YukiHookAPI 仅对已知的获取方式进行了对接,除了提供标准 API 的 Hook Framework 之外,其它情况下模块可能都将无法判断自己是否被激活或是获取 Hook Framework 的相关信息。
# 展望未来
未来是美好的,也是不确定的,让我们共同期待
YukiHookAPI
在未来的发展空间。# 未解决的问题
这里收录了
YukiHookAPI
尚未解决的问题。# YukiHookPrefsBridge
目前仅限完美支持 LSPosed,其它 Xposed 框架需要降级模块 API。
可能完全不支持太极,太极在高版本系统上需要更低的 API 才能适配。
部分 Xposed 模块开发者目前选择 Hook 目标 APP 内置 Sp 存储方案解决模块设置共享问题。
后期 Android 系统的权限将越来越严格,
',9),h={class:"custom-container tip"},p=e("p",{class:"custom-container-title"},"2023.10.06 更新",-1),u={href:"https://github.com/libxposed",target:"_blank",rel:"noopener noreferrer"},_=e("p",null,[o("为了保证大部分模块的兼容性,后期 "),e("strong",null,"YukiHookAPI"),o(" 计划使用自定义的 ContentProvider 实现模块与宿主的数据互通,敬请期待。")],-1),k=a('selinux
就是目前面临的一个大问题,有待讨论和研究。# 未来的计划
这里收录了
YukiHookAPI
可能会在后期添加的功能。# 支持独立使用的 Lite 版本
如果你喜欢
YukiHookAPI
的反射 API,但你的项目可能并不需要相关 Hook 功能。那么这里有一个好消息要告诉你:
',5),f=e("code",null,"YukiHookAPI",-1),b={href:"https://github.com/HighCapable/YukiReflection",target:"_blank",rel:"noopener noreferrer"},g=e("code",null,"YukiReflection",-1),P={href:"https://github.com/HighCapable/KavaRef",target:"_blank",rel:"noopener noreferrer"},A=a('待讨论
目前 API 只支持通过自动处理程序绑定到 xposed_init,若您不喜欢自动处理程序,一定要自己实现模块装载入口,未来会按照需求人数推出仅有 API 功能的 Lite 版本,你可向我们提出 issues。
API 已经提供了 Xposed 原生 API 监听接口,你可以 在这里 找到或查看 Demo 的实现方法。
# 里程碑计划
下方这些计划已在 GitHub 的
issues
中发布,你可以查看每个项目的进度。所有功能预计在
',5),H={href:"https://github.com/HighCapable/YukiHookAPI/issues/49",target:"_blank",rel:"noopener noreferrer"},m={href:"https://github.com/HighCapable/YukiHookAPI/issues/48",target:"_blank",rel:"noopener noreferrer"},I={href:"https://github.com/HighCapable/YukiHookAPI/issues/33",target:"_blank",rel:"noopener noreferrer"},x={href:"https://github.com/HighCapable/KavaRef",target:"_blank",rel:"noopener noreferrer"};function Y(v,C){const t=s("ExternalLinkIcon");return i(),c("div",null,[l,e("div",h,[p,e("p",null,[o("LSPosed 现已实验性推出了 "),e("a",u,[o("Modern Xposed API"),r(t)]),o(",它采用 Service 的方式与模块通信,这将能够解决模块数据存储的问题。")]),_]),k,e("p",null,[e("s",null,[f,o(" 的核心反射 API 已被解耦合为 "),e("a",b,[o("YukiReflection"),r(t)]),o(" 项目,它现在能在任何 Android 项目中使用。")])]),e("p",null,[g,o(" 项目由于很多未能解决的黑盒问题已被弃用,我们不再推荐任何人使用它,现在请迁移到全新设计的 "),e("a",P,[o("KavaRef"),r(t)]),o("。")]),A,e("ul",null,[e("li",null,[e("a",H,[o("New Xposed Module Config Plan"),r(t)])]),e("li",null,[e("a",m,[o("New Hook Entry Class"),r(t)])]),e("li",null,[e("s",null,[e("a",I,[o("New Hook Code Style"),r(t)])]),o(" (已由 "),e("a",x,[o("KavaRef"),r(t)]),o(" 取代)")])])])}const E=n(d,[["render",Y],["__file","future.html.vue"]]);export{E as default}; diff --git a/assets/future.html-L0gip76T.js b/assets/future.html-L0gip76T.js new file mode 100644 index 00000000..1858c207 --- /dev/null +++ b/assets/future.html-L0gip76T.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-ae7b83f2","path":"/en/about/future.html","title":"Looking Toward the Future","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"Unresolved Issues","slug":"unresolved-issues","link":"#unresolved-issues","children":[{"level":3,"title":"YukiHookPrefsBridge","slug":"yukihookprefsbridge","link":"#yukihookprefsbridge","children":[]}]},{"level":2,"title":"Future Plans","slug":"future-plans","link":"#future-plans","children":[{"level":3,"title":"Lite Version Supported for Standalone Use","slug":"lite-version-supported-for-standalone-use","link":"#lite-version-supported-for-standalone-use","children":[]},{"level":3,"title":"Milestone Plan","slug":"milestone-plan","link":"#milestone-plan","children":[]}]}],"git":{"updatedTime":1754155535000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":12}]},"filePathRelative":"en/about/future.md"}');export{e as data}; diff --git a/assets/future.html-aS7aVBMr.js b/assets/future.html-aS7aVBMr.js new file mode 100644 index 00000000..722015ef --- /dev/null +++ b/assets/future.html-aS7aVBMr.js @@ -0,0 +1 @@ +import{_ as s,r as a,o as i,c as d,b as e,d as o,e as n,a as r}from"./app-BpUB8-Q8.js";const l={},u=r('2.0.0
版本完成,敬请期待。# Looking Toward the Future
The future is bright and uncertain, let us look forward to the future development space of
YukiHookAPI
.# Unresolved Issues
Here are the unresolved issues with
YukiHookAPI
.# YukiHookPrefsBridge
Currently only supports LSPosed perfectly, other Xposed Framework need to downgrade the module target api.
TaiChi may not be supported at all, and TaiChi needs a lower target api to adapt on high-version systems.
Some Xposed Module developers currently choose the Hook target app self's SharedPreferences storage solution to solve the module settings sharing problem.
In the later period, the permissions of the Android system will become more and more strict, and
',9),h={class:"custom-container tip"},c=e("p",{class:"custom-container-title"},"Updated on 2023.10.06",-1),p={href:"https://github.com/libxposed",target:"_blank",rel:"noopener noreferrer"},f=e("p",null,[o("In order to ensure the compatibility of most modules, "),e("strong",null,"YukiHookAPI"),o(" plans to use a customized ContentProvider to realize data exchange between the Module App and the Host App in the future, so stay tuned.")],-1),b=r('selinux
is a big problem currently facing, which needs to be discussed and studied.# Future Plans
Features that
YukiHookAPI
may add later are included here.# Lite Version Supported for Standalone Use
If you like the Reflection API of
YukiHookAPI
, but your project may not need related Hook functions.Well here is some good news for you:
',5),m=e("code",null,"YukiHookAPI",-1),g={href:"https://github.com/HighCapable/YukiReflection",target:"_blank",rel:"noopener noreferrer"},k=e("code",null,"YukiReflection",-1),_={href:"https://github.com/HighCapable/KavaRef",target:"_blank",rel:"noopener noreferrer"},v=r('To be Discussed
At present, the API only supports binding to xposed_init through the automatic builder.
If you don't like the automatic builder, you must implement the module loading entry yourself.
In the future, the Lite version with only API functions will be launched according to the number of people required.
You can submit issues with us.
We have provided the Xposed native API listening interface, you can find or view the implementation method of the Demo here.
# Milestone Plan
The plans below have been published in
issues
on GitHub, and you can view the progress of each project.All functions are expected to be completed in
',5),y={href:"https://github.com/HighCapable/YukiHookAPI/issues/49",target:"_blank",rel:"noopener noreferrer"},w={href:"https://github.com/HighCapable/YukiHookAPI/issues/48",target:"_blank",rel:"noopener noreferrer"},P={href:"https://github.com/HighCapable/YukiHookAPI/issues/33",target:"_blank",rel:"noopener noreferrer"},H={href:"https://github.com/HighCapable/KavaRef",target:"_blank",rel:"noopener noreferrer"};function I(x,A){const t=a("ExternalLinkIcon");return i(),d("div",null,[u,e("div",h,[c,e("p",null,[o("LSPosed has now experimentally launched "),e("a",p,[o("Modern Xposed API"),n(t)]),o(", which uses Service to communicate with modules, which will solve the problem of module data storage.")]),f]),b,e("p",null,[e("s",null,[o("The core Reflection API of "),m,o(" has been decoupled into "),e("a",g,[o("YukiReflection"),n(t)]),o(" project, which can now be used in any Android project.")])]),e("p",null,[o("The "),k,o(" project has been deprecated due to many unsolved black box issues, so we no longer recommend anyone to use it. Please now migrate to the brand new design "),e("a",_,[o("KavaRef"),n(t)]),o(".")]),v,e("ul",null,[e("li",null,[e("a",y,[o("New Xposed Module Config Plan"),n(t)])]),e("li",null,[e("a",w,[o("New Hook Entry Class"),n(t)])]),e("li",null,[e("s",null,[e("a",P,[o("New Hook Code Style"),n(t)])]),o(" (Replaced by "),e("a",H,[o("KavaRef"),n(t)]),o(")")])])])}const Y=s(l,[["render",I],["__file","future.html.vue"]]);export{Y as default}; diff --git a/assets/home.html-BWNdBIZw.js b/assets/home.html-BWNdBIZw.js new file mode 100644 index 00000000..7c350c66 --- /dev/null +++ b/assets/home.html-BWNdBIZw.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-64fc7bb8","path":"/en/api/home.html","title":"Document Introduce","lang":"en-US","frontmatter":{"next":{"text":"Public API","link":"/en/api/public/com/highcapable/yukihookapi/YukiHookAPI"}},"headers":[{"level":2,"title":"Function Description","slug":"function-description","link":"#function-description","children":[]},{"level":2,"title":"Function Example Description","slug":"function-example-description","link":"#function-example-description","children":[]},{"level":2,"title":"Change Record Description","slug":"change-record-description","link":"#change-record-description","children":[]},{"level":2,"title":"Related Symbols Description","slug":"related-symbols-description","link":"#related-symbols-description","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":2}]},"filePathRelative":"en/api/home.md"}');export{e as data}; diff --git a/assets/home.html-Bhz1Th03.js b/assets/home.html-Bhz1Th03.js new file mode 100644 index 00000000..0d23b976 --- /dev/null +++ b/assets/home.html-Bhz1Th03.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-efb45d4c","path":"/en/guide/home.html","title":"Introduction","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"Background","slug":"background","link":"#background","children":[]},{"level":2,"title":"Usage","slug":"usage","link":"#usage","children":[]},{"level":2,"title":"Language Requirement","slug":"language-requirement","link":"#language-requirement","children":[]},{"level":2,"title":"Source of Inspiration","slug":"source-of-inspiration","link":"#source-of-inspiration","children":[]}],"git":{"updatedTime":1754155535000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":12}]},"filePathRelative":"en/guide/home.md"}');export{e as data}; diff --git a/assets/home.html-CSP-y2Sx.js b/assets/home.html-CSP-y2Sx.js new file mode 100644 index 00000000..7f80addd --- /dev/null +++ b/assets/home.html-CSP-y2Sx.js @@ -0,0 +1 @@ +import{_ as e,o,c as t,a as i}from"./app-BpUB8-Q8.js";const n={},c=i('2.0.0
version, so stay tuned.# Document Introduce
The document here will synchronize the relevant usage of the latest API version, please keep
YukiHookAPI
as the latest version to use the latest version of the function.Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
. If you encounter unsolvable problems, you can contact us via Contact Us.# Function Description
The function description mainly introduces the related usage and purpose of the current API.
# Function Example Description
The function examples mainly show the basic usage examples of the current API for reference.
# Change Record Description
The function of the first version will be marked as
v<version>
first
;New function added later will be marked as
v<version>
added
;Later modified function will be appended as
v<version>
modified
;Later deprecated function will be marked as
v<version>
deprecated
and strikethrough;Later removed function will be marked as
v<version>
removed
and strikethrough.# Related Symbols Description
',15),a=[c];function d(r,l){return o(),t("div",null,a)}const p=e(n,[["render",d],["__file","home.html.vue"]]);export{p as default}; diff --git a/assets/home.html-Cg57uIpM.js b/assets/home.html-Cg57uIpM.js new file mode 100644 index 00000000..20c1c7d5 --- /dev/null +++ b/assets/home.html-Cg57uIpM.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-6a609e09","path":"/zh-cn/guide/home.html","title":"介绍","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"背景","slug":"背景","link":"#背景","children":[]},{"level":2,"title":"用途","slug":"用途","link":"#用途","children":[]},{"level":2,"title":"语言要求","slug":"语言要求","link":"#语言要求","children":[]},{"level":2,"title":"灵感来源","slug":"灵感来源","link":"#灵感来源","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":12}]},"filePathRelative":"zh-cn/guide/home.md"}');export{e as data}; diff --git a/assets/home.html-DAJQxBy-.js b/assets/home.html-DAJQxBy-.js new file mode 100644 index 00000000..c100a3ef --- /dev/null +++ b/assets/home.html-DAJQxBy-.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-c8deafb2","path":"/zh-cn/api/home.html","title":"文档介绍","lang":"zh-CN","frontmatter":{"next":{"text":"Public API","link":"/zh-cn/api/public/com/highcapable/yukihookapi/YukiHookAPI"}},"headers":[{"level":2,"title":"功能描述说明","slug":"功能描述说明","link":"#功能描述说明","children":[]},{"level":2,"title":"功能示例说明","slug":"功能示例说明","link":"#功能示例说明","children":[]},{"level":2,"title":"变更记录说明","slug":"变更记录说明","link":"#变更记录说明","children":[]},{"level":2,"title":"相关符号说明","slug":"相关符号说明","link":"#相关符号说明","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":2}]},"filePathRelative":"zh-cn/api/home.md"}');export{e as data}; diff --git a/assets/home.html-DVG1oAZg.js b/assets/home.html-DVG1oAZg.js new file mode 100644 index 00000000..0cf44b8b --- /dev/null +++ b/assets/home.html-DVG1oAZg.js @@ -0,0 +1,71 @@ +import{_ as t,r as n,o as p,c as i,b as s,d as l,e,w as a,a as A}from"./app-BpUB8-Q8.js";const d={},y=s("h1",{id:"介绍",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#介绍","aria-hidden":"true"},"#"),l(" 介绍")],-1),D=s("blockquote",null,[s("p",null,[s("code",null,"YukiHookAPI"),l(" 是一个集成化的 Hook API 框架,本身不提供任何 Hook 功能,需要 Xposed 相关基础 API 的支持。")])],-1),B=s("h2",{id:"背景",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#背景","aria-hidden":"true"},"#"),l(" 背景")],-1),C=s("p",null,"这是一个使用 Kotlin 基于 Xposed API 重新构建的高效 Hook API,同时为 Xposed 模块的开发打造了丰富的功能扩展。",-1),u={href:"https://www.bilibili.com/bangumi/play/ss5016",target:"_blank",rel:"noopener noreferrer"},m={href:"https://github.com/fankes/TMore",target:"_blank",rel:"noopener noreferrer"},b=A('
kt Kotlin Static File
annotation Annotation Class
interface Interface Class
object Class (Singleton)
class Class
field Field or
get
/set
method or read-onlyget
methodmethod Method
enum Enum constant
ext-field Extension field (global)
ext-method Extension method (global)
i-ext-field Extension field (internal)
i-ext-method Extension method (internal)
# 用途
YukiHookAPI
完全采用 Kotlin lambda 语法构建。抛弃原始不太友好的
XposedHelpers
,你可以使用它来轻松创建 Xposed 模块以及轻松实现自定义 Hook API。# 语言要求
请使用 Kotlin,框架部分代码构成同样兼容 Java 但基础 Hook 场景的实现可能完全无法使用。
文档全部的 Demo 示例代码都将使用 Kotlin 进行描述,如果你完全不会使用 Kotlin 那你将有可能无法使用
YukiHookAPI
。# 灵感来源
以前,我们在构建 Xposed 模块的时候,首先需要在
assets
下创建xposed_init
文件。然后,将自己的入口类名手动填入文件中,使用
XposedHelpers
去实现我们的 Hook 逻辑。自 Kotlin 作为 Android 主要开发语言以来,这套 API 用起来确实已经不是很优雅了。
有没有什么 好用、轻量、优雅 的解决办法呢?
本着这样的想法,
YukiHookAPI
诞生了。现在,我们只需要编写少量的代码,一切时间开销和花费交给自动化处理。
借助 Kotlin 优雅的 lambda 写法以及
YukiHookAPI
,可以让你的 Hook 逻辑更加美观清晰。',15),v=s("div",{class:"language-kotlin line-numbers-mode","data-ext":"kt"},[s("pre",{class:"shiki github-dark-dimmed",style:{"background-color":"#22272e"},tabindex:"0"},[s("code",null,[s("span",{class:"line"},[s("span",{style:{color:"#F69D50"}},"@InjectYukiHookWithXposed")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#F47067"}},"object"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F69D50"}},"HookEntry"),s("span",{style:{color:"#ADBAC7"}}," : "),s("span",{style:{color:"#F69D50"}},"IYukiHookXposedInit"),s("span",{style:{color:"#ADBAC7"}}," {")]),l(` +`),s("span",{class:"line"}),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"onHook"),s("span",{style:{color:"#ADBAC7"}},"() "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"encase"),s("span",{style:{color:"#ADBAC7"}}," {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"loadZygote"),s("span",{style:{color:"#ADBAC7"}}," {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," Activity::"),s("span",{style:{color:"#DCBDFB"}},"class"),s("span",{style:{color:"#ADBAC7"}},"."),s("span",{style:{color:"#DCBDFB"}},"resolve"),s("span",{style:{color:"#ADBAC7"}},"()."),s("span",{style:{color:"#DCBDFB"}},"firstMethod"),s("span",{style:{color:"#ADBAC7"}}," {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," name "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#96D0FF"}},'"onCreate"')]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"parameters"),s("span",{style:{color:"#ADBAC7"}},"(Bundle::"),s("span",{style:{color:"#DCBDFB"}},"class"),s("span",{style:{color:"#ADBAC7"}},")")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }."),s("span",{style:{color:"#DCBDFB"}},"hook"),s("span",{style:{color:"#ADBAC7"}}," {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"before"),s("span",{style:{color:"#ADBAC7"}}," {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Your code here.")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"after"),s("span",{style:{color:"#ADBAC7"}}," {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Your code here.")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"loadApp"),s("span",{style:{color:"#ADBAC7"}},"(name "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#96D0FF"}},'"com.android.browser"'),s("span",{style:{color:"#ADBAC7"}},") {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," Activity::"),s("span",{style:{color:"#DCBDFB"}},"class"),s("span",{style:{color:"#ADBAC7"}},"."),s("span",{style:{color:"#DCBDFB"}},"resolve"),s("span",{style:{color:"#ADBAC7"}},"()."),s("span",{style:{color:"#DCBDFB"}},"firstMethod"),s("span",{style:{color:"#ADBAC7"}}," {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," name "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#96D0FF"}},'"onCreate"')]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"parameters"),s("span",{style:{color:"#ADBAC7"}},"(Bundle::"),s("span",{style:{color:"#DCBDFB"}},"class"),s("span",{style:{color:"#ADBAC7"}},")")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }."),s("span",{style:{color:"#DCBDFB"}},"hook"),s("span",{style:{color:"#ADBAC7"}}," {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"before"),s("span",{style:{color:"#ADBAC7"}}," {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Your code here.")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"after"),s("span",{style:{color:"#ADBAC7"}}," {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Your code here.")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}},"}")]),l(` +`),s("span",{class:"line"})])]),s("div",{class:"line-numbers","aria-hidden":"true"},[s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"})])],-1),h=s("div",{class:"language-kotlin line-numbers-mode","data-ext":"kt"},[s("pre",{class:"shiki github-dark-dimmed",style:{"background-color":"#22272e"},tabindex:"0"},[s("code",null,[s("span",{class:"line"},[s("span",{style:{color:"#F47067"}},"class"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F69D50"}},"HookEntry"),s("span",{style:{color:"#ADBAC7"}}," : "),s("span",{style:{color:"#F69D50"}},"IXposedHookZygoteInit"),s("span",{style:{color:"#ADBAC7"}},", "),s("span",{style:{color:"#DCBDFB"}},"IXposedHookLoadPackage"),s("span",{style:{color:"#ADBAC7"}}," {")]),l(` +`),s("span",{class:"line"}),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"private"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"lateinit"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"var"),s("span",{style:{color:"#ADBAC7"}}," moduleResources: "),s("span",{style:{color:"#F69D50"}},"XModuleResources")]),l(` +`),s("span",{class:"line"}),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"initZygote"),s("span",{style:{color:"#ADBAC7"}},"(sparam: "),s("span",{style:{color:"#F69D50"}},"IXposedHookZygoteInit"),s("span",{style:{color:"#ADBAC7"}},".StartupParam) {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," moduleResources "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," XModuleResources."),s("span",{style:{color:"#DCBDFB"}},"createInstance"),s("span",{style:{color:"#ADBAC7"}},"(sparam.modulePath, "),s("span",{style:{color:"#6CB6FF"}},"null"),s("span",{style:{color:"#ADBAC7"}},")")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," XposedHelpers."),s("span",{style:{color:"#DCBDFB"}},"findAndHookMethod"),s("span",{style:{color:"#ADBAC7"}},"(")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," Activity::"),s("span",{style:{color:"#DCBDFB"}},"class"),s("span",{style:{color:"#ADBAC7"}},".java.name,")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#6CB6FF"}},"null"),s("span",{style:{color:"#ADBAC7"}},", "),s("span",{style:{color:"#96D0FF"}},'"onCreate"'),s("span",{style:{color:"#ADBAC7"}},",")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," Bundle::"),s("span",{style:{color:"#DCBDFB"}},"class"),s("span",{style:{color:"#ADBAC7"}},".java,")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," object : "),s("span",{style:{color:"#F69D50"}},"XC_MethodHook"),s("span",{style:{color:"#ADBAC7"}},"() {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"beforeHookedMethod"),s("span",{style:{color:"#ADBAC7"}},"(param: "),s("span",{style:{color:"#F69D50"}},"MethodHookParam"),s("span",{style:{color:"#ADBAC7"}},"?) {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Your code here.")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),l(` +`),s("span",{class:"line"}),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"afterHookedMethod"),s("span",{style:{color:"#ADBAC7"}},"(param: "),s("span",{style:{color:"#F69D50"}},"MethodHookParam"),s("span",{style:{color:"#ADBAC7"}},"?) {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Your code here.")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," })")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),l(` +`),s("span",{class:"line"}),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"handleLoadPackage"),s("span",{style:{color:"#ADBAC7"}},"(lpparam: "),s("span",{style:{color:"#F69D50"}},"XC_LoadPackage"),s("span",{style:{color:"#ADBAC7"}},".LoadPackageParam) {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"if"),s("span",{style:{color:"#ADBAC7"}}," (lpparam.packageName "),s("span",{style:{color:"#F47067"}},"=="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#96D0FF"}},'"com.android.browser"'),s("span",{style:{color:"#ADBAC7"}},")")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," XposedHelpers."),s("span",{style:{color:"#DCBDFB"}},"findAndHookMethod"),s("span",{style:{color:"#ADBAC7"}},"(")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," Activity::"),s("span",{style:{color:"#DCBDFB"}},"class"),s("span",{style:{color:"#ADBAC7"}},".java.name,")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," lpparam.classLoader, "),s("span",{style:{color:"#96D0FF"}},'"onCreate"'),s("span",{style:{color:"#ADBAC7"}},",")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," Bundle::"),s("span",{style:{color:"#DCBDFB"}},"class"),s("span",{style:{color:"#ADBAC7"}},".java,")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," object : "),s("span",{style:{color:"#F69D50"}},"XC_MethodHook"),s("span",{style:{color:"#ADBAC7"}},"() {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"beforeHookedMethod"),s("span",{style:{color:"#ADBAC7"}},"(param: "),s("span",{style:{color:"#F69D50"}},"MethodHookParam"),s("span",{style:{color:"#ADBAC7"}},"?) {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Your code here.")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),l(` +`),s("span",{class:"line"}),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"afterHookedMethod"),s("span",{style:{color:"#ADBAC7"}},"(param: "),s("span",{style:{color:"#F69D50"}},"MethodHookParam"),s("span",{style:{color:"#ADBAC7"}},"?) {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Your code here.")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," })")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}},"}")]),l(` +`),s("span",{class:"line"})])]),s("div",{class:"line-numbers","aria-hidden":"true"},[s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"})])],-1),F=s("p",null,"是的,你没有看错,仅仅就需要这些代码,就能完全取代传统的 Xposed API 实现同样的功能。",-1),k=s("p",null,[l("现在,借助高效强大的 "),s("code",null,"YukiHookAPI"),l(",你就可以实现一个非常简单的 Xposed 模块。")],-1),_={class:"custom-container tip"},f=s("p",{class:"custom-container-title"},"小提示",-1),H=s("code",null,"1.3.0",-1),I=s("code",null,"YukiHookAPI",-1),g={href:"https://github.com/HighCapable/KavaRef",target:"_blank",rel:"noopener noreferrer"},P=s("p",null,[l("现在,你可以借助 "),s("code",null,"KavaRef"),l(" 的强大反射能力让 "),s("code",null,"YukiHookAPI"),l(" 更加易用。")],-1);function X(Y,x){const o=n("ExternalLinkIcon"),c=n("CodeGroupItem"),r=n("CodeGroup");return p(),i("div",null,[y,D,B,C,s("p",null,[l("名称取自 "),s("a",u,[l("《ももくり》女主 栗原 雪(Yuki)"),e(o)]),l("。")]),s("p",null,[l("前身为 "),s("a",m,[l("开发学习项目"),e(o)]),l(" 中使用的 Innocent Xposed API,现在重新命名并开源。")]),b,e(r,null,{default:a(()=>[e(c,{title:"Yuki Hook API"},{default:a(()=>[v]),_:1}),e(c,{title:"Rovo89 Xposed API"},{default:a(()=>[h]),_:1})]),_:1}),F,k,s("div",_,[f,s("p",null,[l("从 "),H,l(" 版本开始,"),I,l(" 已将自身的反射 API 部分迁移至 "),s("a",g,[l("KavaRef"),e(o)]),l(" (包括上方演示的反射 API 部分)。")]),P])])}const K=t(d,[["render",X],["__file","home.html.vue"]]);export{K as default}; diff --git a/assets/home.html-DwzlpDun.js b/assets/home.html-DwzlpDun.js new file mode 100644 index 00000000..4d15d71c --- /dev/null +++ b/assets/home.html-DwzlpDun.js @@ -0,0 +1 @@ +import{_ as e,o,c,a as i}from"./app-BpUB8-Q8.js";const d={},t=i('示例如下
# 文档介绍
这里的文档将同步最新 API 版本的相关用法,请保持
YukiHookAPI
为最新版本以使用最新版本的功能。注意
由于维护成本,
YukiHookAPI
从1.3.0
版本开始将不再会对此文档进行更新且在2.0.0
版本切换为 Dokka 插件自动生成的 API 文档,如遇到无法解决的问题,你可以通过 联系我们 与我们联系。# 功能描述说明
功能描述主要介绍当前 API 的相关用法和用途。
# 功能示例说明
功能示例主要展示了当前 API 的基本用法示例,可供参考。
# 变更记录说明
首个版本的功能将标记为
v<version>
添加
;后期新增加的功能将标记为
v<version>
新增
;后期修改的功能将被追加为
v<version>
修改
;后期被作废的功能将标记为
v<version>
作废
并会标注删除线;后期被删除的功能将标记为
v<version>
移除
并会标注删除线。# 相关符号说明
',15),a=[t];function l(p,n){return o(),c("div",null,a)}const h=e(d,[["render",l],["__file","home.html.vue"]]);export{h as default}; diff --git a/assets/home.html-Hj1hpUN3.js b/assets/home.html-Hj1hpUN3.js new file mode 100644 index 00000000..61dd32c7 --- /dev/null +++ b/assets/home.html-Hj1hpUN3.js @@ -0,0 +1,71 @@ +import{_ as t,r as n,o as i,c as p,b as s,d as e,e as l,w as a,a as d}from"./app-BpUB8-Q8.js";const A={},y=s("h1",{id:"introduction",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#introduction","aria-hidden":"true"},"#"),e(" Introduction")],-1),u=s("blockquote",null,[s("p",null,[s("code",null,"YukiHookAPI"),e(" is an integrated Hook API Framework, which does not provide any Hook functions, and needs the support of Xposed related basic APIs.")])],-1),D=s("h2",{id:"background",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#background","aria-hidden":"true"},"#"),e(" Background")],-1),B=s("p",null,"This is an efficient Hook API rebuilt based on the Xposed API using Kotlin, and creates rich function extensions for the development of Xposed Modules.",-1),C={href:"https://www.bilibili.com/bangumi/play/ss5016",target:"_blank",rel:"noopener noreferrer"},m={href:"https://github.com/fankes/TMore",target:"_blank",rel:"noopener noreferrer"},h=d('
kt Kotlin Static File
annotation 注解
interface 接口
object 类 (单例)
class 类
field 变量或
get
、set
方法或只读的get
方法method 方法
enum Enum 常量
ext-field 扩展的变量 (全局)
ext-method 扩展的方法 (全局)
i-ext-field 扩展的变量 (调用域限制)
i-ext-method 扩展的方法 (调用域限制)
# Usage
YukiHookAPI
is built entirely with Kotlin lambda syntax.Abandoning the original less friendly
XposedHelpers
, you can use it to easily create Xposed Modules and easily implement custom Hook API.# Language Requirement
Please use Kotlin, the framework part of the code composition is also compatible with Java but the implementation of the basic Hook scene may not work at all.
All demo code in this document will be described using Kotlin, if you don't know how to use Kotlin then you may not be able to use
YukiHookAPI
.# Source of Inspiration
Previously, when we built an Xposed Module, we first needed to create an
xposed_init
file underassets
.Then, manually fill in your own entry class name into the file and use
XposedHelpers
to implement our Hook logic.Since Kotlin is the main Android development language, this API is really not very elegant to use.
Is there any easy to use, light, elegant solution?
With this idea,
YukiHookAPI
was born.Now, we only need to write a small amount of code, and all the time and expense are handed over to automation.
With Kotlin's elegant lambda writing and
YukiHookAPI
, you can make your Hook logic more beautiful and clear.',15),b=s("div",{class:"language-kotlin line-numbers-mode","data-ext":"kt"},[s("pre",{class:"shiki github-dark-dimmed",style:{"background-color":"#22272e"},tabindex:"0"},[s("code",null,[s("span",{class:"line"},[s("span",{style:{color:"#F69D50"}},"@InjectYukiHookWithXposed")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#F47067"}},"object"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F69D50"}},"HookEntry"),s("span",{style:{color:"#ADBAC7"}}," : "),s("span",{style:{color:"#F69D50"}},"IYukiHookXposedInit"),s("span",{style:{color:"#ADBAC7"}}," {")]),e(` +`),s("span",{class:"line"}),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"onHook"),s("span",{style:{color:"#ADBAC7"}},"() "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"encase"),s("span",{style:{color:"#ADBAC7"}}," {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"loadZygote"),s("span",{style:{color:"#ADBAC7"}}," {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," Activity::"),s("span",{style:{color:"#DCBDFB"}},"class"),s("span",{style:{color:"#ADBAC7"}},"."),s("span",{style:{color:"#DCBDFB"}},"resolve"),s("span",{style:{color:"#ADBAC7"}},"()."),s("span",{style:{color:"#DCBDFB"}},"firstMethod"),s("span",{style:{color:"#ADBAC7"}}," {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," name "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#96D0FF"}},'"onCreate"')]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"parameters"),s("span",{style:{color:"#ADBAC7"}},"(Bundle::"),s("span",{style:{color:"#DCBDFB"}},"class"),s("span",{style:{color:"#ADBAC7"}},")")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }."),s("span",{style:{color:"#DCBDFB"}},"hook"),s("span",{style:{color:"#ADBAC7"}}," {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"before"),s("span",{style:{color:"#ADBAC7"}}," {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Your code here.")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"after"),s("span",{style:{color:"#ADBAC7"}}," {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Your code here.")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"loadApp"),s("span",{style:{color:"#ADBAC7"}},"(name "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#96D0FF"}},'"com.android.browser"'),s("span",{style:{color:"#ADBAC7"}},") {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," Activity::"),s("span",{style:{color:"#DCBDFB"}},"class"),s("span",{style:{color:"#ADBAC7"}},"."),s("span",{style:{color:"#DCBDFB"}},"resolve"),s("span",{style:{color:"#ADBAC7"}},"()."),s("span",{style:{color:"#DCBDFB"}},"firstMethod"),s("span",{style:{color:"#ADBAC7"}}," {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," name "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#96D0FF"}},'"onCreate"')]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"parameters"),s("span",{style:{color:"#ADBAC7"}},"(Bundle::"),s("span",{style:{color:"#DCBDFB"}},"class"),s("span",{style:{color:"#ADBAC7"}},")")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }."),s("span",{style:{color:"#DCBDFB"}},"hook"),s("span",{style:{color:"#ADBAC7"}}," {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"before"),s("span",{style:{color:"#ADBAC7"}}," {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Your code here.")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"after"),s("span",{style:{color:"#ADBAC7"}}," {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Your code here.")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}},"}")]),e(` +`),s("span",{class:"line"})])]),s("div",{class:"line-numbers","aria-hidden":"true"},[s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"})])],-1),v=s("div",{class:"language-kotlin line-numbers-mode","data-ext":"kt"},[s("pre",{class:"shiki github-dark-dimmed",style:{"background-color":"#22272e"},tabindex:"0"},[s("code",null,[s("span",{class:"line"},[s("span",{style:{color:"#F47067"}},"class"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F69D50"}},"HookEntry"),s("span",{style:{color:"#ADBAC7"}}," : "),s("span",{style:{color:"#F69D50"}},"IXposedHookZygoteInit"),s("span",{style:{color:"#ADBAC7"}},", "),s("span",{style:{color:"#DCBDFB"}},"IXposedHookLoadPackage"),s("span",{style:{color:"#ADBAC7"}}," {")]),e(` +`),s("span",{class:"line"}),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"private"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"lateinit"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"var"),s("span",{style:{color:"#ADBAC7"}}," moduleResources: "),s("span",{style:{color:"#F69D50"}},"XModuleResources")]),e(` +`),s("span",{class:"line"}),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"initZygote"),s("span",{style:{color:"#ADBAC7"}},"(sparam: "),s("span",{style:{color:"#F69D50"}},"IXposedHookZygoteInit"),s("span",{style:{color:"#ADBAC7"}},".StartupParam) {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," moduleResources "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," XModuleResources."),s("span",{style:{color:"#DCBDFB"}},"createInstance"),s("span",{style:{color:"#ADBAC7"}},"(sparam.modulePath, "),s("span",{style:{color:"#6CB6FF"}},"null"),s("span",{style:{color:"#ADBAC7"}},")")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," XposedHelpers."),s("span",{style:{color:"#DCBDFB"}},"findAndHookMethod"),s("span",{style:{color:"#ADBAC7"}},"(")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," Activity::"),s("span",{style:{color:"#DCBDFB"}},"class"),s("span",{style:{color:"#ADBAC7"}},".java.name,")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#6CB6FF"}},"null"),s("span",{style:{color:"#ADBAC7"}},", "),s("span",{style:{color:"#96D0FF"}},'"onCreate"'),s("span",{style:{color:"#ADBAC7"}},",")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," Bundle::"),s("span",{style:{color:"#DCBDFB"}},"class"),s("span",{style:{color:"#ADBAC7"}},".java,")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," object : "),s("span",{style:{color:"#F69D50"}},"XC_MethodHook"),s("span",{style:{color:"#ADBAC7"}},"() {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"beforeHookedMethod"),s("span",{style:{color:"#ADBAC7"}},"(param: "),s("span",{style:{color:"#F69D50"}},"MethodHookParam"),s("span",{style:{color:"#ADBAC7"}},"?) {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Your code here.")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),e(` +`),s("span",{class:"line"}),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"afterHookedMethod"),s("span",{style:{color:"#ADBAC7"}},"(param: "),s("span",{style:{color:"#F69D50"}},"MethodHookParam"),s("span",{style:{color:"#ADBAC7"}},"?) {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Your code here.")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," })")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),e(` +`),s("span",{class:"line"}),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"handleLoadPackage"),s("span",{style:{color:"#ADBAC7"}},"(lpparam: "),s("span",{style:{color:"#F69D50"}},"XC_LoadPackage"),s("span",{style:{color:"#ADBAC7"}},".LoadPackageParam) {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"if"),s("span",{style:{color:"#ADBAC7"}}," (lpparam.packageName "),s("span",{style:{color:"#F47067"}},"=="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#96D0FF"}},'"com.android.browser"'),s("span",{style:{color:"#ADBAC7"}},")")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," XposedHelpers."),s("span",{style:{color:"#DCBDFB"}},"findAndHookMethod"),s("span",{style:{color:"#ADBAC7"}},"(")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," Activity::"),s("span",{style:{color:"#DCBDFB"}},"class"),s("span",{style:{color:"#ADBAC7"}},".java.name,")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," lpparam.classLoader, "),s("span",{style:{color:"#96D0FF"}},'"onCreate"'),s("span",{style:{color:"#ADBAC7"}},",")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," Bundle::"),s("span",{style:{color:"#DCBDFB"}},"class"),s("span",{style:{color:"#ADBAC7"}},".java,")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," object : "),s("span",{style:{color:"#F69D50"}},"XC_MethodHook"),s("span",{style:{color:"#ADBAC7"}},"() {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"beforeHookedMethod"),s("span",{style:{color:"#ADBAC7"}},"(param: "),s("span",{style:{color:"#F69D50"}},"MethodHookParam"),s("span",{style:{color:"#ADBAC7"}},"?) {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Your code here.")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),e(` +`),s("span",{class:"line"}),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"afterHookedMethod"),s("span",{style:{color:"#ADBAC7"}},"(param: "),s("span",{style:{color:"#F69D50"}},"MethodHookParam"),s("span",{style:{color:"#ADBAC7"}},"?) {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Your code here.")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," })")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}},"}")]),e(` +`),s("span",{class:"line"})])]),s("div",{class:"line-numbers","aria-hidden":"true"},[s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"})])],-1),F=s("p",null,"Yes, you read that right, just needing these codes can completely replace the traditional Xposed API to achieve the same function.",-1),k=s("p",null,[e("Now, with the help of the efficient and powerful "),s("code",null,"YukiHookAPI"),e(", you can implement a very simple Xposed Module.")],-1),f={class:"custom-container tip"},g=s("p",{class:"custom-container-title"},"Tips",-1),_=s("code",null,"1.3.0",-1),H=s("code",null,"YukiHookAPI",-1),I={href:"https://github.com/HighCapable/KavaRef",target:"_blank",rel:"noopener noreferrer"},w=s("p",null,[e("Now, you can make the "),s("code",null,"YukiHookAPI"),e(" more easy to use with the powerful reflection ability of "),s("code",null,"KavaRef"),e(".")],-1);function P(X,x){const o=n("ExternalLinkIcon"),r=n("CodeGroupItem"),c=n("CodeGroup");return i(),p("div",null,[y,u,D,B,s("p",null,[e("The name is taken from "),s("a",C,[e('"ももくり" heroine Yuki Kurihara'),l(o)]),e(".")]),s("p",null,[e("Formerly the Innocent Xposed API used in "),s("a",m,[e("Development Learning Project"),l(o)]),e(", now renamed and open sourced.")]),h,l(c,null,{default:a(()=>[l(r,{title:"Yuki Hook API"},{default:a(()=>[b]),_:1}),l(r,{title:"Rovo89 Xposed API"},{default:a(()=>[v]),_:1})]),_:1}),F,k,s("div",f,[g,s("p",null,[e("Starting with version "),_,e(", "),H,e(" has migrated its own reflection API part to "),s("a",I,[e("KavaRef"),l(o)]),e(" (including the reflection API part demonstrated above).")]),w])])}const Y=t(A,[["render",P],["__file","home.html.vue"]]);export{Y as default}; diff --git a/assets/host-inject.html-BNOoOrx_.js b/assets/host-inject.html-BNOoOrx_.js new file mode 100644 index 00000000..7d21ef05 --- /dev/null +++ b/assets/host-inject.html-BNOoOrx_.js @@ -0,0 +1,150 @@ +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(`The following example
# 宿主资源注入扩展
这是一个将模块资源、
Activity
组件以及Context
主题注入到宿主的扩展功能。在使用以下功能之前,为防止资源 ID 互相冲突,你需要在当前 Xposed 模块项目的
build.gradle
中修改资源 ID。Kotlin DSL
android { + androidResources.additionalParameters += listOf("--allow-reserved-package-id", "--package-id", "0x64") +} +
Groovy DSL
android { + androidResources.additionalParameters += ['--allow-reserved-package-id', '--package-id', '0x64'] +} +
注意
过往版本中的 aaptOptions.additionalParameters 已被作废,请参考上述写法并保持你的 Android Gradle Plugin 为最新版本。
提供的示例资源 ID 值仅供参考,不可使用 0x7f,默认为 0x64,为了防止当前宿主存在多个 Xposed 模块,建议自定义你自己的资源 ID。
# 注入模块资源 (Resources)
在 Hook 宿主之后,我们可以直接在 Hooker 中得到的
Context
注入当前模块资源。示例如下
resolve().firstMethod { + name = "onCreate" + parameters(Bundle::class) +}.hook { + after { + instance<Activity>().also { + // <方案1> 通过 Context 注入模块资源 + it.injectModuleAppResources() + // <方案2> 直接得到宿主 Resources 注入模块资源 + it.resources.injectModuleAppResources() + // 直接使用模块资源 ID + it.getString(R.id.app_name) + } + } +} +
你还可以直接在
AppLifecycle
中注入当前模块资源。示例如下
onAppLifecycle { + onCreate { + // 全局注入模块资源,但仅限于全局生命周期 + // 类似 ImageView.setImageResource 这样的方法在 Activity 中需要单独注入 + // <方案1> 通过 Context 注入模块资源 + injectModuleAppResources() + // <方案2> 直接得到宿主 Resources 注入模块资源 + resources.injectModuleAppResources() + // 直接使用模块资源 ID + getString(R.id.app_name) + } +} +
小提示
更多功能请参考 Context+Resources.injectModuleAppResources 方法。
# 注册模块 Activity
在 Android 系统中所有应用的
Activity
启动时,都需要在AndroidManifest.xml
中进行注册,在 Hook 过程中,如果我们想通过宿主来直接启动模块中未注册的Activity
要怎么做呢?在 Hook 宿主之后,我们可以直接在 Hooker 中得到的
Context
注册当前模块的Activity
代理。示例如下
resolve().firstMethod { + name = "onCreate" + parameters(Bundle::class) +}.hook { + after { + instance<Activity>().registerModuleAppActivities() + } +} +
你还可以直接在
AppLifecycle
中注册当前模块的Activity
代理。示例如下
onAppLifecycle { + onCreate { + registerModuleAppActivities() + } +} +
如果没有填写
proxy
参数,API 将会根据当前Context
自动获取当前宿主的启动入口Activity
进行代理。通常情况下,它是有效的,但是以上情况在一些 APP 中会失效,例如一些
Activity
会在注册清单上加入启动参数,那么我们就需要使用另一种解决方案。若未注册的
Activity
不能被正确启动,我们可以手动拿到宿主的AndroidManifest.xml
进行分析,来得到一个注册过的Activity
标签,获取其中的name
。你需要选择一个当前宿主可能用不到的、不需要的
Activity
作为一个“傀儡”将其进行代理,通常是有效的。比如我们已经找到了能够被代理的合适
Activity
。示例如下
<activity + android:name="com.demo.test.activity.TestActivity" + ...> +
根据其中的
name
,我们只需要在方法中加入这个参数进行注册即可。示例如下
registerModuleAppActivities(proxy = "com.demo.test.activity.TestActivity") +
另一种情况,如果你对宿主的类编写了一个
stub
,那么你可以直接通过Class
对象来进行注册。示例如下
registerModuleAppActivities(TestActivity::class.java) +
注册完成后,请将你需要使用宿主启动的模块中的
Activity
实现ModuleActivity
接口。这些
Activity
现在无需注册即可无缝存活于宿主中。我们推荐你创建
BaseActivity
作为所有模块Activity
的基类。示例如下
abstract class BaseActivity : AppCompatActivity(), ModuleActivity { + + // 设置 AppCompat 主题 (如果当前是 [AppCompatActivity]) + override val moduleTheme get() = R.style.YourAppTheme + + override fun getClassLoader() = delegate.getClassLoader() + + override fun onCreate(savedInstanceState: Bundle?) { + delegate.onCreate(savedInstanceState) + super.onCreate(savedInstanceState) + } + + override fun onConfigurationChanged(newConfig: Configuration) { + delegate.onConfigurationChanged(newConfig) + super.onConfigurationChanged(newConfig) + } + + override fun onRestoreInstanceState(savedInstanceState: Bundle) { + delegate.onRestoreInstanceState(savedInstanceState) + super.onRestoreInstanceState(savedInstanceState) + } +} +
然后将需要实现的
Activity
继承于BaseActivity
。示例如下
class HostTestActivity : BaseActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + // 模块资源已被自动注入,可以直接使用 xml 装载布局 + setContentView(R.layout.activity_main) + } +} +
以上步骤全部完成后,你就可以在 (Xposed) 宿主环境任意存在
Context
的地方愉快地调用startActivity
了。示例如下
val context: Context = ... // 假设这就是你的 Context +context.startActivity(context, HostTestActivity::class.java) +
上面我们在
registerModuleAppActivities
方法中设置的proxy
参数为默认的全局代理Activity
。如果你需要指定某个代理的
Activity
使用另外的宿主Activity
进行代理,你可以参考如下方法。示例如下
class HostTestActivity : BaseActivity() { + + // 指定一个另外的代理 Activity 类名,其也必须存在于宿主的 AndroidManifest 中 + override val proxyClassName get() = "com.demo.test.activity.OtherActivity" + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + // 模块资源已被自动注入,可以直接使用 xml 装载布局 + setContentView(R.layout.activity_main) + } +} +
小提示
更多功能请参考 Context.registerModuleAppActivities 方法。
# 创建 ContextThemeWrapper 代理
有时候,我们需要使用
MaterialAlertDialogBuilder
来美化自己在宿主中的对话框,但是拿不到 AppCompat 主题就无法创建。
- 会得到如下异常
The style on this component requires your app theme to be Theme.AppCompat (or a descendant). +
这时,我们想在宿主被 Hook 的当前
Activity
中使用MaterialAlertDialogBuilder
来创建对话框,就可以有如下方法。示例如下
resolve().firstMethod { + name = "onCreate" + parameters(Bundle::class) +}.hook { + after { + // 使用 applyModuleTheme 创建一个当前模块中的主题资源 + val appCompatContext = instance<Activity>().applyModuleTheme(R.style.Theme_AppCompat) + // 直接使用这个包装了模块主题后的 Context 创建对话框 + MaterialAlertDialogBuilder(appCompatContext) + .setTitle("AppCompat 主题对话框") + .setMessage("我是一个在宿主中显示的 AppCompat 主题对话框。") + .setPositiveButton("确定", null) + .show() + } +} +
你还可以对当前
Context
通过uiMode
设置原生的夜间模式和日间模式,至少需要 Android 10 及以上系统版本支持且当前主题包含夜间模式相关元素。示例如下
resolve().firstMethod { + name = "onCreate" + parameters(Bundle::class) +}.hook { + after { + // 定义当前模块中的主题资源 + var appCompatContext: ModuleContextThemeWrapper + // <方案1> 直接得到 Configuration 对象进行设置 + appCompatContext = instance<Activity>() + .applyModuleTheme(R.style.Theme_AppCompat) + .applyConfiguration { uiMode = Configuration.UI_MODE_NIGHT_YES } + // <方案2> 创建一个新的 Configuration 对象 + // 此方案会破坏当前宿主中原有的字体缩放大小等设置,你需要手动重新传递 densityDpi 等参数 + appCompatContext = instance<Activity>().applyModuleTheme( + theme = R.style.Theme_AppCompat, + configuration = Configuration().apply { uiMode = Configuration.UI_MODE_NIGHT_YES } + ) + // 直接使用这个包装了模块主题后的 Context 创建对话框 + MaterialAlertDialogBuilder(appCompatContext) + .setTitle("AppCompat 主题对话框") + .setMessage("我是一个在宿主中显示的 AppCompat 主题对话框。") + .setPositiveButton("确定", null) + .show() + } +} +
这样,我们就可以在宿主中非常简单地使用
`,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(`MaterialAlertDialogBuilder
创建对话框了。小提示
更多功能请参考 Context.applyModuleTheme 方法。
# ClassLoader 冲突问题
本页面所介绍的内容都是直接将模块的资源注入到了宿主,由于模块与宿主不在同一个进程 (同一个 APK) 中,其可能存在
ClassLoader
冲突的问题。若发生了
ClassLoader
冲突,你可能会遇到ClassCastException
异常。
YukiHookAPI
默认已解决了可能冲突的问题,其余情况需要你自行配置排除列表。排除列表决定了这些
Class
需要被模块还是宿主的ClassLoader
进行装载。示例如下
// 排除属于宿主的 Class 类名 +// 它们将会被宿主的 ClassLoader 装载 +// 以下内容仅供演示,不要直接使用,请以你的实际情况为准 +ModuleClassLoader.excludeHostClasses( + "androidx.core.app.ActivityCompat", + "com.demo.Test" +) +// 排除属于模块的 Class 类名 +// 它们将会被模块 (当前 Hook 进程) 的 ClassLoader 装载 +// 以下内容仅供演示,不要直接使用,请以你的实际情况为准 +ModuleClassLoader.excludeModuleClasses( + "com.demo.entry.HookEntry", + "com.demo.controller.ModuleController" +) +
你需要在向宿主注入模块资源的方法执行之前进行设置才能生效。
此功能仅为解决宿主与模块中可能存在同名的
Class
情况,例如共用的 SDK 以及依赖,在大部分情况下你不会用到此功能。`,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}; diff --git a/assets/host-inject.html-BRZka0o7.js b/assets/host-inject.html-BRZka0o7.js new file mode 100644 index 00000000..691166cc --- /dev/null +++ b/assets/host-inject.html-BRZka0o7.js @@ -0,0 +1 @@ +const e=JSON.parse(`{"key":"v-12042f1f","path":"/en/api/special-features/host-inject.html","title":"Host Resource Injection Extension","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"Inject Module App's Resources","slug":"inject-module-app-s-resources","link":"#inject-module-app-s-resources","children":[]},{"level":2,"title":"Register Module App's Activity","slug":"register-module-app-s-activity","link":"#register-module-app-s-activity","children":[]},{"level":2,"title":"Create ContextThemeWrapper Proxy","slug":"create-contextthemewrapper-proxy","link":"#create-contextthemewrapper-proxy","children":[]},{"level":2,"title":"ClassLoader Conflict Problem","slug":"classloader-conflict-problem","link":"#classloader-conflict-problem","children":[]}],"git":{"updatedTime":1750250366000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":10}]},"filePathRelative":"en/api/special-features/host-inject.md"}`);export{e as data}; diff --git a/assets/host-inject.html-COD96F06.js b/assets/host-inject.html-COD96F06.js new file mode 100644 index 00000000..5d51d8dd --- /dev/null +++ b/assets/host-inject.html-COD96F06.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-6ac5be8e","path":"/zh-cn/api/special-features/host-inject.html","title":"宿主资源注入扩展","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"注入模块资源 (Resources)","slug":"注入模块资源-resources","link":"#注入模块资源-resources","children":[]},{"level":2,"title":"注册模块 Activity","slug":"注册模块-activity","link":"#注册模块-activity","children":[]},{"level":2,"title":"创建 ContextThemeWrapper 代理","slug":"创建-contextthemewrapper-代理","link":"#创建-contextthemewrapper-代理","children":[]},{"level":2,"title":"ClassLoader 冲突问题","slug":"classloader-冲突问题","link":"#classloader-冲突问题","children":[]}],"git":{"updatedTime":1750250366000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":9}]},"filePathRelative":"zh-cn/api/special-features/host-inject.md"}');export{e as data}; diff --git a/assets/host-inject.html-DyCVxqXv.js b/assets/host-inject.html-DyCVxqXv.js new file mode 100644 index 00000000..4c02c735 --- /dev/null +++ b/assets/host-inject.html-DyCVxqXv.js @@ -0,0 +1,156 @@ +import{_ as l,r as o,o as p,c as t,b as s,d as e,e as c,a as n}from"./app-BpUB8-Q8.js";const i={},r=n(`小提示
更多功能请参考 ModuleClassLoader。
# Host Resource Injection Extension
This is an extension that injects Module App's Resources,
Activity
components, andContext
topics into the Host App.Before using the following functions, in order to prevent Resource Id from conflicting with each other, you need to modify the Resource Id in the
build.gradle
of the current Xposed Module project.Kotlin DSL
android { + androidResources.additionalParameters += listOf("--allow-reserved-package-id", "--package-id", "0x64") +} +
Groovy DSL
android { + androidResources.additionalParameters += ['--allow-reserved-package-id', '--package-id', '0x64'] +} +
Notice
aaptOptions.additionalParameters in previous versions has been deprecated, please refer to the above writing method and keep your Android Gradle Plugin to the latest version.
The sample Resource Id value provided is for reference only, 0x7f cannot be used, the default is 0x64.
In order to prevent the existence of multiple Xposed Modules in the current Host App, it is recommended to customize your own Resource Id.
# Inject Module App's Resources
After the Host App is hooked, we can directly inject the
Context
obtained in the Hooker into the current Module App's Resources.The following example
resolve().firstMethod { + name = "onCreate" + parameters(Bundle::class) +}.hook { + after { + instance<Activity>().also { + // <Scenario 1> Inject Module App's Resources through Context + it.injectModuleAppResources() + // <Scenario 2> Get the Host App's Resources directly and inject the Module App's Resources + it.resources.injectModuleAppResources() + // Use the Module App's Resource Id directly + it.getString(R.id.app_name) + } + } +} +
You can also inject current Module App's Resources directly in
AppLifecycle
.The following example
onAppLifecycle { + onCreate { + // Globally inject Module App's Resources, but only in the global lifecycle + // Methods like ImageView.setImageResource need to be injected separately in Activity + // <Scenario 1> Inject Module App's Resources through Context + injectModuleAppResources() + // <Scenario 2> Get the Host App's Resources directly and inject the Module App's Resources + resources.injectModuleAppResources() + // Use the Module App's Resource Id directly + getString(R.id.app_name) + } +} +
Tips
For more functions, please refer to the Context+Resources.injectModuleAppResources method.
# Register Module App's Activity
When the
Activity
of all applications in the Android system starts, it needs to be registered inAndroidManifest.xml
.During the Hook process, if we want to directly start the unregistered
Activity
in the Module App through the Host App, what should we do?After the Host App is hooked, we can directly register the
Activity
proxy of the current Module App in theContext
obtained in the Hooker.The following example
resolve().firstMethod { + name = "onCreate" + parameters(Bundle::class) +}.hook { + after { + instance<Activity>().registerModuleAppActivities() + } +} +
You can also register the current Module App's
Activity
proxy directly inAppLifecycle
.The following example
onAppLifecycle { + onCreate { + registerModuleAppActivities() + } +} +
If the
proxy
parameter is not filled in, the API will automatically obtain the current Host App's launching entryActivity
for proxying according to the currentContext
.Usually, it works, but the above situation will fail in some apps, for example, some
Activity
will add launching parameters to the registration list, so we need to use another solution.If the unregistered
Activity
cannot be launched correctly, we can manually get the Host App'sAndroidManifest.xml
for analysis to get a registeredActivity
tag and get thename
.You need to choose an unneeded
Activity
that may not be used by the current Host App as a "puppet" to proxy it, which usually works.For example, we have found a suitable
Activity
that can be proxied.The following example
<activity + android:name="com.demo.test.activity.TestActivity" + ...> +
According to the
name
, we only need to add this parameter to the method for registration.The following example
registerModuleAppActivities(proxy = "com.demo.test.activity.TestActivity") +
Alternatively, if you write a
stub
for the Host App's class, you can register it directly through theClass
object.The following example
registerModuleAppActivities(TestActivity::class.java) +
After registration is completed, please implement the
ModuleActivity
interface using theActivity
module in the host-started module.These
Activity
(ies) now live seamlessly in the host without registration.We recommend that you create
BaseActivity
as the base class for all modulesActivity
.The following example
abstract class BaseActivity : AppCompatActivity(), ModuleActivity { + + // Set up AppCompat Theme (if currently is [AppCompatActivity]) + override val moduleTheme get() = R.style.YourAppTheme + + override fun getClassLoader() = delegate.getClassLoader() + + override fun onCreate(savedInstanceState: Bundle?) { + delegate.onCreate(savedInstanceState) + super.onCreate(savedInstanceState) + } + + override fun onConfigurationChanged(newConfig: Configuration) { + delegate.onConfigurationChanged(newConfig) + super.onConfigurationChanged(newConfig) + } + + override fun onRestoreInstanceState(savedInstanceState: Bundle) { + delegate.onRestoreInstanceState(savedInstanceState) + super.onRestoreInstanceState(savedInstanceState) + } +} +
Then inherit the
Activity
you want to implement inBaseActivity
.The following example
class HostTestActivity : BaseActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + // Module App's Resources have been injected automatically + // You can directly use xml to load the layout + setContentView(R.layout.activity_main) + } +} +
After all the above steps are completed, you can happily call
startActivity
anywhere in the (Xposed) Host environment where aContext
exists.The following example
val context: Context = ... // Assume this is your Context +context.startActivity(context, HostTestActivity::class.java) +
The
proxy
parameter we set in theregisterModuleAppActivities
method above is the default global proxyActivity
.If you need to specify a delegated
Activity
to use another Host App'sActivity
as a proxy, you can refer to the following method.The following example
class HostTestActivity : BaseActivity() { + + // Specify an additional proxy Activity class name + // Which must also exist in the Host App's AndroidManifest + override val proxyClassName get() = "com.demo.test.activity.OtherActivity" + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + // Module App's Resources have been injected automatically + // You can directly use xml to load the layout + setContentView(R.layout.activity_main) + } +} +
Tips
For more functions, please refer to the Context.registerModuleAppActivities method.
# Create ContextThemeWrapper Proxy
Sometimes, we need to use
MaterialAlertDialogBuilder
to beautify our own dialogs in the Host App, but we can't create them without the AppCompat theme.
- Will got the following exception
The style on this component requires your app theme to be Theme.AppCompat (or a descendant). +
At this time, we want to use
MaterialAlertDialogBuilder
to create a dialog in the currentActivity
of the Host App being hooked, you can have the following methods.The following example
resolve().firstMethod { + name = "onCreate" + parameters(Bundle::class) +}.hook { + after { + // Use applyModuleTheme to create a theme resource in the current Module App + val appCompatContext = instance<Activity>().applyModuleTheme(R.style.Theme_AppCompat) + // Directly use this Context that wraps the Module App's theme to create a dialog + MaterialAlertDialogBuilder(appCompatContext) + .setTitle("AppCompat Theme Dialog") + .setMessage("I am an AppCompat theme dialog displayed in the Host App.") + .setPositiveButton("OK", null) + .show() + } +} +
You can also set the system (native) night mode and day mode on the current
Context
throughuiMode
.Which requires at least Android 10 and above system version support and the current theme contains night mode related elements.
The following example
resolve().firstMethod { + name = "onCreate" + parameters(Bundle::class) +}.hook { + after { + // Define the theme resource in the current Module App + var appCompatContext: ModuleContextThemeWrapper + // <Scenario 1> Get the Configuration object directly to set + appCompatContext = instance<Activity>() + .applyModuleTheme(R.style.Theme_AppCompat) + .applyConfiguration { uiMode = Configuration.UI_MODE_NIGHT_YES } + // <Scenario 2> Create a new Configuration object + // This solution will destroy the original font scaling and other settings in the current Host App + // You need to manually re-pass parameters such as densityDpi + appCompatContext = instance<Activity>().applyModuleTheme( + theme = R.style.Theme_AppCompat, + configuration = Configuration().apply { uiMode = Configuration.UI_MODE_NIGHT_YES } + ) + // Directly use this Context that wraps the Module App's theme to create a dialog + MaterialAlertDialogBuilder(appCompatContext) + .setTitle("AppCompat Theme Dialog") + .setMessage("I am an AppCompat theme dialog displayed in the Host App.") + .setPositiveButton("OK", null) + .show() + } +} +
This way, we can create dialogs in the Host App very simply using
`,66),d={class:"custom-container warning"},A=s("p",{class:"custom-container-title"},"Possible Problems",-1),y=s("p",null,[e("Because some "),s("strong",null,"androidx"),e(" dependent libraries or custom themes used by some apps may interfere with the actual style of the current "),s("strong",null,"MaterialAlertDialog"),e(", such as the button style of the dialog.")],-1),u=s("strong",null,"Module App Demo",-1),D={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,[s("strong",null,"ClassCastException"),e(" may occur when some apps are created, please manually specify a new "),s("strong",null,"Configuration"),e(" instance to fix.")],-1),B=n(`MaterialAlertDialogBuilder
.Tips
For more functions, please refer to the Context.applyModuleTheme method.
# ClassLoader Conflict Problem
The content introduced on this page is to directly inject the resources of the Module App into the Host App.
Since the Module App and the Host App are not in the same process (the same APK), there may be a
ClassLoader
conflict.If a
ClassLoader
conflict occurs, you may encounter aClassCastException
.
YukiHookAPI
has solved the problem of possible conflicts by default, and you need to configure the exclusion list by yourself in other cases.The exclusion list determines whether these
Class
need to be loaded by the Module App or the Host App'sClassLoader
.The following example
// Exclude Class names belonging to the Host App +// They will be loaded by the Host App's ClassLoader +// The following content is for demonstration only +// DO NOT USE IT DIRECTLY, please refer to your actual situation +ModuleClassLoader.excludeHostClasses( + "androidx.core.app.ActivityCompat", + "com.demo.Test" +) +// Exclude Class names belonging to the Module App +// They will be loaded by the ClassLoader of the Module App (the current Hook process) +// The following content is for demonstration only +// DO NOT USE IT DIRECTLY, please refer to your actual situation +ModuleClassLoader.excludeModuleClasses( + "com.demo.entry.HookEntry", + "com.demo.controller.ModuleController" +) +
You need to set it before the method of injecting Module App's resources into the Host App is executed to take effect.
This function is only to solve the situation that
Class
with the same name may exist in the Host App and Module App, such as shared SDK and dependencies.In most cases, you will not use this function.
`,13);function C(m,h){const a=o("ExternalLinkIcon");return p(),t("div",null,[r,s("div",d,[A,y,s("p",null,[e("You can refer to the "),u,e(" in this case and see "),s("a",D,[e("here is the sample code"),c(a)]),e(" to fix this problem.")]),v]),B])}const g=l(i,[["render",C],["__file","host-inject.html.vue"]]);export{g as default}; diff --git a/assets/host-lifecycle.html-BgnOErBM.js b/assets/host-lifecycle.html-BgnOErBM.js new file mode 100644 index 00000000..05d2dfea --- /dev/null +++ b/assets/host-lifecycle.html-BgnOErBM.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-deaff1d0","path":"/en/api/special-features/host-lifecycle.html","title":"Host Lifecycle Extension","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"Listener Lifecycle","slug":"listener-lifecycle","link":"#listener-lifecycle","children":[]},{"level":2,"title":"Register System Broadcast","slug":"register-system-broadcast","link":"#register-system-broadcast","children":[]}],"git":{"updatedTime":1669656909000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":3}]},"filePathRelative":"en/api/special-features/host-lifecycle.md"}');export{e as data}; diff --git a/assets/host-lifecycle.html-BqYisHbJ.js b/assets/host-lifecycle.html-BqYisHbJ.js new file mode 100644 index 00000000..02809266 --- /dev/null +++ b/assets/host-lifecycle.html-BqYisHbJ.js @@ -0,0 +1,51 @@ +import{_ as s,o as n,c as a,a as e}from"./app-BpUB8-Q8.js";const l={},p=e(`Tips
For more functions, please refer to ModuleClassLoader.
# Host Lifecycle Extension
This is an extension of the lifecycle of an automatic hooking Host App.
# Listener Lifecycle
Implement the listening function by automating the lifecycle method of the Host App.
We need to listen to the startup and lifecycle methods of the Host App's
Application
, just use the following methods.The following example
loadApp(name = "com.example.demo") { + // Register lifecycle listeners + // Optional parameter: + // You can set isOnFailureThrowToApp = false + // So that the exception will not be thrown to the Host App to prevent the Host App from crashing + // The default is true + onAppLifecycle(isOnFailureThrowToApp = true) { + // You can implement lifecycle method listeners in Application here + attachBaseContext { baseContext, hasCalledSuper -> + // Determine whether + // The super.attachBaseContext(base) method has been executed by judging hasCalledSuper + // ... + } + onCreate { + // Get the current Application instance through this + // ... + } + onTerminate { + // Get the current Application instance through this + // ... + } + onLowMemory { + // Get the current Application instance through this + // ... + } + onTrimMemory { self, level -> + // Here you can judge whether the app has switched to the background + if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { + // ... + } + // ... + } + onConfigurationChanged { self, config -> + // ... + } + } +} +
Tips
For more functions, please refer to AppLifecycle.
# Register System Broadcast
Register system broadcast through the
Application.onCreate
method to listening system broadcast.We can also register system broadcast in the Host App's
Application
.The following example
loadApp(name = "com.example.demo") { + // Register lifecycle listeners + onAppLifecycle { + // Broadcast listening when the registered user is unlocked + registerReceiver(Intent.ACTION_USER_PRESENT) { context, intent -> + // ... + } + // Register multiple broadcast listeners, will call back multiple times at the same time + registerReceiver(Intent.ACTION_PACKAGE_CHANGED, Intent.ACTION_TIME_TICK) { context, intent -> + // ... + } + } +} +
`,14),o=[p];function i(c,t){return n(),a("div",null,o)}const d=s(l,[["render",i],["__file","host-lifecycle.html.vue"]]);export{d as default}; diff --git a/assets/host-lifecycle.html-BsjcaKw0.js b/assets/host-lifecycle.html-BsjcaKw0.js new file mode 100644 index 00000000..770cda14 --- /dev/null +++ b/assets/host-lifecycle.html-BsjcaKw0.js @@ -0,0 +1,47 @@ +import{_ as s,o as n,c as a,a as l}from"./app-BpUB8-Q8.js";const e={},p=l(`Tips
For more functions, please refer to AppLifecycle.
# 宿主生命周期扩展
这是一个自动 Hook 宿主 APP 生命周期的扩展功能。
# 监听生命周期
通过自动化 Hook 宿主 APP 的生命周期方法,来实现监听功能。
我们需要监听宿主
Application
的启动和生命周期方法,只需要使用以下方式实现。示例如下
loadApp(name = "com.example.demo") { + // 注册生命周期监听 + // 可选参数:你可以设置 isOnFailureThrowToApp = false 使得其中的异常不会抛出给宿主防止宿主崩溃,默认为 true + onAppLifecycle(isOnFailureThrowToApp = true) { + // 你可以在这里实现 Application 中的生命周期方法监听 + attachBaseContext { baseContext, hasCalledSuper -> + // 通过判断 hasCalledSuper 来确定是否已执行 super.attachBaseContext(base) 方法 + // ... + } + onCreate { + // 通过 this 得到当前 Application 实例 + // ... + } + onTerminate { + // 通过 this 得到当前 Application 实例 + // ... + } + onLowMemory { + // 通过 this 得到当前 Application 实例 + // ... + } + onTrimMemory { self, level -> + // 可在这里判断 APP 是否已切换到后台 + if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { + // ... + } + // ... + } + onConfigurationChanged { self, config -> + // ... + } + } +} +
小提示
更多功能请参考 AppLifecycle。
# 注册系统广播
通过
Application.onCreate
方法注册系统广播,来实现对系统广播的监听。我们还可以在宿主
Application
中注册系统广播。示例如下
loadApp(name = "com.example.demo") { + // 注册生命周期监听 + onAppLifecycle { + // 注册用户解锁时的广播监听 + registerReceiver(Intent.ACTION_USER_PRESENT) { context, intent -> + // ... + } + // 注册多个广播监听,会同时回调多次 + registerReceiver(Intent.ACTION_PACKAGE_CHANGED, Intent.ACTION_TIME_TICK) { context, intent -> + // ... + } + } +} +
`,14),o=[p];function c(i,r){return n(),a("div",null,o)}const d=s(e,[["render",c],["__file","host-lifecycle.html.vue"]]);export{d as default}; diff --git a/assets/host-lifecycle.html-C7PzYAZN.js b/assets/host-lifecycle.html-C7PzYAZN.js new file mode 100644 index 00000000..5eef8b5d --- /dev/null +++ b/assets/host-lifecycle.html-C7PzYAZN.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-357a8d49","path":"/zh-cn/api/special-features/host-lifecycle.html","title":"宿主生命周期扩展","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"监听生命周期","slug":"监听生命周期","link":"#监听生命周期","children":[]},{"level":2,"title":"注册系统广播","slug":"注册系统广播","link":"#注册系统广播","children":[]}],"git":{"updatedTime":1669656909000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":3}]},"filePathRelative":"zh-cn/api/special-features/host-lifecycle.md"}');export{e as data}; diff --git a/assets/index.html-5uusgM1u.js b/assets/index.html-5uusgM1u.js new file mode 100644 index 00000000..defdc70e --- /dev/null +++ b/assets/index.html-5uusgM1u.js @@ -0,0 +1 @@ +import{_ as e,o as c,c as t}from"./app-BpUB8-Q8.js";const n={};function _(o,r){return c(),t("div")}const a=e(n,[["render",_],["__file","index.html.vue"]]);export{a as default}; diff --git a/assets/index.html-Bo0olcew.js b/assets/index.html-Bo0olcew.js new file mode 100644 index 00000000..236b2c95 --- /dev/null +++ b/assets/index.html-Bo0olcew.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-c0c85b84","path":"/zh-cn/","title":"首页","lang":"zh-CN","frontmatter":{"home":true,"title":"首页","heroImage":"/images/logo.png","actions":[{"text":"快速上手","link":"/zh-cn/guide/home","type":"primary"},{"text":"更新日志","link":"/zh-cn/about/changelog","type":"secondary"}],"features":[{"title":"Xposed 模块开发","details":"自动构建程序可以帮你快速创建一个 Xposed 模块,完全省去配置入口类和 xposed_init 等文件。"},{"title":"轻量优雅","details":"拥有一套强大、优雅、人性化、完全使用 Kotlin lambda 打造的 API,可以帮你快速实现方法 Hook 以及更多便捷功能。"},{"title":"高效调试","details":"拥有丰富的调试日志功能,细到每个 Hook 方法的名称、所在类以及查找耗时,可进行快速调试和排错。"},{"title":"方便移植","details":"原生支持多种 Xposed API 用法,并原生对接多种 Xposed API,支持范围内的 Hook Frameworks 都能进行快速对接。"},{"title":"支持混淆","details":"构建的 Xposed 模块原生支持 R8 压缩优化混淆,混淆不会破坏 Hook 入口点,R8 下无需任何其它配置。"},{"title":"快速上手","details":"简单易用,不需要繁琐的配置,不需要十足的开发经验,搭建环境集成依赖即可立即开始使用。"}],"footer":"Apache-2.0 License | Copyright (C) 2019 HighCapable"},"headers":[{"level":3,"title":"所有 Hook 流程一步到位,拒绝繁琐","slug":"所有-hook-流程一步到位-拒绝繁琐","link":"#所有-hook-流程一步到位-拒绝繁琐","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":9}]},"filePathRelative":"zh-cn/index.md"}');export{e as data}; diff --git a/assets/index.html-CB7-jiwu.js b/assets/index.html-CB7-jiwu.js new file mode 100644 index 00000000..6e07aecb --- /dev/null +++ b/assets/index.html-CB7-jiwu.js @@ -0,0 +1,14 @@ +import{_ as s,o as n,c as a,a as l}from"./app-BpUB8-Q8.js";const e={},o=l(`小提示
更多功能请参考 AppLifecycle。
# 所有 Hook 流程一步到位,拒绝繁琐
`,2),p=[o];function c(r,i){return n(),a("div",null,p)}const d=s(e,[["render",c],["__file","index.html.vue"]]);export{d as default}; diff --git a/assets/index.html-CHgP8geU.js b/assets/index.html-CHgP8geU.js new file mode 100644 index 00000000..b2f1abf7 --- /dev/null +++ b/assets/index.html-CHgP8geU.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-2d0a870d","path":"/en/","title":"Home","lang":"en-US","frontmatter":{"home":true,"title":"Home","heroImage":"/images/logo.png","actions":[{"text":"Get Started","link":"/en/guide/home","type":"primary"},{"text":"Changelog","link":"/en/about/changelog","type":"secondary"}],"features":[{"title":"Xposed Module Develop","details":"The automatic builder can help you quickly create an Xposed Module, automatic configure the entry class and xposed_init files."},{"title":"Light and Elegant","details":"A powerful, elegant, beautiful API built with Kotlin lambda can help you quickly implement method Hook and more convenient functions."},{"title":"Debugging Efficient","details":"A rich debug log function, detailing the name of each hooked method, time-consuming to find the class can quickly debug and find errors."},{"title":"Easy to Transplant","details":"Natively supports multiple Xposed API usages and natively connects to multiple Xposed APIs, Hook Frameworks within the supported range can be quickly integrated."},{"title":"Obfuscate Support","details":"The built Xposed Module simply supports R8, obfuscate will not destroy the hook entry point, and no other configuration is required under R8."},{"title":"Quick to Start","details":"Simple and easy to use it now! Do not need complex configuration and full development experience, Integrate dependencies and enjoy yourself."}],"footer":"Apache-2.0 License | Copyright (C) 2019 HighCapable"},"headers":[{"level":3,"title":"All Hook process in one step, everything is simplified","slug":"all-hook-process-in-one-step-everything-is-simplified","link":"#all-hook-process-in-one-step-everything-is-simplified","children":[]}],"git":{"updatedTime":1754157645000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":10}]},"filePathRelative":"en/index.md"}');export{e as data}; diff --git a/assets/index.html-D6YZKtoe.js b/assets/index.html-D6YZKtoe.js new file mode 100644 index 00000000..1d43f436 --- /dev/null +++ b/assets/index.html-D6YZKtoe.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-8daa1a0e","path":"/","title":"","lang":"en-US","frontmatter":{"home":true,"navbar":false,"sidebar":false,"title":null,"heroAlt":null,"heroText":null,"tagline":"Select a language","actions":[{"text":"English","link":"/en/","type":"secondary"},{"text":"简体中文","link":"/zh-cn/","type":"secondary"}],"footer":"Apache-2.0 License | Copyright (C) 2019 HighCapable"},"headers":[],"git":{"updatedTime":1736736532000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":5}]},"filePathRelative":"index.md"}');export{e as data}; diff --git a/assets/index.html-NYRlXN7n.js b/assets/index.html-NYRlXN7n.js new file mode 100644 index 00000000..59ad96b3 --- /dev/null +++ b/assets/index.html-NYRlXN7n.js @@ -0,0 +1,14 @@ +import{_ as s,o as n,c as a,a as l}from"./app-BpUB8-Q8.js";const e={},o=l(`loadApp(name = "com.android.browser") { + Activity::class.resolve().firstMethod { + name = "onCreate" + parameters(Bundle::class) + }.hook { + before { + // Your code here. + } + after { + // Your code here. + } + } +} +
# All Hook process in one step, everything is simplified
`,2),p=[o];function i(c,r){return n(),a("div",null,p)}const d=s(e,[["render",i],["__file","index.html.vue"]]);export{d as default}; diff --git a/assets/knowledge.html-BJFcZiJH.js b/assets/knowledge.html-BJFcZiJH.js new file mode 100644 index 00000000..7932a775 --- /dev/null +++ b/assets/knowledge.html-BJFcZiJH.js @@ -0,0 +1 @@ +const e=JSON.parse(`{"key":"v-277b35ca","path":"/en/guide/knowledge.html","title":"Basic Knowledge","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"Related Introduction","slug":"related-introduction","link":"#related-introduction","children":[{"level":3,"title":"What is Xposed","slug":"what-is-xposed","link":"#what-is-xposed","children":[]},{"level":3,"title":"What can Xposed do","slug":"what-can-xposed-do","link":"#what-can-xposed-do","children":[]},{"level":3,"title":"Development Process","slug":"development-process","link":"#development-process","children":[]},{"level":3,"title":"Derivatives","slug":"derivatives","link":"#derivatives","children":[]},{"level":3,"title":"What YukiHookAPI does","slug":"what-yukihookapi-does","link":"#what-yukihookapi-does","children":[]}]},{"level":2,"title":"Let's Started","slug":"let-s-started","link":"#let-s-started","children":[]}],"git":{"updatedTime":1695444575000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":4}]},"filePathRelative":"en/guide/knowledge.md"}`);export{e as data}; diff --git a/assets/knowledge.html-BvjZCte4.js b/assets/knowledge.html-BvjZCte4.js new file mode 100644 index 00000000..966db582 --- /dev/null +++ b/assets/knowledge.html-BvjZCte4.js @@ -0,0 +1,13 @@ +import{_ as s,r,o as i,c as d,b as e,d as o,e as n,a}from"./app-BpUB8-Q8.js";const l={},p=a(`loadApp(name = "com.android.browser") { + Activity::class.resolve().firstMethod { + name = "onCreate" + parameters(Bundle::class) + }.hook { + before { + // Your code here. + } + after { + // Your code here. + } + } +} +
# Basic Knowledge
Here is a collection of Xposed-related introductions and the key points of knowledge that need to be grasped before start.
Anyone who already knows can skip it.
The basic knowledge content not necessarily completely accurate, please read it according to your own opinion.
If you find any errors in this page, please correct it and help us improve.
# Related Introduction
Here's an introduction to Xposed and how Hooks work.
# What is Xposed
Xposed Framework is a set of open source framework services that run in Android high-privilege mode. It can affect program operation (modify the system) without modifying the APK file. Based on it, many Powerful modules that operate simultaneously without conflicting functions.
The above content is copied from Baidu Encyclopedia.
# What can Xposed do
The structure below describes the basic workings and principles of Xposed.
Xposed Framework +└── App's Environment + └── Hooker (Hooked) + ... + App's Environment + └── Hooker (Hooked) + ... + ... +
We can achieve the ultimate goal of controlling its behavior by injecting the Host (App) when the Host (App) is running.
This mode of operation of Xposed is called parasitism. The Xposed Module follows the lifecycle of the host and completes its own life course within the lifecycle of the Host.
We can call the Host's methods, fields, and constructors through reflection, and use the Hook operation provided by
XposedBridge
to dynamically insert our own code before and after the method to be executed by the Host (App), or completely replace the target, or even intercept.# Development Process
Today's Xposed Manager has been completely replaced by its derivative works, and the era of SuperSU has ended, and now, with Magisk, everything behind is possible again.
Its development history can be roughly divided into Xposed(Dalvik) → Xposed(ART) → Xposed(Magisk) → EdXposed(Riru)/LSPosed(Riru/ Zygisk)
# Derivatives
The structure below describes how and how the Xposed-like Hook Framework works.
App's Environment +└── Hook Framework + └── Hooker (Hooked) + ... +
Through the operation principle of Xposed, many frameworks of the same type have been derived. As mobile devices in today's era are more and more difficult to obtain Root permissions or even flash, and when they are not just needed, some Root-free frameworks are also produced, such as LSPatch、TaiChi.
These Hook Frameworks at the ART level can also complete the Hook process with the same principle as Xposed without using the Xposed API. The operating principle of Root-free is to modify the APK and inject the Hook process into the Host, and control it through external modules.
Another product is to use the existing functions of the Android operating environment to virtualize an environment that is completely the same as the current device system, and run App in it. This is the virtual App technology VirtualApp, which was later derived as VirtualXposed .
`,24),c={href:"https://github.com/LSPosed/LSPatch",target:"_blank",rel:"noopener noreferrer"},h={href:"https://taichi.cool/",target:"_blank",rel:"noopener noreferrer"},u={href:"https://github.com/asLody/VirtualApp",target:"_blank",rel:"noopener noreferrer"},g={href:"https://github.com/asLody/SandVXposed",target:"_blank",rel:"noopener noreferrer"},m=a('# What YukiHookAPI does
Since Xposed appeared until now, apart from
XposedHelpers
, which is well known to developers, there is still no set of syntactic sugar for Kotlin and API with complete usage encapsulation.The birth of this API framework is to hope that in the current era of Xposed, more capable Xposed Module developers can avoid detours and complete the entire development process more easily and simply.
In the future,
YukiHookAPI
will adapt to more third-party Hook Frameworks based on the goal of using the Xposed API, so as to improve the entire ecosystem and help more developers make Xposed Module development simpler and easier to understand.# Let's Started
Before starting, you need to have the following basics to better use
',6),f=e("li",null,[e("p",null,"Grasp and understand Android development and simple system operation principles")],-1),k={href:"https://github.com/skylot/jadx",target:"_blank",rel:"noopener noreferrer"},b={href:"https://github.com/iBotPeaches/Apktool",target:"_blank",rel:"noopener noreferrer"},y=e("li",null,[e("p",null,"Grasp and proficient in using Java reflection, understand simple Smali syntax, understand Dex file structure, and use reverse analysis to locate method locations")],-1),v={href:"https://api.xposed.info",target:"_blank",rel:"noopener noreferrer"},w={href:"https://blog.ketal.icu/en/Xposed%E6%A8%A1%E5%9D%97%E5%BC%80%E5%8F%91%E5%85%A5%E9%97%A8%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/",target:"_blank",rel:"noopener noreferrer"},_=e("strong",null,"(Friend Link)",-1),A=e("li",null,[e("p",null,[o("Grasp Kotlin language and learn to use "),e("strong",null,"Kotlin lambda")])],-1),x=e("li",null,[e("p",null,"Grasp and understand Kotlin and Java mixing, calling each other, and Java bytecode generated by Kotlin")],-1);function X(H,T){const t=r("ExternalLinkIcon");return i(),d("div",null,[p,e("p",null,[o("The Root-free frameworks mentioned above are "),e("a",c,[o("LSPatch"),n(t)]),o("、"),e("a",h,[o("TaiChi"),n(t)]),o("、"),e("a",u,[o("VirtualApp"),n(t)]),o("、"),e("a",g,[o("SandVXposed"),n(t)]),o(".")]),m,e("ul",null,[f,e("li",null,[e("p",null,[o("To grasp and understand the internal structure of Android APK and simple decompilation knowledge, you can refer to "),e("a",k,[o("Jadx"),n(t)]),o(" and "),e("a",b,[o("ApkTool"),n(t)])])]),y,e("li",null,[e("p",null,[o("Grasp the basic native "),e("a",v,[o("Xposed API"),n(t)]),o(" usage, understand the operation principle of Xposed, see "),e("a",w,[o("here"),n(t)]),o(),_])]),A,x])])}const P=s(l,[["render",X],["__file","knowledge.html.vue"]]);export{P as default}; diff --git a/assets/knowledge.html-CFMQgPep.js b/assets/knowledge.html-CFMQgPep.js new file mode 100644 index 00000000..5fcfde78 --- /dev/null +++ b/assets/knowledge.html-CFMQgPep.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-b4f1a468","path":"/zh-cn/guide/knowledge.html","title":"基础知识","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"相关介绍","slug":"相关介绍","link":"#相关介绍","children":[{"level":3,"title":"Xposed 是什么","slug":"xposed-是什么","link":"#xposed-是什么","children":[]},{"level":3,"title":"Xposed 能做什么","slug":"xposed-能做什么","link":"#xposed-能做什么","children":[]},{"level":3,"title":"发展过程","slug":"发展过程","link":"#发展过程","children":[]},{"level":3,"title":"衍生产品","slug":"衍生产品","link":"#衍生产品","children":[]},{"level":3,"title":"YukiHookAPI 做了什么","slug":"yukihookapi-做了什么","link":"#yukihookapi-做了什么","children":[]}]},{"level":2,"title":"让我们开始吧","slug":"让我们开始吧","link":"#让我们开始吧","children":[]}],"git":{"updatedTime":1695444575000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":5}]},"filePathRelative":"zh-cn/guide/knowledge.md"}');export{e as data}; diff --git a/assets/knowledge.html-CabyS3rt.js b/assets/knowledge.html-CabyS3rt.js new file mode 100644 index 00000000..1612a702 --- /dev/null +++ b/assets/knowledge.html-CabyS3rt.js @@ -0,0 +1,13 @@ +import{_ as r,r as t,o as p,c as l,b as o,d as e,e as s,a as n}from"./app-BpUB8-Q8.js";const d={},c=n(`YukiHookAPI
.# 基础知识
这里收集了 Xposed 相关的介绍以及开启前需要掌握的知识要点,已经了解的同学可以略过。
基础知识内容并不一定完全准确,请根据自己的见解酌情阅读,若发现内容有错误欢迎指正并帮助我们完善和改进。
# 相关介绍
这里介绍了 Xposed 以及 Hook 的工作原理。
# Xposed 是什么
Xposed 框架 (Xposed Framework) 是一套开源的、在 Android 高权限模式下运行的框架服务,可以在不修改 APK 文件的情况下影响程序运行(修改系统)的框架服务,基于它可以制作出许多功能强大的模块,且在功能不冲突的情况下同时运作。
上述内容复制自百度百科。
# Xposed 能做什么
下方的结构描述了 Xposed 的基本工作方式和原理。
Xposed Framework +└── App's Environment + └── Hooker (Hooked) + ... + App's Environment + └── Hooker (Hooked) + ... + ... +
我们可以在宿主 (APP) 运行时通过注入宿主 (APP) 来达到控制其行为的最终目的。
Xposed 的这种运行方式被称为寄生,Xposed 模块跟随宿主的生命周期,在宿主的生命周期内完成自己的生命历程。
我们可以通过反射的方式调用宿主的方法、变量、构造方法,以及使用
XposedBridge
所提供的 Hook 操作动态地在宿主 (APP) 要执行的方法前后插入自己的代码,或完全替换目标,甚至是拦截。# 发展过程
如今的 Xposed 管理器已完全被其衍生作品替代,而 SuperSU 的时代也已经落幕了,现在,借助 Magisk 使后面的一切又成为了可能。
其发展史大致可分为 Xposed(Dalvik) → Xposed(ART) → Xposed(Magisk) → EdXposed(Riru)/LSPosed(Riru/Zygisk)
# 衍生产品
下方的结构描述了类似 Xposed 的 Hook Framework 的工作方式和原理。
App's Environment +└── Hook Framework + └── Hooker (Hooked) + ... +
通过 Xposed 的运行原理,从而衍生了很多同类型框架,随着当今时代的移动设备获取 Root 权限甚至刷机越来越困难且不是刚需的时候,一些免 Root 框架也随之产生,例如 LSPatch、太极。
这些在 ART 层面上的 Hook Framework 同样也可不借助 Xposed API 完成其和 Xposed 原理一样的 Hook 流程,免 Root 的运行原理为修改 APK 并将 Hook 进程注入宿主,通过外部模块对其进行控制。
另外一种产品就是利用 Android 运行环境现有的功能虚拟出一个完全与当前设备系统一样的环境,并在其中运行 APP,这个就是虚拟 APP 技术 VirtualApp,后来衍生为 VirtualXposed。
`,23),i={href:"https://github.com/LSPosed/LSPatch",target:"_blank",rel:"noopener noreferrer"},h={href:"https://taichi.cool/zh/",target:"_blank",rel:"noopener noreferrer"},k={href:"https://github.com/asLody/VirtualApp",target:"_blank",rel:"noopener noreferrer"},u={href:"https://github.com/asLody/SandVXposed",target:"_blank",rel:"noopener noreferrer"},g=n('# YukiHookAPI 做了什么
自从 Xposed 出现到现在为止,除了开发者人人皆知的
XposedHelpers
,依然没有一套针对 Kotlin 打造的语法糖以及用法封装十分完善的 API。本 API 框架的诞生就是希望在 Xposed 的如今时代,能让更多有动手能力的 Xposed 模块开发者少走弯路,更容易、更简单地完成整个开发流程。
未来,
YukiHookAPI
将在使用 Xposed API 的目标基础上适配更多第三方 Hook Framework,使得整个生态得到完善,并帮助更多开发者让 Xposed 模块开发变得更加简单和易懂。# 让我们开始吧
在开始之前,你需要拥有以下基础才能更好地使用
',6),b=o("li",null,[o("p",null,"掌握并了解 Android 开发及简单的系统运行原理")],-1),_={href:"https://github.com/skylot/jadx",target:"_blank",rel:"noopener noreferrer"},A={href:"https://github.com/iBotPeaches/Apktool",target:"_blank",rel:"noopener noreferrer"},f=o("li",null,[o("p",null,"掌握并熟练使用 Java 反射,了解简单的 Smali 语法,了解 DEX 文件结构,会使用逆向分析定位方法位置")],-1),X={href:"https://api.xposed.info",target:"_blank",rel:"noopener noreferrer"},m={href:"https://blog.ketal.icu/cn/Xposed%E6%A8%A1%E5%9D%97%E5%BC%80%E5%8F%91%E5%85%A5%E9%97%A8%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/",target:"_blank",rel:"noopener noreferrer"},x=o("strong",null,"(友情链接)",-1),P={href:"https://blog.ketal.icu/cn/kotlin-lambda%E5%85%A5%E9%97%A8/",target:"_blank",rel:"noopener noreferrer"},y=o("strong",null,"(友情链接)",-1),E=o("li",null,[o("p",null,"掌握并了解 Kotlin 与 Java 混编、互相调用以及 Kotlin 生成的 Java 字节码")],-1);function H(v,q){const a=t("ExternalLinkIcon");return p(),l("div",null,[c,o("p",null,[e("上述提到的免 Root 框架分别为 "),o("a",i,[e("LSPatch"),s(a)]),e("、"),o("a",h,[e("太极"),s(a)]),e("、"),o("a",k,[e("VirtualApp"),s(a)]),e("、"),o("a",u,[e("SandVXposed"),s(a)]),e("。")]),g,o("ul",null,[b,o("li",null,[o("p",null,[e("掌握并了解 Android APK 内部结构以及简单的反编译知识要领,可参考 "),o("a",_,[e("Jadx"),s(a)]),e(" 与 "),o("a",A,[e("ApkTool"),s(a)])])]),f,o("li",null,[o("p",null,[e("掌握基础的原生 "),o("a",X,[e("Xposed API"),s(a)]),e(" 用法,了解 Xposed 的运行原理,可参考本文以及 "),o("a",m,[e("这里"),s(a)]),e(),x])]),o("li",null,[o("p",null,[e("掌握 Kotlin 语言,学会灵活运用 "),o("a",P,[e("Kotlin lambda"),s(a)]),e(),y])]),E])])}const I=r(d,[["render",H],["__file","knowledge.html.vue"]]);export{I as default}; diff --git a/assets/logger.html-B-OHJyal.js b/assets/logger.html-B-OHJyal.js new file mode 100644 index 00000000..87ce6310 --- /dev/null +++ b/assets/logger.html-B-OHJyal.js @@ -0,0 +1,47 @@ +import{_ as o,r as e,o as l,c as p,b as s,d as a,e as c,a as i}from"./app-BpUB8-Q8.js";const t={},r=s("h1",{id:"调试日志",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#调试日志","aria-hidden":"true"},"#"),a(" 调试日志")],-1),d=s("blockquote",null,[s("p",null,[a("日志是调试过程最重要的一环,"),s("code",null,"YukiHookAPI"),a(" 为开发者封装了一套稳定高效的调试日志功能。")])],-1),u={class:"custom-container tip"},y=s("p",{class:"custom-container-title"},"小提示",-1),b=s("code",null,"KavaRef",-1),g={href:"https://highcapable.github.io/KavaRef/zh-cn/library/kavaref-core#%E6%97%A5%E5%BF%97%E7%AE%A1%E7%90%86",target:"_blank",rel:"noopener noreferrer"},A=s("code",null,"KavaRef",-1),m=s("p",null,[s("code",null,"YukiHookAPI"),a(" 默认接管了 "),s("code",null,"KavaRef"),a(" 的日志功能,你也可以自己配置 "),s("code",null,"KavaRef"),a(" 的日志功能。")],-1),v=i(`YukiHookAPI
。# 普通日志
你可以调用
YLog.debug
、YLog.info
、YLog.warn
来向控制台打印普通日志。使用方法如下所示。
示例如下
YLog.debug(msg = "This is a log") +
此时,
YukiHookAPI
会调用android.util.Log
与 (Xposed) 宿主环境中的日志功能同时打印这条日志。日志默认的
TAG
为你在YLog.Configs.tag
中设置的值。你也可以动态自定义这个值,但是不建议轻易修改
TAG
防止过滤不到日志。示例如下
YLog.debug(tag = "YukiHookAPI", msg = "This is a log") +
打印的结果为如下所示。
示例如下
[YukiHookAPI][D][宿主包名] This is a log +
你还可以使用
YLog.EnvType
自定义日志打印的环境,可选择使用android.util.Log
还是 (Xposed) 宿主环境中的日志功能来打印日志。默认类型为
YLog.EnvType.BOTH
,含义为同时使用这两个方法来打印日志。比如我们仅使用
android.util.Log
来打印日志。示例如下
YLog.debug(tag = "YukiHookAPI", msg = "This is a log", env = YLog.EnvType.LOGD) +
或仅使用 (Xposed) 宿主环境中的日志功能来打印日志,此方法仅可在 (Xposed) 宿主环境使用。
示例如下
YLog.debug(tag = "YukiHookAPI", msg = "This is a log", env = YLog.EnvType.XPOSED_ENVIRONMENT) +
若你想智能区分 (Xposed) 宿主环境与模块环境,可以写为如下形式。
示例如下
YLog.debug(tag = "YukiHookAPI", msg = "This is a log", env = YLog.EnvType.SCOPE) +
这样 API 就会在不同环境智能选择指定的方法类型去打印这条日志。
小提示
更多功能请参考 YLog.debug、YLog.info 及 YLog.warn 方法。
# 错误日志
你可以调用
YLog.error
来向控制台打印E
级别的日志。使用方法如下所示。
示例如下
YLog.error(msg = "This is an error") +
错误日志的级别是最高的,无论你有没有过滤仅为
E
级别的日志。对于错误级别的日志,你还可以在后面加上一个异常堆栈。
// 假设这就是被抛出的异常 +val throwable = Throwable(...) +// 打印日志 +YLog.error(msg = "This is an error", e = throwable) +
打印的结果为如下所示。
示例如下
[YukiHookAPI][E][宿主包名] This is an error +
同时,日志会帮你打印整个异常堆栈。
示例如下
java.lang.Throwable + at com.demo.Test.<init>(...) + at com.demo.Test.doTask(...) + at com.demo.Test.stop(...) + at com.demo.Test.init(...) + at a.a.a(...) + ... 3 more +
在错误日志中,你同样也可以使用
YLog.EnvType
来指定当前打印日志所用到的方法类型。小提示
更多功能请参考 YLog.error 方法。
# 保存日志与自定义元素
你可以使用
YLog.saveToFile
方法直接保存当前已打印的全部日志到文件。示例如下
// 请注意保存的文件路径必须拥有读写权限,否则会抛出异常 +YLog.saveToFile("/sdcard/Documents/debug_log.log") +
你还可以使用
YLog.contents
获取当前已打印的全部日志文件内容。示例如下
// 获取当前已打印的全部日志文件内容 +val fileContent = YLog.contents +
如果你需要一个实时日志的数据结构数组,你可以直接获取
YLog.inMemoryData
的内容。示例如下
// 获取当前已打印的实时日志数据结构数组 +YLog.inMemoryData.forEach { + it.timestamp // 获取时间戳 + it.time // 获取 UTC 时间 + it.priority // 获取优先级 + it.msg // 获取消息 + it.throwable // 获取异常 + // ... +} +
如果你想对得到的自定义日志数据进行格式化或保存到文件,你只需要使用如下方法即可。
示例如下
// 假设这就是你得到的自定义日志数据 +val data: List<YLogData> +// 格式化日志数据到字符串 +val dataString = YLog.contents(data) +// 保存日志数据到文件 +// 请注意保存的文件路径必须拥有读写权限,否则会抛出异常 +YLog.saveToFile("/sdcard/Documents/debug_log.log", data) +
特别注意
你需要启用 YLog.Configs.isRecord 才能获取到 YLog.inMemoryData 的内容。
获取到的日志数据在 Hook APP (宿主) 及模块进程中是相互隔离的。
你只能在对应的进程中获取对应的日志数据,如果你需要在任何地方实时得到这些日志数据,请参考 Xposed 模块与宿主通讯桥、注册模块 Activity。
如果你只想通过模块或宿主来实时得到日志数据,请参考可选方案 YukiHookDataChannel.obtainLoggerInMemoryData 方法。
你还可以使用
YLog.Configs.elements
自定义调试日志对外显示的元素。此功能需要在 Hook 入口类的
onInit
中对YukiHookAPI.Configs
进行配置。示例如下
override fun onInit() = configs { + debugLog { + // ... + elements(TAG, PRIORITY, PACKAGE_NAME, USER_ID) + } + // ... +} +
`,61);function h(k,D){const n=e("ExternalLinkIcon");return l(),p("div",null,[r,d,s("div",u,[y,s("p",null,[b,a(" 的日志可以由其自身单独管理,详细的配置方案你可以参考 "),s("a",g,[a("这里"),c(n)]),a(",这将跳转到 "),A,a(" 的文档。")]),m]),v])}const C=o(t,[["render",h],["__file","logger.html.vue"]]);export{C as default}; diff --git a/assets/logger.html-BW4Gjfc-.js b/assets/logger.html-BW4Gjfc-.js new file mode 100644 index 00000000..9ef2be2c --- /dev/null +++ b/assets/logger.html-BW4Gjfc-.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-1f0f591e","path":"/zh-cn/api/special-features/logger.html","title":"调试日志","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"普通日志","slug":"普通日志","link":"#普通日志","children":[]},{"level":2,"title":"错误日志","slug":"错误日志","link":"#错误日志","children":[]},{"level":2,"title":"保存日志与自定义元素","slug":"保存日志与自定义元素","link":"#保存日志与自定义元素","children":[]}],"git":{"updatedTime":1750149121000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":13}]},"filePathRelative":"zh-cn/api/special-features/logger.md"}');export{e as data}; diff --git a/assets/logger.html-C9kwF_yM.js b/assets/logger.html-C9kwF_yM.js new file mode 100644 index 00000000..9860ea7f --- /dev/null +++ b/assets/logger.html-C9kwF_yM.js @@ -0,0 +1,51 @@ +import{_ as a,r as n,o as l,c as t,b as s,d as e,e as p,a as i}from"./app-BpUB8-Q8.js";const c={},r=s("h1",{id:"debug-logs",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#debug-logs","aria-hidden":"true"},"#"),e(" Debug Logs")],-1),d=s("blockquote",null,[s("p",null,[e("Log is the most important part of the debugging process, "),s("code",null,"YukiHookAPI"),e(" encapsulates a set of stable and efficient debugging log functions for developers.")])],-1),u={class:"custom-container tip"},g=s("p",{class:"custom-container-title"},"Tips",-1),h=s("code",null,"KavaRef",-1),y={href:"https://highcapable.github.io/KavaRef/en/library/kavaref-core#log-management",target:"_blank",rel:"noopener noreferrer"},m=s("code",null,"KavaRef",-1),b=s("p",null,[s("code",null,"YukiHookAPI"),e(" has taken over the logging function of "),s("code",null,"KavaRef"),e(" by default, and you can also configure the logging function of "),s("code",null,"KavaRef"),e(" yourself.")],-1),v=i(`小提示
更多功能请参考 YLog.inMemoryData、YLog.contents、YLog.contents、YLog.saveToFile 方法以及 YLog.Configs。
# Normal Logs
You can call
YLog.debug
,YLog.info
,YLog.warn
to print normal logs to the console.The usage method is as follows.
The following example
YLog.debug(msg = "This is a log") +
At this ponit,
YukiHookAPI
will callandroid.util.Log
and log function in (Xposed) Host environment to print this log at the same time.The default
TAG
of the log is the value you set inYLog.Configs.tag
.You can also customize this value dynamically, but it is not recommended to modify
TAG
easily to prevent logs from being filtered.The following example
YLog.debug(tag = "YukiHookAPI", msg = "This is a log") +
The printed result is as shown below.
The following example
[YukiHookAPI][D][host package name] This is a log +
You can also use
YLog.EnvType
to customize the type of log printing.You can choose to use
android.util.Log
or the log function in the (Xposed) Host environment to print logs.The default type is
YLog.EnvType.BOTH
, which means that both methods are used to print logs.For example we only use
android.util.Log
to print logs.The following example
YLog.debug(tag = "YukiHookAPI", msg = "This is a log", env = YLog.EnvType.LOGD) +
Or just use the log function that in the (Xposed) Host environment to print the log, this method can only be used in the (Xposed) Host environment.
The following example
YLog.debug(tag = "YukiHookAPI", msg = "This is a log", env = YLog.EnvType.XPOSED_ENVIRONMENT) +
If you want to intelligently distinguish the (Xposed) Host environment from the Module environment, you can write it in the following form.
The following example
YLog.debug(tag = "YukiHookAPI", msg = "This is a log", env = YLog.EnvType.SCOPE) +
In this way, the API will intelligently select the specified method type to print this log in different environments.
Tips
For more functions, please refer to YLog.debug, YLog.info and YLog.warn methods.
# Error Logs
You can call
YLog.error
to printE
level logs to the console.The usage method is as follows.
The following example
YLog.error(msg = "This is an error") +
The error log is the highest level, regardless of whether you have filtered only
E
level logs.For error-level logging, you can also append an exception stack.
// Assume this is the exception that was thrown +val throwable = Throwable(...) +// Print log +YLog.error(msg = "This is an error", e = throwable) +
The printed result is as shown below.
The following example
[YukiHookAPI][E][host package name] This is an error +
At the same time, the log will help you print the entire exception stack.
The following example
java.lang.Throwable + at com.demo.Test.<init>(...) + at com.demo.Test.doTask(...) + at com.demo.Test.stop(...) + at com.demo.Test.init(...) + at a.a.a(...) + ... 3 more +
In the error log, you can also use
YLog.EnvType
to specify the method type currently used to print the log.Tips
For more functions, please refer to the YLog.error method.
# Save Logs and Custom Elements
You can save all currently printed logs directly to a file using the
YLog.saveToFile
method.The following example
// Please note +// The saved file path must have read and write permissions +// Otherwise an exception will be thrown +YLog.saveToFile("/sdcard/Documents/debug_log.log") +
You can also use
YLog.contents
to get all the log file contents that have been printed so far.The following example
// Get the contents of all log files that have been printed so far +val fileContent = YLog.contents +
If you need an array of real-time log data structures, you can directly get the content of
YLog.inMemoryData
.The following example
// Get the currently printed real-time log data structure array +YLog.inMemoryData.forEach { + it.timestamp // Get timestamp + it.time // Get UTC time + it.priority // Get priority + it.msg // Get message + it.throwable // Get exception + // ... +} +
If you want to format or save the obtained custom log data to a file, you only need to use the following method.
The following example
// Assume this is the custom log data you get +val data: List<YLogData> +// Format log data to String +val dataString = YLog.contents(data) +// Save log data to file +// Please note +// The saved file path must have read and write permissions +// Otherwise an exception will be thrown +YLog.saveToFile("/sdcard/Documents/debug_log.log", data) +
Pay Attention
You need to enable YLog.Configs.isRecord to get the contents of YLog.inMemoryData.
The obtained log data is isolated from each other in the Host App and the Module App's process.
You can only get the corresponding log data in the corresponding process.
If you need to get these log data in real time anywhere, please refer to Xposed Module and Host Channel, Register Module App's Activity.
If you only want to get log data in real time through Module App or Host App, Please refer to the optional solution YukiHookDataChannel.obtainLoggerInMemoryData method.
You can also use
YLog.Configs.elements
to customize the elements that debug logs display externally.This function requires
YukiHookAPI.Configs
to be configured inonInit
of the Hook entry class.The following example
override fun onInit() = configs { + debugLog { + // ... + elements(TAG, PRIORITY, PACKAGE_NAME, USER_ID) + } + // ... +} +
`,62);function A(k,D){const o=n("ExternalLinkIcon");return l(),t("div",null,[r,d,s("div",u,[g,s("p",null,[e("The logs of "),h,e(" can be managed separately by itself. For detailed configuration plans, you can refer to "),s("a",y,[e("here"),p(o)]),e(", which will jump to the "),m,e(" document.")]),b]),v])}const B=a(c,[["render",A],["__file","logger.html.vue"]]);export{B as default}; diff --git a/assets/logger.html-Dfs7bQRS.js b/assets/logger.html-Dfs7bQRS.js new file mode 100644 index 00000000..f769fda8 --- /dev/null +++ b/assets/logger.html-Dfs7bQRS.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-33c1dc26","path":"/en/api/special-features/logger.html","title":"Debug Logs","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"Normal Logs","slug":"normal-logs","link":"#normal-logs","children":[]},{"level":2,"title":"Error Logs","slug":"error-logs","link":"#error-logs","children":[]},{"level":2,"title":"Save Logs and Custom Elements","slug":"save-logs-and-custom-elements","link":"#save-logs-and-custom-elements","children":[]}],"git":{"updatedTime":1750149121000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":11}]},"filePathRelative":"en/api/special-features/logger.md"}');export{e as data}; diff --git a/assets/move-to-api-1-2-x.html-CCb8Xv2u.js b/assets/move-to-api-1-2-x.html-CCb8Xv2u.js new file mode 100644 index 00000000..0cd5f30a --- /dev/null +++ b/assets/move-to-api-1-2-x.html-CCb8Xv2u.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-de1c6dbe","path":"/en/config/move-to-api-1-2-x.html","title":"Migrate to YukiHookAPI 1.2.x","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"Default Behavior Changes","slug":"default-behavior-changes","link":"#default-behavior-changes","children":[]},{"level":2,"title":"New API","slug":"new-api","link":"#new-api","children":[]},{"level":2,"title":"Differential Functions","slug":"differential-functions","link":"#differential-functions","children":[{"level":3,"title":"New Multi-Hook Usage","slug":"new-multi-hook-usage","link":"#new-multi-hook-usage","children":[]},{"level":3,"title":"New allMembers(...) Usage","slug":"new-allmembers-usage","link":"#new-allmembers-usage","children":[]}]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":3}]},"filePathRelative":"en/config/move-to-api-1-2-x.md"}');export{e as data}; diff --git a/assets/move-to-api-1-2-x.html-D8SebGDZ.js b/assets/move-to-api-1-2-x.html-D8SebGDZ.js new file mode 100644 index 00000000..75b0f3b5 --- /dev/null +++ b/assets/move-to-api-1-2-x.html-D8SebGDZ.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-4b553790","path":"/zh-cn/config/move-to-api-1-2-x.html","title":"迁移至 YukiHookAPI 1.2.x","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"默认行为变更","slug":"默认行为变更","link":"#默认行为变更","children":[]},{"level":2,"title":"新版 API","slug":"新版-api","link":"#新版-api","children":[]},{"level":2,"title":"差异性功能","slug":"差异性功能","link":"#差异性功能","children":[{"level":3,"title":"新的多重 Hook 用法","slug":"新的多重-hook-用法","link":"#新的多重-hook-用法","children":[]},{"level":3,"title":"新的 allMembers(...) 用法","slug":"新的-allmembers-用法","link":"#新的-allmembers-用法","children":[]}]}],"git":{"updatedTime":1750318245000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":4}]},"filePathRelative":"zh-cn/config/move-to-api-1-2-x.md"}');export{e as data}; diff --git a/assets/move-to-api-1-2-x.html-IonwGaOH.js b/assets/move-to-api-1-2-x.html-IonwGaOH.js new file mode 100644 index 00000000..20f46e55 --- /dev/null +++ b/assets/move-to-api-1-2-x.html-IonwGaOH.js @@ -0,0 +1,67 @@ +import{_ as l,r as o,o as p,c,b as n,d as s,e as i,a}from"./app-BpUB8-Q8.js";const r={},t=a('Tips
For more functions, please refer to YLog.inMemoryData, YLog.contents, YLog.contents, YLog.saveToFile methods and YLog.Configs.
# 迁移至 YukiHookAPI 1.2.x
YukiHookAPI
从1.2.0
版本开始进行了大量调整,你可以继续向下阅读以查看有哪些注意事项和新功能。注意
如果你正在使用
1.2.x
之前版本的YukiHookAPI
,建议先参考此文档迁移至1.2.x
版本。如果你正在使用
1.2.x
版本的YukiHookAPI
,请直接阅读 迁移至 YukiHookAPI 1.3.x 而不是此文档。# 默认行为变更
从
1.2.0
版本开始,@InjectYukiHookWithXposed
中isUsingResourcesHook
功能默认不再启用,如有需要请手动启用。注意
Resources Hook (资源钩子) 将在 2.0.0 版本被移除,现已被标记 LegacyResourcesHook,你可以使用 @OptIn(LegacyResourcesHook::class) 的方式消除警告以继续在 1.x.x 版本使用。
# 新版 API
',7),d=n("code",null,"YukiHookAPI",-1),A=n("code",null,"1.2.0",-1),u=n("code",null,"2.0.0",-1),D={href:"https://github.com/HighCapable/YukiHookAPI/issues/33",target:"_blank",rel:"noopener noreferrer"},B=n("code",null,"2.0.0",-1),y=a(`注意
所有旧版 API 已被标记 LegacyHookApi,你可以使用 @OptIn(LegacyHookApi::class) 的方式消除警告以继续使用旧版 API。
例如,我们要 Hook
com.example.Test
类中的test
方法。旧版 API
findClass("com.example.Test").hook { + injectMember { + method { + name = "test" + } + beforeHook { + // Your code here. + } + afterHook { + // Your code here. + } + } +} +
新版 API
"com.example.Test".toClass() + .method { + name = "test" + }.hook { + before { + // Your code here. + } + after { + // Your code here. + } + } +
新版 API 的 Hook 对象从
Class
迁移至了Member
,这种方式将更加直观。# 差异性功能
下面是对接新版 API 的部分差异性功能。
# 新的多重 Hook 用法
之前我们需要这样去 Hook 所有匹配条件的方法。
示例如下
injectMembers { + method { + name { it.contains("some") } + }.all() + afterHook { + // Your code here. + } +} +
现在,你可以改用下面这种方式。
示例如下
method { + name { it.contains("some") } +}.hookAll { + after { + // Your code here. + } +} +
# 新的
allMembers(...)
用法之前我们需要这样去 Hook 所有方法、构造方法。
示例如下
injectMembers { + allMembers(MembersType.METHOD) + afterHook { + // Your code here. + } +} +
injectMembers { + allMembers(MembersType.CONSTRUCTOR) + afterHook { + // Your code here. + } +} +
现在,你可以改用下面这种方式。
示例如下
method().hookAll { + after { + // Your code here. + } +} +
constructor().hookAll { + after { + // Your code here. + } +} +
当不填写查找条件时,默认获取当前
Class
中的所有成员对象。如果你想 Hook
MembersType.ALL
,目前暂时没有可以直接对接的方法,但是你可以将所有成员对象拼接后进行 Hook。示例如下
(method().giveAll() + constructor().giveAll()).hookAll { + after { + // Your code here. + } +} +
但我们并不推荐这种做法,一次性 Hook 过多的成员是不可控的,还会发生问题。
`,30);function v(m,C){const e=o("ExternalLinkIcon");return p(),c("div",null,[t,n("p",null,[d,s(" 在 "),A,s(" 版本引入了 "),u,s(" 准备实现的 "),n("a",D,[s("New Hook Code Style"),i(e)]),s(" (新版 API),现处于实验性阶段,你可以在 "),B,s(" 版本正式发布前,开始迁移并体验新版 API。")]),y])}const k=l(r,[["render",v],["__file","move-to-api-1-2-x.html.vue"]]);export{k as default}; diff --git a/assets/move-to-api-1-2-x.html-etgyp2HF.js b/assets/move-to-api-1-2-x.html-etgyp2HF.js new file mode 100644 index 00000000..47a63ba3 --- /dev/null +++ b/assets/move-to-api-1-2-x.html-etgyp2HF.js @@ -0,0 +1,67 @@ +import{_ as l,r as o,o as i,c as p,b as n,d as s,e as c,a as e}from"./app-BpUB8-Q8.js";const t={},r=e('# Migrate to YukiHookAPI 1.2.x
YukiHookAPI
has undergone a lot of adjustments since version1.2.0
, you can read on to see what are the notes and new features.Notice
If you are using the YukiHookAPI previous version of
1.2.x
, it is recommended to refer to this document to migrate to the1.2.x
version first.If you are using the
1.2.x
version ofYukiHookAPI
, please read directly Migrate to YukiHookAPI 1.3.x instead of this document.# Default Behavior Changes
Since version
1.2.0
, theisUsingResourcesHook
function in@InjectYukiHookWithXposed
is no longer enabled by default, please enable it manually if necessary.Notice
Resources Hook will be removed in version 2.0.0 and is now marked LegacyResourcesHook.
You can use @OptIn(LegacyResourcesHook::class) to eliminate the warning, continue to use version 1.x.x.
# New API
',7),d=n("code",null,"YukiHookAPI",-1),u={href:"https://github.com/HighCapable/YukiHookAPI/issues/33",target:"_blank",rel:"noopener noreferrer"},A=n("code",null,"2.0.0",-1),m=n("code",null,"1.2.0",-1),y=e(`You can before the
2.0.0
version is officially released, start migrating and experience the New API.Notice
All legacy APIs have been marked LegacyHookApi, you can use @OptIn(LegacyHookApi::class) to eliminate the warning and continue to use the legacy API.
For example, we want to Hook the
test
method in thecom.example.Test
class.Legacy API
findClass("com.example.Test").hook { + injectMember { + method { + name = "test" + } + beforeHook { + // Your code here. + } + afterHook { + // Your code here. + } + } +} +
New API
"com.example.Test".toClass() + .method { + name = "test" + }.hook { + before { + // Your code here. + } + after { + // Your code here. + } + } +
The Hook object of the New API has been migrated from
Class
toMember
, which will be more intuitive.# Differential Functions
The following are some of the different functions of connecting to the new version of the API.
# New Multi-Hook Usage
Previously we needed to hook all methods that match conditions like this.
The following example
injectMembers { + method { + name { it.contains("some") } + }.all() + afterHook { + // Your code here. + } +} +
Now, you can use the following method instead.
The following example
method { + name { it.contains("some") } +}.hookAll { + after { + // Your code here. + } +} +
# New
allMembers(...)
UsagePreviously we needed to hook all methods and constructors like this.
The following example
injectMembers { + allMembers(MembersType.METHOD) + afterHook { + // Your code here. + } +} +
injectMembers { + allMembers(MembersType.CONSTRUCTOR) + afterHook { + // Your code here. + } +} +
Now, you can use the following method instead.
The following example
method().hookAll { + after { + // Your code here. + } +} +
constructor().hookAll { + after { + // Your code here. + } +} +
When the find conditions are not filled in, all members in the current
Class
are obtained by default.If you want to hook
MembersType.ALL
, there is currently no direct method, but you can concatenate all members and then hook.The following example
(method().giveAll() + constructor().giveAll()).hookAll { + after { + // Your code here. + } +} +
But we do not recommend this approach, too many hook members at one time are uncontrollable and problems may occur.
`,31);function v(D,B){const a=o("ExternalLinkIcon");return i(),p("div",null,[r,n("p",null,[d,s(" introduced the "),n("a",u,[s("New Hook Code Style"),c(a)]),s(" (New API) of "),A,s(" in the "),m,s(" version, it is now in the experimental stage.")]),y])}const h=l(t,[["render",v],["__file","move-to-api-1-2-x.html.vue"]]);export{h as default}; diff --git a/assets/move-to-api-1-3-x.html-C6uNfo-e.js b/assets/move-to-api-1-3-x.html-C6uNfo-e.js new file mode 100644 index 00000000..f66cde7e --- /dev/null +++ b/assets/move-to-api-1-3-x.html-C6uNfo-e.js @@ -0,0 +1,18 @@ +import{_ as t,r as l,o as i,c as r,b as e,d as o,e as s,a as n}from"./app-BpUB8-Q8.js";const c={},d=n('# Migrate to YukiHookAPI 1.3.x
YukiHookAPI
has deprecated its own reflection API since1.3.0
, you can read on to see what are the notes and new features.Notice
If you are using
1.2.x
and previous versions ofYukiHookAPI
, it is recommended to read Migrate to YukiHookAPI 1.2.x instead of this document.# Self-reflection API Deprecated
',4),p=e("code",null,"YukiHookAPI",-1),h=e("code",null,"1.3.0",-1),u={href:"https://github.com/HighCapable/KavaRef",target:"_blank",rel:"noopener noreferrer"},m=e("code",null,"YukiHookAPI",-1),v={href:"https://highcapable.github.io/KavaRef/en/config/migration",target:"_blank",rel:"noopener noreferrer"},A=e("code",null,"KavaRef",-1),y=e("p",null,[e("code",null,"YukiHookAPI"),o(" has now implemented complete decoupling of the reflection API. The reflection API used by its internal API has also been migrated to "),e("code",null,"KavaRef"),o(" and has been tested stably.")],-1),f=e("p",null,[o("In later versions of "),e("code",null,"2.0.0"),o(", the self-reflection API will be completely removed, during which time you will have enough time to learn and migrate to this brand new set of reflection APIs.")],-1),b=e("h2",{id:"freereflection-deprecated",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#freereflection-deprecated","aria-hidden":"true"},"#"),o(" FreeReflection Deprecated")],-1),g=e("code",null,"YukiHookAPI",-1),k={href:"https://github.com/tiann/FreeReflection",target:"_blank",rel:"noopener noreferrer"},B=e("code",null,"1.3.0",-1),D={href:"https://github.com/LSPosed/AndroidHiddenApiBypass",target:"_blank",rel:"noopener noreferrer"},_=n(`When the reflection system hides the API, you cannot reflect directly like before, but need to do some operations.
YukiHookAPI has built-in
AndroidHiddenApiBypassResolver
inKavaRef
's third-party Member parser, and now you can use it like this where you need the reflection system to hide the API.The following example
`,4),C={class:"custom-container warning"},w=e("p",{class:"custom-container-title"},"Notice",-1),P=e("code",null,"AndroidHiddenApiBypassResolver",-1),I=e("code",null,"2.0.0",-1),x={href:"https://highcapable.github.io/KavaRef/en/config/processor-resolvers",target:"_blank",rel:"noopener noreferrer"},F=e("code",null,"KavaRef",-1),H=n(`"android.app.ActivityThread".toClass() + .resolve() + // Add a custom Member parser + .processor(AndroidHiddenApiBypassResolver.get()) + .firstMethod { + name = "currentActivityThread" + emptyParameters() + }.invoke() +
# Original Method Call
Xposed
provides theXposedBridge.invokeOriginalMethod
function, which can call original methods without a Hook.Due to deprecation of the self-reflection API, the method
method { ... }.get().original().call(...)
will no longer be available.So, YukiHookAPI has added an extension to
KavaRef
, and you can still implement this feature now.
YukiHookAPI
provides the following methods to connect to the original method calls ofKavaRef
.
invokeOriginal(...)
→invoke(...)
invokeOriginalQuietly(...)
→invokeQuietly(...)
The following example
// Suppose this is an instance of the Test class +val instance: Any +// Original call to the method using KavaRef +"com.example.Test".toClass() + .resolve() + .firstMethod { + name = "test" + emptyParameters() + }.of(instance).invokeOriginal() +
# Repeat Hook Restricted Deprecated
YukiHookAPI
has deprecated the restriction of duplicate Hook since the1.3.0
version. Now,YukiHookAPI
no longer limits duplicate Hooks to the same method, you can hook multiple times on the same method.
YukiHookAPI
also deprecated theonAlreadyHooked
method ofhook { ... }
. Now this method will be useless and will not be called back. If necessary, please manually handle the relevant logic of duplicate Hooks.# Register Module App's Activity Behavior Change
YukiHookAPI
starting with1.3.0
, the way in which the moduleActivity
behavior has changed.Please read Register Module App's Activity for more information.
# YLog Behavior Change
`,16);function R(Y,q){const a=l("ExternalLinkIcon");return i(),r("div",null,[d,e("p",null,[p,o(" has deprecated its own reflection API since the "),h,o(" version. Now we recommend that all developers move to a brand new development. "),e("a",u,[o("KavaRef"),s(a)]),o(", we no longer recommend the reflection API of "),m,o(" itself, which have been marked as deprecated.")]),e("p",null,[o("Please refer to the migration document "),e("a",v,[o("here"),s(a)]),o(" which will jump to the "),A,o(" document.")]),y,f,b,e("p",null,[g,o(" has deprecated "),e("a",k,[o("FreeReflection"),s(a)]),o(" since the "),B,o(" version and migrated to a maintained by the LSPosed team "),e("a",D,[o("AndroidHiddenApiBypass"),s(a)]),o(".")]),_,e("div",C,[w,e("p",null,[P,o(" is a tentative feature and may be migrated to a separate module in the "),I,o(" version, you can also refer to "),e("a",x,[o("Third-party Member Resolvers"),s(a)]),o(" implement one by yourself, which will jump to the "),F,o(" document.")])]),H])}const M=t(c,[["render",R],["__file","move-to-api-1-3-x.html.vue"]]);export{M as default}; diff --git a/assets/move-to-api-1-3-x.html-CPnNzAVm.js b/assets/move-to-api-1-3-x.html-CPnNzAVm.js new file mode 100644 index 00000000..9991a33c --- /dev/null +++ b/assets/move-to-api-1-3-x.html-CPnNzAVm.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-99933722","path":"/zh-cn/config/move-to-api-1-3-x.html","title":"迁移至 YukiHookAPI 1.3.x","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"自身反射 API 弃用","slug":"自身反射-api-弃用","link":"#自身反射-api-弃用","children":[]},{"level":2,"title":"FreeReflection 弃用","slug":"freereflection-弃用","link":"#freereflection-弃用","children":[]},{"level":2,"title":"方法原始调用","slug":"方法原始调用","link":"#方法原始调用","children":[]},{"level":2,"title":"重复 Hook 限制弃用","slug":"重复-hook-限制弃用","link":"#重复-hook-限制弃用","children":[]},{"level":2,"title":"注册模块 Activity 行为变更","slug":"注册模块-activity-行为变更","link":"#注册模块-activity-行为变更","children":[]},{"level":2,"title":"YLog 行为变更","slug":"ylog-行为变更","link":"#ylog-行为变更","children":[]}],"git":{"updatedTime":1750318245000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":5}]},"filePathRelative":"zh-cn/config/move-to-api-1-3-x.md"}');export{e as data}; diff --git a/assets/move-to-api-1-3-x.html-DBMmjUYq.js b/assets/move-to-api-1-3-x.html-DBMmjUYq.js new file mode 100644 index 00000000..db2f1176 --- /dev/null +++ b/assets/move-to-api-1-3-x.html-DBMmjUYq.js @@ -0,0 +1,18 @@ +import{_ as l,r as c,o as i,c as t,b as e,d as o,e as n,a}from"./app-BpUB8-Q8.js";const d={},r=a('
YukiHookAPI
allows themsg
parameter ofYLog
to be passed into any object starting from1.3.0
, and they will be automatically converted using thetoString()
method.# 迁移至 YukiHookAPI 1.3.x
YukiHookAPI
从1.3.0
版本开始弃用了自身的反射 API,你可以继续向下阅读以查看有哪些注意事项和新功能。注意
如果你正在使用
1.2.x
及之前版本的YukiHookAPI
,建议先阅读 迁移至 YukiHookAPI 1.2.x 而不是此文档。# 自身反射 API 弃用
',4),p=e("code",null,"YukiHookAPI",-1),A=e("code",null,"1.3.0",-1),h={href:"https://github.com/HighCapable/KavaRef",target:"_blank",rel:"noopener noreferrer"},u=e("code",null,"YukiHookAPI",-1),v={href:"https://highcapable.github.io/KavaRef/zh-cn/config/migration",target:"_blank",rel:"noopener noreferrer"},y=e("code",null,"KavaRef",-1),k=e("p",null,[e("code",null,"YukiHookAPI"),o(" 目前已经实现了反射 API 的完全解耦合,其内部 API 使用的反射 API 同样迁移至了 "),e("code",null,"KavaRef"),o(",且已经稳定测试通过。")],-1),B=e("p",null,[o("在后期的 "),e("code",null,"2.0.0"),o(" 版本中,自身反射 API 将被完全移除,在此期间,你将有足够的时间来学习和迁移至这套全新的反射 API。")],-1),_=e("h2",{id:"freereflection-弃用",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#freereflection-弃用","aria-hidden":"true"},"#"),o(" FreeReflection 弃用")],-1),D=e("code",null,"YukiHookAPI",-1),m=e("code",null,"1.3.0",-1),b={href:"https://github.com/tiann/FreeReflection",target:"_blank",rel:"noopener noreferrer"},f={href:"https://github.com/LSPosed/AndroidHiddenApiBypass",target:"_blank",rel:"noopener noreferrer"},C=a(`在反射系统隐藏 API 时,你不可以像之前那样直接进行反射,而是需要进行一些操作。
YukiHookAPI
内置了KavaRef
的第三方 Member 解析器
中的AndroidHiddenApiBypassResolver
,现在你可以在需要反射系统隐藏 API 的地方这样去使用它。示例如下
`,4),g={class:"custom-container warning"},P=e("p",{class:"custom-container-title"},"注意",-1),I=e("code",null,"AndroidHiddenApiBypassResolver",-1),H=e("code",null,"2.0.0",-1),F={href:"https://highcapable.github.io/KavaRef/zh-cn/config/processor-resolvers",target:"_blank",rel:"noopener noreferrer"},x=e("code",null,"KavaRef",-1),Y=a(`"android.app.ActivityThread".toClass() + .resolve() + // 添加自定义 Member 解析器 + .processor(AndroidHiddenApiBypassResolver.get()) + .firstMethod { + name = "currentActivityThread" + emptyParameters() + }.invoke() +
# 方法原始调用
Xposed
提供了XposedBridge.invokeOriginalMethod
功能,可以调用未经 Hook 的原始方法。由于自身反射 API 的弃用,
method { ... }.get().original().call(...)
的方式将不再可用。所以,
YukiHookAPI
为KavaRef
添加了扩展功能,现在你依然可以实现这个功能。
YukiHookAPI
提供了以下方法来对接KavaRef
的原始方法调用。
invokeOriginal(...)
→invoke(...)
invokeOriginalQuietly(...)
→invokeQuietly(...)
示例如下
// 假设这就是 Test 类的实例 +val instance: Any +// 使用 KavaRef 的方法原始调用 +"com.example.Test".toClass() + .resolve() + .firstMethod { + name = "test" + emptyParameters() + }.of(instance).invokeOriginal() +
# 重复 Hook 限制弃用
YukiHookAPI
从1.3.0
版本开始弃用了重复 Hook 的限制,现在,YukiHookAPI
不再限制重复 Hook 同一个方法,你可以在同一个方法上多次 Hook。
YukiHookAPI
同时弃用了hook { ... }
的onAlreadyHooked
方法,现在此方法将无作用且不会被回调,如有需要,请手动处理重复 Hook 的相关逻辑。# 注册模块 Activity 行为变更
YukiHookAPI
从1.3.0
版本开始,注册模块Activity
行为的方式发生了变更。请阅读 注册模块 Activity 以了解更多信息。
# YLog 行为变更
`,16);function R(q,K){const s=c("ExternalLinkIcon");return i(),t("div",null,[r,e("p",null,[p,o(" 从 "),A,o(" 版本开始弃用了自身的反射 API,现在我们推荐所有开发者迁移至全新开发的 "),e("a",h,[o("KavaRef"),n(s)]),o(",我们不再推荐使用 "),u,o(" 自身的反射 API,这些 API 已被标记为弃用。")]),e("p",null,[o("请参考 "),e("a",v,[o("这里"),n(s)]),o(" 的迁移文档,这将跳转到 "),y,o(" 的文档。")]),k,B,_,e("p",null,[D,o(" 从 "),m,o(" 版本开始弃用了 "),e("a",b,[o("FreeReflection"),n(s)]),o(" 并迁移至由 LSPosed 团队维护的 "),e("a",f,[o("AndroidHiddenApiBypass"),n(s)]),o("。")]),C,e("div",g,[P,e("p",null,[I,o(" 是暂定的功能,可能会在 "),H,o(" 版本迁移至单独的模块中,你也可以参考 "),e("a",F,[o("第三方 Member 解析器"),n(s)]),o(" 自己实现一份,这将跳转到 "),x,o(" 的文档。")])]),Y])}const L=l(d,[["render",R],["__file","move-to-api-1-3-x.html.vue"]]);export{L as default}; diff --git a/assets/move-to-api-1-3-x.html-f3TZzPCU.js b/assets/move-to-api-1-3-x.html-f3TZzPCU.js new file mode 100644 index 00000000..3ee6143b --- /dev/null +++ b/assets/move-to-api-1-3-x.html-f3TZzPCU.js @@ -0,0 +1 @@ +const e=JSON.parse(`{"key":"v-0e5a1400","path":"/en/config/move-to-api-1-3-x.html","title":"Migrate to YukiHookAPI 1.3.x","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"Self-reflection API Deprecated","slug":"self-reflection-api-deprecated","link":"#self-reflection-api-deprecated","children":[]},{"level":2,"title":"FreeReflection Deprecated","slug":"freereflection-deprecated","link":"#freereflection-deprecated","children":[]},{"level":2,"title":"Original Method Call","slug":"original-method-call","link":"#original-method-call","children":[]},{"level":2,"title":"Repeat Hook Restricted Deprecated","slug":"repeat-hook-restricted-deprecated","link":"#repeat-hook-restricted-deprecated","children":[]},{"level":2,"title":"Register Module App's Activity Behavior Change","slug":"register-module-app-s-activity-behavior-change","link":"#register-module-app-s-activity-behavior-change","children":[]},{"level":2,"title":"YLog Behavior Change","slug":"ylog-behavior-change","link":"#ylog-behavior-change","children":[]}],"git":{"updatedTime":1750317936000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":5}]},"filePathRelative":"en/config/move-to-api-1-3-x.md"}`);export{e as data}; diff --git a/assets/move-to-new-api.html-Bd10LyS9.js b/assets/move-to-new-api.html-Bd10LyS9.js new file mode 100644 index 00000000..bb0eef6e --- /dev/null +++ b/assets/move-to-new-api.html-Bd10LyS9.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-77d752a2","path":"/en/guide/move-to-new-api.html","title":"Migrate from Other Hook APIs","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"Rovo89 Xposed API","slug":"rovo89-xposed-api","link":"#rovo89-xposed-api","children":[{"level":3,"title":"Migrate Hook Entry Point","slug":"migrate-hook-entry-point","link":"#migrate-hook-entry-point","children":[]},{"level":3,"title":"Migrate Hook Method Body","slug":"migrate-hook-method-body","link":"#migrate-hook-method-body","children":[]},{"level":3,"title":"Notes on Migrating XposedHelpers","slug":"notes-on-migrating-xposedhelpers","link":"#notes-on-migrating-xposedhelpers","children":[]}]},{"level":2,"title":"Migrate More Functions Related to Hook API","slug":"migrate-more-functions-related-to-hook-api","link":"#migrate-more-functions-related-to-hook-api","children":[]}],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":8}]},"filePathRelative":"en/guide/move-to-new-api.md"}');export{e as data}; diff --git a/assets/move-to-new-api.html-CtQJCJWD.js b/assets/move-to-new-api.html-CtQJCJWD.js new file mode 100644 index 00000000..86ef5bcc --- /dev/null +++ b/assets/move-to-new-api.html-CtQJCJWD.js @@ -0,0 +1,208 @@ +import{_ as p,r as t,o as i,c as d,b as s,d as e,e as l,w as n,a as o}from"./app-BpUB8-Q8.js";const A={},y=s("h1",{id:"migrate-from-other-hook-apis",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#migrate-from-other-hook-apis","aria-hidden":"true"},"#"),e(" Migrate from Other Hook APIs")],-1),u=s("p",null,[e("This document can help you quickly migrate from the Hook APIs you are familiar with to "),s("code",null,"YukiHookAPI"),e(" to become familiar with the related writing methods of "),s("code",null,"YukiHookAPI"),e(".")],-1),D=s("h2",{id:"rovo89-xposed-api",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#rovo89-xposed-api","aria-hidden":"true"},"#"),e(" Rovo89 Xposed API")],-1),B={href:"https://api.xposed.info/",target:"_blank",rel:"noopener noreferrer"},m=s("code",null,"YukiHookAPI",-1),C=o('
YukiHookAPI
从1.3.0
版本开始允许YLog
的msg
参数传入任意对象,它们都会自动使用toString()
方法进行转换。# Migrate Hook Entry Point
Migrated from
XC_LoadPackage.LoadPackageParam
toPackageParam
.
YukiHookAPI
implements the lambda method bodythis
usage forPackageParam
, and thePackageParam
object can be obtained globally in theencase
method body.',4),h=s("div",{class:"language-kotlin line-numbers-mode","data-ext":"kt"},[s("pre",{class:"shiki github-dark-dimmed",style:{"background-color":"#22272e"},tabindex:"0"},[s("code",null,[s("span",{class:"line"},[s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"onHook"),s("span",{style:{color:"#ADBAC7"}},"() "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"encase"),s("span",{style:{color:"#ADBAC7"}}," {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Get the package name of the current Hook")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," packageName")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Get the ApplicationInfo of the current Hook")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," appInfo")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Get the system context object")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," systemContext")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Get the host Application lifecycle")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," appContext")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Hook specified app")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"loadApp"),s("span",{style:{color:"#ADBAC7"}},"(name "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#96D0FF"}},'"com.demo.test"'),s("span",{style:{color:"#ADBAC7"}},") {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Member Hook")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#96D0FF"}},'"com.demo.test.TestClass"'),s("span",{style:{color:"#ADBAC7"}},"."),s("span",{style:{color:"#DCBDFB"}},"toClass"),s("span",{style:{color:"#ADBAC7"}},"()")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," ."),s("span",{style:{color:"#DCBDFB"}},"resolve"),s("span",{style:{color:"#ADBAC7"}},"()")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," ."),s("span",{style:{color:"#DCBDFB"}},"firstMethod"),s("span",{style:{color:"#ADBAC7"}}," {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," name "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#96D0FF"}},'"test"')]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"parameters"),s("span",{style:{color:"#ADBAC7"}},"(Boolean::"),s("span",{style:{color:"#DCBDFB"}},"class"),s("span",{style:{color:"#ADBAC7"}},")")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }."),s("span",{style:{color:"#DCBDFB"}},"hook"),s("span",{style:{color:"#ADBAC7"}}," {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"after"),s("span",{style:{color:"#ADBAC7"}}," {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// ...")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Resources Hook (fixed usage)")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"resources"),s("span",{style:{color:"#ADBAC7"}},"()."),s("span",{style:{color:"#DCBDFB"}},"hook"),s("span",{style:{color:"#ADBAC7"}}," {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"injectResource"),s("span",{style:{color:"#ADBAC7"}}," {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"conditions"),s("span",{style:{color:"#ADBAC7"}}," {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," name "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#96D0FF"}},'"ic_launcher"')]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"mipmap"),s("span",{style:{color:"#ADBAC7"}},"()")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"replaceToModuleResource"),s("span",{style:{color:"#ADBAC7"}},"(R.mipmap.ic_launcher)")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}},"}")]),e(` +`),s("span",{class:"line"})])]),s("div",{class:"line-numbers","aria-hidden":"true"},[s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"})])],-1),b=s("div",{class:"language-kotlin line-numbers-mode","data-ext":"kt"},[s("pre",{class:"shiki github-dark-dimmed",style:{"background-color":"#22272e"},tabindex:"0"},[s("code",null,[s("span",{class:"line"},[s("span",{style:{color:"#F47067"}},"private"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"lateinit"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"var"),s("span",{style:{color:"#ADBAC7"}}," moduleResources: "),s("span",{style:{color:"#F69D50"}},"XModuleResources")]),e(` +`),s("span",{class:"line"}),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"initZygote"),s("span",{style:{color:"#ADBAC7"}},"(sparam: "),s("span",{style:{color:"#F69D50"}},"IXposedHookZygoteInit"),s("span",{style:{color:"#ADBAC7"}},".StartupParam) {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," moduleResources "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," XModuleResources."),s("span",{style:{color:"#DCBDFB"}},"createInstance"),s("span",{style:{color:"#ADBAC7"}},"(sparam.modulePath, "),s("span",{style:{color:"#6CB6FF"}},"null"),s("span",{style:{color:"#ADBAC7"}},")")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}},"}")]),e(` +`),s("span",{class:"line"}),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"handleLoadPackage"),s("span",{style:{color:"#ADBAC7"}},"(lpparam: "),s("span",{style:{color:"#F69D50"}},"XC_LoadPackage"),s("span",{style:{color:"#ADBAC7"}},".LoadPackageParam) {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Get the package name of the current Hook")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," lpparam.packageName")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Get the ApplicationInfo of the current Hook")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," lpparam.applicationInfo")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Get the system context object")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// There is no ready-made calling method in the Rovo89 Xposed API, you need to reflect ActivityThread to achieve it")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Get the host Application lifecycle")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," AndroidAppHelper."),s("span",{style:{color:"#DCBDFB"}},"currentApplication"),s("span",{style:{color:"#ADBAC7"}},"()")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Class Hook")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"if"),s("span",{style:{color:"#ADBAC7"}},"(lpparam.packageName "),s("span",{style:{color:"#F47067"}},"=="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#96D0FF"}},'"com.demo.test"'),s("span",{style:{color:"#ADBAC7"}},")")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," XposedHelpers."),s("span",{style:{color:"#DCBDFB"}},"findAndHookMethod"),s("span",{style:{color:"#ADBAC7"}},"(")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#96D0FF"}},'"com.demo.test.TestClass"'),s("span",{style:{color:"#ADBAC7"}},", lpparam.classLoader,")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#96D0FF"}},'"test"'),s("span",{style:{color:"#ADBAC7"}},", Boolean::"),s("span",{style:{color:"#DCBDFB"}},"class"),s("span",{style:{color:"#ADBAC7"}},".java,")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," object : "),s("span",{style:{color:"#F69D50"}},"XC_MethodHook"),s("span",{style:{color:"#ADBAC7"}},"() {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"afterHookedMethod"),s("span",{style:{color:"#ADBAC7"}},"(param: "),s("span",{style:{color:"#F69D50"}},"MethodHookParam"),s("span",{style:{color:"#ADBAC7"}},") {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// ...")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," )")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}},"}")]),e(` +`),s("span",{class:"line"}),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"handleInitPackageResources"),s("span",{style:{color:"#ADBAC7"}},"(resparam: "),s("span",{style:{color:"#F69D50"}},"XC_InitPackageResources"),s("span",{style:{color:"#ADBAC7"}},".InitPackageResourcesParam) {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Get the package name of the current Hook")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," resparam.packageName")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Resources Hook")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," resparam.res."),s("span",{style:{color:"#DCBDFB"}},"setReplacement"),s("span",{style:{color:"#ADBAC7"}},"(")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#96D0FF"}},'"com.demo.test"'),s("span",{style:{color:"#ADBAC7"}},", "),s("span",{style:{color:"#96D0FF"}},'"mipmap"'),s("span",{style:{color:"#ADBAC7"}},", "),s("span",{style:{color:"#96D0FF"}},'"ic_launcher"'),s("span",{style:{color:"#ADBAC7"}},",")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," moduleResources."),s("span",{style:{color:"#DCBDFB"}},"fwd"),s("span",{style:{color:"#ADBAC7"}},"(R.mipmap.ic_launcher)")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," )")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}},"}")]),e(` +`),s("span",{class:"line"})])]),s("div",{class:"line-numbers","aria-hidden":"true"},[s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"})])],-1),v=o('The API function differences are compared as follows
# Migrate Hook Method Body
Migrated from
XC_MethodHook.MethodHookParam
toHookParam
.# Before/After Hook
YukiHookAPI
also implements the lambda method bodythis
usage forHookParam
, and theHookParam
object can be obtained globally in the method bodies such asbefore
andafter
.',5),F=s("div",{class:"language-kotlin line-numbers-mode","data-ext":"kt"},[s("pre",{class:"shiki github-dark-dimmed",style:{"background-color":"#22272e"},tabindex:"0"},[s("code",null,[s("span",{class:"line"},[s("span",{style:{color:"#DCBDFB"}},"after"),s("span",{style:{color:"#ADBAC7"}}," {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Get the current Hook instance")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," instance")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Get the Class instance of the current Hook")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," instanceClass")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Get and cast the current Hook instance to the specified type T")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"instance"),s("span",{style:{color:"#ADBAC7"}},"<"),s("span",{style:{color:"#F69D50"}},"T"),s("span",{style:{color:"#ADBAC7"}},">()")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Get the method parameter array")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," args")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Get the first T of the method parameter")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"args"),s("span",{style:{color:"#ADBAC7"}},"()."),s("span",{style:{color:"#DCBDFB"}},"first"),s("span",{style:{color:"#ADBAC7"}},"()."),s("span",{style:{color:"#DCBDFB"}},"cast"),s("span",{style:{color:"#ADBAC7"}},"<"),s("span",{style:{color:"#F69D50"}},"T"),s("span",{style:{color:"#ADBAC7"}},">()")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Get the last bit of the method parameter T")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"args"),s("span",{style:{color:"#ADBAC7"}},"()."),s("span",{style:{color:"#DCBDFB"}},"last"),s("span",{style:{color:"#ADBAC7"}},"()."),s("span",{style:{color:"#DCBDFB"}},"cast"),s("span",{style:{color:"#ADBAC7"}},"<"),s("span",{style:{color:"#F69D50"}},"T"),s("span",{style:{color:"#ADBAC7"}},">()")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Get any subscript T of the method parameter, here is an example of 2")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"args"),s("span",{style:{color:"#ADBAC7"}},"(index "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#6CB6FF"}},"2"),s("span",{style:{color:"#ADBAC7"}},")."),s("span",{style:{color:"#DCBDFB"}},"cast"),s("span",{style:{color:"#ADBAC7"}},"<"),s("span",{style:{color:"#F69D50"}},"T"),s("span",{style:{color:"#ADBAC7"}},">()")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Set any subscript of the method parameter, here is an example of 2")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"args"),s("span",{style:{color:"#ADBAC7"}},"(index "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#6CB6FF"}},"2"),s("span",{style:{color:"#ADBAC7"}},")."),s("span",{style:{color:"#DCBDFB"}},"set"),s("span",{style:{color:"#ADBAC7"}},"("),s("span",{style:{color:"#F47067"}},".."),s("span",{style:{color:"#ADBAC7"}},".)")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Get the return value")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," result")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Get the return value and cast to T")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"result"),s("span",{style:{color:"#ADBAC7"}},"<"),s("span",{style:{color:"#F69D50"}},"T"),s("span",{style:{color:"#ADBAC7"}},">()")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Modify the content of the return value")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," result "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},".."),s("span",{style:{color:"#ADBAC7"}},".")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Remove the content of the return value")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"resultNull"),s("span",{style:{color:"#ADBAC7"}},"()")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Get the data storage instance within the scope of the current callback method body")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," dataExtra")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Throw an exception to the Hook app")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"Throwable"),s("span",{style:{color:"#ADBAC7"}},"("),s("span",{style:{color:"#96D0FF"}},'"Fatal"'),s("span",{style:{color:"#ADBAC7"}},")."),s("span",{style:{color:"#DCBDFB"}},"throwToApp"),s("span",{style:{color:"#ADBAC7"}},"()")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Execute the original method without hook and call with the original method parameters, generics can be omitted")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"callOriginal"),s("span",{style:{color:"#ADBAC7"}},"<"),s("span",{style:{color:"#F69D50"}},"Any"),s("span",{style:{color:"#ADBAC7"}},"?>()")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Execute the original method without Hook and customize the method parameter call, the generic type can be omitted")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"invokeOriginal"),s("span",{style:{color:"#ADBAC7"}},"<"),s("span",{style:{color:"#F69D50"}},"Any"),s("span",{style:{color:"#ADBAC7"}},"?>("),s("span",{style:{color:"#F47067"}},".."),s("span",{style:{color:"#ADBAC7"}},".)")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}},"}")]),e(` +`),s("span",{class:"line"})])]),s("div",{class:"line-numbers","aria-hidden":"true"},[s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"})])],-1),k=s("div",{class:"language-kotlin line-numbers-mode","data-ext":"kt"},[s("pre",{class:"shiki github-dark-dimmed",style:{"background-color":"#22272e"},tabindex:"0"},[s("code",null,[s("span",{class:"line"},[s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"afterHookedMethod"),s("span",{style:{color:"#ADBAC7"}},"(param: "),s("span",{style:{color:"#F69D50"}},"MethodHookParam"),s("span",{style:{color:"#ADBAC7"}},") {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Get the current Hook instance")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," param.thisObject")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Get the Class instance of the current Hook")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," param.thisObject.javaClass")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Get and cast the current Hook instance to the specified type T")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," param.thisObject "),s("span",{style:{color:"#F47067"}},"as"),s("span",{style:{color:"#ADBAC7"}}," T")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Get the method parameter array")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," param.args")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Get the first T of the method parameter")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," param.args["),s("span",{style:{color:"#6CB6FF"}},"0"),s("span",{style:{color:"#ADBAC7"}},"] "),s("span",{style:{color:"#F47067"}},"as"),s("span",{style:{color:"#ADBAC7"}}," T")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Get the last bit of the method parameter T")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," param.args[param.args.lastIndex] "),s("span",{style:{color:"#F47067"}},"as"),s("span",{style:{color:"#ADBAC7"}}," T")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Get any subscript T of the method parameter, here is an example of 2")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," param.args["),s("span",{style:{color:"#6CB6FF"}},"2"),s("span",{style:{color:"#ADBAC7"}},"] "),s("span",{style:{color:"#F47067"}},"as"),s("span",{style:{color:"#ADBAC7"}}," T")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Set any subscript of the method parameter, here is an example of 2")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," param.args["),s("span",{style:{color:"#6CB6FF"}},"2"),s("span",{style:{color:"#ADBAC7"}},"] "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},".."),s("span",{style:{color:"#ADBAC7"}},".")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Get the return value")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," param.result")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Get the return value and cast to T")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," param.result "),s("span",{style:{color:"#F47067"}},"as"),s("span",{style:{color:"#ADBAC7"}}," T")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Modify the content of the return value")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," param.result "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},".."),s("span",{style:{color:"#ADBAC7"}},".")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Remove the content of the return value")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," param.result "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#6CB6FF"}},"null")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Get the data storage instance within the scope of the current callback method body")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," param.extra")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Throw an exception to the Hook app")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," param.throwable "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"Throwable"),s("span",{style:{color:"#ADBAC7"}},"("),s("span",{style:{color:"#96D0FF"}},'"Fatal"'),s("span",{style:{color:"#ADBAC7"}},")")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Execute the original method without hooking")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," XposedBridge."),s("span",{style:{color:"#DCBDFB"}},"invokeOriginalMethod"),s("span",{style:{color:"#ADBAC7"}},"(param.method, param.thisObject, "),s("span",{style:{color:"#F47067"}},".."),s("span",{style:{color:"#ADBAC7"}},".)")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}},"}")]),e(` +`),s("span",{class:"line"})])]),s("div",{class:"line-numbers","aria-hidden":"true"},[s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"})])],-1),f=s("h4",{id:"replace-hook",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#replace-hook","aria-hidden":"true"},"#"),e(" Replace Hook")],-1),g=s("p",null,[e("The "),s("code",null,"replaceHook"),e(" method is special, and the "),s("code",null,"YukiHookAPI"),e(" makes a variety of forms for it to choose from.")],-1),_=s("blockquote",null,[s("p",null,"The API function differences are compared as follows")],-1),H=s("div",{class:"language-kotlin line-numbers-mode","data-ext":"kt"},[s("pre",{class:"shiki github-dark-dimmed",style:{"background-color":"#22272e"},tabindex:"0"},[s("code",null,[s("span",{class:"line"},[s("span",{style:{color:"#768390"}},"/// A method with no return value void")]),e(` +`),s("span",{class:"line"}),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#DCBDFB"}},"replaceUnit"),s("span",{style:{color:"#ADBAC7"}}," {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Implement the replaced logic directly here")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}},"}")]),e(` +`),s("span",{class:"line"}),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#768390"}},"/// A method with a return value")]),e(` +`),s("span",{class:"line"}),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#DCBDFB"}},"replaceAny"),s("span",{style:{color:"#ADBAC7"}}," {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Implement the replaced logic here")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// ...")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Need to return the return value corresponding to the method, no need to write return, just put the parameter in the last digit")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Assuming the return value of this method is an Int, we just need to ensure that the last bit is the return value we need")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#6CB6FF"}},"0")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}},"}")]),e(` +`),s("span",{class:"line"}),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#768390"}},"/// For some methods, we just need to replace their return value, then there are the following implementations")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#768390"}},"/// It should be noted that the parameters passed in by the method of directly replacing the return value are fixed. If you want to dynamically replace the return value, please use the above replaceAny method body")]),e(` +`),s("span",{class:"line"}),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#768390"}},"// Replace with the return value you need")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#DCBDFB"}},"replaceTo"),s("span",{style:{color:"#ADBAC7"}},"("),s("span",{style:{color:"#F47067"}},".."),s("span",{style:{color:"#ADBAC7"}},".)")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#768390"}},"// Replace with return value of type Boolean")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#DCBDFB"}},"replaceToTrue"),s("span",{style:{color:"#ADBAC7"}},"()")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#768390"}},"// Intercept return value")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#DCBDFB"}},"intercept"),s("span",{style:{color:"#ADBAC7"}},"()")]),e(` +`),s("span",{class:"line"})])]),s("div",{class:"line-numbers","aria-hidden":"true"},[s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"})])],-1),P=s("div",{class:"language-kotlin line-numbers-mode","data-ext":"kt"},[s("pre",{class:"shiki github-dark-dimmed",style:{"background-color":"#22272e"},tabindex:"0"},[s("code",null,[s("span",{class:"line"},[s("span",{style:{color:"#768390"}},"/// A method with no return value void")]),e(` +`),s("span",{class:"line"}),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"replaceHookedMethod"),s("span",{style:{color:"#ADBAC7"}},"(param: "),s("span",{style:{color:"#F69D50"}},"MethodHookParam"),s("span",{style:{color:"#ADBAC7"}},"): "),s("span",{style:{color:"#F69D50"}},"Any"),s("span",{style:{color:"#ADBAC7"}},"? {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Implement the replaced logic directly here")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"return"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#6CB6FF"}},"null")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}},"}")]),e(` +`),s("span",{class:"line"}),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#768390"}},"/// A method with a return value")]),e(` +`),s("span",{class:"line"}),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"replaceHookedMethod"),s("span",{style:{color:"#ADBAC7"}},"(param: "),s("span",{style:{color:"#F69D50"}},"MethodHookParam"),s("span",{style:{color:"#ADBAC7"}},"): "),s("span",{style:{color:"#F69D50"}},"Int"),s("span",{style:{color:"#ADBAC7"}}," {")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Implement the replaced logic here")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// ...")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Assume the return value of this method is an Int")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"return"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#6CB6FF"}},"0")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}},"}")]),e(` +`),s("span",{class:"line"}),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#768390"}},"/// For some methods, we just need to replace their return value, then there are the following implementations")]),e(` +`),s("span",{class:"line"}),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#768390"}},"// Replace with the return value you need")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"replaceHookedMethod"),s("span",{style:{color:"#ADBAC7"}},"(param: "),s("span",{style:{color:"#F69D50"}},"MethodHookParam"),s("span",{style:{color:"#ADBAC7"}},") "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},".."),s("span",{style:{color:"#ADBAC7"}},".")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#768390"}},"// Replace with return value of type Boolean")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"replaceHookedMethod"),s("span",{style:{color:"#ADBAC7"}},"(param: "),s("span",{style:{color:"#F69D50"}},"MethodHookParam"),s("span",{style:{color:"#ADBAC7"}},") "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#6CB6FF"}},"true")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#768390"}},"// Intercept return value")]),e(` +`),s("span",{class:"line"},[s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"replaceHookedMethod"),s("span",{style:{color:"#ADBAC7"}},"(param: "),s("span",{style:{color:"#F69D50"}},"MethodHookParam"),s("span",{style:{color:"#ADBAC7"}},") "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#6CB6FF"}},"null")]),e(` +`),s("span",{class:"line"})])]),s("div",{class:"line-numbers","aria-hidden":"true"},[s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"})])],-1),x=o('The API function differences are compared as follows
# Notes on Migrating XposedHelpers
The reflection functionality provided in
YukiHookAPI
differs from the reflection functionality ofXposedHelpers
.Here is a guide to avoid common pitfalls.
Methods like
',4),I={class:"custom-container warning"},w=s("p",{class:"custom-container-title"},"Notice",-1),T=s("p",null,[e("The reflection API of "),s("code",null,"YukiHookAPI"),e(" itself has been deprecated in "),s("code",null,"1.3.0"),e(" version. The following content is only used as migration guidelines before "),s("code",null,"1.3.0"),e(" version, we will retain it but will not update the content again.")],-1),M={href:"https://github.com/HighCapable/KavaRef",target:"_blank",rel:"noopener noreferrer"},G=s("code",null,"KavaRef",-1),R=o(`XposedHelpers.callMethod
andXposedHelpers.callStaticMethod
automatically search and invoke all public methods (including those in superclasses), which is a feature of native Java reflection. In contrast, the reflection solution provided byYukiHookAPI
first searches and then calls, and by default, the search process does not automatically look for methods in superclasses.For example, class
A
inherits fromB
, andB
has a public methodtest
, whileA
does not.public class B { + public void test(String a) { + // ... + } +} + +public class A extends B { + // ... +} +
Usage with
XposedHelpers
.val instance: A = ... +XposedHelpers.callMethod(instance, "test", "some string") +
Usage with
YukiHookAPI
.val instance: A = ... +instance.current().method { + name = "test" + // Note that you need to add this search condition to ensure it searches for methods in superclasses. + superClass() +}.call("some string") +// Or directly call the superClass() method. +instance.current().superClass()?.method { + name = "test" +}?.call("some string") +
# Migrate More Functions Related to Hook API
`,8);function q(X,j){const r=t("ExternalLinkIcon"),a=t("CodeGroupItem"),c=t("CodeGroup");return i(),d("div",null,[y,u,D,s("blockquote",null,[s("p",null,[e("If you are familiar with "),s("a",B,[e("Rovo89 Xposed API"),l(r)]),e(", you can refer to the same point below to quickly migrate your API to "),m,e(".")])]),C,l(c,null,{default:n(()=>[l(a,{title:"Yuki Hook API"},{default:n(()=>[h]),_:1}),l(a,{title:"Rovo89 Xposed API"},{default:n(()=>[b]),_:1})]),_:1}),v,l(c,null,{default:n(()=>[l(a,{title:"Yuki Hook API"},{default:n(()=>[F]),_:1}),l(a,{title:"Rovo89 Xposed API"},{default:n(()=>[k]),_:1})]),_:1}),f,g,_,l(c,null,{default:n(()=>[l(a,{title:"Yuki Hook API"},{default:n(()=>[H]),_:1}),l(a,{title:"Rovo89 Xposed API"},{default:n(()=>[P]),_:1})]),_:1}),x,s("div",I,[w,T,s("p",null,[e("You can migrate to "),s("a",M,[e("KavaRef"),l(r)]),e(", and this feature is also applicable to "),G,e(".")])]),R])}const N=p(A,[["render",q],["__file","move-to-new-api.html.vue"]]);export{N as default}; diff --git a/assets/move-to-new-api.html-DwX5LqED.js b/assets/move-to-new-api.html-DwX5LqED.js new file mode 100644 index 00000000..a25028f3 --- /dev/null +++ b/assets/move-to-new-api.html-DwX5LqED.js @@ -0,0 +1,208 @@ +import{_ as t,r,o as i,c as A,b as s,d as l,e as n,w as e,a as o}from"./app-BpUB8-Q8.js";const y={},d=s("h1",{id:"从其它-hook-api-迁移",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#从其它-hook-api-迁移","aria-hidden":"true"},"#"),l(" 从其它 Hook API 迁移")],-1),D=s("p",null,[l("此文档可以帮助你快速从你熟悉的 Hook API 迁移至 "),s("code",null,"YukiHookAPI"),l(" 来熟悉对 "),s("code",null,"YukiHookAPI"),l(" 的相关写法。")],-1),B=s("h2",{id:"rovo89-xposed-api",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#rovo89-xposed-api","aria-hidden":"true"},"#"),l(" Rovo89 Xposed API")],-1),C={href:"https://api.xposed.info/",target:"_blank",rel:"noopener noreferrer"},u=s("code",null,"YukiHookAPI",-1),m=o('
YukiHookAPI
is a brand new Hook API, which is fundamentally different from other Hook APIs, you can refer to API Document and Special Features to determine some functional Migration and use.# 迁移 Hook 入口点
从
XC_LoadPackage.LoadPackageParam
迁移至PackageParam
。
YukiHookAPI
对PackageParam
实现了 lambda 方法体this
用法,在encase
方法体内即可全局得到PackageParam
对象。',4),v=s("div",{class:"language-kotlin line-numbers-mode","data-ext":"kt"},[s("pre",{class:"shiki github-dark-dimmed",style:{"background-color":"#22272e"},tabindex:"0"},[s("code",null,[s("span",{class:"line"},[s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"onHook"),s("span",{style:{color:"#ADBAC7"}},"() "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"encase"),s("span",{style:{color:"#ADBAC7"}}," {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 得到当前 Hook 的包名")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," packageName")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 得到当前 Hook 的 ApplicationInfo")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," appInfo")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 得到系统上下文对象")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," systemContext")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 得到宿主 Application 生命周期")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," appContext")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Hook 指定的 APP")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"loadApp"),s("span",{style:{color:"#ADBAC7"}},"(name "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#96D0FF"}},'"com.demo.test"'),s("span",{style:{color:"#ADBAC7"}},") {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Member Hook")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#96D0FF"}},'"com.demo.test.TestClass"'),s("span",{style:{color:"#ADBAC7"}},"."),s("span",{style:{color:"#DCBDFB"}},"toClass"),s("span",{style:{color:"#ADBAC7"}},"()")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," ."),s("span",{style:{color:"#DCBDFB"}},"resolve"),s("span",{style:{color:"#ADBAC7"}},"()")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," ."),s("span",{style:{color:"#DCBDFB"}},"firstMethod"),s("span",{style:{color:"#ADBAC7"}}," {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," name "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#96D0FF"}},'"test"')]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"parameters"),s("span",{style:{color:"#ADBAC7"}},"(Boolean::"),s("span",{style:{color:"#DCBDFB"}},"class"),s("span",{style:{color:"#ADBAC7"}},")")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }."),s("span",{style:{color:"#DCBDFB"}},"hook"),s("span",{style:{color:"#ADBAC7"}}," {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"after"),s("span",{style:{color:"#ADBAC7"}}," {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// ...")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Resources Hook (固定用法)")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"resources"),s("span",{style:{color:"#ADBAC7"}},"()."),s("span",{style:{color:"#DCBDFB"}},"hook"),s("span",{style:{color:"#ADBAC7"}}," {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"injectResource"),s("span",{style:{color:"#ADBAC7"}}," {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"conditions"),s("span",{style:{color:"#ADBAC7"}}," {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," name "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#96D0FF"}},'"ic_launcher"')]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"mipmap"),s("span",{style:{color:"#ADBAC7"}},"()")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"replaceToModuleResource"),s("span",{style:{color:"#ADBAC7"}},"(R.mipmap.ic_launcher)")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}},"}")]),l(` +`),s("span",{class:"line"})])]),s("div",{class:"line-numbers","aria-hidden":"true"},[s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"})])],-1),b=s("div",{class:"language-kotlin line-numbers-mode","data-ext":"kt"},[s("pre",{class:"shiki github-dark-dimmed",style:{"background-color":"#22272e"},tabindex:"0"},[s("code",null,[s("span",{class:"line"},[s("span",{style:{color:"#F47067"}},"private"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"lateinit"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"var"),s("span",{style:{color:"#ADBAC7"}}," moduleResources: "),s("span",{style:{color:"#F69D50"}},"XModuleResources")]),l(` +`),s("span",{class:"line"}),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"initZygote"),s("span",{style:{color:"#ADBAC7"}},"(sparam: "),s("span",{style:{color:"#F69D50"}},"IXposedHookZygoteInit"),s("span",{style:{color:"#ADBAC7"}},".StartupParam) {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," moduleResources "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," XModuleResources."),s("span",{style:{color:"#DCBDFB"}},"createInstance"),s("span",{style:{color:"#ADBAC7"}},"(sparam.modulePath, "),s("span",{style:{color:"#6CB6FF"}},"null"),s("span",{style:{color:"#ADBAC7"}},")")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}},"}")]),l(` +`),s("span",{class:"line"}),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"handleLoadPackage"),s("span",{style:{color:"#ADBAC7"}},"(lpparam: "),s("span",{style:{color:"#F69D50"}},"XC_LoadPackage"),s("span",{style:{color:"#ADBAC7"}},".LoadPackageParam) {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 得到当前 Hook 的包名")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," lpparam.packageName")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 得到当前 Hook 的 ApplicationInfo")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," lpparam.applicationInfo")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 得到系统上下文对象")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 在 Rovo89 Xposed API 中没有现成的调用方法,你需要自行反射 ActivityThread 来实现")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 得到宿主 Application 生命周期")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," AndroidAppHelper."),s("span",{style:{color:"#DCBDFB"}},"currentApplication"),s("span",{style:{color:"#ADBAC7"}},"()")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Class Hook")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"if"),s("span",{style:{color:"#ADBAC7"}},"(lpparam.packageName "),s("span",{style:{color:"#F47067"}},"=="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#96D0FF"}},'"com.demo.test"'),s("span",{style:{color:"#ADBAC7"}},")")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," XposedHelpers."),s("span",{style:{color:"#DCBDFB"}},"findAndHookMethod"),s("span",{style:{color:"#ADBAC7"}},"(")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#96D0FF"}},'"com.demo.test.TestClass"'),s("span",{style:{color:"#ADBAC7"}},", lpparam.classLoader,")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#96D0FF"}},'"test"'),s("span",{style:{color:"#ADBAC7"}},", Boolean::"),s("span",{style:{color:"#DCBDFB"}},"class"),s("span",{style:{color:"#ADBAC7"}},".java,")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," object : "),s("span",{style:{color:"#F69D50"}},"XC_MethodHook"),s("span",{style:{color:"#ADBAC7"}},"() {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"afterHookedMethod"),s("span",{style:{color:"#ADBAC7"}},"(param: "),s("span",{style:{color:"#F69D50"}},"MethodHookParam"),s("span",{style:{color:"#ADBAC7"}},") {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// ...")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," }")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," )")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}},"}")]),l(` +`),s("span",{class:"line"}),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"handleInitPackageResources"),s("span",{style:{color:"#ADBAC7"}},"(resparam: "),s("span",{style:{color:"#F69D50"}},"XC_InitPackageResources"),s("span",{style:{color:"#ADBAC7"}},".InitPackageResourcesParam) {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 得到当前 Hook 的包名")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," resparam.packageName")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// Resources Hook")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," resparam.res."),s("span",{style:{color:"#DCBDFB"}},"setReplacement"),s("span",{style:{color:"#ADBAC7"}},"(")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#96D0FF"}},'"com.demo.test"'),s("span",{style:{color:"#ADBAC7"}},", "),s("span",{style:{color:"#96D0FF"}},'"mipmap"'),s("span",{style:{color:"#ADBAC7"}},","),s("span",{style:{color:"#96D0FF"}},'"ic_launcher"'),s("span",{style:{color:"#ADBAC7"}},",")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," moduleResources."),s("span",{style:{color:"#DCBDFB"}},"fwd"),s("span",{style:{color:"#ADBAC7"}},"(R.mipmap.ic_launcher)")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," )")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}},"}")]),l(` +`),s("span",{class:"line"})])]),s("div",{class:"line-numbers","aria-hidden":"true"},[s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"})])],-1),F=o('API 功能差异对比如下
# 迁移 Hook 方法体
从
XC_MethodHook.MethodHookParam
迁移至HookParam
。# Before/After Hook
YukiHookAPI
同样对HookParam
实现了 lambda 方法体this
用法,在before
、after
等方法体内即可全局得到HookParam
对象。',5),k=s("div",{class:"language-kotlin line-numbers-mode","data-ext":"kt"},[s("pre",{class:"shiki github-dark-dimmed",style:{"background-color":"#22272e"},tabindex:"0"},[s("code",null,[s("span",{class:"line"},[s("span",{style:{color:"#DCBDFB"}},"after"),s("span",{style:{color:"#ADBAC7"}}," {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 得到当前 Hook 的实例")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," instance")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 得到当前 Hook 的 Class 实例")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," instanceClass")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 得到并 cast 当前 Hook 的实例为指定类型 T")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"instance"),s("span",{style:{color:"#ADBAC7"}},"<"),s("span",{style:{color:"#F69D50"}},"T"),s("span",{style:{color:"#ADBAC7"}},">()")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 得到方法参数数组")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," args")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 得到方法参数的第一位 T")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"args"),s("span",{style:{color:"#ADBAC7"}},"()."),s("span",{style:{color:"#DCBDFB"}},"first"),s("span",{style:{color:"#ADBAC7"}},"()."),s("span",{style:{color:"#DCBDFB"}},"cast"),s("span",{style:{color:"#ADBAC7"}},"<"),s("span",{style:{color:"#F69D50"}},"T"),s("span",{style:{color:"#ADBAC7"}},">()")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 得到方法参数的最后一位 T")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"args"),s("span",{style:{color:"#ADBAC7"}},"()."),s("span",{style:{color:"#DCBDFB"}},"last"),s("span",{style:{color:"#ADBAC7"}},"()."),s("span",{style:{color:"#DCBDFB"}},"cast"),s("span",{style:{color:"#ADBAC7"}},"<"),s("span",{style:{color:"#F69D50"}},"T"),s("span",{style:{color:"#ADBAC7"}},">()")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 得到方法参数的任意下标 T,这里用 2 举例")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"args"),s("span",{style:{color:"#ADBAC7"}},"(index "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#6CB6FF"}},"2"),s("span",{style:{color:"#ADBAC7"}},")."),s("span",{style:{color:"#DCBDFB"}},"cast"),s("span",{style:{color:"#ADBAC7"}},"<"),s("span",{style:{color:"#F69D50"}},"T"),s("span",{style:{color:"#ADBAC7"}},">()")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 设置方法参数的任意下标,这里用 2 举例")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"args"),s("span",{style:{color:"#ADBAC7"}},"(index "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#6CB6FF"}},"2"),s("span",{style:{color:"#ADBAC7"}},")."),s("span",{style:{color:"#DCBDFB"}},"set"),s("span",{style:{color:"#ADBAC7"}},"("),s("span",{style:{color:"#F47067"}},".."),s("span",{style:{color:"#ADBAC7"}},".)")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 得到返回值")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," result")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 得到返回值并 cast 为 T")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"result"),s("span",{style:{color:"#ADBAC7"}},"<"),s("span",{style:{color:"#F69D50"}},"T"),s("span",{style:{color:"#ADBAC7"}},">()")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 修改返回值内容")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," result "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},".."),s("span",{style:{color:"#ADBAC7"}},".")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 删除返回值内容")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"resultNull"),s("span",{style:{color:"#ADBAC7"}},"()")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 获取当前回调方法体范围内的数据存储实例")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," dataExtra")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 向 Hook APP 抛出异常")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"Throwable"),s("span",{style:{color:"#ADBAC7"}},"("),s("span",{style:{color:"#96D0FF"}},'"Fatal"'),s("span",{style:{color:"#ADBAC7"}},")."),s("span",{style:{color:"#DCBDFB"}},"throwToApp"),s("span",{style:{color:"#ADBAC7"}},"()")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 执行未经 Hook 的原始方法并使用原始方法参数调用,泛型可略")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"callOriginal"),s("span",{style:{color:"#ADBAC7"}},"<"),s("span",{style:{color:"#F69D50"}},"Any"),s("span",{style:{color:"#ADBAC7"}},"?>()")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 执行未经 Hook 的原始方法并自定义方法参数调用,泛型可略")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"invokeOriginal"),s("span",{style:{color:"#ADBAC7"}},"<"),s("span",{style:{color:"#F69D50"}},"Any"),s("span",{style:{color:"#ADBAC7"}},"?>("),s("span",{style:{color:"#F47067"}},".."),s("span",{style:{color:"#ADBAC7"}},".)")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}},"}")]),l(` +`),s("span",{class:"line"})])]),s("div",{class:"line-numbers","aria-hidden":"true"},[s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"})])],-1),h=s("div",{class:"language-kotlin line-numbers-mode","data-ext":"kt"},[s("pre",{class:"shiki github-dark-dimmed",style:{"background-color":"#22272e"},tabindex:"0"},[s("code",null,[s("span",{class:"line"},[s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"afterHookedMethod"),s("span",{style:{color:"#ADBAC7"}},"(param: "),s("span",{style:{color:"#F69D50"}},"MethodHookParam"),s("span",{style:{color:"#ADBAC7"}},") {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 得到当前 Hook 的实例")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," param.thisObject")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 得到当前 Hook 的 Class 实例")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," param.thisObject.javaClass")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 得到并 cast 当前 Hook 的实例为指定类型 T")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," param.thisObject "),s("span",{style:{color:"#F47067"}},"as"),s("span",{style:{color:"#ADBAC7"}}," T")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 得到方法参数数组")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," param.args")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 得到方法参数的第一位 T")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," param.args["),s("span",{style:{color:"#6CB6FF"}},"0"),s("span",{style:{color:"#ADBAC7"}},"] "),s("span",{style:{color:"#F47067"}},"as"),s("span",{style:{color:"#ADBAC7"}}," T")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 得到方法参数的最后一位 T")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," param.args[param.args.lastIndex] "),s("span",{style:{color:"#F47067"}},"as"),s("span",{style:{color:"#ADBAC7"}}," T")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 得到方法参数的任意下标 T,这里用 2 举例")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," param.args["),s("span",{style:{color:"#6CB6FF"}},"2"),s("span",{style:{color:"#ADBAC7"}},"] "),s("span",{style:{color:"#F47067"}},"as"),s("span",{style:{color:"#ADBAC7"}}," T")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 设置方法参数的任意下标,这里用 2 举例")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," param.args["),s("span",{style:{color:"#6CB6FF"}},"2"),s("span",{style:{color:"#ADBAC7"}},"] "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},".."),s("span",{style:{color:"#ADBAC7"}},".")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 得到返回值")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," param.result")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 得到返回值并 cast 为 T")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," param.result "),s("span",{style:{color:"#F47067"}},"as"),s("span",{style:{color:"#ADBAC7"}}," T")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 修改返回值内容")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," param.result "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},".."),s("span",{style:{color:"#ADBAC7"}},".")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 删除返回值内容")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," param.result "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#6CB6FF"}},"null")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 获取当前回调方法体范围内的数据存储实例")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," param.extra")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 向 Hook APP 抛出异常")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," param.throwable "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"Throwable"),s("span",{style:{color:"#ADBAC7"}},"("),s("span",{style:{color:"#96D0FF"}},'"Fatal"'),s("span",{style:{color:"#ADBAC7"}},")")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 执行未经 Hook 的原始方法")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," XposedBridge."),s("span",{style:{color:"#DCBDFB"}},"invokeOriginalMethod"),s("span",{style:{color:"#ADBAC7"}},"(param.method, param.thisObject, "),s("span",{style:{color:"#F47067"}},".."),s("span",{style:{color:"#ADBAC7"}},".)")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}},"}")]),l(` +`),s("span",{class:"line"})])]),s("div",{class:"line-numbers","aria-hidden":"true"},[s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"})])],-1),_=s("h4",{id:"replace-hook",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#replace-hook","aria-hidden":"true"},"#"),l(" Replace Hook")],-1),g=s("p",null,[s("code",null,"replaceHook"),l(" 方法比较特殊,"),s("code",null,"YukiHookAPI"),l(" 为它做出了多种形式以供选择。")],-1),H=s("blockquote",null,[s("p",null,"API 功能差异对比如下")],-1),f=s("div",{class:"language-kotlin line-numbers-mode","data-ext":"kt"},[s("pre",{class:"shiki github-dark-dimmed",style:{"background-color":"#22272e"},tabindex:"0"},[s("code",null,[s("span",{class:"line"},[s("span",{style:{color:"#768390"}},"/// 无返回值的方法 void")]),l(` +`),s("span",{class:"line"}),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#DCBDFB"}},"replaceUnit"),s("span",{style:{color:"#ADBAC7"}}," {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 直接在这里实现被替换的逻辑")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}},"}")]),l(` +`),s("span",{class:"line"}),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#768390"}},"/// 有返回值的方法")]),l(` +`),s("span",{class:"line"}),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#DCBDFB"}},"replaceAny"),s("span",{style:{color:"#ADBAC7"}}," {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 在这里实现被替换的逻辑")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// ...")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 需要返回方法对应的返回值,无需写 return,只需将参数放到最后一位")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 假设这个方法的返回值是 Int,我们只需要保证最后一位是我们需要的返回值即可")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#6CB6FF"}},"0")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}},"}")]),l(` +`),s("span",{class:"line"}),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#768390"}},"/// 有些方法我们只需替换其返回值,则有如下实现")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#768390"}},"/// 需要注意的是:直接替换返回值的方法传入的参数是固定不变的,若想实现动态替换返回值请使用上面的 replaceAny 方法体")]),l(` +`),s("span",{class:"line"}),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#768390"}},"// 替换为你需要的返回值")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#DCBDFB"}},"replaceTo"),s("span",{style:{color:"#ADBAC7"}},"("),s("span",{style:{color:"#F47067"}},".."),s("span",{style:{color:"#ADBAC7"}},".)")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#768390"}},"// 替换为 Boolean 类型的返回值")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#DCBDFB"}},"replaceToTrue"),s("span",{style:{color:"#ADBAC7"}},"()")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#768390"}},"// 拦截返回值")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#DCBDFB"}},"intercept"),s("span",{style:{color:"#ADBAC7"}},"()")]),l(` +`),s("span",{class:"line"})])]),s("div",{class:"line-numbers","aria-hidden":"true"},[s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"})])],-1),P=s("div",{class:"language-kotlin line-numbers-mode","data-ext":"kt"},[s("pre",{class:"shiki github-dark-dimmed",style:{"background-color":"#22272e"},tabindex:"0"},[s("code",null,[s("span",{class:"line"},[s("span",{style:{color:"#768390"}},"/// 无返回值的方法 void")]),l(` +`),s("span",{class:"line"}),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"replaceHookedMethod"),s("span",{style:{color:"#ADBAC7"}},"(param: "),s("span",{style:{color:"#F69D50"}},"MethodHookParam"),s("span",{style:{color:"#ADBAC7"}},"): "),s("span",{style:{color:"#F69D50"}},"Any"),s("span",{style:{color:"#ADBAC7"}},"? {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 直接在这里实现被替换的逻辑")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"return"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#6CB6FF"}},"null")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}},"}")]),l(` +`),s("span",{class:"line"}),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#768390"}},"/// 有返回值的方法")]),l(` +`),s("span",{class:"line"}),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"replaceHookedMethod"),s("span",{style:{color:"#ADBAC7"}},"(param: "),s("span",{style:{color:"#F69D50"}},"MethodHookParam"),s("span",{style:{color:"#ADBAC7"}},"): "),s("span",{style:{color:"#F69D50"}},"Int"),s("span",{style:{color:"#ADBAC7"}}," {")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 在这里实现被替换的逻辑")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// ...")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#768390"}},"// 假设这个方法的返回值是 Int")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"return"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#6CB6FF"}},"0")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#ADBAC7"}},"}")]),l(` +`),s("span",{class:"line"}),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#768390"}},"/// 有些方法我们只需替换其返回值,则有如下实现")]),l(` +`),s("span",{class:"line"}),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#768390"}},"// 替换为你需要的返回值")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"replaceHookedMethod"),s("span",{style:{color:"#ADBAC7"}},"(param: "),s("span",{style:{color:"#F69D50"}},"MethodHookParam"),s("span",{style:{color:"#ADBAC7"}},") "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},".."),s("span",{style:{color:"#ADBAC7"}},".")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#768390"}},"// 替换为 Boolean 类型的返回值")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"replaceHookedMethod"),s("span",{style:{color:"#ADBAC7"}},"(param: "),s("span",{style:{color:"#F69D50"}},"MethodHookParam"),s("span",{style:{color:"#ADBAC7"}},") "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#6CB6FF"}},"true")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#768390"}},"// 拦截返回值")]),l(` +`),s("span",{class:"line"},[s("span",{style:{color:"#F47067"}},"override"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#F47067"}},"fun"),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#DCBDFB"}},"replaceHookedMethod"),s("span",{style:{color:"#ADBAC7"}},"(param: "),s("span",{style:{color:"#F69D50"}},"MethodHookParam"),s("span",{style:{color:"#ADBAC7"}},") "),s("span",{style:{color:"#F47067"}},"="),s("span",{style:{color:"#ADBAC7"}}," "),s("span",{style:{color:"#6CB6FF"}},"null")]),l(` +`),s("span",{class:"line"})])]),s("div",{class:"line-numbers","aria-hidden":"true"},[s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"})])],-1),I=o('API 功能差异对比如下
# 迁移 XposedHelpers 注意事项
YukiHookAPI
中提供的反射功能与XposedHelpers
的反射功能有所不同,这里提供一个误区指引。',3),x={class:"custom-container warning"},T=s("p",{class:"custom-container-title"},"注意",-1),M=s("p",null,[s("code",null,"YukiHookAPI"),l(" 自身的反射 API 在 "),s("code",null,"1.3.0"),l(" 版本已被弃用,以下内容仅作为 "),s("code",null,"1.3.0"),l(" 版本之前的迁移指引,我们会对其进行保留但不会再进行内容的更新。")],-1),R={href:"https://github.com/HighCapable/KavaRef",target:"_blank",rel:"noopener noreferrer"},q=s("code",null,"KavaRef",-1),X=o(`
XposedHelpers.callMethod
、XposedHelpers.callStaticMethod
等方法自动查找的方法会自动调用所有公开的方法 (包括super
超类),这是 Java 原生反射的特性, 而YukiHookAPI
提供的反射方案为先反射查找再调用,而查找过程默认不会自动查找super
超类的方法。例如,类
A
继承于B
,B
中存在公开的方法test
,而A
中并不存在。public class B { + public void test(String a) { + // ... + } +} + +public class A extends B { + // ... +} +
此时
XposedHelpers
的用法。val instance: A = ... +XposedHelpers.callMethod(instance, "test", "some string") +
YukiHookAPI
的用法。val instance: A = ... +instance.current().method { + name = "test" + // 请注意,这里需要添加此查找条件以确保其会查找超类的方法 + superClass() +}.call("some string") +// 或者直接调用 superClass() 方法 +instance.current().superClass()?.method { + name = "test" +}?.call("some string") +
# 迁移更多有关 Hook API 的功能
`,8);function Y(j,w){const p=r("ExternalLinkIcon"),a=r("CodeGroupItem"),c=r("CodeGroup");return i(),A("div",null,[d,D,B,s("blockquote",null,[s("p",null,[l("若你熟悉 "),s("a",C,[l("Rovo89 Xposed API"),n(p)]),l(",你可以参考下方的相同点将自己的 API 快速迁移至 "),u,l("。")])]),m,n(c,null,{default:e(()=>[n(a,{title:"Yuki Hook API"},{default:e(()=>[v]),_:1}),n(a,{title:"Rovo89 Xposed API"},{default:e(()=>[b]),_:1})]),_:1}),F,n(c,null,{default:e(()=>[n(a,{title:"Yuki Hook API"},{default:e(()=>[k]),_:1}),n(a,{title:"Rovo89 Xposed API"},{default:e(()=>[h]),_:1})]),_:1}),_,g,H,n(c,null,{default:e(()=>[n(a,{title:"Yuki Hook API"},{default:e(()=>[f]),_:1}),n(a,{title:"Rovo89 Xposed API"},{default:e(()=>[P]),_:1})]),_:1}),I,s("div",x,[T,M,s("p",null,[l("你可以迁移至 "),s("a",R,[l("KavaRef"),n(p)]),l(","),q,l(" 同样适用此特性。")])]),X])}const L=t(y,[["render",Y],["__file","move-to-new-api.html.vue"]]);export{L as default}; diff --git a/assets/move-to-new-api.html-kyRByfpu.js b/assets/move-to-new-api.html-kyRByfpu.js new file mode 100644 index 00000000..6183257f --- /dev/null +++ b/assets/move-to-new-api.html-kyRByfpu.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-c0d5dada","path":"/zh-cn/guide/move-to-new-api.html","title":"从其它 Hook API 迁移","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"Rovo89 Xposed API","slug":"rovo89-xposed-api","link":"#rovo89-xposed-api","children":[{"level":3,"title":"迁移 Hook 入口点","slug":"迁移-hook-入口点","link":"#迁移-hook-入口点","children":[]},{"level":3,"title":"迁移 Hook 方法体","slug":"迁移-hook-方法体","link":"#迁移-hook-方法体","children":[]},{"level":3,"title":"迁移 XposedHelpers 注意事项","slug":"迁移-xposedhelpers-注意事项","link":"#迁移-xposedhelpers-注意事项","children":[]}]},{"level":2,"title":"迁移更多有关 Hook API 的功能","slug":"迁移更多有关-hook-api-的功能","link":"#迁移更多有关-hook-api-的功能","children":[]}],"git":{"updatedTime":1750318245000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":9}]},"filePathRelative":"zh-cn/guide/move-to-new-api.md"}');export{e as data}; diff --git a/assets/quick-start.html-CnOHbn2J.js b/assets/quick-start.html-CnOHbn2J.js new file mode 100644 index 00000000..9943e5a3 --- /dev/null +++ b/assets/quick-start.html-CnOHbn2J.js @@ -0,0 +1,170 @@ +import{_ as o,r as p,o as i,c as t,b as n,d as s,e,a as l}from"./app-BpUB8-Q8.js";const r={},c=l('
YukiHookAPI
是一套全新的 Hook API,与其它 Hook API 存在着本质区别,你可以参考 API 文档 以及 特色功能 来决定一些功能性的迁移和使用。# Quick Start
Integrate
YukiHookAPI
into your project.# Project Requirements
The project needs to be created using
',4),d={href:"https://developer.android.com/studio",target:"_blank",rel:"noopener noreferrer"},u={href:"https://www.jetbrains.com/idea",target:"_blank",rel:"noopener noreferrer"},y=n("li",null,[n("p",null,"Kotlin 1.9.0+, Gradle 8+, Java 11, 17+, Android Gradle Plugin 8+")],-1),A=l('Android Studio
orIntelliJ IDEA
and be of type Android project and have integrated Kotlin environment dependencies.# Automatically Build Project
YukiHookAPI
provides an automated build tool that can help you quickly build an Android standard project template with Xposed Module dependencies, and use the built template to start the next step directly.You can click here to check it out.
# Manually Configure Project
If you don't want to use automated build tools, you can still manually configure project dependencies as follows.
# Create Project
Use
Android Studio
orIntelliJ IDEA
to create a new Android project and select Kotlin in theLanguage
column to automatically add basic dependencies.# Integration Dependencies
',8),v={href:"https://github.com/HighCapable/SweetDependency",target:"_blank",rel:"noopener noreferrer"},D=l(`# SweetDependency (Recommended)
Add the repositories and dependencies in your project's
SweetDependency
configuration file.The following example
repositories: + # Must be added when used as an Xposed Module, otherwise optional + rovo89-xposed-api: + url: https://api.xposed.info/ + +plugins: + # Must be added when used as an Xposed Module, otherwise optional + com.google.devtools.ksp: + version: + + ... + +libraries: + # Must be added when used as an Xposed Module, otherwise optional + de.robv.android.xposed: + api: + version: 82 + repositories: + rovo89-xposed-api + com.highcapable.yukihookapi: + api: + version: + + # Must be added when used as an Xposed Module, otherwise optional + ksp-xposed: + version-ref: <this>::api + # YukiHookAPI version 1.3.0 uses KavaRef as core reflection API + # YukiHookAPI no longer binds its own reflection API, you can start trying to use KavaRef + com.highcapable.kavaref: + kavaref-core: + version: + + kavaref-extension: + version: + + ... +
After adding it, run Gradle Sync and all dependencies will be autowired.
Next, deploy plugins in your project's
build.gradle.kts
.The following example
plugins { + // Must be added when used as an Xposed Module, otherwise optional + autowire(libs.plugins.com.google.devtools.ksp) + // ... +} +
Then, deploy dependencies in your project's
build.gradle.kts
.The following example
dependencies { + // Basic dependencies + implementation(com.highcapable.yukihookapi.api) + // It is recommended to use KavaRef as the core reflection API + implementation(com.highcapable.kavaref.kavaref.core) + implementation(com.highcapable.kavaref.kavaref.extension) + // Must be added when used as an Xposed Module, otherwise optional + compileOnly(de.robv.android.xposed.api) + // Must be added when used as an Xposed Module, otherwise optional + ksp(com.highcapable.yukihookapi.ksp.xposed) +} +
# Version Catalog
Add repositories in your project's
build.gradle.kts
.Kotlin DSL
repositories { + google() + mavenCentral() + // Must be added when used as an Xposed Module, otherwise optional + maven("https://api.xposed.info/") +} +
Add dependency in your project's
gradle/libs.versions.toml
.The following example
[versions] +yukihookapi = "<yuki-version>" +ksp = "<ksp-version>" +kavaref-core = "<kavaref-version>" +kavaref-extension = "<kavaref-version>" + +[plugins] +# Must be added when used as an Xposed Module, otherwise optional +ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } + +[libraries] +yukihookapi-api = { module = "com.highcapable.yukihookapi:api", version.ref = "yukihookapi" } +# Must be added when used as an Xposed Module, otherwise optional +yukihookapi-ksp-xposed = { module = "com.highcapable.yukihookapi:ksp-xposed", version.ref = "yukihookapi" } +# YukiHookAPI version 1.3.0 uses KavaRef as core reflection API +# YukiHookAPI no longer binds its own reflection API, you can start trying to use KavaRef +kavaref-core = { module = "com.highcapable.kavaref:kavaref-core", version.ref = "kavaref-core" } +kavaref-extension = { module = "com.highcapable.kavaref:kavaref-extension", version.ref = "kavaref-extension" } +# Must be added when used as an Xposed Module, otherwise optional +xposed-api = { module = "de.robv.android.xposed:api", version = "82" } +
Next, deploy plugins in your project's
build.gradle.kts
.Kotlin DSL
plugins { + // Must be added when used as an Xposed Module, otherwise optional + alias(libs.plugins.ksp) +} +
Then, deploy dependencies in your project's
build.gradle.kts
.Kotlin DSL
dependencies { + // Basic dependency + implementation(libs.yukihookapi.api) + // It is recommended to use KavaRef as the core reflection API + implementation(libs.kavaref.core) + implementation(libs.kavaref.extension) + // Must be added when used as an Xposed Module, otherwise optional + compileOnly(libs.xposed.api) + // Must be added when used as an Xposed Module, otherwise optional + ksp(libs.yukihookapi.ksp.xposed) +} +
# Traditional Method
Add repositories in your project's
build.gradle.kts
.Kotlin DSL
repositories { + google() + mavenCentral() + // Must be added when used as an Xposed Module, otherwise optional + maven("https://api.xposed.info/") +} +
Add plugins in your project's
build.gradle.kts
.Kotlin DSL
plugins { + // Must be added when used as an Xposed Module, otherwise optional + id("com.google.devtools.ksp") version "<ksp-version>" +} +
Add dependencies in your project's
build.gradle.kts
.Kotlin DSL
`,34),m=n("strong",null,"dependencies { + // Basic dependency + implementation("com.highcapable.yukihookapi:api:<yuki-version>") + // It is recommended to use KavaRef as the core reflection API + implementation("com.highcapable.kavaref:kavaref-core:<kavaref-version>") + implementation("com.highcapable.kavaref:kavaref-extension:<kavaref-version>") + // Must be added when used as an Xposed Module, otherwise optional + compileOnly("de.robv.android.xposed:api:82") + // Must be added when used as an Xposed Module, otherwise optional + ksp("com.highcapable.yukihookapi:ksp-xposed:<yuki-version>") +} +
",-1),b={href:"https://github.com/google/ksp/releases",target:"_blank",rel:"noopener noreferrer"},B=n("strong",null,"(please note to select your current corresponding Kotlin version)",-1),C=n("p",null,[s("Please change "),n("strong",null," "),s(" to the latest version "),n("a",{href:"../about/changelog"},"here"),s(".")],-1),h=n("strong",null," ",-1),k={href:"https://highcapable.github.io/KavaRef/en/about/changelog",target:"_blank",rel:"noopener noreferrer"},g=l(` Pay Attention
The api and ksp-xposed dependency versions of YukiHookAPI must correspond one-to-one, otherwise a version mismatch error will occur.
# Configure Java Version
Modify the Java version of Kotlin in your project
build.gradle.kts
orbuild.gradle
to 17 or above.Kotlin DSL
android { + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = "17" + } +} +
Groovy DSL
android { + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = '17' + } +} +
Notice
Since API 1.0.80, the Java version used by Kotlin defaults to 11, and versions 1.8 and below are no longer supported.
Since API 1.2.0, the Java version used by Kotlin defaults to 17, and versions 11 and below are no longer supported.
# Use as Xposed Module
Add the base code to your
AndroidManifest.xml
.The following example
<!-- Set as Xposed Module --> +<meta-data + android:name="xposedmodule" + android:value="true" /> + +<!-- Set your Xposed Module description --> +<meta-data + android:name="xposeddescription" + android:value="Fill in your Xposed Module description" /> + +<!-- The minimum Xposed version number --> +<!-- If you are using EdXposed/LSPosed, the minimum recommended is 93 --> +<meta-data + android:name="xposedminversion" + android:value="93" /> + +<!-- Optional: Configure support for New XSharedPreferences without adjusting xposedminversion to 93 --> +<meta-data + android:name="xposedsharedprefs" + android:value="true"/> +
Create a Hook entry class in your project, implements
IYukiHookXposedInit
and add the annotation@InjectYukiHookWithXposed
.The following example
@InjectYukiHookWithXposed +object HookEntry : IYukiHookXposedInit { + + override fun onHook() = YukiHookAPI.encase { + // Your code here. + } +} +
Suggestion
Please configure YukiHookAPI in the onInit method and set the isDebug mode to the following form.
The following example
override fun onInit() = configs { + isDebug = BuildConfig.DEBUG +} +
You can also extends Application of your Module App from ModuleApplication to achieve a complete user experience.
For more functions, please refer to ModuleApplication.
Then, you can start writing Hook code.
For configuration details related to use as an Xposed Module, you can click here to continue reading.
If you are currently using Hook APIs such as Rovo89 Xposed API, you can refer to Migrate from Other Hook APIs.
# Use as Hook API
# Integration
Create your custom
Application
.Pay Attention
Regardless of the Hook Framework you use, you need to add its docking Xposed dependency support.
If the target Hook Framework does not integrate Rovo89 Xposed API, you need to implement and connect XposedBridge by yourself.
Add
YukiHookAPI.encase
method toattachBaseContext
.The following example
override fun attachBaseContext(base: Context?) { + // Load Hook Framework + // + // Your code here. + // + // Load YukiHookAPI + YukiHookAPI.encase(base) { + // Your code here. + } + super.attachBaseContext(base) +} +
Then, you can start writing Hook code in much the same way you would use it as an Xposed Module.
For configuration details related to use as a Hook API, you can click here to continue reading.
`,29);function F(f,q){const a=p("ExternalLinkIcon");return i(),t("div",null,[c,n("ul",null,[n("li",null,[n("p",null,[s("Android Studio (It is recommended to get the latest version from "),n("a",d,[s("here"),e(a)]),s(")")])]),n("li",null,[n("p",null,[s("IntelliJ IDEA (It is recommended to get the latest version from "),n("a",u,[s("here"),e(a)]),s(")")])]),y]),A,n("p",null,[s("We recommend using Kotlin DSL as the Gradle build script language and "),n("a",v,[s("SweetDependency"),e(a)]),s(" to manage dependencies.")]),D,n("p",null,[s("Please modify "),m,s(" to the latest version found "),n("a",b,[s("here"),e(a)]),s(),B,s(".")]),C,n("p",null,[s("Please change "),h,s(" to the latest version "),n("a",k,[s("here"),e(a)]),s(".")]),g])}const w=o(r,[["render",F],["__file","quick-start.html.vue"]]);export{w as default}; diff --git a/assets/quick-start.html-Dq2QHQuy.js b/assets/quick-start.html-Dq2QHQuy.js new file mode 100644 index 00000000..44f1dfff --- /dev/null +++ b/assets/quick-start.html-Dq2QHQuy.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-24840ff0","path":"/zh-cn/guide/quick-start.html","title":"快速开始","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"项目要求","slug":"项目要求","link":"#项目要求","children":[]},{"level":2,"title":"自动构建项目","slug":"自动构建项目","link":"#自动构建项目","children":[]},{"level":2,"title":"手动配置项目","slug":"手动配置项目","link":"#手动配置项目","children":[{"level":3,"title":"创建项目","slug":"创建项目","link":"#创建项目","children":[]},{"level":3,"title":"集成依赖","slug":"集成依赖","link":"#集成依赖","children":[]},{"level":3,"title":"作为 Xposed 模块使用","slug":"作为-xposed-模块使用","link":"#作为-xposed-模块使用","children":[]},{"level":3,"title":"作为 Hook API 使用","slug":"作为-hook-api-使用","link":"#作为-hook-api-使用","children":[]}]}],"git":{"updatedTime":1754158575000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":16},{"name":"sorrw.","email":"145167297+sorrow404Null@users.noreply.github.com","commits":1}]},"filePathRelative":"zh-cn/guide/quick-start.md"}');export{e as data}; diff --git a/assets/quick-start.html-pUciT6Ob.js b/assets/quick-start.html-pUciT6Ob.js new file mode 100644 index 00000000..40d95a35 --- /dev/null +++ b/assets/quick-start.html-pUciT6Ob.js @@ -0,0 +1,160 @@ +import{_ as o,r as p,o as i,c,b as n,d as s,e as l,a as e}from"./app-BpUB8-Q8.js";const r={},t=e('Notice
YukiHookPrefsBridge, YukiHookDataChannel and Resources Hook functionality will not work when using a custom Hook Framework instead of the full Xposed Module.
# 快速开始
集成
YukiHookAPI
到你的项目中。# 项目要求
项目需要使用
',4),d={href:"https://developer.android.com/studio",target:"_blank",rel:"noopener noreferrer"},A={href:"https://www.jetbrains.com/idea",target:"_blank",rel:"noopener noreferrer"},u=n("li",null,[n("p",null,"Kotlin 1.9.0+、Gradle 8+、Java 11、17+、Android Gradle Plugin 8+")],-1),v=e('Android Studio
或IntelliJ IDEA
创建且类型为 Android 项目并已集成 Kotlin 环境依赖。# 自动构建项目
YukiHookAPI
提供了一个自动化构建工具,它可以帮助你快速构建一个拥有 Xposed 模块依赖的 Android 标准项目模板,使用构建好的模板即可直接开始下一步工作。你可以 点击这里 进行查看。
# 手动配置项目
若你不想使用自动化构建工具,你依然可以按照以下方式手动配置项目依赖。
# 创建项目
使用
Android Studio
或IntelliJ IDEA
创建新的 Android 项目,并在Language
一栏选择 Kotlin 以自动添加基础依赖。# 集成依赖
',8),y={href:"https://github.com/HighCapable/SweetDependency",target:"_blank",rel:"noopener noreferrer"},D=e(`# SweetDependency (推荐)
在你的项目
SweetDependency
配置文件中添加存储库和依赖。示例如下
repositories: + # 作为 Xposed 模块使用务必添加,其它情况可选 + rovo89-xposed-api: + url: https://api.xposed.info/ + +plugins: + # 作为 Xposed 模块使用务必添加,其它情况可选 + com.google.devtools.ksp: + version: + + ... + +libraries: + # 作为 Xposed 模块使用务必添加,其它情况可选 + de.robv.android.xposed: + api: + version: 82 + repositories: + rovo89-xposed-api + com.highcapable.yukihookapi: + api: + version: + + # 作为 Xposed 模块使用务必添加,其它情况可选 + ksp-xposed: + version-ref: <this>::api + # YukiHookAPI 1.3.0 版本后使用 KavaRef 作为核心反射 API + # YukiHookAPI 不再绑定自身的反射 API,你可以开始尝试使用 KavaRef + com.highcapable.kavaref: + kavaref-core: + version: + + kavaref-extension: + version: + + ... +
添加完成后运行一次 Gradle Sync,所有依赖版本将自动装配。
接下来,在你的项目
build.gradle.kts
中部署插件。示例如下
plugins { + // 作为 Xposed 模块使用务必添加,其它情况可选 + autowire(libs.plugins.com.google.devtools.ksp) + // ... +} +
然后,在你的项目
build.gradle.kts
中部署依赖。示例如下
dependencies { + // 基础依赖 + implementation(com.highcapable.yukihookapi.api) + // 推荐使用 KavaRef 作为核心反射 API + implementation(com.highcapable.kavaref.kavaref.core) + implementation(com.highcapable.kavaref.kavaref.extension) + // 作为 Xposed 模块使用务必添加,其它情况可选 + compileOnly(de.robv.android.xposed.api) + // 作为 Xposed 模块使用务必添加,其它情况可选 + ksp(com.highcapable.yukihookapi.ksp.xposed) +} +
# Version Catalog
在你的项目
build.gradle.kts
中添加存储库。Kotlin DSL
repositories { + google() + mavenCentral() + // 作为 Xposed 模块使用务必添加,其它情况可选 + maven("https://api.xposed.info/") +} +
在你的项目
gradle/libs.versions.toml
中添加依赖。示例如下
[versions] +yukihookapi = "<yuki-version>" +ksp = "<ksp-version>" +kavaref-core = "<kavaref-version>" +kavaref-extension = "<kavaref-version>" + +[plugins] +# 作为 Xposed 模块使用务必添加,其它情况可选 +ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } + +[libraries] +yukihookapi-api = { module = "com.highcapable.yukihookapi:api", version.ref = "yukihookapi" } +# 作为 Xposed 模块使用务必添加,其它情况可选 +yukihookapi-ksp-xposed = { module = "com.highcapable.yukihookapi:ksp-xposed", version.ref = "yukihookapi" } +# YukiHookAPI 1.3.0 版本后使用 KavaRef 作为核心反射 API +# YukiHookAPI 不再绑定自身的反射 API,你可以开始尝试使用 KavaRef +kavaref-core = { module = "com.highcapable.kavaref:kavaref-core", version.ref = "kavaref-core" } +kavaref-extension = { module = "com.highcapable.kavaref:kavaref-extension", version.ref = "kavaref-extension" } +# 作为 Xposed 模块使用务必添加,其它情况可选 +xposed-api = { module = "de.robv.android.xposed:api", version = "82" } +
接下来,在你的项目
build.gradle.kts
中部署插件。Kotlin DSL
plugins { + // 作为 Xposed 模块使用务必添加,其它情况可选 + alias(libs.plugins.ksp) +} +
然后,在你的项目
build.gradle.kts
中部署依赖。Kotlin DSL
dependencies { + // 基础依赖 + implementation(libs.yukihookapi.api) + // 推荐使用 KavaRef 作为核心反射 API + implementation(libs.kavaref.core) + implementation(libs.kavaref.extension) + // 作为 Xposed 模块使用务必添加,其它情况可选 + compileOnly(libs.xposed.api) + // 作为 Xposed 模块使用务必添加,其它情况可选 + ksp(libs.yukihookapi.ksp.xposed) +} +
# 传统方式
在你的项目
build.gradle.kts
中添加存储库。Kotlin DSL
repositories { + google() + mavenCentral() + // 作为 Xposed 模块使用务必添加,其它情况可选 + maven("https://api.xposed.info/") +} +
在你的项目
build.gradle.kts
中添加插件。Kotlin DSL
plugins { + // 作为 Xposed 模块使用务必添加,其它情况可选 + id("com.google.devtools.ksp") version "<ksp-version>" +} +
在你的项目
build.gradle.kts
中添加依赖。Kotlin DSL
`,34),B=n("strong",null,"dependencies { + // 基础依赖 + implementation("com.highcapable.yukihookapi:api:<yuki-version>") + // 推荐使用 KavaRef 作为核心反射 API + implementation("com.highcapable.kavaref:kavaref-core:<kavaref-version>") + implementation("com.highcapable.kavaref:kavaref-extension:<kavaref-version>") + // 作为 Xposed 模块使用务必添加,其它情况可选 + compileOnly("de.robv.android.xposed:api:82") + // 作为 Xposed 模块使用务必添加,其它情况可选 + ksp("com.highcapable.yukihookapi:ksp-xposed:<yuki-version>") +} +
",-1),b={href:"https://github.com/google/ksp/releases",target:"_blank",rel:"noopener noreferrer"},m=n("strong",null,"(请注意选择你当前对应的 Kotlin 版本)",-1),C=n("p",null,[s("请将 "),n("strong",null," "),s(" 修改为 "),n("a",{href:"../about/changelog"},"这里"),s(" 的最新版本。")],-1),k=n("strong",null," ",-1),h={href:"https://highcapable.github.io/KavaRef/zh-cn/about/changelog",target:"_blank",rel:"noopener noreferrer"},g=e(` 特别注意
YukiHookAPI 的 api 与 ksp-xposed 依赖的版本必须一一对应,否则将会造成版本不匹配错误。
# 配置 Java 版本
在你的项目
build.gradle.kts
中修改 Kotlin 的 Java 版本为 17 及以上。Kotlin DSL
android { + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = "17" + } +} +
注意
自 API 1.0.80 版本后 Kotlin 使用的 Java 版本默认为 11,不再支持 1.8 及以下版本。
自 API 1.2.0 版本后 Kotlin 使用的 Java 版本默认为 17,不再支持 11 及以下版本。
# 作为 Xposed 模块使用
在你的
AndroidManifest.xml
中添加基础代码。示例如下
<!-- 设置为 Xposed 模块 --> +<meta-data + android:name="xposedmodule" + android:value="true" /> + +<!-- 设置你的模块描述 --> +<meta-data + android:name="xposeddescription" + android:value="填写你的 Xposed 模块描述" /> + +<!-- 最低 Xposed 版本号,若你正在使用 EdXposed/LSPosed,建议最低为 93 --> +<meta-data + android:name="xposedminversion" + android:value="93" /> + +<!-- 可选:配置支持 New XSharedPreferences 可无需调整 xposedminversion 为 93 --> +<meta-data + android:name="xposedsharedprefs" + android:value="true"/> +
在你的项目中创建一个 Hook 入口类,继承于
IYukiHookXposedInit
并加入注解@InjectYukiHookWithXposed
。示例如下
@InjectYukiHookWithXposed +object HookEntry : IYukiHookXposedInit { + + override fun onHook() = YukiHookAPI.encase { + // Your code here. + } +} +
建议
请在 onInit 方法中配置 YukiHookAPI 并将 isDebug 模式设置为如下形式。
示例如下
override fun onInit() = configs { + isDebug = BuildConfig.DEBUG +} +
你还可以将你的模块 APP 的 Application 继承于 ModuleApplication 以实现完整使用体验。
更多功能请参考 ModuleApplication。
然后,你就可以开始编写 Hook 代码了。
有关作为 Xposed 模块使用的相关配置详细内容,你可以 点击这里 继续阅读。
若你目前正在使用 Rovo89 Xposed API 等 Hook API,你可以参考 从其它 Hook API 迁移。
# 作为 Hook API 使用
# 集成方式
创建你的自定义
Application
。特别注意
无论使用任何 Hook Framework,你都需要加入其对接的 Xposed 依赖支持。
若目标 Hook Framework 没有集成 Rovo89 Xposed API 你需要自行实现并对接 XposedBridge。
在
attachBaseContext
中添加YukiHookAPI.encase
方法。示例如下
override fun attachBaseContext(base: Context?) { + // 装载 Hook Framework + // + // Your code here. + // + // 装载 YukiHookAPI + YukiHookAPI.encase(base) { + // Your code here. + } + super.attachBaseContext(base) +} +
然后,你就可以开始编写 Hook 代码了,方式与作为 Xposed 模块使用基本一致。
有关作为 Hook API 使用的相关配置详细内容,你可以 点击这里 继续阅读。
`,27);function F(q,f){const a=p("ExternalLinkIcon");return i(),c("div",null,[t,n("ul",null,[n("li",null,[n("p",null,[s("Android Studio (建议从 "),n("a",d,[s("这里"),l(a)]),s(" 获取最新版本)")])]),n("li",null,[n("p",null,[s("IntelliJ IDEA (建议从 "),n("a",A,[s("这里"),l(a)]),s(" 获取最新版本)")])]),u]),v,n("p",null,[s("我们推荐使用 Kotlin DSL 作为 Gradle 构建脚本语言并推荐使用 "),n("a",y,[s("SweetDependency"),l(a)]),s(" 来管理依赖。")]),D,n("p",null,[s("请将 "),B,s(" 修改为 "),n("a",b,[s("这里"),l(a)]),s(" 的最新版本 "),m,s("。")]),C,n("p",null,[s("请将 "),k,s(" 修改为 "),n("a",h,[s("这里"),l(a)]),s(" 的最新版本。")]),g])}const _=o(r,[["render",F],["__file","quick-start.html.vue"]]);export{_ as default}; diff --git a/assets/quick-start.html-teZCSUoB.js b/assets/quick-start.html-teZCSUoB.js new file mode 100644 index 00000000..81c630d3 --- /dev/null +++ b/assets/quick-start.html-teZCSUoB.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-72889797","path":"/en/guide/quick-start.html","title":"Quick Start","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"Project Requirements","slug":"project-requirements","link":"#project-requirements","children":[]},{"level":2,"title":"Automatically Build Project","slug":"automatically-build-project","link":"#automatically-build-project","children":[]},{"level":2,"title":"Manually Configure Project","slug":"manually-configure-project","link":"#manually-configure-project","children":[{"level":3,"title":"Create Project","slug":"create-project","link":"#create-project","children":[]},{"level":3,"title":"Integration Dependencies","slug":"integration-dependencies","link":"#integration-dependencies","children":[]},{"level":3,"title":"Use as Xposed Module","slug":"use-as-xposed-module","link":"#use-as-xposed-module","children":[]},{"level":3,"title":"Use as Hook API","slug":"use-as-hook-api","link":"#use-as-hook-api","children":[]}]}],"git":{"updatedTime":1754157645000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":19},{"name":"sorrw.","email":"145167297+sorrow404Null@users.noreply.github.com","commits":1}]},"filePathRelative":"en/guide/quick-start.md"}');export{e as data}; diff --git a/assets/r8-proguard.html-BruKL-ec.js b/assets/r8-proguard.html-BruKL-ec.js new file mode 100644 index 00000000..67da05ea --- /dev/null +++ b/assets/r8-proguard.html-BruKL-ec.js @@ -0,0 +1,2 @@ +import{_ as e,o,c as a,a as r}from"./app-BpUB8-Q8.js";const n={},s=r(`注意
使用自定义的 Hook Framework 而并非完整的 Xposed 模块时,YukiHookPrefsBridge、YukiHookDataChannel 以及 Resources Hook 功能将失效。
# R8 & Proguard Obfuscate
In most scenarios, the Xposed Module can be compressed by native obfuscation.
Here is the configuration method of obfuscation.
# R8
If you are using
R8
then you don't need any special configuration forYukiHookAPI
.# Proguard
If you are still usingProguard
, you need to do some rule configuration.Pay Attention
Proguard rules have been deprecated, please don't use them anymore.
Since Android Gradle Plugin 4.2, the obfuscator with the latest version of the Android Jetpack default is R8, and you no longer need to consider obfuscation.
To enable
R8
in any version, please add the following rules to thegradle.properties
file, no configuration is required for Android Gradle Plugin 7.0 and above.`,9),d=[s];function t(i,c){return o(),a("div",null,d)}const u=e(n,[["render",t],["__file","r8-proguard.html.vue"]]);export{u as default}; diff --git a/assets/r8-proguard.html-C9EyjikD.js b/assets/r8-proguard.html-C9EyjikD.js new file mode 100644 index 00000000..68e88ee0 --- /dev/null +++ b/assets/r8-proguard.html-C9EyjikD.js @@ -0,0 +1,2 @@ +import{_ as e,o as a,c as o,a as r}from"./app-BpUB8-Q8.js";const d={},s=r(`android.enableR8=true +
# R8 与 Proguard 混淆
大部分场景下 Xposed 模块可通过原生混淆压缩体积,这里介绍了混淆的配置方法。
# R8
如果你使用的是
R8
,那么你无需对YukiHookAPI
进行任何特殊配置。# Proguard
如果你仍然在使用Proguard
,你需要做一些规则配置。特别注意
Proguard 规则已被弃用,请不要再使用,自从 Android Gradle Plugin 4.2 后,拥有 Android Jetpack 套件最新版本的混淆处理程序默认均为 R8,不再需要考虑混淆的问题。
若要在任何版本下启用
R8
,请在gradle.properties
文件中加入如下规则,Android Gradle Plugin 7.0 及以上版本无需任何配置。`,9),n=[s];function c(t,i){return a(),o("div",null,n)}const p=e(d,[["render",c],["__file","r8-proguard.html.vue"]]);export{p as default}; diff --git a/assets/r8-proguard.html-DnD4WWCL.js b/assets/r8-proguard.html-DnD4WWCL.js new file mode 100644 index 00000000..733a54b4 --- /dev/null +++ b/assets/r8-proguard.html-DnD4WWCL.js @@ -0,0 +1 @@ +const r=JSON.parse('{"key":"v-154d6f69","path":"/zh-cn/config/r8-proguard.html","title":"R8 与 Proguard 混淆","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"R8","slug":"r8","link":"#r8","children":[]},{"level":2,"title":"Proguard","slug":"proguard","link":"#proguard","children":[]}],"git":{"updatedTime":1663397167000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":1}]},"filePathRelative":"zh-cn/config/r8-proguard.md"}');export{r as data}; diff --git a/assets/r8-proguard.html-Y47fgLwe.js b/assets/r8-proguard.html-Y47fgLwe.js new file mode 100644 index 00000000..88e6edf9 --- /dev/null +++ b/assets/r8-proguard.html-Y47fgLwe.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-29d6c1ba","path":"/en/config/r8-proguard.html","title":"R8 & Proguard Obfuscate","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"R8","slug":"r8","link":"#r8","children":[]},{"level":2,"title":"Proguard","slug":"proguard","link":"#proguard","children":[]}],"git":{"updatedTime":1663397167000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":1}]},"filePathRelative":"en/config/r8-proguard.md"}');export{e as data}; diff --git a/assets/reflection.html-BZdJSVZS.js b/assets/reflection.html-BZdJSVZS.js new file mode 100644 index 00000000..d33a87cb --- /dev/null +++ b/assets/reflection.html-BZdJSVZS.js @@ -0,0 +1,822 @@ +import{_ as c,r as e,o as t,c as r,b as s,d as n,e as a,a as o}from"./app-BpUB8-Q8.js";const i={},d=s("h1",{id:"字节码与反射扩展-已迁移",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#字节码与反射扩展-已迁移","aria-hidden":"true"},"#"),n(" 字节码与反射扩展 (已迁移)")],-1),A=s("blockquote",null,[s("p",null,[s("code",null,"YukiHookAPI"),n(" 为开发者封装了一套接近零反射写法的反射 API,它几乎可以完全取代原生 Java 的反射 API 相关用法。")])],-1),y={href:"https://github.com/HighCapable/YukiReflection",target:"_blank",rel:"noopener noreferrer"},D=o("android.enableR8=true +
现在YukiReflection
作为核心依赖集成于YukiHookAPI
。",2),B={class:"custom-container warning"},C=s("p",{class:"custom-container-title"},"注意",-1),u=s("code",null,"1.3.0",-1),v=s("code",null,"YukiHookAPI",-1),m={href:"https://github.com/HighCapable/KavaRef",target:"_blank",rel:"noopener noreferrer"},b=s("code",null,"YukiHookAPI",-1),F=s("p",null,[s("code",null,"YukiReflection"),n(" 项目由于很多未能解决的黑盒问题已被弃用,我们不再推荐任何人使用它。")],-1),k=s("code",null,"YukiHookAPI",-1),h={href:"https://highcapable.github.io/KavaRef/zh-cn/config/migration",target:"_blank",rel:"noopener noreferrer"},g=s("code",null,"KavaRef",-1),q={style:{opacity:"0.35"}},T=o(`
YukiHookAPI
在YukiReflection
的基础上加入了针对 Hook 功能的相关扩展,使用YukiHookAPI
无需引入此依赖。# Class 扩展
这里是 Class 对象自身相关的扩展功能。
# 对象转换
假设我们要得到一个不能直接调用的
Class
,通常情况下,我们可以使用标准的反射 API 去查找这个Class
。示例如下
// 默认 ClassLoader 环境下的 Class +var instance = Class.forName("com.demo.Test") +// 指定 ClassLoader 环境下的 Class +val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader +var instance = customClassLoader?.loadClass("com.demo.Test") +
这种写法大概不是很友好,此时
YukiHookAPI
就为你提供了一个可在任意地方使用的语法糖。以上写法换做
YukiHookAPI
可写作如下形式。示例如下
// 直接得到这个 Class +// 如果当前正处于 PackageParam 环境,那么你可以不需要考虑 ClassLoader +var instance = "com.demo.Test".toClass() +// 自定义 Class 所在的 ClassLoader +val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader +var instance = "com.demo.Test".toClass(customClassLoader) +
如果当前
Class
并不存在,使用上述方法会抛出异常,如果你不确定Class
是否存在,可以参考下面的解决方案。示例如下
// 直接得到这个 Class +// 如果当前正处于 PackageParam 环境,那么你可以不需要考虑 ClassLoader +// 得不到时结果会为 null 但不会抛出异常 +var instance = "com.demo.Test".toClassOrNull() +// 自定义 Class 所在的 ClassLoader +val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader +// 得不到时结果会为 null 但不会抛出异常 +var instance = "com.demo.Test".toClassOrNull(customClassLoader) +
我们还可以通过映射来得到一个存在的
Class
对象。示例如下
// 假设这个 Class 是能够被直接得到的 +var instance = classOf<Test>() +// 我们同样可以自定义 Class 所在的 ClassLoader,这对于 stub 来说非常有效 +val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader +var instance = classOf<Test>(customClassLoader) +
小提示
更多功能请参考 classOf、String.toClass、String.toClassOrNull、PackageParam → String+VariousClass.toClass、PackageParam → String+VariousClass.toClassOrNull 方法。
# 延迟装载
假设我们要得到一个不能直接调用的
Class
,但是我们也不是立刻就需要这个Class
。这个时候,你可以使用
lazyClass
来完成这个功能。示例如下
// 延迟装载这个 Class +// 如果当前正处于 PackageParam 环境,那么你可以不需要考虑 ClassLoader +val instance by lazyClass("com.demo.Test") +// 自定义 Class 所在的 ClassLoader +val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader +val instance by lazyClass("com.demo.Test") { customClassLoader } +// 在适当的时候调用这个 Class +instance.method { + // ... +} +
如果当前
Class
并不存在,使用上述方法会抛出异常,如果你不确定Class
是否存在,可以参考下面的解决方案。示例如下
// 延迟装载这个 Class +// 如果当前正处于 PackageParam 环境,那么你可以不需要考虑 ClassLoader +// 得不到时结果会为 null 但不会抛出异常 +val instance by lazyClassOrNull("com.demo.Test") +// 自定义 Class 所在的 ClassLoader +val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader +// 得不到时结果会为 null 但不会抛出异常 +val instance by lazyClassOrNull("com.demo.Test") { customClassLoader } +// 在适当的时候调用这个 Class +instance?.method { + // ... +} +
# 存在判断
假设我们要判断一个
Class
是否存在,通常情况下,我们可以使用标准的反射 API 去查找这个Class
通过异常来判断是否存在。示例如下
// 默认 ClassLoader 环境下的 Class +var isExist = try { + Class.forName("com.demo.Test") + true +} catch (_: Throwable) { + false +} +// 指定 ClassLoader 环境下的 Class +val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader +var isExist = try { + customClassLoader?.loadClass("com.demo.Test") + true +} catch (_: Throwable) { + false +} +
这种写法大概不是很友好,此时
YukiHookAPI
就为你提供了一个可在任意地方使用的语法糖。以上写法换做
YukiHookAPI
可写作如下形式。示例如下
// 判断这个 Class 是否存在 +// 如果当前正处于 PackageParam 环境,那么你可以不需要考虑 ClassLoader +var isExist = "com.demo.Test".hasClass() +// 自定义 Class 所在的 ClassLoader +val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader +var isExist = "com.demo.Test".hasClass(customClassLoader) +
`,35),x={id:"模糊查找",tabindex:"-1"},f=s("a",{class:"header-anchor",href:"#模糊查找","aria-hidden":"true"},"#",-1),P=o('小提示
更多功能请参考 String.hasClass、PackageParam → String.hasClass 方法。
在 R8 等工具混淆后的宿主 Dex 中的
Class
名称将会难以分辨,且不确定其正确位置,不能直接通过 对象转换 来得到。此时就有了
DexClassFinder
,它的作用是通过需要查找的Class
中的字节码特征来确定这个Class
的实例。',3),S={class:"custom-container danger"},_=s("p",{class:"custom-container-title"},"特别注意",-1),j=s("strong",null,"YukiHookAPI",-1),I=s("strong",null,"2.0.0",-1),L={href:"https://github.com/HighCapable/YukiReflection",target:"_blank",rel:"noopener noreferrer"},H={href:"https://github.com/LuckyPray/DexKit",target:"_blank",rel:"noopener noreferrer"},R=s("strong",null,"Dex",-1),Y=o(`注意
目前 DexClassFinder 的功能尚在实验阶段,由于仅通过 Java 层实现查找功能,在宿主 Class 过多时性能可能不能达到最佳水平,如果发生查找不到、定位有误的问题欢迎向我们反馈。
由于是反射层面的 API,目前它只能通过类与成员的特征来定位指定的 Class,不能通过指定字节码中的字符串和方法内容特征来进行定位。
查找 Class 的速度取决于当前设备的性能,目前主流的移动端处理器在 10~15w 数量的 Class 中条件不算复杂的情况下大概在 3~10s 区间,条件稍微复杂的情况下最快速度能达到 25s 以内,匹配到的同类型 Class 越多速度越慢。
# 开始使用
下面是一个简单的用法示例。
假设下面这个
Class
是我们想要得到的,其中的名称经过了混淆,在每个版本可能都不一样。示例如下
package com.demo; + +public class a extends Activity implements Serializable { + + public a(String var1) { + // ... + } + + private String a; + + private String b; + + private boolean a; + + protected void onCreate(Bundle var1) { + // ... + } + + private static void a(String var1) { + // ... + } + + private String a(boolean var1, String var2) { + // ... + } + + private void a() { + // ... + } + + public void a(boolean var1, a var2, b var3, String var4) { + // ... + } +} +
此时,我们想得到这个
Class
,可以直接使用ClassLoader.searchClass
方法。在
PackageParam
中,你可以直接使用searchClass
方法,它将自动指定appClassLoader
。下方演示的条件中每一个都是可选的,条件越复杂定位越精确,同时性能也会越差。
示例如下
searchClass { + // 从指定的包名范围开始查找,实际使用时,你可以同时指定多个包名范围 + from("com.demo") + // 指定当前 Class 的 getSimpleName 的结果,你可以直接对这个字符串进行逻辑判断 + // 这里我们不确定它的名称是不是 a,可以只判断字符串长度 + simpleName { it.length == 1 } + // 指定继承的父类对象,如果是存在的 stub,可以直接用泛型表示 + extends<Activity>() + // 指定继承的父类对象,可以直接写为完整类名,你还可以同时指定多个 + extends("android.app.Activity") + // 指定实现的接口,如果是存在的 stub,可以直接用泛型表示 + implements<Serializable>() + // 指定实现的接口,可以直接写为完整类名,你还可以同时指定多个 + implements("java.io.Serializable") + // 指定构造方法的类型与样式,以及在当前类中存在的个数 count + constructor { param(StringClass) }.count(num = 1) + // 指定变量的类型与样式,以及在当前类中存在的个数 count + field { type = StringClass }.count(num = 2) + // 指定变量的类型与样式,以及在当前类中存在的个数 count + field { type = BooleanType }.count(num = 1) + // 直接指定所有变量在当前类中存在的个数 count + field().count(num = 3) + // 如果你认为变量的个数是不确定的,还可以使用如下自定义条件 + field().count(1..3) + field().count { it >= 3 } + // 指定方法的类型与样式,以及在当前类中存在的个数 count + method { + name = "onCreate" + param(BundleClass) + }.count(num = 1) + // 指定方法的类型与样式,同时指定修饰符,以及在当前类中存在的个数 count + method { + modifiers { isStatic && isPrivate } + param(StringClass) + returnType = UnitType + }.count(num = 1) + // 指定方法的类型与样式,同时指定修饰符,以及在当前类中存在的个数 count + method { + modifiers { isPrivate && isStatic.not() } + param(BooleanType, StringClass) + returnType = StringClass + }.count(num = 1) + // 指定方法的类型与样式,同时指定修饰符,以及在当前类中存在的个数 count + method { + modifiers { isPrivate && isStatic.not() } + emptyParam() + returnType = UnitType + }.count(num = 1) + // 指定方法的类型与样式,同时指定修饰符和模糊类型 VagueType,以及在当前类中存在的个数 count + method { + modifiers { isPrivate && isStatic.not() } + param(BooleanType, VagueType, VagueType, StringClass) + returnType = UnitType + }.count(num = 1) + // 直接指定所有方法在当前类中存在的个数 count + method().count(num = 5) + // 如果你认为方法的个数是不确定的,还可以使用如下自定义条件 + method().count(1..5) + method().count { it >= 5 } + // 直接指定所有成员 (Member) 在当前类中存在的个数 count + // 成员包括:Field (变量)、Method (方法)、Constructor (构造方法) + member().count(num = 9) + // 所有成员中一定存在一个 static 修饰符,可以这样加入此条件 + member { + modifiers { isStatic } + } +}.get() // 得到这个 Class 本身的实例,找不到会返回 null +
小提示
上述用法中对于 Field、Method、Constructor 的条件用法与 Member 扩展 中的相关用法是一致的,仅有小部分区别。
更多功能请参考 MemberRules、FieldRules、MethodRules、ConstructorRules。
# 异步查找
默认情况下
DexClassFinder
会使用同步方式查找Class
,会阻塞当前线程直到找到或找不到发生异常为止,若查找消耗的时间过长,可能会导致宿主发生 ANR 问题。针对上述问题,我们可以启用异步,只需要加入参数
async = true
,这将不需要你再次启动一个线程,API 已帮你处理好相关问题。注意
对于异步情况下你需要使用 wait 方法来得到结果,get 方法将不再起作用。
示例如下
searchClass(async = true) { + // ... +}.wait { class1 -> + // 得到异步结果 +} +searchClass(async = true) { + // ... +}.wait { class2 -> + // 得到异步结果 +} +
这样我们的查找过程就是异步运行了,它将不会阻塞主线程,每个查找都将在单独的线程同时进行,可达到并行任务的效果。
# 本地缓存
由于每次重新打开宿主都会重新进行查找,在宿主版本不变的情况下这是一种重复性能浪费。
此时我们可以通过指定
name
参数来对当前宿主版本的查找结果进行本地缓存,下一次将直接从本地缓存中读取查找到的类名。本地缓存使用的是
SharedPreferences
,它将被保存到宿主的数据目录中,在宿主版本更新后会重新进行缓存。启用本地缓存后,将同时设置
async = true
,你可以不需要再手动进行设置。示例如下
searchClass(name = "com.demo.class1") { + // ... +}.wait { class1 -> + // 得到异步结果 +} +searchClass(name = "com.demo.class2") { + // ... +}.wait { class2 -> + // 得到异步结果 +} +
如果你想手动清除本地缓存,可以使用如下方法清除当前版本的宿主缓存。
示例如下
// 直接调用,在宿主的 appContext 为空时可能会失败,失败会打印警告信息 +DexClassFinder.clearCache() +// 监听宿主的生命周期后调用 +onAppLifecycle { + onCreate { + DexClassFinder.clearCache(context = this) + } +} +
你还可以清除指定版本的宿主缓存。
示例如下
// 直接调用,在宿主的 appContext 为空时可能会失败,失败会打印警告信息 +DexClassFinder.clearCache(versionName = "1.0", versionCode = 1) +// 监听宿主的生命周期后调用 +onAppLifecycle { + onCreate { + DexClassFinder.clearCache(context = this, versionName = "1.0", versionCode = 1) + } +} +
# 多重查找
如果你需要使用固定的条件同时查找一组
Class
,那么你只需要使用all
或waitAll
方法来得到结果。// 同步查找,使用 all 得到条件全部查找到的结果 +searchClass { + // ... +}.all().forEach { clazz -> + // 得到每个结果 +} +// 同步查找,使用 all { ... } 遍历每个结果 +searchClass { + // ... +}.all { clazz -> + // 得到每个结果 +} +// 异步查找,使用 waitAll 得到条件全部查找到的结果 +searchClass(async = true) { + // ... +}.waitAll { classes -> + classes.forEach { + // 得到每个结果 + } +} +
小提示
更多功能请参考 ClassLoader.searchClass、PackageParam.searchClass 方法。
# Member 扩展
这里是 Class 字节码成员变量 Field、Method、Constructor 相关的扩展功能。
小提示
Member 是 Field、Method、Constructor 的接口描述对象,它在 Java 反射中为 Class 中字节码成员的总称。
假设有一个这样的
Class
。示例如下
package com.demo; + +public class BaseTest { + + public BaseTest() { + // ... + } + + public BaseTest(boolean isInit) { + // ... + } + + private void doBaseTask(String taskName) { + // ... + } +} +
package com.demo; + +public class Test extends BaseTest { + + public Test() { + // ... + } + + public Test(boolean isInit) { + // ... + } + + private static TAG = "Test"; + + private BaseTest baseInstance; + + private String a; + + private boolean a; + + private boolean isTaskRunning = false; + + private static void init() { + // ... + } + + private void doTask(String taskName) { + // ... + } + + private void release(String taskName, Function<boolean, String> task, boolean isFinish) { + // ... + } + + private void stop() { + // ... + } + + private String getName() { + // ... + } + + private void b() { + // ... + } + + private void b(String a) { + // ... + } +} +
# 查找与反射调用
假设我们要得到
Test
(以下统称“当前Class
”)的doTask
方法并执行,通常情况下,我们可以使用标准的反射 API 去查找这个方法。示例如下
// 假设这就是这个 Class 的实例 +val instance = Test() +// 使用反射 API 调用并执行 +Test::class.java + .getDeclaredMethod("doTask", String::class.java) + .apply { isAccessible = true } + .invoke(instance, "task_name") +
这种写法大概不是很友好,此时
YukiHookAPI
就为你提供了一个可在任意地方使用的语法糖。以上写法换做
YukiHookAPI
可写作如下形式。示例如下
// 假设这就是这个 Class 的实例 +val instance = Test() +// 使用 YukiHookAPI 调用并执行 +Test::class.java.method { + name = "doTask" + param(StringClass) +}.get(instance).call("task_name") +
小提示
更多功能请参考 MethodFinder。
同样地,我们需要得到
isTaskRunning
变量也可以写作如下形式。示例如下
// 假设这就是这个 Class 的实例 +val instance = Test() +// 使用 YukiHookAPI 调用并执行 +Test::class.java.field { + name = "isTaskRunning" + type = BooleanType +}.get(instance).any() // any 为 Field 的任意类型实例化对象 +
小提示
更多功能请参考 FieldFinder。
也许你还想得到当前
Class
的构造方法,同样可以实现。示例如下
Test::class.java.constructor { + param(BooleanType) +}.get().call(true) // 可创建一个新的实例 +
若想得到的是
Class
的无参构造方法,可写作如下形式。示例如下
Test::class.java.constructor().get().call() // 可创建一个新的实例 +
小提示
更多功能请参考 ConstructorFinder。
# 可选的查找条件
假设我们要得到
Class
中的getName
方法,可以使用如下实现。示例如下
// 假设这就是这个 Class 的实例 +val instance = Test() +// 使用 YukiHookAPI 调用并执行 +Test::class.java.method { + name = "getName" + emptyParam() + returnType = StringClass +}.get(instance).string() // 得到方法的结果 +
通过观察发现,这个
Class
中只有一个名为getName
的方法,那我们可不可以再简单一点呢?示例如下
// 假设这就是这个 Class 的实例 +val instance = Test() +// 使用 YukiHookAPI 调用并执行 +Test::class.java.method { + name = "getName" + emptyParam() +}.get(instance).string() // 得到方法的结果 +
是的,对于确切不会变化的方法,你可以精简查找条件。
在只使用
get
或wait
方法得到结果时YukiHookAPI
会默认按照字节码顺序匹配第一个查找到的结果。问题又来了,这个
Class
中有一个release
方法,但是它的方法参数很长,而且部分类型可能无法直接得到。通常情况下我们会使用
param(...)
来查找这个方法,但是有没有更简单的方法呢。此时,在确定方法唯一性后,你可以使用
paramCount
来查找到这个方法。示例如下
// 假设这就是这个 Class 的实例 +val instance = Test() +// 使用 YukiHookAPI 调用并执行 +Test::class.java.method { + name = "release" + // 此时我们不必确定方法参数具体类型,写个数就好 + paramCount = 3 +}.get(instance) // 得到这个方法 +
上述示例虽然能够匹配成功,但是不精确,此时你还可以使用
VagueType
来填充你不想填写的方法参数类型。示例如下
// 假设这就是这个 Class 的实例 +val instance = Test() +// 使用 YukiHookAPI 调用并执行 +Test::class.java.method { + name = "release" + // 使用 VagueType 来填充不想填写的类型,同时保证其它类型能够匹配 + param(StringClass, VagueType, BooleanType) +}.get(instance) // 得到这个方法 +
如果你并不确定每一个参数的类型,你可以通过
param { ... }
方法来创建一个条件方法体。示例如下
// 假设这就是这个 Class 的实例 +val instance = Test() +// 使用 YukiHookAPI 调用并执行 +Test::class.java.method { + name = "release" + // 得到 it (Class) 方法参数类型数组实例来仅判断已知的类型和它的位置 + param { it[0] == StringClass && it[2] == BooleanType } +}.get(instance) // 得到这个方法 +
小提示
使用 param { ... } 创建一个条件方法体,其中的变量 it 即当前方法参数的 Class 类型数组实例,此时你就可以自由使用 Class 中的所有对象及其方法。
方法体末尾条件需要返回一个 Boolean,即最终的条件判断结果。
更多功能请参考 FieldFinder.type、MethodFinder.param、MethodFinder.returnType、ConstructorFinder.param 方法。
# 在父类查找
你会注意到
Test
继承于BaseTest
,现在我们想得到BaseTest
的doBaseTask
方法,在不知道父类名称的情况下,要怎么做呢?参照上面的查找条件,我们只需要在查找条件中加入一个
superClass
即可实现这个功能。示例如下
// 假设这就是这个 Class 的实例 +val instance = Test() +// 使用 YukiHookAPI 调用并执行 +Test::class.java.method { + name = "doBaseTask" + param(StringClass) + // 只需要添加这个条件 + superClass() +}.get(instance).call("task_name") +
这个时候我们就可以在父类中取到这个方法了。
superClass
有一个参数为isOnlySuperClass
,设置为true
后,可以跳过当前Class
仅查找当前Class
的父类。由于我们现在已知
doBaseTask
方法只存在于父类,可以加上这个条件节省查找时间。示例如下
// 假设这就是这个 Class 的实例 +val instance = Test() +// 使用 YukiHookAPI 调用并执行 +Test::class.java.method { + name = "doBaseTask" + param(StringClass) + // 加入一个查找条件 + superClass(isOnlySuperClass = true) +}.get(instance).call("task_name") +
这个时候我们同样可以得到父类中的这个方法。
superClass
一旦设置就会自动循环向后查找全部继承的父类中是否有这个方法,直到查找到目标没有父类(继承关系为java.lang.Object
)为止。特别注意
当前查找的 Method 除非指定 superClass 条件,否则只能查找到当前 Class 的 Method,这是 Java 反射 API 的默认行为。
# 模糊查找
如果我们想查找一个方法名称,但是又不确定它在每个版本中是否发生变化,此时我们就可以使用模糊查找功能。
假设我们要得到
Class
中的doTask
方法,可以使用如下实现。示例如下
// 假设这就是这个 Class 的实例 +val instance = Test() +// 使用 YukiHookAPI 调用并执行 +Test::class.java.method { + name { + // 设置名称不区分大小写 + it.equals("dotask", isIgnoreCase = true) + } + param(StringClass) +}.get(instance).call("task_name") +
已知当前
Class
中仅有一个doTask
方法,我们还可以判断方法名称仅包含其中指定的字符。示例如下
// 假设这就是这个 Class 的实例 +val instance = Test() +// 使用 YukiHookAPI 调用并执行 +Test::class.java.method { + name { + // 仅包含 oTas + it.contains("oTas") + } + param(StringClass) +}.get(instance).call("task_name") +
我们还可以根据首尾字符串进行判断。
示例如下
// 假设这就是这个 Class 的实例 +val instance = Test() +// 使用 YukiHookAPI 调用并执行 +Test::class.java.method { + name { + // 开头包含 do,结尾包含 Task + it.startsWith("do") && it.endsWith("Task") + } + param(StringClass) +}.get(instance).call("task_name") +
通过观察发现这个方法名称中只包含字母,我们还可以再增加一个精确的查找条件。
示例如下
// 假设这就是这个 Class 的实例 +val instance = Test() +// 使用 YukiHookAPI 调用并执行 +Test::class.java.method { + name { + // 开头包含 do,结尾包含 Task,仅包含字母 + it.startsWith("do") && it.endsWith("Task") && it.isOnlyLetters() + } + param(StringClass) +}.get(instance).call("task_name") +
小提示
使用 name { ... } 创建一个条件方法体,其中的变量 it 即当前名称的字符串,此时你就可以在 NameRules 的扩展方法中自由使用其中的功能。
方法体末尾条件需要返回一个 Boolean,即最终的条件判断结果。
更多功能请参考 FieldFinder.name、MethodFinder.name 方法以及 NameRules。
# 多重查找
有些时候,我们可能需要查找一个
Class
中具有相同特征的一组方法、构造方法、变量,此时,我们就可以利用相对条件匹配来完成。在查找条件结果的基础上,我们只需要把
get
换为all
即可得到匹配条件的全部字节码。假设这次我们要得到
Class
中方法参数个数范围在1..3
的全部方法,可以使用如下实现。示例如下
// 假设这就是这个 Class 的实例 +val instance = Test() +// 使用 YukiHookAPI 调用并执行 +Test::class.java.method { + paramCount(1..3) +}.all(instance).forEach { instance -> + // 调用执行每个方法 + instance.call(...) +} +
上述示例可完美匹配到如下 3 个方法。
private void doTask(String taskName)
private void release(String taskName, Function<boolean, String> task, boolean isFinish)
private void b(String a)
如果你想更加自由地定义参数个数范围的条件,可以使用如下实现。
示例如下
// 假设这就是这个 Class 的实例 +val instance = Test() +// 使用 YukiHookAPI 调用并执行 +Test::class.java.method { + paramCount { it < 3 } +}.all(instance).forEach { instance -> + // 调用执行每个方法 + instance.call(...) +} +
上述示例可完美匹配到如下 6 个方法。
private static void init()
private void doTask(String taskName)
private void stop(String a)
private void getName(String a)
private void b()
private void b(String a)
通过观察
Class
中有两个名称为b
的方法,可以使用如下实现。示例如下
// 假设这就是这个 Class 的实例 +val instance = Test() +// 使用 YukiHookAPI 调用并执行 +Test::class.java.method { + name = "b" +}.all(instance).forEach { instance -> + // 调用执行每个方法 + instance.call(...) +} +
上述示例可完美匹配到如下 2 个方法。
private void b()
private void b(String a)
小提示
使用 paramCount { ... } 创建一个条件方法体,其中的变量 it 即当前参数个数的整数,此时你就可以在 CountRules 的扩展方法中自由使用其中的功能。
方法体末尾条件需要返回一个 Boolean,即最终的条件判断结果。
更多功能请参考 MethodFinder.paramCount、ConstructorFinder.paramCount 方法以及 CountRules。
# 静态字节码
有些方法和变量在
Class
中是静态的实现,这个时候,我们不需要传入实例就可以调用它们。假设我们这次要得到静态变量
TAG
的内容。示例如下
Test::class.java.field { + name = "TAG" + type = StringClass +}.get().string() // Field 的类型是字符串,可直接进行 cast +
假设
Class
中存在同名的非静态TAG
变量,这个时候怎么办呢?加入一个筛选条件即可。
示例如下
Test::class.java.field { + name = "TAG" + type = StringClass + // 标识查找的这个变量需要是静态 + modifiers { isStatic } +}.get().string() // Field 的类型是字符串,可直接进行 cast +
我们还可以调用名为
init
的静态方法。示例如下
Test::class.java.method { + name = "init" + emptyParam() +}.get().call() +
同样地,你可以标识它是一个静态。
示例如下
Test::class.java.method { + name = "init" + emptyParam() + // 标识查找的这个方法需要是静态 + modifiers { isStatic } +}.get().call() +
小提示
使用 modifiers { ... } 创建一个条件方法体,此时你就可以在 ModifierRules 中自由使用其中的功能。
方法体末尾条件需要返回一个 Boolean,即最终的条件判断结果。
更多功能请参考 FieldFinder.modifiers、MethodFinder.modifiers、ConstructorFinder.modifiers 方法以及 ModifierRules。
# 混淆的字节码
你可能已经注意到了,这里给出的示例
Class
中有两个混淆的变量名称,它们都是a
,这个时候我们要怎么得到它们呢?有两种方案。
第一种方案,确定变量的名称和类型。
示例如下
// 假设这就是这个 Class 的实例 +val instance = Test() +// 使用 YukiHookAPI 调用并执行 +Test::class.java.field { + name = "a" + type = BooleanType +}.get(instance).any() // 得到名称为 a 类型为 Boolean 的变量 +
第二种方案,确定变量的类型所在的位置。
示例如下
// 假设这就是这个 Class 的实例 +val instance = Test() +// 使用 YukiHookAPI 调用并执行 +Test::class.java.field { + type(BooleanType).index().first() +}.get(instance).any() // 得到第一个类型为 Boolean 的变量 +
以上两种情况均可得到对应的变量
private boolean a
。同样地,这个
Class
中也有两个混淆的方法名称,它们都是b
。你也可以有两种方案来得到它们。
第一种方案,确定方法的名称和方法参数。
示例如下
// 假设这就是这个 Class 的实例 +val instance = Test() +// 使用 YukiHookAPI 调用并执行 +Test::class.java.method { + name = "b" + param(StringClass) +}.get(instance).call("test_string") // 得到名称为 b 方法参数为 [String] 的方法 +
第二种方案,确定方法的参数所在的位置。
示例如下
// 假设这就是这个 Class 的实例 +val instance = Test() +// 使用 YukiHookAPI 调用并执行 +Test::class.java.method { + param(StringClass).index().first() +}.get(instance).call("test_string") // 得到第一个方法参数为 [String] 的方法 +
由于观察到这个方法在
Class
的最后一个,那我们还有一个备选方案。示例如下
// 假设这就是这个 Class 的实例 +val instance = Test() +// 使用 YukiHookAPI 调用并执行 +Test::class.java.method { + order().index().last() +}.get(instance).call("test_string") // 得到当前 Class 的最后一个方法 +
注意
请尽量避免使用 order 来筛选字节码的下标,它们可能是不确定的,除非你确定它在这个 Class 中的位置一定不会变。
# 直接调用
上面介绍的调用字节码的方法都需要使用
get(instance)
才能调用对应的方法,有没有简单一点的办法呢?此时,你可以在任意实例上使用
current
方法来创建一个调用空间。示例如下
// 假设这就是这个 Class 的实例 +val instance = Test() +// 假设这个 Class 是不能被直接得到的 +instance.current { + // 执行 doTask 方法 + method { + name = "doTask" + param(StringClass) + }.call("task_name") + // 执行 stop 方法 + method { + name = "stop" + emptyParam() + }.call() + // 得到 name + val name = method { name = "getName" }.string() +} +
我们还可以用
superClass
调用当前Class
父类的方法。示例如下
// 假设这就是这个 Class 的实例 +val instance = Test() +// 假设这个 Class 是不能被直接得到的 +instance.current { + // 执行父类的 doBaseTask 方法 + superClass().method { + name = "doBaseTask" + param(StringClass) + }.call("task_name") +} +
如果你不喜欢使用一个大括号的调用域来创建当前实例的命名空间,你可以直接使用
current()
方法。示例如下
// 假设这就是这个 Class 的实例,这个 Class 是不能被直接得到的 +val instance = Test() +// 执行 doTask 方法 +instance + .current() + .method { + name = "doTask" + param(StringClass) + }.call("task_name") +// 执行 stop 方法 +instance + .current() + .method { + name = "stop" + emptyParam() + }.call() +// 得到 name +val name = instance.current().method { name = "getName" }.string() +
同样地,它们之间可以连续调用,但不允许内联调用。
示例如下
// 假设这就是这个 Class 的实例 +val instance = Test() +// 假设这个 Class 是不能被直接得到的 +instance.current { + method { + name = "doTask" + param(StringClass) + }.call("task_name") +}.current() + .method { + name = "stop" + emptyParam() + }.call() +// 注意,因为 current() 返回的是 CurrentClass 自身对象,所以不能像下面这样调用 +instance.current().current() +
针对
Field
实例,还有一个便捷的方法,可以直接获取Field
所在实例的对象。示例如下
// 假设这就是这个 Class 的实例 +val instance = Test() +// 假设这个 Class 是不能被直接得到的 +instance.current { + // <方案1> + field { + name = "baseInstance" + }.current { + method { + name = "doBaseTask" + param(StringClass) + }.call("task_name") + } + // <方案2> + field { + name = "baseInstance" + }.current() + ?.method { + name = "doBaseTask" + param(StringClass) + }?.call("task_name") +} +
注意
上述 current 方法相当于帮你调用了 CurrentClass 中的 field { ... }.any()?.current() 方法。
若不存在 CurrentClass 调用域,你需要使用 field { ... }.get(instance).current() 来进行调用。
问题又来了,我想使用反射的方式创建如下的实例并调用其中的方法,该怎么做呢?
示例如下
Test(true).doTask("task_name") +
通常情况下,我们可以使用标准的反射 API 来调用。
示例如下
"com.demo.Test".toClass() + .getDeclaredConstructor(Boolean::class.java) + .apply { isAccessible = true } + .newInstance(true) + .apply { + javaClass + .getDeclaredMethod("doTask", String::class.java) + .apply { isAccessible = true } + .invoke(this, "task_name") + } +
但是感觉这种做法好麻烦,有没有更简洁的调用方法呢?
这个时候,我们还可以借助
buildOf
方法来创建一个实例。示例如下
"com.demo.Test".toClass().buildOf(true) { param(BooleanType) }?.current { + method { + name = "doTask" + param(StringClass) + }.call("task_name") +} +
若你希望
buildOf
方法返回当前实例的类型,你可以在其中加入类型泛型声明,而无需使用as
来cast
目标类型。这种情况多用于实例本身的构造方法是私有的,但是里面的方法是公有的,这样我们只需要对其构造方法进行反射创建即可。
示例如下
// 假设这个 Class 是能够直接被得到的 +val test = Test::class.java.buildOf<Test>(true) { param(BooleanType) } +test.doTask("task_name") +
小提示
更多功能请参考 CurrentClass 以及 Class.buildOf 方法。
# 原始调用
若你正在使用反射调用的一个方法是被 Hook 过的,此时我们如何调用其原始方法呢?
原生的
XposedBridge
为我们提供了一个XposedBridge.invokeOriginalMethod
功能。现在,在
YukiHookAPI
中你可以使用如下方法便捷地实现这个功能。假设下面是我们要演示的
Class
。示例如下
public class Test { + + public static String getString() { + return "Original"; + } +} +
下面是 Hook 这个
Class
中getString
方法的方式。示例如下
Test::class.java.method { + name = "getString" + emptyParam() + returnType = StringClass +}.hook { + replaceTo("Hooked") +} +
此时,我们再使用反射调用这个方法,则会得到 Hook 后的结果
"Hooked"
。示例如下
// result 的结果会是 "Hooked" +val result = Test::class.java.method { + name = "getString" + emptyParam() + returnType = StringClass +}.get().string() +
如果我们想得到这个方法未经 Hook 的原始方法及结果,只需要在结果中加入
original
即可。示例如下
// result 的结果会是 "Original" +val result = Test::class.java.method { + name = "getString" + emptyParam() + returnType = StringClass +}.get().original().string() +
小提示
更多功能请参考 MethodFinder.Result.original 方法。
# 再次查找
假设有三个不同版本的
Class
,它们都是这个宿主不同版本相同的Class
。这里面同样都有一个方法
doTask
,假设它们的功能是一样的。版本 A 示例如下
public class Test { + + public void doTask() { + // ... + } +} +
版本 B 示例如下
public class Test { + + public void doTask(String taskName) { + // ... + } +} +
版本 C 示例如下
public class Test { + + public void doTask(String taskName, int type) { + // ... + } +} +
我们需要在不同的版本中得到这个相同功能的
doTask
方法,要怎么做呢?此时,你可以使用
RemedyPlan
完成你的需求。示例如下
// 假设这就是这个 Class 的实例 +val instance = Test() +// 使用 YukiHookAPI 调用并执行 +Test::class.java.method { + name = "doTask" + emptyParam() +}.remedys { + method { + name = "doTask" + param(StringClass) + }.onFind { + // 可在这里实现找到的逻辑 + } + method { + name = "doTask" + param(StringClass, IntType) + }.onFind { + // 可在这里实现找到的逻辑 + } +}.wait(instance) { + // 得到方法的结果 +} +
特别注意
使用了 RemedyPlan 的方法查找结果不能再使用 get 的方式得到方法实例,应当使用 wait 方法。
另外,你还可以在使用 多重查找 的情况下继续使用
RemedyPlan
。示例如下
// 假设这就是这个 Class 的实例 +val instance = Test() +// 使用 YukiHookAPI 调用并执行 +Test::class.java.method { + name = "doTask" + emptyParam() +}.remedys { + method { + name = "doTask" + paramCount(0..1) + }.onFind { + // 可在这里实现找到的逻辑 + } + method { + name = "doTask" + paramCount(1..2) + }.onFind { + // 可在这里实现找到的逻辑 + } +}.waitAll(instance) { + // 得到方法的结果 +} +
# 相对匹配
假设宿主中不同版本中存在功能相同的
Class
但仅有Class
的名称不一样。版本 A 示例如下
public class ATest { + + public static void doTask() { + // ... + } +} +
版本 B 示例如下
public class BTest { + + public static void doTask() { + // ... + } +} +
这个时候我们想在每个版本都调用这个
Class
里的doTask
方法该怎么做呢?通常做法是判断
Class
是否存在。示例如下
// 首先查找到这个 Class +val currentClass = + if("com.demo.ATest".hasClass()) "com.demo.ATest".toClass() else "com.demo.BTest".toClass() +// 然后再查找这个方法并调用 +currentClass.method { + name = "doTask" + emptyParam() +}.get().call() +
感觉这种方案非常的不优雅且繁琐,那么此时
YukiHookAPI
就为你提供了一个非常方便的VariousClass
专门来解决这个问题。现在,你可以直接使用以下方式获取到这个
Class
。示例如下
VariousClass("com.demo.ATest", "com.demo.BTest").get().method { + name = "doTask" + emptyParam() +}.get().call() +
若当前
Class
在指定的ClassLoader
中存在,你可以在get
中填入你的ClassLoader
。示例如下
val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader +VariousClass("com.demo.ATest", "com.demo.BTest").get(customClassLoader).method { + name = "doTask" + emptyParam() +}.get().call() +
若你不确定所有的
Class
一定会被匹配到,你可以使用getOrNull
方法。示例如下
val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader +VariousClass("com.demo.ATest", "com.demo.BTest").getOrNull(customClassLoader)?.method { + name = "doTask" + emptyParam() +}?.get()?.call() +
若你正在
PackageParam
中操作 (Xposed) 宿主环境的Class
,可以直接使用toClass()
进行设置。示例如下
VariousClass("com.demo.ATest", "com.demo.BTest").toClass().method { + name = "doTask" + emptyParam() +}.get().call() +
小提示
更多功能请参考 VariousClass。
若在创建 Hook 的时候使用,可以更加方便,还可以自动拦截找不到
Class
的异常。你可以把这个
Class
定义为一个常量类型来使用。示例如下
// 定义常量类型 +val ABTestClass = VariousClass("com.demo.ATest", "com.demo.BTest") +// 直接使用 +ABTestClass.hook { + // Your code here. +} +
# 调用泛型
在反射过程中,我们可能会遇到泛型问题,在泛型的反射处理上,
YukiHookAPI
同样提供了一个可在任意地方使用的语法糖。例如我们有如下的泛型类。
示例如下
class TestGeneric<T, R> (t: T, r: R) { + + fun foo() { + // ... + } +} +
当我们想在当前
Class
中获得泛型T
或R
的Class
实例,只需要如下实现。示例如下
class TestGeneric<T, R> (t: T, r: R) { + + fun foo() { + // 获得当前实例的操作对象 + // 获得 T 的 Class 实例,在参数第 0 位,默认值可以不写 + val tClass = current().generic()?.argument() + // 获得 R 的 Class 实例,在参数第 1 位 + val rClass = current().generic()?.argument(index = 1) + // 你还可以使用如下写法 + current().generic { + // 获得 T 的 Class 实例,在参数第 0 位,默认值可以不写 + val tClass = argument() + // 获得 R 的 Class 实例,在参数第 1 位 + val rClass = argument(index = 1) + } + } +} +
当我们想在外部调用这个
Class
时,就可以有如下实现。示例如下
// 假设这个就是 T 的 Class +class TI { + + fun foo() { + // ... + } +} +// 假设这个就是 T 的实例 +val tInstance: TI? = ... +// 获得 T 的 Class 实例,在参数第 0 位,默认值可以不写,并获得其中的方法 foo 并调用 +TestGeneric::class.java.generic()?.argument()?.method { + name = "foo" + emptyParam() +}?.get(tInstance)?.invoke<TI>() +
小提示
更多功能请参考 CurrentClass.generic、Class.generic 方法以及 GenericClass。
# 注意误区
这里列举了使用时可能会遇到的误区部分,可供参考。
# 限制性查找条件
在查找条件中,除了
order
你只能使用一次index
功能。示例如下
method { + name = "test" + param(BooleanType).index(num = 2) + // 错误的使用方法,请仅保留一个 index 方法 + returnType(StringClass).index(num = 1) +} +
以下查找条件的使用是没有任何问题的。
示例如下
method { + name = "test" + param(BooleanType).index(num = 2) + order().index(num = 1) +} +
# 必要的查找条件
在普通方法查找条件中,即使是无参的方法也需要设置查找条件。
假设我们有如下的
Class
。示例如下
public class TestFoo { + + public void foo(String string) { + // ... + } + + public void foo() { + // ... + } +} +
我们要得到其中的
public void foo()
方法,可以写作如下形式。示例如下
TestFoo::class.java.method { + name = "foo" +} +
但是,上面的例子是错误的。
你会发现这个
Class
中有两个foo
方法,其中一个带有方法参数。由于上述例子没有设置
param
的查找条件,得到的结果将会是匹配名称且匹配字节码顺序的第一个方法public void foo(String string)
,而不是我们需要的最后一个方法。这是一个经常会出现的错误,没有方法参数就会丢失方法参数查找条件的使用问题。
正确的使用方法如下。
示例如下
TestFoo::class.java.method { + name = "foo" + // ✅ 正确的使用方法,添加详细的筛选条件 + emptyParam() +} +
至此,上述的示例将可以完美地匹配到
public void foo()
方法。兼容性说明
在过往历史版本的 API 中是允许匹配不写默认匹配无参方法的做法的,但是最新版本更正了这一问题,请确保你使用的是最新的 API 版本。
在构造方法查找条件中,即使是无参的构造方法也需要设置查找条件。
假设我们有如下的
Class
。示例如下
public class TestFoo { + + public TestFoo() { + // ... + } +} +
我们要得到其中的
public TestFoo()
构造方法,必须写作如下形式。示例如下
TestFoo::class.java.constructor { emptyParam() } +
上面的例子可以成功获取到
public TestFoo()
构造方法。如果你写作
constructor()
而丢失了emptyParam()
,此时查找到的结果会是按照字节码顺序排列的的第一位,可能并不是无参的。兼容性说明
在过往历史版本的 API 中构造方法不填写任何查找参数会直接找不到构造方法,这是一个 BUG,最新版本已经进行修复,请确保你使用的是最新的 API 版本。
API 行为变更
在 1.2.0 及之后的版本中,constructor() 的行为不再是 constructor { emptyParam() } 而是 constructor {},请注意行为变更合理调整查找参数。
# 不设置查找条件
在不设置查找条件的情况下,使用
field()
、constructor()
、method()
将返回当前Class
下的所有成员对象。使用
get(...)
或give()
的方式获取将只能得到按照字节码顺序排列的的第一位。示例如下
Test::class.java.field().get(...) +Test::class.java.method().give() +
如果你想得到全部成员对象,你可以使用
all(...)
或giveAll()
示例如下
Test::class.java.field().all(...) +Test::class.java.method().giveAll() +
兼容性说明
在过往历史版本的 API 中,不设置查找条件将抛出异常,此特性在 1.2.0 及之后的版本中加入。
# 字节码类型
在字节码调用结果中,cast 方法只能指定字节码对应的类型。
例如我们想得到一个
Boolean
类型的变量,把他转换为String
。以下是错误的使用方法。
示例如下
field { + name = "test" + type = BooleanType +}.get().string() // 错误的使用方法,必须 cast 为字节码目标类型 +
以下是正确的使用方法。
示例如下
field { + name = "test" + type = BooleanType +}.get().boolean().toString() // ✅ 正确的使用方法,得到类型后再进行转换 +
# 常用类型扩展
在查找方法、变量的时候我们通常需要指定所查找的类型。
示例如下
field { + name = "test" + type = Boolean::class.javaPrimitiveType +} +
在 Kotlin 中表达出
Boolean::class.javaPrimitiveType
这个类型的写法很长,感觉并不方便。因此,
YukiHookAPI
为开发者封装了常见的类型调用,其中包含了 Android 的相关类型和 Java 的常见类型与原始类型关键字。这个时候上面的类型就可以写作如下形式了。
示例如下
field { + name = "test" + type = BooleanType +} +
在 Java 常见类型中的原始类型 (或基本类型) 关键字都已被封装为 类型 + Type 的方式,例如
IntType
、FloatType
(它们的字节码类型为int
、float
)。相应地,数组类型也有方便的使用方法,假设我们要获得
String[]
类型的数组。需要写做
java.lang.reflect.Array.newInstance(String::class.java, 0).javaClass
才能得到这个类型。感觉是不是很麻烦,这个时候我们可以使用方法
ArrayClass(StringClass)
来得到这个类型。同时由于
String
是常见类型,所以还可以直接使用StringArrayClass
来得到这个类型。一些常见的 Hook 中查找的方法,都有其对应的封装类型以供使用,格式为 类型 + Class。
例如 Hook
onCreate
方法需要查找Bundle::class.java
类型。示例如下
method { + name = "onCreate" + param(BundleClass) +} +
以下是 Java 中一些特例类型在
YukiHookAPI
中的封装名称。
void
→UnitType
java.lang.Void
→UnitClass
java.lang.Object
→AnyClass
java.lang.Integer
→IntClass
java.lang.Character
→CharClass
注意
以 类型 + Type 封装类型会且仅会表示为 Java 原始类型关键字,由于 Kotlin 中不存在原始类型这个概念,所以它们都会被定义为 KClass。
Java 中共有 9 个原始类型关键字,其中 8 个为原始类型,分别为 boolean、char、byte、short、int、float、long、double,其中 void 类型是一个特例。
同时它们都有 Java 自身对应的封装类型,例如 java.lang.Boolean、java.lang.Integer,这些类型是不相等的,请注意区分。
同样地,数组也有对应的封装类型,它们也需要与 Java 原始类型关键字 进行区分。
例如 byte[] 的封装类型为 ByteArrayType 或 ArrayClass(ByteType),而 Byte[] 的封装类型为 ByteArrayClass 或 ArrayClass(ByteClass),这些类型也是不相等的。
同时,欢迎你能贡献更多的常用类型。
`,363);function N(M,O){const l=e("ExternalLinkIcon"),p=e("Badge");return t(),r("div",null,[d,A,s("p",null,[s("s",null,[n("此功能的核心部分已被解耦合为 "),s("a",y,[n("YukiReflection"),a(l)]),n(" 项目,它可以独立使用于任何 Java、Android 项目中。")])]),D,s("div",B,[C,s("p",null,[n("从 "),u,n(" 版本开始,"),v,n(" 已将自身的反射 API 部分迁移至 "),s("a",m,[n("KavaRef"),a(l)]),n(",我们不再推荐使用 "),b,n(" 自身的反射 API,这些 API 已被标记为弃用。")]),F,s("p",null,[n("如果你依然在使用 "),k,n(" 的反射 API 部分,请参考 "),s("a",h,[n("这里"),a(l)]),n(" 的迁移文档,这将跳转到 "),g,n(" 的文档。")])]),s("div",q,[T,s("h3",x,[f,n(" 模糊查找 "),a(p,{type:"tip",text:"Beta",vertical:"middle"})]),P,s("div",S,[_,s("p",null,[s("s",null,[n("在 "),j,n(" 发布 "),I,n(" 版本后,此功能将被标记为作废,且不再会迁移到 "),s("a",L,[n("YukiReflection"),a(l)]),n("。")])]),s("p",null,[n("我们欢迎各位开发者开始使用 "),s("a",H,[n("DexKit"),a(l)]),n(",它是一个使用 C++ 实现的 "),R,n(" 高性能运行时解析库,在性能方面比 Java 层更加高效与优秀,目前尚在开发阶段,欢迎提出宝贵建议。")])]),Y])])}const V=c(i,[["render",N],["__file","reflection.html.vue"]]);export{V as default}; diff --git a/assets/reflection.html-BohdUWGg.js b/assets/reflection.html-BohdUWGg.js new file mode 100644 index 00000000..4a265c29 --- /dev/null +++ b/assets/reflection.html-BohdUWGg.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-581ddb9c","path":"/en/api/special-features/reflection.html","title":"Reflection Extensions (Migrated)","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"Class Extensions","slug":"class-extensions","link":"#class-extensions","children":[{"level":3,"title":"Object Conversion","slug":"object-conversion","link":"#object-conversion","children":[]},{"level":3,"title":"Lazy Loading","slug":"lazy-loading","link":"#lazy-loading","children":[]},{"level":3,"title":"Existential Judgment","slug":"existential-judgment","link":"#existential-judgment","children":[]},{"level":3,"title":"Vague Search","slug":"vague-search","link":"#vague-search","children":[]}]},{"level":2,"title":"Member Extensions","slug":"member-extensions","link":"#member-extensions","children":[{"level":3,"title":"Find and Reflection","slug":"find-and-reflection","link":"#find-and-reflection","children":[]},{"level":3,"title":"Optional Find Conditions","slug":"optional-find-conditions","link":"#optional-find-conditions","children":[]},{"level":3,"title":"Find in Super Class","slug":"find-in-super-class","link":"#find-in-super-class","children":[]},{"level":3,"title":"Vague Find","slug":"vague-find","link":"#vague-find","children":[]},{"level":3,"title":"Multiple Find","slug":"multiple-find","link":"#multiple-find","children":[]},{"level":3,"title":"Static Bytecode","slug":"static-bytecode","link":"#static-bytecode","children":[]},{"level":3,"title":"Obfuscated Bytecode","slug":"obfuscated-bytecode","link":"#obfuscated-bytecode","children":[]},{"level":3,"title":"Directly Called","slug":"directly-called","link":"#directly-called","children":[]},{"level":3,"title":"Original Called","slug":"original-called","link":"#original-called","children":[]},{"level":3,"title":"Find Again","slug":"find-again","link":"#find-again","children":[]},{"level":3,"title":"Relative Matching","slug":"relative-matching","link":"#relative-matching","children":[]},{"level":3,"title":"Calling Generics","slug":"calling-generics","link":"#calling-generics","children":[]},{"level":3,"title":"Pay Attention of Trap","slug":"pay-attention-of-trap","link":"#pay-attention-of-trap","children":[]}]},{"level":2,"title":"Common Type Extensions","slug":"common-type-extensions","link":"#common-type-extensions","children":[]}],"git":{"updatedTime":1750318245000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":19}]},"filePathRelative":"en/api/special-features/reflection.md"}');export{e as data}; diff --git a/assets/reflection.html-D65pVYER.js b/assets/reflection.html-D65pVYER.js new file mode 100644 index 00000000..d138c7b6 --- /dev/null +++ b/assets/reflection.html-D65pVYER.js @@ -0,0 +1,849 @@ +import{_ as t,r as o,o as c,c as i,b as s,d as n,e as a,a as l}from"./app-BpUB8-Q8.js";const r={},d=s("h1",{id:"reflection-extensions-migrated",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#reflection-extensions-migrated","aria-hidden":"true"},"#"),n(" Reflection Extensions (Migrated)")],-1),y=s("blockquote",null,[s("p",null,[s("code",null,"YukiHookAPI"),n(" encapsulates a set of reflection API with near-zero reflection writing for developers, which can almost completely replace the usage of reflection API in Java.")])],-1),A={href:"https://github.com/HighCapable/YukiReflection",target:"_blank",rel:"noopener noreferrer"},u=l("
NowYukiReflection
is integrated intoYukiHookAPI
as a core dependency.",2),D={class:"custom-container warning"},B=s("p",{class:"custom-container-title"},"Notice",-1),C=s("code",null,"1.3.0",-1),m=s("code",null,"YukiHookAPI",-1),v={href:"https://github.com/HighCapable/KavaRef",target:"_blank",rel:"noopener noreferrer"},h=s("code",null,"YukiHookAPI",-1),b=s("p",null,[n("The "),s("code",null,"YukiReflection"),n(" project has been deprecated due to many unsolved black box issues, and we no longer recommend anyone to use it.")],-1),F=s("code",null,"YukiHookAPI",-1),g={href:"https://highcapable.github.io/KavaRef/zh-cn/config/migration",target:"_blank",rel:"noopener noreferrer"},k=s("code",null,"KavaRef",-1),f={style:{opacity:"0.35"}},w=l(`
YukiHookAPI
adds related extensions for Hook functions on the basis ofYukiReflection
, and there is no need to introduce this dependency to useYukiHookAPI
.# Class Extensions
Here are the extension functions related to the Class object itself.
# Object Conversion
Suppose we want to get a
Class
that cannot be called directly.Normally, we can use the standard reflection API to find this
Class
.The following example
// Class in the default ClassLoader environment +var instance = Class.forName("com.demo.Test") +// Specify the Class in the ClassLoader environment +val customClassLoader: ClassLoader? = ... // Assume this is your ClassLoader +var instance = customClassLoader?.loadClass("com.demo.Test") +
This is probably not very friendly, and
YukiHookAPI
provides you with a syntactic sugar that can be used anywhere.The above writing can be written as
YukiHookAPI
as follows.The following example
// Get this Class directly +// If you are currently in the PackageParam environment, then you don't need to consider ClassLoader +var instance = "com.demo.Test".toClass() +// ClassLoader where the custom Class is located +val customClassLoader: ClassLoader? = ... // Assume this is your ClassLoader +var instance = "com.demo.Test".toClass(customClassLoader) +
If the current
Class
does not exist, using the above method will throw an exception.If you are not sure whether the
Class
exists, you can refer to the following solutions.The following example
// Get this Class directly +// If you are currently in the PackageParam environment, then you don't need to consider ClassLoader +// If not available, the result will be null but no exception will be thrown +var instance = "com.demo.Test".toClassOrNull() +// ClassLoader where the custom Class is located +val customClassLoader: ClassLoader? = ... // Assume this is your ClassLoader +// If not available, the result will be null but no exception will be thrown +var instance = "com.demo.Test".toClassOrNull(customClassLoader) +
We can also get an existing
Class
object by mapping.The following example
// Assume this Class can be obtained directly +var instance = classOf<Test>() +// We can also customize the ClassLoader where the Class is located, which is very effective for stubs +val customClassLoader: ClassLoader? = ... // Assume this is your ClassLoader +var instance = classOf<Test>(customClassLoader) +
Tips
For more functions, please refer to classOf, String.toClass, String.toClassOrNull, PackageParam → String+ VariousClass.toClass, PackageParam → String+VariousClass.toClassOrNull methods.
# Lazy Loading
Suppose we want to get a
Class
that cannot be called directly, but we do not need thisClass
immediately.At this time, you can use
lazyClass
to complete this function.The following example
// Lazy loading of this Class +// If you are currently in a PackageParam environment, then you do not need to consider ClassLoader +val instance by lazyClass("com.demo.Test") +// Customize the ClassLoader where the Class is located +val customClassLoader: ClassLoader? = ... // Assume this is your ClassLoader +val instance by lazyClass("com.demo.Test") { customClassLoader } +// Call this Class at the appropriate time +instance.method { + // ... +} +
If the current
Class
does not exist, using the above method will throw an exception.If you are not sure whether
Class
exists, you can refer to the following solution.The following example
// Lazy loading of this Class +// If you are currently in a PackageParam environment, then you do not need to consider ClassLoader +// If not available, the result will be null but no exception will be thrown +val instance by lazyClassOrNull("com.demo.Test") +// Customize the ClassLoader where the Class is located +val customClassLoader: ClassLoader? = ... // Assume this is your ClassLoader +// If not available, the result will be null but no exception will be thrown +val instance by lazyClassOrNull("com.demo.Test") { customClassLoader } +// Call this Class at the appropriate time +instance?.method { + // ... +} +
Tips
For more functions, please refer to lazyClass, lazyClassOrNull, PackageParam → lazyClass, PackageParam → lazyClassOrNull methods.
# Existential Judgment
Suppose we want to determine whether a
Class
exists.Usually, we can use the standard reflection API to find this
Class
to determine whether it exists by exception.The following example
// Class in the default ClassLoader environment +var isExist = try { + Class.forName("com.demo.Test") + true +} catch (_: Throwable) { + false +} +// Specify the Class in the ClassLoader environment +val customClassLoader: ClassLoader? = ... // Assume this is your ClassLoader +var isExist = try { + customClassLoader?.loadClass("com.demo.Test") + true +} catch (_: Throwable) { + false +} +
This is probably not very friendly, and
YukiHookAPI
provides you with a syntactic sugar that can be used anywhere.The above writing can be written as
YukiHookAPI
as follows.The following example
// Check if this class exists +// If you are currently in the PackageParam environment, then you don't need to consider ClassLoader +var isExist = "com.demo.Test".hasClass() +// ClassLoader where the custom Class is located +val customClassLoader: ClassLoader? = ... // Assume this is your ClassLoader +var isExist = "com.demo.Test".hasClass(customClassLoader) +
`,39),x={id:"vague-search",tabindex:"-1"},q=s("a",{class:"header-anchor",href:"#vague-search","aria-hidden":"true"},"#",-1),T=l('Tips
For more functions, please refer to String.hasClass, PackageParam → String.hasClass methods.
The
Class
name in the Host App's Dex after being obfuscated by tools such as R8 will be difficult to distinguish.Its correct position is uncertain, and cannot be obtained directly through Object Conversion.
At this point, there is
DexClassFinder
, its role is to determine the instance of thisClass
by the bytecode features in theClass
that need to be searched.',4),S={class:"custom-container danger"},I=s("p",{class:"custom-container-title"},"Pay Attention",-1),P=s("strong",null,"YukiHookAPI",-1),j=s("strong",null,"2.0.0",-1),_={href:"https://github.com/HighCapable/YukiReflection",target:"_blank",rel:"noopener noreferrer"},H={href:"https://github.com/LuckyPray/DexKit",target:"_blank",rel:"noopener noreferrer"},L=s("strong",null,"Dex",-1),N=l(`Notice
At present, the function of DexClassFinder is still in the experimental stage.
Since the search function is only implemented through the Java layer, the performance may not reach the optimal level when there are too many Host App's Class.
If something got wrong welcome to feedback.
Since it is a reflection-level API, currently it can only locate the specified Class through the characteristics of Class and Member, and cannot locate it by specifying the string and method content characteristics in the bytecode.
The speed of searching Class depends on the performance of the current device.
At present, the mainstream mobile processors are in the 3~10s range when the conditions are not complicated in the 10~15w number of Class, the fastest speed can reach within 25s under slightly complex conditions.
Please note that the more the same type Class is matched, the slower the speed.
# Get Started
Below is a simple usage example.
Suppose the following
Class
is what we want, the names are obfuscated and may be different in each version.The following example
package com.demo; + +public class a extends Activity implements Serializable { + + public a(String var1) { + // ... + } + + private String a; + + private String b; + + private boolean a; + + protected void onCreate(Bundle var1) { + // ... + } + + private static void a(String var1) { + // ... + } + + private String a(boolean var1, String var2) { + // ... + } + + private void a() { + // ... + } + + public void a(boolean var1, a var2, b var3, String var4) { + // ... + } +} +
At this point, we want to get this
Class
, you can use theClassLoader.searchClass
method directly.In
PackageParam
you can use thesearchClass
method directly and it will automatically specify theappClassLoader
.Each of the conditions demonstrated below is optional, and the more complex the conditions, the more accurate the positioning and the worse the performance.
The following example
searchClass { + // Start the search from the specified package name range + // In actual use, you can specify multiple package name ranges at the same time + from("com.demo") + // Specify the result of getSimpleName of the current Class + // You can directly make logical judgments on this string + // Here we are not sure whether its name is a, we can only judge the length of the string + simpleName { it.length == 1 } + // Specify the inherited parent class object + // If it is an existing stub, it can be directly represented by generics + extends<Activity>() + // Specify the inherited parent class object + // Which can be written directly as the full class name + // And you can also specify multiple objects at the same time + extends("android.app.Activity") + // Specify the implemented interface + // If it exists stub, can be directly represented by generics + implements<Serializable>() + // Specify the implemented interface + // Which can be written directly as a full class name, or you can specify multiple at the same time + implements("java.io.Serializable") + // Specify the type and style of the constructor + // And the number count that exists in the current class + constructor { param(StringClass) }.count(num = 1) + // Specify the type and style of the variable + // And the number that exists in the current class count + field { type = StringClass }.count(num = 2) + // Specify the type and style of the variable + // And the number that exists in the current class count + field { type = BooleanType }.count(num = 1) + // Directly specify the number of all variables that exist in the current class count + field().count(num = 3) + // If you think the number of variables is indeterminate + // You can also use the following custom conditions + field().count(1..3) + field().count { it >= 3 } + // Specify the type and style of the method + // And the number that exists in the current class count + method { + name = "onCreate" + param(BundleClass) + }.count(num = 1) + // Specify the type and style of the method + // Specify the modifier, and the number count in the current class + method { + modifiers { isStatic && isPrivate } + param(StringClass) + returnType = UnitType + }.count(num = 1) + // Specify the type and style of the method + // Specify the modifier, and the number count in the current class + method { + modifiers { isPrivate && isStatic.not() } + param(BooleanType, StringClass) + returnType = StringClass + }.count(num = 1) + // Specify the type and style of the method + // Specify the modifier, and the number count in the current class + method { + modifiers { isPrivate && isStatic.not() } + emptyParam() + returnType = UnitType + }.count(num = 1) + // Specify the type and style of the method + // As well as the modifier and VagueType + // And the number count that exists in the current class + method { + modifiers { isPrivate && isStatic.not() } + param(BooleanType, VagueType, VagueType, StringClass) + returnType = UnitType + }.count(num = 1) + // Directly specify the number of all methods that exist in the current class count + method().count(num = 5) + // If you think the number of methods is uncertain, you can also use the following custom conditions + method().count(1..5) + method().count { it >= 5 } + // Directly specify the number of all members existing in the current class count + // Members include: Field, Method, Constructor + member().count(num = 9) + // There must be a static modifier in all members, you can add this condition like this + member { + modifiers { isStatic } + } +}.get() // Get the instance of this Class itself, if not found, it will return null +
Tips
The conditional usage of Field, Method, Constructor in the above usage is consistent with the related usage in Member Extensions, with only minor differences.
For more functions, please refer to MemberRules, FieldRules, MethodRules, ConstructorRules.
# Asynchronous Search
By default,
DexClassFinder
will use synchronous mode to searchClass
, which will block the current thread until it finds or finds an exception.If the search takes too long, it may cause ANR problems to the Host App.
In response to the above problems, we can enable asynchronous, just add the parameter
async = true
, which will not require you to start a thread again, the API has already handled the related problems for you.Notice
For the asynchronous case you need to use the wait method to get the result, the get method will no longer work.
The following example
searchClass(async = true) { + // ... +}.wait { class1 -> + // Get asynchronous result +} +searchClass(async = true) { + // ... +}.wait { class2 -> + // Get asynchronous result +} +
In this way, our search process runs asynchronously, it will not block the main thread, and each search will be performed in a separate thread at the same time, which can achieve the effect of parallel tasks.
# Local Cache
Since the search is performed again every time the Host App is reopened, this is a waste of repetitive performance when the Host App's version is unchanged.
At this point, we can locally cache the search results of the current Host App's version by specifying the
name
parameter.Next time, the found class name will be directly read from the local cache.
The local cache uses
SharedPreferences
, which will be saved to the Host App's data directory and will be re-cached after the Host App's version is updated.After enabling the local cache,
async = true
will be set at the same time, you don't need to set it manually.The following example
searchClass(name = "com.demo.class1") { + // ... +}.wait { class1 -> + // Get asynchronous result +} +searchClass(name = "com.demo.class2") { + // ... +}.wait { class2 -> + // Get asynchronous result +} +
If you want to clear the local cache manually, you can use the following method to clear the current version of the Host App's cache.
The following example
// Call it directly +// It may fail when the Host App's appContext is null, and a warning message will be printed on failure +DexClassFinder.clearCache() +// Called after listening to the lifecycle of the Host App +onAppLifecycle { + onCreate { + DexClassFinder.clearCache(context = this) + } +} +
You can also clear the Host App's cache for a specific version.
The following example
// Call it directly +// It may fail when the Host App's appContext is null, and a warning message will be printed on failure +DexClassFinder.clearCache(versionName = "1.0", versionCode = 1) +// Called after listening to the lifecycle of the Host App +onAppLifecycle { + onCreate { + DexClassFinder.clearCache(context = this, versionName = "1.0", versionCode = 1) + } +} +
# Multiple Search
If you need to search a set of
Class
at the same time using a fixed condition, then you only need to use theall
orwaitAll
method to get the result.// Synchronous search, use all to get all the results found by the conditions +searchClass { + // ... +}.all().forEach { clazz -> + // Get each result +} +// Synchronous search, using all { ... } to iterate over each result +searchClass { + // ... +}.all { clazz -> + // Get each result +} +// Asynchronous search, use waitAll to get all the results found by the conditions +searchClass(async = true) { + // ... +}.waitAll { classes -> + classes.forEach { + // Get each result + } +} +
Tips
For more functions, please refer to ClassLoader.searchClass, PackageParam.searchClass methods.
# Member Extensions
Here are the extension functions related to the Class bytecode member variables Field, Method, Constructor.
Tips
Member is the interface description object of Field, Method, Constructor, which is the general term for the bytecode members in Class in Java reflection.
Suppose there is such a
Class
.The following example
package com.demo; + +public class BaseTest { + + public BaseTest() { + // ... + } + + public BaseTest(boolean isInit) { + // ... + } + + private void doBaseTask(String taskName) { + // ... + } +} +
package com.demo; + +public class Test extends BaseTest { + + public Test() { + // ... + } + + public Test(boolean isInit) { + // ... + } + + private static TAG = "Test"; + + private BaseTest baseInstance; + + private String a; + + private boolean a; + + private boolean isTaskRunning = false; + + private static void init() { + // ... + } + + private void doTask(String taskName) { + // ... + } + + private void release(String taskName, Function<boolean, String> task, boolean isFinish) { + // ... + } + + private void stop() { + // ... + } + + private String getName() { + // ... + } + + private void b() { + // ... + } + + private void b(String a) { + // ... + } +} +
# Find and Reflection
Suppose we want to get the
doTask
method ofTest
and execute it.Normally, we can use the standard reflection API to find this method.
The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using reflection API +Test::class.java + .getDeclaredMethod("doTask", String::class.java) + .apply { isAccessible = true } + .invoke(instance, "task_name") +
This is probably not very friendly, and
YukiHookAPI
provides you with a syntactic sugar that can be used anywhere.The above writing can be written as
YukiHookAPI
as follows.The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name = "doTask" + param(StringClass) +}.get(instance).call("task_name") +
Tips
For more features, please refer to MethodFinder.
Similarly, we need to get the
isTaskRunning
field can also be written as follows.The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.field { + name = "isTaskRunning" + type = BooleanType +}.get(instance).any() // Any instantiates an object of any type of Field +
Tips
For more features, please refer to FieldFinder.
Maybe you also want to get the current
Class
constructor, the same can be achieved.The following example
Test::class.java.constructor { + param(BooleanType) +}.get().call(true) // Can create a new instance +
If you want to get the no-argument constructor of
Class
, you can write it as follows.The following example
Test::class.java.constructor().get().call() // Create a new instance +
Tips
For more features, please refer to ConstructorFinder.
# Optional Find Conditions
Suppose we want to get the
getName
method inClass
, which can be implemented as follows.The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name = "getName" + emptyParam() + returnType = StringClass +}.get(instance).string() // Get the result of the method +
Through observation, it is found that there is only one method named
getName
in thisClass
, so can we make it simpler?The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name = "getName" + emptyParam() +}.get(instance).string() // Get the result of the method +
Yes, you can refine your find criteria for methods that do not change exactly.
When using only
get
orwait
methods to get results,YukiHookAPI
will match the first found result in bytecode order by default.The problem comes again, this
Class
has arelease
method, but its method parameters are very long, and some types may not be directly available.Normally we would use
param(...)
to find this method, but is there an easier way.At this point, after determining the uniqueness of the method, you can use
paramCount
to find the method.The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name = "release" + // At this point + // We don't have to determine the specific type of method parameters, just write the number + paramCount = 3 +}.get(instance) // Get this method +
Although the above example can be successfully matched, it is not accurate.
At this time, you can also use
VagueType
to fill in the method parameter type that you do not want to fill in.The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name = "release" + // Use VagueType to fill in the type you don't want to fill in + // While ensuring that other types can match + param(StringClass, VagueType, BooleanType) +}.get(instance) // Get this method +
If you are not sure about the type of each parameter, you can create a conditional method body with the
param { ... }
method.The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name = "release" + // Get the it (Class) method parameter type array instance + // To only determine the known type and its position + param { it[0] == StringClass && it[2] == BooleanType } +}.get(instance) // Get this method +
Tips
Use param { ... } to create a conditional method body, where the variable it is the Class type array instance of the current method parameter, and you can freely use Class all objects and their methods in.
The condition at the end of the method body needs to return a Boolean, which is the final condition judgment result.
For more functions, please refer to FieldFinder.type, MethodFinder.param, MethodFinder.returnType, ConstructorFinder.param method.
# Find in Super Class
You will notice that
Test
extendsBaseTest
, now we want to get thedoBaseTask
method ofBaseTest
, how do we do it without knowing the name of the super class?Referring to the above find conditions, we only need to add a
superClass
to the find conditions to achieve this function.The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name = "doBaseTask" + param(StringClass) + // Just add this condition + superClass() +}.get(instance).call("task_name") +
At this time, we can get this method in the super class.
superClass
has a parameterisOnlySuperClass
, when set totrue
, you can skip the currentClass
and only find the super class of the currentClass
.Since we now know that the
doBaseTask
method only exists in the super class, this condition can be added to save finding time.The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name = "doBaseTask" + param(StringClass) + // Add a find condition + superClass(isOnlySuperClass = true) +}.get(instance).call("task_name") +
At this time, we can also get this method in the super class.
Once
superClass
is set, it will automatically cycle backward to find out whether this method exists in all extends super classes, until it finds that the target has no super class (the extends isjava.lang.Object
).Tips
For more functions, please refer to MethodFinder.superClass, ConstructorFinder.superClass, FieldFinder.superClass methods.
Pay Attention
The currently founded Method can only find the Method of the current Class unless the superClass condition is specified, which is the default behavior of the Java Reflection API.
# Vague Find
If we want to find a method name, but are not sure if it has changed in each release, we can use vague find.
Suppose we want to get the
doTask
method inClass
, which can be implemented as follows.The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name { + // Set name is case insensitive + it.equals("dotask", isIgnoreCase = true) + } + param(StringClass) +}.get(instance).call("task_name") +
Knowing that there is currently only one
doTask
method inClass
, we can also judge that the method name contains only the characters specified in it.The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name { + // Only contains oTas + it.contains("oTas") + } + param(StringClass) +}.get(instance).call("task_name") +
We can also judge based on the first and last strings.
The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name { + // Contains do at the beginning and Task at the end + it.startsWith("do") && it.endsWith("Task") + } + param(StringClass) +}.get(instance).call("task_name") +
By observing that this method name contains only letters, we can add a precise search condition.
The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name { + // Start with do, end with Task, just letters + it.startsWith("do") && it.endsWith("Task") && it.isOnlyLetters() + } + param(StringClass) +}.get(instance).call("task_name") +
Tips
Use name { ... } to create a conditional method body, where the variable it is the string of the current name, and you can freely use it in the extension method of NameRules function.
The condition at the end of the method body needs to return a Boolean, which is the final condition judgment result.
For more functions, please refer to FieldFinder.name, MethodFinder.name methods and NameRules.
# Multiple Find
Sometimes, we may need to find a set of methods, constructors, and fields with the same characteristics in a
Class
.At this time, we can use relative condition matching to complete.
Based on the result of the find condition, we only need to replace
get
withall
to get all the bytecodes that match the condition.Suppose this time we want to get all methods in
Class
with the number of method parameters in the range1..3
, you can use the following implementation.The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + paramCount(1..3) +}.all(instance).forEach { instance -> + // Call and execute each method + instance.call(...) +} +
The above example can be perfectly matched to the following 3 methods.
private void doTask(String taskName)
private void release(String taskName, Function<boolean, String> task, boolean isFinish)
private void b(String a)
If you want to define the conditions for the range of the number of parameters more freely, you can use the following implementation.
The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + paramCount { it < 3 } +}.all(instance).forEach { instance -> + // Call and execute each method + instance.call(...) +} +
The above example can be perfectly matched to the following 6 methods.
private static void init()
private void doTask(String taskName)
private void stop(String a)
private void getName(String a)
private void b()
private void b(String a)
By observing that there are two methods named
b
inClass
, you can use the following implementation.The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name = "b" +}.all(instance).forEach { instance -> + // Call and execute each method + instance.call(...) +} +
The above example can be perfectly matched to the following 2 methods.
private void b()
private void b(String a)
Tips
Use paramCount { ... } to create a conditional method body, where the variable it is the integer of the current number of parameters, and you can use it freely in the extension method of CountRules function in it.
The condition at the end of the method body needs to return a Boolean, which is the final condition judgment result.
For more functions, please refer to MethodFinder.paramCount, ConstructorFinder.paramCount methods and CountRules.
# Static Bytecode
Some methods and fields are statically implemented in
Class
, at this time, we can call them without passing in an instance.Suppose we want to get the contents of the static field
TAG
this time.The following example
Test::class.java.field { + name = "TAG" + type = StringClass +}.get().string() // The type of Field is string and can be cast directly +
Assuming that there is a non-static
TAG
field with the same name inClass
, what should I do at this time?Just add a filter.
The following example
Test::class.java.field { + name = "TAG" + type = StringClass + // This field to identify the lookup needs to be static + modifiers { isStatic } +}.get().string() // The type of Field is string and can be cast directly +
We can also call a static method called
init
.The following example
Test::class.java.method { + name = "init" + emptyParam() +}.get().call() +
Likewise, you can identify it as a static.
The following example
Test::class.java.method { + name = "init" + emptyParam() + // This method of identity find needs to be static + modifiers { isStatic } +}.get().call() +
Tips
Use modifiers { ... } to create a conditional method body, at which point you can freely use its functionality in ModifierRules.
The condition at the end of the method body needs to return a Boolean, which is the final condition judgment result.
For more functions, please refer to FieldFinder.modifiers, MethodFinder.modifiers, ConstructorFinder.modifiers methods and ModifierRules.
# Obfuscated Bytecode
You may have noticed that the example
Class
given here has two obfuscated field names, both of which area
, how do we get them at this time?There are two options.
The first option is to determine the name and type of the field.
The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.field { + name = "a" + type = BooleanType +}.get(instance).any() // Get a field named a with type Boolean +
The second option is to determine where the type of the field is located.
The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.field { + type(BooleanType).index().first() +}.get(instance).any() // Get the first field of type Boolean +
In the above two cases, the corresponding field
private boolean a
can be obtained.Likewise, there are two obfuscated method names in this
Class
, both of which areb
.You can also have two options to get them.
The first option is to determine the method name and method parameters.
The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name = "b" + param(StringClass) +}.get(instance).call("test_string") // Get the method whose name is b and whose parameter is [String] +
The second option is to determine where the parameters of the method are located.
The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + param(StringClass).index().first() +}.get(instance).call("test_string") // Get the method whose first method parameter is [String] +
Since it is observed that this method is last in
Class
, then we have an alternative.The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + order().index().last() +}.get(instance).call("test_string") // Get the last method of the current Class +
Notice
Please try to avoid using order to filter bytecode subscripts, they may be indeterminate unless you are sure that its position in this Class must not change.
# Directly Called
The methods of calling bytecode described above all need to use
get(instance)
to call the corresponding method.Is there a simpler way?
At this point, you can use the
current
method on any instance to create a call space.The following example
// Assume this is an instance of this Class +val instance = Test() +// Assume this Class is not directly available +instance.current { + // Execute the doTask method + method { + name = "doTask" + param(StringClass) + }.call("task_name") + // Execute the stop method + method { + name = "stop" + emptyParam() + }.call() + // Get name + val name = method { name = "getName" }.string() +} +
We can also use
superClass
to call methods of the currentClass
super class.The following example
// Assume this is an instance of this Class +val instance = Test() +// Assume this Class is not directly available +instance.current { + // Execute the doBaseTask method of the parent class + superClass().method { + name = "doBaseTask" + param(StringClass) + }.call("task_name") +} +
If you don't like to use a lambda to create the namespace of the current instance, you can use the
current()
method directly.The following example
// Assuming this is an instance of this Class, this Class cannot be obtained directly +val instance = Test() +// Execute the doTask method +instance + .current() + .method { + name = "doTask" + param(StringClass) + }.call("task_name") +// Execute the stop method +instance + .current() + .method { + name = "stop" + emptyParam() + }.call() +// Get name +val name = instance.current().method { name = "getName" }.string() +
Likewise, consecutive calls can be made between them, but inline calls are not allowed.
The following example
// Assume this is an instance of this Class +val instance = Test() +// Assume this Class is not directly available +instance.current { + method { + name = "doTask" + param(StringClass) + }.call("task_name") +}.current() + .method { + name = "stop" + emptyParam() + }.call() +// Note that because current() returns the CurrentClass object itself +// It CANNOT BE CALLED like the following +instance.current().current() +
For
Field
instances, there is also a convenience method that can directly get the object of the instance whereField
is located.The following example
// Assume this is an instance of this Class +val instance = Test() +// Assume this Class is not directly available +instance.current { + // <Plan 1> + field { + name = "baseInstance" + }.current { + method { + name = "doBaseTask" + param(StringClass) + }.call("task_name") + } + // <Plan 2> + field { + name = "baseInstance" + }.current() + ?.method { + name = "doBaseTask" + param(StringClass) + }?.call("task_name") +} +
Notice
The above current method is equivalent to calling the field { ... }.any()?.current() method in CurrentClass for you.
If there is no CurrentClass calling field, you need to use field { ... }.get(instance).current() to call it.
The problem comes again, I want to use reflection to create the following instance and call the method in it, how to do it?
The following example
Test(true).doTask("task_name") +
Usually, we can use the standard reflection API to call.
The following example
"com.demo.Test".toClass() + .getDeclaredConstructor(Boolean::class.java) + .apply { isAccessible = true } + .newInstance(true) + .apply { + javaClass + .getDeclaredMethod("doTask", String::class.java) + .apply { isAccessible = true } + .invoke(this, "task_name") + } +
But I feel that this approach is very troublesome.
Is there a more concise way to call it?
At this time, we can also use the
buildOf
method to create an instance.The following example
"com.demo.Test".toClass().buildOf(true) { param(BooleanType) }?.current { + method { + name = "doTask" + param(StringClass) + }.call("task_name") +} +
If you want the
buildOf
method to return the type of the current instance, you can include a type-generic declaration in it instead of usingas
tocast
the target type.In this case, the constructor of the instance itself is private, but the method inside is public, so we only need to create its constructor by reflection.
The following example
// Assume this Class can be obtained directly +val test = Test::class.java.buildOf<Test>(true) { param(BooleanType) } +test.doTask("task_name") +
Tips
For more functions, please refer to CurrentClass and Class.buildOf method.
# Original Called
If you are using reflection to call a method that has been hooked, how do we call its original method?
The native
XposedBridge
provides us with aXposedBridge.invokeOriginalMethod
function.Now, in
YukiHookAPI
you can use the following method to implement this function conveniently.Suppose below is the
Class
we want to demonstrate.The following example
public class Test { + + public static String getString() { + return "Original"; + } +} +
Here's how the
getString
method in thisClass
Hooks.The following example
Test::class.java.method { + name = "getString" + emptyParam() + returnType = StringClass +}.hook { + replaceTo("Hooked") +} +
At this point, we use reflection to call this method, and we will get the result of Hook
"Hooked"
.The following example
// Result will be "Hooked" +val result = Test::class.java.method { + name = "getString" + emptyParam() + returnType = StringClass +}.get().string() +
If we want to get the original method and result of this method without hooking, we just need to add
original
to the result.The following example
// Result will be "Original" +val result = Test::class.java.method { + name = "getString" + emptyParam() + returnType = StringClass +}.get().original().string() +
Tips
For more functions, please refer to the MethodFinder.Result.original method.
# Find Again
Suppose there are three different versions of
Class
, all of which are the sameClass
for different versions of this Host App.There is also a method
doTask
in it, assuming they function the same.The following example of version A
public class Test { + + public void doTask() { + // ... + } +} +
The following example of version B
public class Test { + + public void doTask(String taskName) { + // ... + } +} +
The following example of version C
public class Test { + + public void doTask(String taskName, int type) { + // ... + } +} +
We need to get this same functionality of the
doTask
method in a different version, how do we do it?At this point, you can use
RemedyPlan
to complete your needs.The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name = "doTask" + emptyParam() +}.remedys { + method { + name = "doTask" + param(StringClass) + }.onFind { + // Found logic can be implemented here + } + method { + name = "doTask" + param(StringClass, IntType) + }.onFind { + // Found logic can be implemented here + } +}.wait(instance) { + // Get the result of the method +} +
Pay Attention
The method lookup result using RemedyPlan can no longer use get to get method instance, you should use wait method.
Also, you can continue to use
RemedyPlan
while using Multiple Find.The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name = "doTask" + emptyParam() +}.remedys { + method { + name = "doTask" + paramCount(0..1) + }.onFind { + // Found logic can be implemented here + } + method { + name = "doTask" + paramCount(1..2) + }.onFind { + // Found logic can be implemented here + } +}.waitAll(instance) { + // Get the result of the method +} +
Tips
For more functions, please refer to MethodFinder.RemedyPlan, ConstructorFinder.RemedyPlan, FieldFinder.RemedyPlan .
# Relative Matching
Suppose there is a
Class
with the same function in different versions of the Host App but only the name of theClass
is different.The following example of version A
public class ATest { + + public static void doTask() { + // ... + } +} +
The following example of version B
public class BTest { + + public static void doTask() { + // ... + } +} +
At this time, what should we do if we want to call the
doTask
method in thisClass
in each version?The usual practice is to check if
Class
exists.The following example
// First find this Class +val currentClass = + if("com.demo.ATest".hasClass()) "com.demo.ATest".toClass() else "com.demo.BTest".toClass() +// Then look for this method and call +currentClass.method { + name = "doTask" + emptyParam() +}.get().call() +
I feel that this solution is very inelegant and cumbersome, then
YukiHookAPI
provides you with a very convenientVariousClass
to solve this problem.Now, you can get this
Class
directly using the following methods.The following example
VariousClass("com.demo.ATest", "com.demo.BTest").get().method { + name = "doTask" + emptyParam() +}.get().call() +
If the current
Class
exists in the specifiedClassLoader
, you can fill in yourClassLoader
inget
.The following example
val customClassLoader: ClassLoader? = ... // Assume this is your ClassLoader +VariousClass("com.demo.ATest", "com.demo.BTest").get(customClassLoader).method { + name = "doTask" + emptyParam() +}.get().call() +
If you are not sure that all
Class
will be matched, you can use thegetOrNull
method.The following example
val customClassLoader: ClassLoader? = ... // Assume this is your ClassLoader +VariousClass("com.demo.ATest", "com.demo.BTest").getOrNull(customClassLoader)?.method { + name = "doTask" + emptyParam() +}?.get()?.call() +
If you are using the
Class
of the (Xposed) Host environment inPackageParam
, you can usetoClass()
to set it directly.The following example
VariousClass("com.demo.ATest", "com.demo.BTest").toClass().method { + name = "doTask" + emptyParam() +}.get().call() +
Tips
For more functions, please refer to VariousClass.
If it is used when creating a Hook, it can be more convenient, and it can also automatically intercept the exception that
Class
cannot be found.You can define this
Class
as a constant type to use.The following example
// Define constant type +val ABTestClass = VariousClass("com.demo.ATest", "com.demo.BTest") +// Use directly +ABTestClass.hook { + // Your code here. +} +
# Calling Generics
In the process of reflection, we may encounter generic problems.
In the reflection processing of generics,
YukiHookAPI
also provides a syntactic sugar that can be used anywhere.For example we have the following generic class.
The following example
class TestGeneric<T, R> (t: T, r: R) { + + fun foo() { + // ... + } +} +
When we want to get a
Class
instance of the genericT
orR
in the currentClass
, only the following implementation is required.The following example
class TestGeneric<T, R> (t: T, r: R) { + + fun foo() { + // Get the operation object of the current instance + // Get the Class instance of T, in the 0th position of the parameter + // The default value can not be written + val tClass = current().generic()?.argument() + // Get the Class instance of R, in parameter 1 + val rClass = current().generic()?.argument(index = 1) + // You can also use the following syntax + current().generic { + // Get the Class instance of T + // In the 0th position of the parameter, the default value can be left blank + val tClass = argument() + // Get the Class instance of R, in parameter 1 + val rClass = argument(index = 1) + } + } +} +
When we want to call this
Class
externally, it can be implemented as follows.The following example
// Assume this is the Class of T +class TI { + + fun foo() { + // ... + } +} +// Assume this is an instance of T +val tInstance: TI? = ... +// Get the Class instance of T +// In the 0th position of the parameter, the default value can be left blank +// And get the method foo and call it +TestGeneric::class.java.generic()?.argument()?.method { + name = "foo" + emptyParam() +}?.get(tInstance)?.invoke<TI>() +
Tips
For more functions, please refer to CurrentClass.generic, Class.generic methods and GenericClass.
# Pay Attention of Trap
Here are some misunderstandings that may be encountered during use for reference.
# Restrictive Find Conditions
In find conditions you can only use
index
function once exceptorder
.The following example
method { + name = "test" + param(BooleanType).index(num = 2) + // Wrong usage, please keep only one index method + returnType(StringClass).index(num = 1) +} +
The following find conditions can be used without any problems.
The following example
method { + name = "test" + param(BooleanType).index(num = 2) + order().index(num = 1) +} +
# Necessary Find Conditions
In common method find conditions, even methods without parameters need to set find conditions.
Suppose we have the following
Class
.The following example
public class TestFoo { + + public void foo(String string) { + // ... + } + + public void foo() { + // ... + } +} +
We want to get the
public void foo()
method, which can be written as follows.The following example
TestFoo::class.java.method { + name = "foo" +} +
However, the above example is wrong.
You will find two
foo
methods in thisClass
, one of which takes a method parameter.Since the above example does not set the find conditions for
param
, the result will be the first methodpublic void foo(String string)
that matches the name and matches the bytecode order, not the last method we need.This is a frequent error, without method parameters, you will lose the use of method parameter find conditions.
The correct usage is as follows.
The following example
TestFoo::class.java.method { + name = "foo" + // ✅ Correct usage, add detailed filter conditions + emptyParam() +} +
At this point, the above example will perfectly match the
public void foo()
method.Compatibility Notes
In the past historical versions of the API, it was allowed to match the method without writing the default matching no-parameter method, but the latest version has corrected this problem, please make sure that you are using the latest API version.
In the find conditions for constructors, even constructors without parameters need to set find conditions.
Suppose we have the following
Class
.The following example
public class TestFoo { + + public TestFoo() { + // ... + } +} +
To get the
public TestFoo()
constructor, we must write it in the following form.The following example
TestFoo::class.java.constructor { emptyParam() } +
The above example can successfully obtain the
public TestFoo()
constructor.If you write
constructor()
and missemptyParam()
, the result found at this time will be the first one in bytecode order, may not be parameterless.Compatibility Notes
In past historical versions of the API, if the constructor does not fill in any search parameters, the constructor will not be found directly.
This is a BUG and has been fixed in the latest version, please make sure you are using the latest API version.
API Behavior Changes
In 1.2.0 and later versions, the behavior of constructor() is no longer constructor { emptyParam() } but constructor {}, please pay attention to the behavior change reasonably adjust the find parameters.
# No Find Conditions
Without setting find conditions, using
field()
,constructor()
,method()
will return all members under the currentClass
.Using
get(...)
orgive()
will only get the first bit in bytecode order.The following example
Test::class.java.field().get(...) +Test::class.java.method().give() +
If you want to get all members, you can use
all(...)
orgiveAll()
The following example
Test::class.java.field().all(...) +Test::class.java.method().giveAll() +
Compatibility Notes
In past historical versions of the API, failure to set find conditions will throw an exception.
This feature was added in 1.2.0 and later versions.
# Bytecode Type
In the bytecode call result, the cast method can only specify the type corresponding to the bytecode.
For example we want to get a field of type
Boolean
and cast it toString
.The following is the wrong way to use it.
The following example
field { + name = "test" + type = BooleanType +}.get().string() // Wrong usage, must be cast to the bytecode target type +
The following is the correct way to use it.
The following example
field { + name = "test" + type = BooleanType +}.get().boolean().toString() // ✅ The correct way to use, get the type and then convert +
# Common Type Extensions
When find methods and fields, we usually need to specify the type in find conditions.
The following example
field { + name = "test" + type = Boolean::class.javaPrimitiveType +} +
Expressing the type of
Boolean::class.javaPrimitiveType
in Kotlin is very long and inconvenient.Therefore,
YukiHookAPI
encapsulates common type calls for developers, including Android related types and Java common types and primitive type keywords.At this time, the above type can be written in the following form.
The following example
field { + name = "test" + type = BooleanType +} +
The primitive type keywords in common Java types have been encapsulated as Type(Class Name) + Type, such as
IntType
,FloatType
(their bytecode types areint
,float
).Correspondingly, array types also have convenient usage methods, assuming we want to get an array of type
String[]
.You need to write
java.lang.reflect.Array.newInstance(String::class.java, 0).javaClass
to get this type.Does it feel very troublesome, at this time we can use the method
ArrayClass(StringClass)
to get this type.At the same time, since
String
is a common type, you can also directly useStringArrayClass
to get this type.Some common methods found in Hook have their corresponding encapsulation types for use, in the format Type(Class Name) + Class.
For example, the Hook
onCreate
method needs to look up theBundle::class.java
type.The following example
method { + name = "onCreate" + param(BundleClass) +} +
The following are wrapper names for some special case types in Java represented in
YukiHookAPI
.
void
→UnitType
java.lang.Void
→UnitClass
java.lang.Object
→AnyClass
java.lang.Integer
→IntClass
java.lang.Character
→CharClass
Notice
Encapsulating types with Type(Class Name) + Type will and only be represented as Java primitive type keywords.
Since the concept of primitive types does not exist in Kotlin, they will all be defined as KClass.
There are 9 primitive type keywords in Java, of which 8 are primitive type, namely boolean, char, byte, short , int, float, long, double, of which the void type is a special case.
At the same time, they all have their own corresponding package types in Java, such as java.lang.Boolean, java.lang.Integer, these types are unequal, Please note the distinction.
Similarly, arrays also have corresponding wrapper types, which also need to be distinguished from Java primitive type keywords.
For example, the encapsulation type of byte[] is ByteArrayType or ArrayClass(ByteType), and the encapsulation type of Byte[] is ByteArrayClass or ArrayClass(ByteClass), these types are also unequal.
Tips
For more types, see ComponentTypeFactory, GraphicsTypeFactory, ViewTypeFactory, VariableTypeFactory.
At the same time, you are welcome to contribute more commonly used types.
`,371);function R(Y,G){const e=o("ExternalLinkIcon"),p=o("Badge");return c(),i("div",null,[d,y,s("p",null,[s("s",null,[n("The core part of this functionality has been decoupled into the "),s("a",A,[n("YukiReflection"),a(e)]),n(" project, which can be used independently in any Java or Android project.")])]),u,s("div",D,[B,s("p",null,[n("Starting with version "),C,n(", "),m,n(" has moved its own reflection API partially to "),s("a",v,[n("KavaRef"),a(e)]),n(", we no longer recommend the reflection API of "),h,n(" itself, which have been marked as deprecated.")]),b,s("p",null,[n("If you are still using the reflection API section of "),F,n(", please refer to the migration document "),s("a",g,[n("here"),a(e)]),n(" which will jump to the "),k,n(" document.")])]),s("div",f,[w,s("h3",x,[q,n(" Vague Search "),a(p,{type:"tip",text:"Beta",vertical:"middle"})]),T,s("div",S,[I,s("p",null,[s("s",null,[n("After "),P,n(),j,n(" released, this function will be deprecated and will no longer be migrated to "),s("a",_,[n("YukiReflection"),a(e)]),n(".")])]),s("p",null,[n("We welcome all developers to start using "),s("a",H,[n("DexKit"),a(e)]),n(", which is a high-performance runtime parsing library for "),L,n(" implemented in C++, which is more efficient than the Java layer in terms of performance, efficient and excellent, it is still in the development stage, your valuable suggestions are welcome.")])]),N])])}const O=t(r,[["render",R],["__file","reflection.html.vue"]]);export{O as default}; diff --git a/assets/reflection.html-DXPuhLBz.js b/assets/reflection.html-DXPuhLBz.js new file mode 100644 index 00000000..9efbd63b --- /dev/null +++ b/assets/reflection.html-DXPuhLBz.js @@ -0,0 +1 @@ +const l=JSON.parse('{"key":"v-001858e3","path":"/zh-cn/api/special-features/reflection.html","title":"字节码与反射扩展 (已迁移)","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"Class 扩展","slug":"class-扩展","link":"#class-扩展","children":[{"level":3,"title":"对象转换","slug":"对象转换","link":"#对象转换","children":[]},{"level":3,"title":"延迟装载","slug":"延迟装载","link":"#延迟装载","children":[]},{"level":3,"title":"存在判断","slug":"存在判断","link":"#存在判断","children":[]},{"level":3,"title":"模糊查找","slug":"模糊查找","link":"#模糊查找","children":[]}]},{"level":2,"title":"Member 扩展","slug":"member-扩展","link":"#member-扩展","children":[{"level":3,"title":"查找与反射调用","slug":"查找与反射调用","link":"#查找与反射调用","children":[]},{"level":3,"title":"可选的查找条件","slug":"可选的查找条件","link":"#可选的查找条件","children":[]},{"level":3,"title":"在父类查找","slug":"在父类查找","link":"#在父类查找","children":[]},{"level":3,"title":"模糊查找","slug":"模糊查找-1","link":"#模糊查找-1","children":[]},{"level":3,"title":"多重查找","slug":"多重查找-1","link":"#多重查找-1","children":[]},{"level":3,"title":"静态字节码","slug":"静态字节码","link":"#静态字节码","children":[]},{"level":3,"title":"混淆的字节码","slug":"混淆的字节码","link":"#混淆的字节码","children":[]},{"level":3,"title":"直接调用","slug":"直接调用","link":"#直接调用","children":[]},{"level":3,"title":"原始调用","slug":"原始调用","link":"#原始调用","children":[]},{"level":3,"title":"再次查找","slug":"再次查找","link":"#再次查找","children":[]},{"level":3,"title":"相对匹配","slug":"相对匹配","link":"#相对匹配","children":[]},{"level":3,"title":"调用泛型","slug":"调用泛型","link":"#调用泛型","children":[]},{"level":3,"title":"注意误区","slug":"注意误区","link":"#注意误区","children":[]}]},{"level":2,"title":"常用类型扩展","slug":"常用类型扩展","link":"#常用类型扩展","children":[]}],"git":{"updatedTime":1750318245000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":21}]},"filePathRelative":"zh-cn/api/special-features/reflection.md"}');export{l as data}; diff --git a/assets/style-DJZs_E_O.css b/assets/style-DJZs_E_O.css new file mode 100644 index 00000000..d6679948 --- /dev/null +++ b/assets/style-DJZs_E_O.css @@ -0,0 +1 @@ +:root{--back-to-top-z-index: 5;--back-to-top-color: #3eaf7c;--back-to-top-color-hover: #71cda3}.back-to-top{cursor:pointer;position:fixed;bottom:2rem;right:2.5rem;width:2rem;height:1.2rem;background-color:var(--back-to-top-color);-webkit-mask:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2049.484%2028.284'%3e%3cg%20transform='translate(-229%20-126.358)'%20fill='currentColor'%3e%3crect%20width='35'%20height='5'%20rx='2'%20transform='rotate(-45%20296.902%20-200.874)'/%3e%3crect%20width='35'%20height='5'%20rx='2'%20transform='rotate(-135%20169.502%2020.377)'/%3e%3c/g%3e%3c/svg%3e") no-repeat;mask:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2049.484%2028.284'%3e%3cg%20transform='translate(-229%20-126.358)'%20fill='currentColor'%3e%3crect%20width='35'%20height='5'%20rx='2'%20transform='rotate(-45%20296.902%20-200.874)'/%3e%3crect%20width='35'%20height='5'%20rx='2'%20transform='rotate(-135%20169.502%2020.377)'/%3e%3c/g%3e%3c/svg%3e") no-repeat;z-index:var(--back-to-top-z-index)}.back-to-top:hover{background-color:var(--back-to-top-color-hover)}@media (max-width: 959px){.back-to-top{display:none}}@media print{.back-to-top{display:none}}.back-to-top-enter-active,.back-to-top-leave-active{transition:opacity .3s}.back-to-top-enter-from,.back-to-top-leave-to{opacity:0}:root{--external-link-icon-color: #aaa}.external-link-icon{position:relative;display:inline-block;color:var(--external-link-icon-color);vertical-align:middle;top:-1px}@media print{.external-link-icon{display:none}}.external-link-icon-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}:root{--medium-zoom-z-index: 100;--medium-zoom-bg-color: #ffffff;--medium-zoom-opacity: 1}.medium-zoom-overlay{background-color:var(--medium-zoom-bg-color)!important;z-index:var(--medium-zoom-z-index)}.medium-zoom-overlay~img{z-index:calc(var(--medium-zoom-z-index) + 1)}.medium-zoom--opened .medium-zoom-overlay{opacity:var(--medium-zoom-opacity)}:root{--nprogress-color: #29d;--nprogress-z-index: 1031}#nprogress{pointer-events:none}#nprogress .bar{background:var(--nprogress-color);position:fixed;z-index:var(--nprogress-z-index);top:0;left:0;width:100%;height:2px}:root{--c-brand: #3eaf7c;--c-brand-light: #4abf8a;--c-bg: #ffffff;--c-bg-light: #f3f4f5;--c-bg-lighter: #eeeeee;--c-bg-dark: #ebebec;--c-bg-darker: #e6e6e6;--c-bg-navbar: var(--c-bg);--c-bg-sidebar: var(--c-bg);--c-bg-arrow: #cccccc;--c-text: #2c3e50;--c-text-accent: var(--c-brand);--c-text-light: #3a5169;--c-text-lighter: #4e6e8e;--c-text-lightest: #6a8bad;--c-text-quote: #999999;--c-border: #eaecef;--c-border-dark: #dfe2e5;--c-tip: #42b983;--c-tip-bg: var(--c-bg-light);--c-tip-title: var(--c-text);--c-tip-text: var(--c-text);--c-tip-text-accent: var(--c-text-accent);--c-warning: #ffc310;--c-warning-bg: #fffae3;--c-warning-bg-light: #fff3ba;--c-warning-bg-lighter: #fff0b0;--c-warning-border-dark: #f7dc91;--c-warning-details-bg: #fff5ca;--c-warning-title: #f1b300;--c-warning-text: #746000;--c-warning-text-accent: #edb100;--c-warning-text-light: #c1971c;--c-warning-text-quote: #ccab49;--c-danger: #f11e37;--c-danger-bg: #ffe0e0;--c-danger-bg-light: #ffcfde;--c-danger-bg-lighter: #ffc9c9;--c-danger-border-dark: #f1abab;--c-danger-details-bg: #ffd4d4;--c-danger-title: #ed1e2c;--c-danger-text: #660000;--c-danger-text-accent: #bd1a1a;--c-danger-text-light: #b5474d;--c-danger-text-quote: #c15b5b;--c-details-bg: #eeeeee;--c-badge-tip: var(--c-tip);--c-badge-warning: #ecc808;--c-badge-warning-text: var(--c-bg);--c-badge-danger: #dc2626;--c-badge-danger-text: var(--c-bg);--t-color: .3s ease;--t-transform: .3s ease;--code-bg-color: #282c34;--code-hl-bg-color: rgba(0, 0, 0, .66);--code-ln-color: #9e9e9e;--code-ln-wrapper-width: 3.5rem;--font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;--font-family-code: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;--navbar-height: 3.6rem;--navbar-padding-v: .7rem;--navbar-padding-h: 1.5rem;--sidebar-width: 20rem;--sidebar-width-mobile: calc(var(--sidebar-width) * .82);--content-width: 740px;--homepage-width: 960px}.back-to-top{--back-to-top-color: var(--c-brand);--back-to-top-color-hover: var(--c-brand-light)}.DocSearch{--docsearch-primary-color: var(--c-brand);--docsearch-text-color: var(--c-text);--docsearch-highlight-color: var(--c-brand);--docsearch-muted-color: var(--c-text-quote);--docsearch-container-background: rgba(9, 10, 17, .8);--docsearch-modal-background: var(--c-bg-light);--docsearch-searchbox-background: var(--c-bg-lighter);--docsearch-searchbox-focus-background: var(--c-bg);--docsearch-searchbox-shadow: inset 0 0 0 2px var(--c-brand);--docsearch-hit-color: var(--c-text-light);--docsearch-hit-active-color: var(--c-bg);--docsearch-hit-background: var(--c-bg);--docsearch-hit-shadow: 0 1px 3px 0 var(--c-border-dark);--docsearch-footer-background: var(--c-bg)}.external-link-icon{--external-link-icon-color: var(--c-text-quote)}.medium-zoom-overlay{--medium-zoom-bg-color: var(--c-bg)}#nprogress{--nprogress-color: var(--c-brand)}.pwa-popup{--pwa-popup-text-color: var(--c-text);--pwa-popup-bg-color: var(--c-bg);--pwa-popup-border-color: var(--c-brand);--pwa-popup-shadow: 0 4px 16px var(--c-brand);--pwa-popup-btn-text-color: var(--c-bg);--pwa-popup-btn-bg-color: var(--c-brand);--pwa-popup-btn-hover-bg-color: var(--c-brand-light)}.search-box{--search-bg-color: var(--c-bg);--search-accent-color: var(--c-brand);--search-text-color: var(--c-text);--search-border-color: var(--c-border);--search-item-text-color: var(--c-text-lighter);--search-item-focus-bg-color: var(--c-bg-light)}html.dark{--c-brand: #3aa675;--c-brand-light: #349469;--c-bg: #22272e;--c-bg-light: #2b313a;--c-bg-lighter: #262c34;--c-bg-dark: #343b44;--c-bg-darker: #37404c;--c-text: #adbac7;--c-text-light: #96a7b7;--c-text-lighter: #8b9eb0;--c-text-lightest: #8094a8;--c-border: #3e4c5a;--c-border-dark: #34404c;--c-tip: #318a62;--c-warning: #e0ad15;--c-warning-bg: #2d2f2d;--c-warning-bg-light: #423e2a;--c-warning-bg-lighter: #44442f;--c-warning-border-dark: #957c35;--c-warning-details-bg: #39392d;--c-warning-title: #fdca31;--c-warning-text: #d8d96d;--c-warning-text-accent: #ffbf00;--c-warning-text-light: #ddb84b;--c-warning-text-quote: #ccab49;--c-danger: #fc1e38;--c-danger-bg: #39232c;--c-danger-bg-light: #4b2b35;--c-danger-bg-lighter: #553040;--c-danger-border-dark: #a25151;--c-danger-details-bg: #482936;--c-danger-title: #fc2d3b;--c-danger-text: #ea9ca0;--c-danger-text-accent: #fd3636;--c-danger-text-light: #d9777c;--c-danger-text-quote: #d56b6b;--c-details-bg: #323843;--c-badge-warning: var(--c-warning);--c-badge-warning-text: #3c2e05;--c-badge-danger: var(--c-danger);--c-badge-danger-text: #401416;--code-hl-bg-color: #363b46}html.dark .DocSearch{--docsearch-logo-color: var(--c-text);--docsearch-modal-shadow: inset 1px 1px 0 0 #2c2e40, 0 3px 8px 0 #000309;--docsearch-key-shadow: inset 0 -2px 0 0 #282d55, inset 0 0 1px 1px #51577d, 0 2px 2px 0 rgba(3, 4, 9, .3);--docsearch-key-gradient: linear-gradient(-225deg, #444950, #1c1e21);--docsearch-footer-shadow: inset 0 1px 0 0 rgba(73, 76, 106, .5), 0 -4px 8px 0 rgba(0, 0, 0, .2)}html,body{padding:0;margin:0;background-color:var(--c-bg);transition:background-color var(--t-color)}html.dark{color-scheme:dark}html{font-size:16px}body{font-family:var(--font-family);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-size:1rem;color:var(--c-text)}a{font-weight:500;color:var(--c-text-accent);text-decoration:none;overflow-wrap:break-word}p a code{font-weight:400;color:var(--c-text-accent)}kbd{font-family:var(--font-family-code);color:var(--c-text);background:var(--c-bg-lighter);border:solid .15rem var(--c-border-dark);border-bottom:solid .25rem var(--c-border-dark);border-radius:.15rem;padding:0 .15em}code{font-family:var(--font-family-code);color:var(--c-text-lighter);padding:.25rem .5rem;margin:0;font-size:.85em;background-color:var(--c-bg-light);border-radius:3px;overflow-wrap:break-word;transition:background-color var(--t-color)}blockquote{font-size:1rem;color:var(--c-text-quote);border-left:.2rem solid var(--c-border-dark);margin:1rem 0;padding:.25rem 0 .25rem 1rem;overflow-wrap:break-word}blockquote>p{margin:0}ul,ol{padding-left:1.2em}strong{font-weight:600}h1,h2,h3,h4,h5,h6{font-weight:600;line-height:1.25;overflow-wrap:break-word}h1:focus-visible,h2:focus-visible,h3:focus-visible,h4:focus-visible,h5:focus-visible,h6:focus-visible{outline:none}h1:hover .header-anchor,h2:hover .header-anchor,h3:hover .header-anchor,h4:hover .header-anchor,h5:hover .header-anchor,h6:hover .header-anchor{opacity:1}h1{font-size:2.2rem}h2{font-size:1.65rem;padding-bottom:.3rem;border-bottom:1px solid var(--c-border);transition:border-color var(--t-color)}h3{font-size:1.35rem}h4{font-size:1.15rem}h5{font-size:1.05rem}h6{font-size:1rem}a.header-anchor{font-size:.85em;float:left;margin-left:-.87em;padding-right:.23em;margin-top:.125em;opacity:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}@media print{a.header-anchor{display:none}}a.header-anchor:hover{text-decoration:none}a.header-anchor:focus-visible{opacity:1}@media print{a[href^="http://"]:after,a[href^="https://"]:after{content:" (" attr(href) ") "}}p,ul,ol{line-height:1.7;overflow-wrap:break-word}hr{border:0;border-top:1px solid var(--c-border)}table{border-collapse:collapse;margin:1rem 0;display:block;overflow-x:auto;transition:border-color var(--t-color)}tr{border-top:1px solid var(--c-border-dark);transition:border-color var(--t-color)}tr:nth-child(2n){background-color:var(--c-bg-light);transition:background-color var(--t-color)}tr:nth-child(2n) code{background-color:var(--c-bg-dark)}th,td{padding:.6em 1em;border:1px solid var(--c-border-dark);transition:border-color var(--t-color)}.arrow{display:inline-block;width:0;height:0}.arrow.up{border-left:4px solid transparent;border-right:4px solid transparent;border-bottom:6px solid var(--c-bg-arrow)}.arrow.down{border-left:4px solid transparent;border-right:4px solid transparent;border-top:6px solid var(--c-bg-arrow)}.arrow.right{border-top:4px solid transparent;border-bottom:4px solid transparent;border-left:6px solid var(--c-bg-arrow)}.arrow.left{border-top:4px solid transparent;border-bottom:4px solid transparent;border-right:6px solid var(--c-bg-arrow)}.badge{display:inline-block;font-size:14px;font-weight:600;height:18px;line-height:18px;border-radius:3px;padding:0 6px;color:var(--c-bg);vertical-align:top;transition:color var(--t-color),background-color var(--t-color)}.badge.tip{background-color:var(--c-badge-tip)}.badge.warning{background-color:var(--c-badge-warning);color:var(--c-badge-warning-text)}.badge.danger{background-color:var(--c-badge-danger);color:var(--c-badge-danger-text)}.badge+.badge{margin-left:5px}code[class*=language-],pre[class*=language-]{color:#ccc;background:none;font-family:var(--font-family-code);font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#2d2d2d}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.comment,.token.block-comment,.token.prolog,.token.doctype,.token.cdata{color:#999}.token.punctuation{color:#ccc}.token.tag,.token.attr-name,.token.namespace,.token.deleted{color:#ec5975}.token.function-name{color:#6196cc}.token.boolean,.token.number,.token.function{color:#f08d49}.token.property,.token.class-name,.token.constant,.token.symbol{color:#f8c555}.token.selector,.token.important,.token.atrule,.token.keyword,.token.builtin{color:#cc99cd}.token.string,.token.char,.token.attr-value,.token.regex,.token.variable{color:#7ec699}.token.operator,.token.entity,.token.url{color:#67cdcc}.token.important,.token.bold{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.token.inserted{color:#3eaf7c}.theme-default-content pre,.theme-default-content pre[class*=language-]{line-height:1.375;padding:1.3rem 1.5rem;margin:.85rem 0;border-radius:6px;overflow:auto}.theme-default-content pre code,.theme-default-content pre[class*=language-] code{color:#fff;padding:0;background-color:transparent!important;border-radius:0;overflow-wrap:unset;-webkit-font-smoothing:auto;-moz-osx-font-smoothing:auto}.theme-default-content .line-number{font-family:var(--font-family-code)}div[class*=language-]{position:relative;background-color:var(--code-bg-color);border-radius:6px}div[class*=language-]:before{content:attr(data-ext);position:absolute;z-index:3;top:.8em;right:1em;font-size:.75rem;color:var(--code-ln-color)}div[class*=language-] pre,div[class*=language-] pre[class*=language-]{background:transparent!important;position:relative;z-index:1}div[class*=language-] .highlight-lines{-webkit-user-select:none;-moz-user-select:none;user-select:none;padding-top:1.3rem;position:absolute;top:0;left:0;width:100%;line-height:1.375}div[class*=language-] .highlight-lines .highlight-line{background-color:var(--code-hl-bg-color)}div[class*=language-]:not(.line-numbers-mode) .line-numbers{display:none}div[class*=language-].line-numbers-mode .highlight-lines .highlight-line{position:relative}div[class*=language-].line-numbers-mode .highlight-lines .highlight-line:before{content:" ";position:absolute;z-index:2;left:0;top:0;display:block;width:var(--code-ln-wrapper-width);height:100%}div[class*=language-].line-numbers-mode pre{margin-left:var(--code-ln-wrapper-width);padding-left:1rem;vertical-align:middle}div[class*=language-].line-numbers-mode .line-numbers{position:absolute;top:0;width:var(--code-ln-wrapper-width);text-align:center;color:var(--code-ln-color);padding-top:1.25rem;line-height:1.375;counter-reset:line-number}div[class*=language-].line-numbers-mode .line-numbers .line-number{position:relative;z-index:3;-webkit-user-select:none;-moz-user-select:none;user-select:none;height:1.375em}div[class*=language-].line-numbers-mode .line-numbers .line-number:before{counter-increment:line-number;content:counter(line-number);font-size:.85em}div[class*=language-].line-numbers-mode:after{content:"";position:absolute;top:0;left:0;width:var(--code-ln-wrapper-width);height:100%;border-radius:6px 0 0 6px;border-right:1px solid var(--code-hl-bg-color)}@media (max-width: 419px){.theme-default-content div[class*=language-]{margin:.85rem -1.5rem;border-radius:0}}.code-group__nav{margin-top:.85rem;margin-bottom:calc(-1.7rem - 6px);padding-bottom:calc(1.7rem - 6px);padding-left:10px;padding-top:10px;border-top-left-radius:6px;border-top-right-radius:6px;background-color:var(--code-bg-color)}.code-group__ul{margin:auto 0;padding-left:0;display:inline-flex;list-style:none}.code-group__nav-tab{border:0;padding:5px;cursor:pointer;background-color:transparent;font-size:.85em;line-height:1.4;color:#ffffffe6;font-weight:600}.code-group__nav-tab:focus{outline:none}.code-group__nav-tab:focus-visible{outline:1px solid rgba(255,255,255,.9)}.code-group__nav-tab-active{border-bottom:var(--c-brand) 1px solid}@media (max-width: 419px){.code-group__nav{margin-left:-1.5rem;margin-right:-1.5rem;border-radius:0}}.code-group-item{display:none}.code-group-item__active{display:block}.code-group-item>pre{background-color:orange}.custom-container{transition:color var(--t-color),border-color var(--t-color),background-color var(--t-color)}.custom-container .custom-container-title{font-weight:600}.custom-container .custom-container-title:not(:only-child){margin-bottom:-.4rem}.custom-container.tip,.custom-container.warning,.custom-container.danger{padding:.1rem 1.5rem;border-left-width:.5rem;border-left-style:solid;margin:1rem 0}.custom-container.tip{border-color:var(--c-tip);background-color:var(--c-tip-bg);color:var(--c-tip-text)}.custom-container.tip .custom-container-title{color:var(--c-tip-title)}.custom-container.tip a{color:var(--c-tip-text-accent)}.custom-container.tip code{background-color:var(--c-bg-dark)}.custom-container.warning{border-color:var(--c-warning);background-color:var(--c-warning-bg);color:var(--c-warning-text)}.custom-container.warning .custom-container-title{color:var(--c-warning-title)}.custom-container.warning a{color:var(--c-warning-text-accent)}.custom-container.warning blockquote{border-left-color:var(--c-warning-border-dark);color:var(--c-warning-text-quote)}.custom-container.warning code{color:var(--c-warning-text-light);background-color:var(--c-warning-bg-light)}.custom-container.warning details{background-color:var(--c-warning-details-bg)}.custom-container.warning details code{background-color:var(--c-warning-bg-lighter)}.custom-container.warning .external-link-icon{--external-link-icon-color: var(--c-warning-text-quote)}.custom-container.danger{border-color:var(--c-danger);background-color:var(--c-danger-bg);color:var(--c-danger-text)}.custom-container.danger .custom-container-title{color:var(--c-danger-title)}.custom-container.danger a{color:var(--c-danger-text-accent)}.custom-container.danger blockquote{border-left-color:var(--c-danger-border-dark);color:var(--c-danger-text-quote)}.custom-container.danger code{color:var(--c-danger-text-light);background-color:var(--c-danger-bg-light)}.custom-container.danger details{background-color:var(--c-danger-details-bg)}.custom-container.danger details code{background-color:var(--c-danger-bg-lighter)}.custom-container.danger .external-link-icon{--external-link-icon-color: var(--c-danger-text-quote)}.custom-container.details{display:block;position:relative;border-radius:2px;margin:1.6em 0;padding:1.6em;background-color:var(--c-details-bg)}.custom-container.details code{background-color:var(--c-bg-darker)}.custom-container.details h4{margin-top:0}.custom-container.details figure:last-child,.custom-container.details p:last-child{margin-bottom:0;padding-bottom:0}.custom-container.details summary{outline:none;cursor:pointer}.home{padding:var(--navbar-height) 2rem 0;max-width:var(--homepage-width);margin:0 auto;display:block}.home .hero{text-align:center}.home .hero img{max-width:100%;max-height:280px;display:block;margin:3rem auto 1.5rem}.home .hero h1{font-size:3rem}.home .hero h1,.home .hero .description,.home .hero .actions{margin:1.8rem auto}.home .hero .actions{display:flex;flex-wrap:wrap;gap:1rem;justify-content:center}.home .hero .description{max-width:35rem;font-size:1.6rem;line-height:1.3;color:var(--c-text-lightest)}.home .hero .action-button{display:inline-block;font-size:1.2rem;padding:.8rem 1.6rem;border-width:2px;border-style:solid;border-radius:4px;transition:background-color var(--t-color);box-sizing:border-box}.home .hero .action-button.primary{color:var(--c-bg);background-color:var(--c-brand);border-color:var(--c-brand)}.home .hero .action-button.primary:hover{background-color:var(--c-brand-light)}.home .hero .action-button.secondary{color:var(--c-brand);background-color:var(--c-bg);border-color:var(--c-brand)}.home .hero .action-button.secondary:hover{color:var(--c-bg);background-color:var(--c-brand-light)}.home .features{border-top:1px solid var(--c-border);transition:border-color var(--t-color);padding:1.2rem 0;margin-top:2.5rem;display:flex;flex-wrap:wrap;align-items:flex-start;align-content:stretch;justify-content:space-between}.home .feature{flex-grow:1;flex-basis:30%;max-width:30%}.home .feature h2{font-size:1.4rem;font-weight:500;border-bottom:none;padding-bottom:0;color:var(--c-text-light)}.home .feature p{color:var(--c-text-lighter)}.home .theme-default-content{padding:0;margin:0}.home .footer{padding:2.5rem;border-top:1px solid var(--c-border);text-align:center;color:var(--c-text-lighter);transition:border-color var(--t-color)}@media (max-width: 719px){.home .features{flex-direction:column}.home .feature{max-width:100%;padding:0 2.5rem}}@media (max-width: 419px){.home{padding-left:1.5rem;padding-right:1.5rem}.home .hero img{max-height:210px;margin:2rem auto 1.2rem}.home .hero h1{font-size:2rem}.home .hero h1,.home .hero .description,.home .hero .actions{margin:1.2rem auto}.home .hero .description{font-size:1.2rem}.home .hero .action-button{font-size:1rem;padding:.6rem 1.2rem}.home .feature h2{font-size:1.25rem}}.page{padding-top:var(--navbar-height);padding-left:var(--sidebar-width)}.navbar{position:fixed;z-index:20;top:0;left:0;right:0;height:var(--navbar-height);box-sizing:border-box;border-bottom:1px solid var(--c-border);background-color:var(--c-bg-navbar);transition:background-color var(--t-color),border-color var(--t-color)}.sidebar{font-size:16px;width:var(--sidebar-width);position:fixed;z-index:10;margin:0;top:var(--navbar-height);left:0;bottom:0;box-sizing:border-box;border-right:1px solid var(--c-border);overflow-y:auto;scrollbar-width:thin;scrollbar-color:var(--c-brand) var(--c-border);background-color:var(--c-bg-sidebar);transition:transform var(--t-transform),background-color var(--t-color),border-color var(--t-color)}.sidebar::-webkit-scrollbar{width:7px}.sidebar::-webkit-scrollbar-track{background-color:var(--c-border)}.sidebar::-webkit-scrollbar-thumb{background-color:var(--c-brand)}.sidebar-mask{position:fixed;z-index:9;top:0;left:0;width:100vw;height:100vh;display:none}.theme-container.sidebar-open .sidebar-mask{display:block}.theme-container.sidebar-open .navbar>.toggle-sidebar-button .icon span:nth-child(1){transform:rotate(45deg) translate3d(5.5px,5.5px,0)}.theme-container.sidebar-open .navbar>.toggle-sidebar-button .icon span:nth-child(2){transform:scale3d(0,1,1)}.theme-container.sidebar-open .navbar>.toggle-sidebar-button .icon span:nth-child(3){transform:rotate(-45deg) translate3d(6px,-6px,0)}.theme-container.sidebar-open .navbar>.toggle-sidebar-button .icon span:nth-child(1),.theme-container.sidebar-open .navbar>.toggle-sidebar-button .icon span:nth-child(3){transform-origin:center}.theme-container.no-navbar .theme-default-content h1,.theme-container.no-navbar .theme-default-content h2,.theme-container.no-navbar .theme-default-content h3,.theme-container.no-navbar .theme-default-content h4,.theme-container.no-navbar .theme-default-content h5,.theme-container.no-navbar .theme-default-content h6{margin-top:1.5rem;padding-top:0}.theme-container.no-navbar .page{padding-top:0}.theme-container.no-navbar .sidebar{top:0}.theme-container.no-sidebar .sidebar{display:none}@media (max-width: 719px){.theme-container.no-sidebar .sidebar{display:block}}.theme-container.no-sidebar .page{padding-left:0}.theme-default-content a:hover{text-decoration:underline}.theme-default-content img{max-width:100%}.theme-default-content h1,.theme-default-content h2,.theme-default-content h3,.theme-default-content h4,.theme-default-content h5,.theme-default-content h6{margin-top:calc(.5rem - var(--navbar-height));padding-top:calc(1rem + var(--navbar-height));margin-bottom:0}.theme-default-content h1:first-child,.theme-default-content h2:first-child,.theme-default-content h3:first-child,.theme-default-content h4:first-child,.theme-default-content h5:first-child,.theme-default-content h6:first-child{margin-bottom:1rem}.theme-default-content h1:first-child+p,.theme-default-content h1:first-child+pre,.theme-default-content h1:first-child+.custom-container,.theme-default-content h2:first-child+p,.theme-default-content h2:first-child+pre,.theme-default-content h2:first-child+.custom-container,.theme-default-content h3:first-child+p,.theme-default-content h3:first-child+pre,.theme-default-content h3:first-child+.custom-container,.theme-default-content h4:first-child+p,.theme-default-content h4:first-child+pre,.theme-default-content h4:first-child+.custom-container,.theme-default-content h5:first-child+p,.theme-default-content h5:first-child+pre,.theme-default-content h5:first-child+.custom-container,.theme-default-content h6:first-child+p,.theme-default-content h6:first-child+pre,.theme-default-content h6:first-child+.custom-container{margin-top:2rem}@media (max-width: 959px){.sidebar{font-size:15px;width:var(--sidebar-width-mobile)}.page{padding-left:var(--sidebar-width-mobile)}}@media (max-width: 719px){.sidebar{top:0;padding-top:var(--navbar-height);transform:translate(-100%)}.page{padding-left:0}.theme-container.sidebar-open .sidebar{transform:translate(0)}.theme-container.no-navbar .sidebar{padding-top:0}}@media (max-width: 419px){h1{font-size:1.9rem}}.navbar{--navbar-line-height: calc( var(--navbar-height) - 2 * var(--navbar-padding-v) );padding:var(--navbar-padding-v) var(--navbar-padding-h);line-height:var(--navbar-line-height)}.navbar .logo{height:var(--navbar-line-height);margin-right:var(--navbar-padding-v);vertical-align:top}.navbar .site-name{font-size:1.3rem;font-weight:600;color:var(--c-text);position:relative}.navbar .navbar-items-wrapper{display:flex;position:absolute;box-sizing:border-box;top:var(--navbar-padding-v);right:var(--navbar-padding-h);height:var(--navbar-line-height);padding-left:var(--navbar-padding-h);white-space:nowrap;font-size:.9rem}.navbar .navbar-items-wrapper .search-box{flex:0 0 auto;vertical-align:top}@media screen and (max-width: 719px){.navbar{padding-left:4rem}.navbar .site-name{display:block;width:calc(100vw - 11rem);overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.navbar .can-hide{display:none}}.navbar-items{display:inline-block}@media print{.navbar-items{display:none}}.navbar-items a{display:inline-block;line-height:1.4rem;color:inherit}.navbar-items a:hover,.navbar-items a.router-link-active{color:var(--c-text)}.navbar-items .navbar-item{position:relative;display:inline-block;margin-left:1.5rem;line-height:var(--navbar-line-height)}.navbar-items .navbar-item:first-child{margin-left:0}.navbar-items .navbar-item>a:hover,.navbar-items .navbar-item>a.router-link-active{margin-bottom:-2px;border-bottom:2px solid var(--c-text-accent)}@media (max-width: 719px){.navbar-items .navbar-item{margin-left:0}.navbar-items .navbar-item>a:hover,.navbar-items .navbar-item>a.router-link-active{margin-bottom:0;border-bottom:none}.navbar-items a:hover,.navbar-items a.router-link-active{color:var(--c-text-accent)}}.toggle-sidebar-button{position:absolute;top:.6rem;left:1rem;display:none;padding:.6rem;cursor:pointer}.toggle-sidebar-button .icon{display:flex;flex-direction:column;justify-content:center;align-items:center;width:1.25rem;height:1.25rem;cursor:inherit}.toggle-sidebar-button .icon span{display:inline-block;width:100%;height:2px;border-radius:2px;background-color:var(--c-text);transition:transform var(--t-transform)}.toggle-sidebar-button .icon span:nth-child(2){margin:6px 0}@media screen and (max-width: 719px){.toggle-sidebar-button{display:block}}.toggle-color-mode-button{display:flex;margin:auto;margin-left:1rem;border:0;background:none;color:var(--c-text);opacity:.8;cursor:pointer}@media print{.toggle-color-mode-button{display:none}}.toggle-color-mode-button:hover{opacity:1}.toggle-color-mode-button .icon{width:1.25rem;height:1.25rem}.DocSearch{transition:background-color var(--t-color)}.navbar-dropdown-wrapper{cursor:pointer}.navbar-dropdown-wrapper .navbar-dropdown-title,.navbar-dropdown-wrapper .navbar-dropdown-title-mobile{display:block;font-size:.9rem;font-family:inherit;cursor:inherit;padding:inherit;line-height:1.4rem;background:transparent;border:none;font-weight:500;color:var(--c-text)}.navbar-dropdown-wrapper .navbar-dropdown-title:hover,.navbar-dropdown-wrapper .navbar-dropdown-title-mobile:hover{border-color:transparent}.navbar-dropdown-wrapper .navbar-dropdown-title .arrow,.navbar-dropdown-wrapper .navbar-dropdown-title-mobile .arrow{vertical-align:middle;margin-top:-1px;margin-left:.4rem}.navbar-dropdown-wrapper .navbar-dropdown-title-mobile{display:none;font-weight:600;font-size:inherit}.navbar-dropdown-wrapper .navbar-dropdown-title-mobile:hover{color:var(--c-text-accent)}.navbar-dropdown-wrapper .navbar-dropdown .navbar-dropdown-item{color:inherit;line-height:1.7rem}.navbar-dropdown-wrapper .navbar-dropdown .navbar-dropdown-item .navbar-dropdown-subtitle{margin:.45rem 0 0;border-top:1px solid var(--c-border);padding:1rem 0 .45rem;font-size:.9rem}.navbar-dropdown-wrapper .navbar-dropdown .navbar-dropdown-item .navbar-dropdown-subtitle>span{padding:0 1.5rem 0 1.25rem}.navbar-dropdown-wrapper .navbar-dropdown .navbar-dropdown-item .navbar-dropdown-subtitle>a{font-weight:inherit}.navbar-dropdown-wrapper .navbar-dropdown .navbar-dropdown-item .navbar-dropdown-subtitle>a.router-link-active:after{display:none}.navbar-dropdown-wrapper .navbar-dropdown .navbar-dropdown-item .navbar-dropdown-subitem-wrapper{padding:0;list-style:none}.navbar-dropdown-wrapper .navbar-dropdown .navbar-dropdown-item .navbar-dropdown-subitem-wrapper .navbar-dropdown-subitem{font-size:.9em}.navbar-dropdown-wrapper .navbar-dropdown .navbar-dropdown-item a{display:block;line-height:1.7rem;position:relative;border-bottom:none;font-weight:400;margin-bottom:0;padding:0 1.5rem 0 1.25rem}.navbar-dropdown-wrapper .navbar-dropdown .navbar-dropdown-item a:hover,.navbar-dropdown-wrapper .navbar-dropdown .navbar-dropdown-item a.router-link-active{color:var(--c-text-accent)}.navbar-dropdown-wrapper .navbar-dropdown .navbar-dropdown-item a.router-link-active:after{content:"";width:0;height:0;border-left:5px solid var(--c-text-accent);border-top:3px solid transparent;border-bottom:3px solid transparent;position:absolute;top:calc(50% - 2px);left:9px}.navbar-dropdown-wrapper .navbar-dropdown .navbar-dropdown-item:first-child .navbar-dropdown-subtitle{margin-top:0;padding-top:0;border-top:0}.navbar-dropdown-wrapper.mobile.open .navbar-dropdown-title,.navbar-dropdown-wrapper.mobile.open .navbar-dropdown-title-mobile{margin-bottom:.5rem}.navbar-dropdown-wrapper.mobile .navbar-dropdown-title,.navbar-dropdown-wrapper.mobile .navbar-dropdown-title-mobile{display:none}.navbar-dropdown-wrapper.mobile .navbar-dropdown-title-mobile{display:block}.navbar-dropdown-wrapper.mobile .navbar-dropdown{transition:height .1s ease-out;overflow:hidden}.navbar-dropdown-wrapper.mobile .navbar-dropdown .navbar-dropdown-item .navbar-dropdown-subtitle{border-top:0;margin-top:0;padding-top:0;padding-bottom:0}.navbar-dropdown-wrapper.mobile .navbar-dropdown .navbar-dropdown-item .navbar-dropdown-subtitle,.navbar-dropdown-wrapper.mobile .navbar-dropdown .navbar-dropdown-item>a{font-size:15px;line-height:2rem}.navbar-dropdown-wrapper.mobile .navbar-dropdown .navbar-dropdown-item .navbar-dropdown-subitem{font-size:14px;padding-left:1rem}.navbar-dropdown-wrapper:not(.mobile){height:1.8rem}.navbar-dropdown-wrapper:not(.mobile):hover .navbar-dropdown,.navbar-dropdown-wrapper:not(.mobile).open .navbar-dropdown{display:block!important}.navbar-dropdown-wrapper:not(.mobile).open:blur{display:none}.navbar-dropdown-wrapper:not(.mobile) .navbar-dropdown{display:none;height:auto!important;box-sizing:border-box;max-height:calc(100vh - 2.7rem);overflow-y:auto;position:absolute;top:100%;right:0;background-color:var(--c-bg-navbar);padding:.6rem 0;border:1px solid var(--c-border);border-bottom-color:var(--c-border-dark);text-align:left;border-radius:.25rem;white-space:nowrap;margin:0}.page{padding-bottom:2rem;display:block}.page .theme-default-content{max-width:var(--content-width);margin:0 auto;padding:2rem 2.5rem;padding-top:0}@media (max-width: 959px){.page .theme-default-content{padding:2rem}}@media (max-width: 419px){.page .theme-default-content{padding:1.5rem}}.page-meta{max-width:var(--content-width);margin:0 auto;padding:1rem 2.5rem;overflow:auto}@media (max-width: 959px){.page-meta{padding:2rem}}@media (max-width: 419px){.page-meta{padding:1.5rem}}.page-meta .meta-item{cursor:default;margin-top:.8rem}.page-meta .meta-item .meta-item-label{font-weight:500;color:var(--c-text-lighter)}.page-meta .meta-item .meta-item-info{font-weight:400;color:var(--c-text-quote)}.page-meta .edit-link{display:inline-block;margin-right:.25rem}@media print{.page-meta .edit-link{display:none}}.page-meta .last-updated{float:right}@media (max-width: 719px){.page-meta .last-updated{font-size:.8em;float:none}.page-meta .contributors{font-size:.8em}}.page-nav{max-width:var(--content-width);margin:0 auto;padding:1rem 2.5rem 2rem;padding-bottom:0}@media (max-width: 959px){.page-nav{padding:2rem}}@media (max-width: 419px){.page-nav{padding:1.5rem}}.page-nav .inner{min-height:2rem;margin-top:0;border-top:1px solid var(--c-border);transition:border-color var(--t-color);padding-top:1rem;overflow:auto}.page-nav .prev a:before{content:"←"}.page-nav .next{float:right}.page-nav .next a:after{content:"→"}.sidebar ul{padding:0;margin:0;list-style-type:none}.sidebar a{display:inline-block}.sidebar .navbar-items{display:none;border-bottom:1px solid var(--c-border);transition:border-color var(--t-color);padding:.5rem 0 .75rem}.sidebar .navbar-items a{font-weight:600}.sidebar .navbar-items .navbar-item{display:block;line-height:1.25rem;font-size:1.1em;padding:.5rem 0 .5rem 1.5rem}.sidebar .sidebar-items{padding:1.5rem 0}@media (max-width: 719px){.sidebar .navbar-items{display:block}.sidebar .navbar-items .navbar-dropdown-wrapper .navbar-dropdown .navbar-dropdown-item a.router-link-active:after{top:calc(1rem - 2px)}.sidebar .sidebar-items{padding:1rem 0}}.sidebar-item{cursor:default;border-left:.25rem solid transparent;color:var(--c-text)}.sidebar-item:focus-visible{outline-width:1px;outline-offset:-1px}.sidebar-item.active:not(p.sidebar-heading){font-weight:600;color:var(--c-text-accent);border-left-color:var(--c-text-accent)}.sidebar-item.sidebar-heading{transition:color .15s ease;font-size:1.1em;font-weight:700;padding:.35rem 1.5rem .35rem 1.25rem;width:100%;box-sizing:border-box;margin:0}.sidebar-item.sidebar-heading+.sidebar-item-children{transition:height .1s ease-out;overflow:hidden;margin-bottom:.75rem}.sidebar-item.collapsible{cursor:pointer}.sidebar-item.collapsible .arrow{position:relative;top:-.12em;left:.5em}.sidebar-item:not(.sidebar-heading){font-size:1em;font-weight:400;display:inline-block;margin:0;padding:.35rem 1rem .35rem 2rem;line-height:1.4;width:100%;box-sizing:border-box}.sidebar-item:not(.sidebar-heading)+.sidebar-item-children{padding-left:1rem;font-size:.95em}.sidebar-item-children .sidebar-item-children .sidebar-item:not(.sidebar-heading){padding:.25rem 1rem .25rem 1.75rem}.sidebar-item-children .sidebar-item-children .sidebar-item:not(.sidebar-heading).active{font-weight:500;border-left-color:transparent}a.sidebar-heading+.sidebar-item-children .sidebar-item:not(.sidebar-heading).active{border-left-color:transparent}a.sidebar-item{cursor:pointer}a.sidebar-item:hover{color:var(--c-text-accent)}.table-of-contents .badge{vertical-align:middle}.dropdown-enter-from,.dropdown-leave-to{height:0!important}.fade-slide-y-enter-active{transition:all .2s ease}.fade-slide-y-leave-active{transition:all .2s cubic-bezier(1,.5,.8,1)}.fade-slide-y-enter-from,.fade-slide-y-leave-to{transform:translateY(10px);opacity:0}:root{--c-brand: rgb(237, 150, 73);--c-brand-light: rgb(244, 200, 161);--content-width: 965px}code{padding:3px 5px;border-radius:5px}.badge{margin-bottom:5px}.custom-container{border-radius:5px}.sidebar-item{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.language-text ::-webkit-scrollbar-track{background:#56606e;border-radius:50px}.language-text ::-webkit-scrollbar-thumb:hover{background:#79879b}.language-kotlin ::-webkit-scrollbar-track{background:#56606e;border-radius:50px}.language-kotlin ::-webkit-scrollbar-thumb:hover{background:#79879b}.language-java ::-webkit-scrollbar-track{background:#56606e;border-radius:50px}.language-java ::-webkit-scrollbar-thumb:hover{background:#79879b}.language-groovy ::-webkit-scrollbar-track{background:#56606e;border-radius:50px}.language-groovy ::-webkit-scrollbar-thumb:hover{background:#79879b}.language-xml ::-webkit-scrollbar-track{background:#56606e;border-radius:50px}.language-xml ::-webkit-scrollbar-thumb:hover{background:#79879b}.hidden-anchor-page h6{color:transparent;margin-bottom:-35px;padding-top:50px}.code-page h1{font-size:24pt}.code-page h2{font-size:18pt}.code-page h3{font-size:15pt}.code-page h4{font-size:12pt}.code-page h5{font-size:9.6pt}.code-page h6{font-size:8.4pt}.code-page .symbol{color:#8e9ba8}.code-page .deprecated{color:#8e9ba8;text-decoration:line-through}html{scroll-behavior:smooth}html ::-webkit-scrollbar{width:8px;height:6.5px}html ::-webkit-scrollbar-track{background:#eaecef}html ::-webkit-scrollbar-thumb{background:#bdbdbd;border-radius:50px}html ::-webkit-scrollbar-thumb:hover{background:#858585;border-radius:50px}html.dark{--c-brand: rgb(237, 150, 73);--c-brand-light: rgb(244, 200, 161);--content-width: 965px}html.dark ::-webkit-scrollbar{width:8px;height:6.5px}html.dark ::-webkit-scrollbar-track{background:#292e35}html.dark ::-webkit-scrollbar-thumb{background:#414853;border-radius:50px}html.dark ::-webkit-scrollbar-thumb:hover{background:#383e48;border-radius:50px}:root{--search-bg-color: #ffffff;--search-accent-color: #3eaf7c;--search-text-color: #2c3e50;--search-border-color: #eaecef;--search-item-text-color: #5d81a5;--search-item-focus-bg-color: #f3f4f5;--search-input-width: 8rem;--search-result-width: 20rem}.search-box{display:inline-block;position:relative;margin-left:1rem}@media print{.search-box{display:none}}.search-box input{-webkit-appearance:none;-moz-appearance:none;appearance:none;cursor:text;width:var(--search-input-width);height:2rem;color:var(--search-text-color);display:inline-block;border:1px solid var(--search-border-color);border-radius:2rem;font-size:.9rem;line-height:2rem;padding:0 .5rem 0 2rem;outline:none;transition:all ease .3s;background:var(--search-bg-color) url("data:image/svg+xml,%3c?xml%20version='1.0'%20encoding='UTF-8'?%3e%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='12'%20height='13'%3e%3cg%20stroke-width='2'%20stroke='%23aaa'%20fill='none'%3e%3cpath%20d='M11.29%2011.71l-4-4'/%3e%3ccircle%20cx='5'%20cy='5'%20r='4'/%3e%3c/g%3e%3c/svg%3e") .6rem .5rem no-repeat;background-size:1rem}.search-box input:focus{cursor:auto;border-color:var(--search-accent-color)}.search-box .suggestions{background:var(--search-bg-color);width:var(--search-result-width);position:absolute;top:2rem;right:0;border:1px solid var(--search-border-color);border-radius:6px;padding:.4rem;list-style-type:none}.search-box .suggestion{line-height:1.4;padding:.4rem .6rem;border-radius:4px;cursor:pointer}.search-box .suggestion.focus{background-color:var(--search-item-focus-bg-color)}.search-box .suggestion.focus a{color:var(--search-accent-color)}.search-box .suggestion a{white-space:normal;color:var(--search-item-text-color)}.search-box .suggestion .page-title{font-weight:600}.search-box .suggestion .page-header{font-size:.9em;margin-left:.25em}@media (max-width: 719px){.search-box input{cursor:pointer;width:0;border-color:transparent;position:relative}.search-box input:focus{cursor:text;left:0;width:10rem}}@media (max-width: 419px){.search-box input:focus{width:8rem}.search-box .suggestions{width:calc(100vw - 4rem);right:-.5rem}} diff --git a/assets/supportive.html-CTTW-ar9.js b/assets/supportive.html-CTTW-ar9.js new file mode 100644 index 00000000..d25b1786 --- /dev/null +++ b/assets/supportive.html-CTTW-ar9.js @@ -0,0 +1 @@ +import{_ as n,r as s,o as r,c as d,b as t,d as l,e as o}from"./app-BpUB8-Q8.js";const u={},_=t("h1",{id:"支持性",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#支持性","aria-hidden":"true"},"#"),l(" 支持性")],-1),h=t("p",null,[l("以下是 "),t("code",null,"YukiHookAPI"),l(" 支持的相关功能、Xposed 框架、Hook Frameworks、Hook APIs。")],-1),i=t("blockquote",null,[t("p",null,"基本功能")],-1),a=t("thead",null,[t("tr",null,[t("th",null,"Name"),t("th",null,"ST"),t("th",null,"Description")])],-1),c=t("td",null,"自动化 Xposed 模块构建",-1),p=t("td",null,"✅",-1),f=t("code",null,"YukiHookAPI",-1),b=t("code",null,"2.0.0",-1),k={href:"https://github.com/HighCapable/YukiHookAPI/issues/49",target:"_blank",rel:"noopener noreferrer"},g=t("tr",null,[t("td",null,"ART 动态方法 Hook"),t("td",null,"✅"),t("td",null,"多场景下稳定使用")],-1),m=t("tr",null,[t("td",null,"Xposed 资源钩子 (Resources Hook)"),t("td",null,"❗"),t("td",null,[l("支持,但计划 "),t("code",null,"YukiHookAPI"),l(),t("code",null,"2.0.0"),l(" 版本移除")])],-1),A=t("blockquote",null,[t("p",null,"扩展功能")],-1),P=t("thead",null,[t("tr",null,[t("th",null,"Name"),t("th",null,"ST"),t("th",null,"Description")])],-1),H=t("td",null,[t("s",null,[t("a",{href:"../api/special-features/reflection"},"字节码与反射扩展")])],-1),E=t("td",null,"❗",-1),I={href:"https://github.com/HighCapable/KavaRef",target:"_blank",rel:"noopener noreferrer"},S=t("code",null,"YukiHookAPI",-1),X=t("code",null,"2.0.0",-1),v=t("tr",null,[t("td",null,[t("a",{href:"../api/special-features/xposed-storage"},"Xposed 模块数据存储")]),t("td",null,"✅"),t("td",null,"正常使用")],-1),L=t("tr",null,[t("td",null,[t("a",{href:"../api/special-features/xposed-channel"},"Xposed 模块与宿主通讯桥")]),t("td",null,"✅"),t("td",null,"正常使用")],-1),y=t("tr",null,[t("td",null,[t("a",{href:"../api/special-features/host-lifecycle"},"宿主生命周期扩展")]),t("td",null,"✅"),t("td",null,"正常使用")],-1),x=t("tr",null,[t("td",null,[t("a",{href:"../api/special-features/host-inject#%E6%B3%A8%E5%85%A5%E6%A8%A1%E5%9D%97%E8%B5%84%E6%BA%90-resources"},"注入模块资源 (Resources)")]),t("td",null,"✅"),t("td",null,"正常使用")],-1),D=t("tr",null,[t("td",null,[t("a",{href:"../api/special-features/host-inject#%E6%B3%A8%E5%86%8C%E6%A8%A1%E5%9D%97-activity"},"注册模块 Activity")]),t("td",null,"✅"),t("td",null,"正常使用")],-1),R=t("blockquote",null,[t("p",null,"Xposed 框架")],-1),T=t("thead",null,[t("tr",null,[t("th",null,"Name"),t("th",null,"ST"),t("th",null,"Description")])],-1),N={href:"https://github.com/LSPosed/LSPosed",target:"_blank",rel:"noopener noreferrer"},Y=t("td",null,"✅",-1),B=t("td",null,"多场景下稳定使用",-1),C={href:"https://github.com/LSPosed/LSPatch",target:"_blank",rel:"noopener noreferrer"},F=t("td",null,"⭕",-1),q=t("td",null,"支持,将在此项目完善后逐渐加入 API 支持",-1),w={href:"https://github.com/ElderDrivers/EdXposed",target:"_blank",rel:"noopener noreferrer"},V=t("td",null,"❎",-1),j=t("td",null,"已停止维护,不再推荐使用",-1),K={href:"https://github.com/canyie/Dreamland",target:"_blank",rel:"noopener noreferrer"},G=t("td",null,"⭕",-1),M=t("td",null,"理论支持 (未经过开发者测试)",-1),W={href:"https://github.com/taichi-framework/TaiChi",target:"_blank",rel:"noopener noreferrer"},z=t("td",null,"⭕",-1),J=t("td",null,"Hook 功能正常 (部分功能有限制)",-1),O={href:"https://github.com/rovo89/Xposed",target:"_blank",rel:"noopener noreferrer"},Q=t("td",null,"❎",-1),U=t("td",null,"已停止维护,不再推荐使用",-1),Z=t("blockquote",null,[t("p",null,"Hook 框架 (Hook Frameworks)")],-1),$=t("thead",null,[t("tr",null,[t("th",null,"Name"),t("th",null,"ST"),t("th",null,"Description")])],-1),tt={href:"https://github.com/LSPosed/LSPlant",target:"_blank",rel:"noopener noreferrer"},lt=t("td",null,"⭕",-1),et={href:"https://github.com/Aliucord/hook",target:"_blank",rel:"noopener noreferrer"},ot={href:"https://github.com/canyie/pine",target:"_blank",rel:"noopener noreferrer"},nt=t("td",null,"⭕",-1),st=t("td",null,"理论支持 (未经过开发者测试)",-1),rt={href:"https://github.com/asLody/SandHook",target:"_blank",rel:"noopener noreferrer"},dt=t("td",null,"❎",-1),ut=t("td",null,"不支持较新版本的 Android,需要自行对接 Rovo89 Xposed API",-1),_t={href:"https://github.com/asLody/whale",target:"_blank",rel:"noopener noreferrer"},ht=t("td",null,"❎",-1),it=t("td",null,"不支持较新版本的 Android,需要自行对接 Rovo89 Xposed API",-1),at={href:"https://github.com/PAGalaxyLab/YAHFA",target:"_blank",rel:"noopener noreferrer"},ct=t("td",null,"❎",-1),pt=t("td",null,"不支持较新版本的 Android,需要自行对接 Rovo89 Xposed API",-1),ft={href:"https://github.com/turing-technician/FastHook",target:"_blank",rel:"noopener noreferrer"},bt=t("td",null,"❎",-1),kt=t("td",null,"已停止维护,不再推荐使用",-1),gt={href:"https://github.com/tiann/epic",target:"_blank",rel:"noopener noreferrer"},mt=t("td",null,"❎",-1),At=t("td",null,"已停止维护,不再推荐使用",-1),Pt=t("blockquote",null,[t("p",null,"Hook APIs")],-1),Ht=t("thead",null,[t("tr",null,[t("th",null,"Name"),t("th",null,"ST"),t("th",null,"Description")])],-1),Et={href:"https://api.xposed.info/",target:"_blank",rel:"noopener noreferrer"},It=t("td",null,"✅",-1),St=t("td",null,"多场景下稳定使用",-1),Xt={href:"https://github.com/libxposed",target:"_blank",rel:"noopener noreferrer"},vt=t("td",null,"❎",-1),Lt=t("td",null,[l("计划 "),t("code",null,"YukiHookAPI"),l(),t("code",null,"2.0.0"),l(" 版本支持")],-1);function yt(xt,Dt){const e=s("ExternalLinkIcon");return r(),d("div",null,[_,h,i,t("table",null,[a,t("tbody",null,[t("tr",null,[c,p,t("td",null,[l("计划 "),f,l(),b,l(" 版本使用 "),t("a",k,[l("新的 Xposed 模块配置方案"),o(e)])])]),g,m])]),A,t("table",null,[P,t("tbody",null,[t("tr",null,[H,E,t("td",null,[l("已全面弃用,推荐迁移至 "),t("a",I,[l("KavaRef"),o(e)]),l(",计划 "),S,l(),X,l(" 版本移除")])]),v,L,y,x,D])]),R,t("table",null,[T,t("tbody",null,[t("tr",null,[t("td",null,[t("a",N,[l("LSPosed"),o(e)])]),Y,B]),t("tr",null,[t("td",null,[t("a",C,[l("LSPatch"),o(e)])]),F,q]),t("tr",null,[t("td",null,[t("a",w,[l("EdXposed"),o(e)])]),V,j]),t("tr",null,[t("td",null,[t("a",K,[l("Dreamland"),o(e)])]),G,M]),t("tr",null,[t("td",null,[t("a",W,[l("TaiChi"),o(e)])]),z,J]),t("tr",null,[t("td",null,[t("a",O,[l("Xposed"),o(e)])]),Q,U])])]),Z,t("table",null,[$,t("tbody",null,[t("tr",null,[t("td",null,[t("a",tt,[l("LSPlant"),o(e)])]),lt,t("td",null,[l("请参考 "),t("a",et,[l("AliuHook"),o(e)])])]),t("tr",null,[t("td",null,[t("a",ot,[l("Pine"),o(e)])]),nt,st]),t("tr",null,[t("td",null,[t("a",rt,[l("SandHook"),o(e)])]),dt,ut]),t("tr",null,[t("td",null,[t("a",_t,[l("Whale"),o(e)])]),ht,it]),t("tr",null,[t("td",null,[t("a",at,[l("YAHFA"),o(e)])]),ct,pt]),t("tr",null,[t("td",null,[t("a",ft,[l("FastHook"),o(e)])]),bt,kt]),t("tr",null,[t("td",null,[t("a",gt,[l("Epic"),o(e)])]),mt,At])])]),Pt,t("table",null,[Ht,t("tbody",null,[t("tr",null,[t("td",null,[t("a",Et,[l("Rovo89 Xposed API"),o(e)])]),It,St]),t("tr",null,[t("td",null,[t("a",Xt,[l("Modern Xposed API"),o(e)])]),vt,Lt])])])])}const Tt=n(u,[["render",yt],["__file","supportive.html.vue"]]);export{Tt as default}; diff --git a/assets/supportive.html-Cd4sY_Jm.js b/assets/supportive.html-Cd4sY_Jm.js new file mode 100644 index 00000000..dc49b5fc --- /dev/null +++ b/assets/supportive.html-Cd4sY_Jm.js @@ -0,0 +1 @@ +import{_ as n,r as s,o as r,c as d,b as e,d as t,e as l}from"./app-BpUB8-Q8.js";const u={},a=e("h1",{id:"supportive",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#supportive","aria-hidden":"true"},"#"),t(" Supportive")],-1),i=e("p",null,[t("The following are the related functions, Xposed Frameworks, Hook Frameworks and Hook APIs supported by "),e("code",null,"YukiHookAPI"),t(".")],-1),h=e("blockquote",null,[e("p",null,"Basic Functions")],-1),c=e("thead",null,[e("tr",null,[e("th",null,"Name"),e("th",null,"ST"),e("th",null,"Description")])],-1),_=e("td",null,"Xposed Module Auto Builder",-1),p=e("td",null,"✅",-1),f={href:"https://github.com/HighCapable/YukiHookAPI/issues/49",target:"_blank",rel:"noopener noreferrer"},b=e("code",null,"YukiHookAPI",-1),m=e("code",null,"2.0.0",-1),k=e("tr",null,[e("td",null,"ART Dynamic Method Hook"),e("td",null,"✅"),e("td",null,"Stable use in multiple scenarios")],-1),g=e("tr",null,[e("td",null,"Xposed Resources Hook"),e("td",null,"❗"),e("td",null,[t("Supported, but will be removed on "),e("code",null,"YukiHookAPI"),t(),e("code",null,"2.0.0")])],-1),A=e("blockquote",null,[e("p",null,"Extended Functions")],-1),y=e("thead",null,[e("tr",null,[e("th",null,"Name"),e("th",null,"ST"),e("th",null,"Description")])],-1),P=e("td",null,[e("s",null,[e("a",{href:"../api/special-features/reflection"},"Reflection Extensions")])],-1),v=e("td",null,"❗",-1),H={href:"https://github.com/HighCapable/KavaRef",target:"_blank",rel:"noopener noreferrer"},S=e("code",null,"YukiHookAPI",-1),I=e("code",null,"2.0.0",-1),X=e("tr",null,[e("td",null,[e("a",{href:"../api/special-features/xposed-storage"},"Xposed Module Data Storage")]),e("td",null,"✅"),e("td",null,"Normal use")],-1),x=e("tr",null,[e("td",null,[e("a",{href:"../api/special-features/xposed-channel"},"Xposed Module and Host Channel")]),e("td",null,"✅"),e("td",null,"Normal use")],-1),L=e("tr",null,[e("td",null,[e("a",{href:"../api/special-features/host-lifecycle"},"Host Lifecycle Extension")]),e("td",null,"✅"),e("td",null,"Normal use")],-1),T=e("tr",null,[e("td",null,[e("a",{href:"../api/special-features/host-inject#inject-module-apps-resources"},"Inject Module Apps Resources")]),e("td",null,"✅"),e("td",null,"Normal use")],-1),N=e("tr",null,[e("td",null,[e("a",{href:"../api/special-features/host-inject#register-module-apps-activity"},"Register Module Apps Activity")]),e("td",null,"✅"),e("td",null,"Normal use")],-1),M=e("blockquote",null,[e("p",null,"Xposed Frameworks")],-1),R=e("thead",null,[e("tr",null,[e("th",null,"Name"),e("th",null,"ST"),e("th",null,"Description")])],-1),w={href:"https://github.com/LSPosed/LSPosed",target:"_blank",rel:"noopener noreferrer"},D=e("td",null,"✅",-1),E=e("td",null,"Stable use in multiple scenarios",-1),F={href:"https://github.com/LSPosed/LSPatch",target:"_blank",rel:"noopener noreferrer"},C=e("td",null,"⭕",-1),Y=e("td",null,"Support, API support will be gradually added after the project is completed",-1),j={href:"https://github.com/ElderDrivers/EdXposed",target:"_blank",rel:"noopener noreferrer"},q=e("td",null,"❎",-1),B=e("td",null,"Maintenance has stopped and is no longer recommended",-1),V={href:"https://github.com/canyie/Dreamland",target:"_blank",rel:"noopener noreferrer"},W=e("td",null,"⭕",-1),K=e("td",null,"Theoretical support (not tested by developer)",-1),G={href:"https://github.com/taichi-framework/TaiChi",target:"_blank",rel:"noopener noreferrer"},z=e("td",null,"⭕",-1),J=e("td",null,"Hook functions normally (some functions have restrictions)",-1),O={href:"https://github.com/rovo89/Xposed",target:"_blank",rel:"noopener noreferrer"},Q=e("td",null,"❎",-1),U=e("td",null,"Maintenance has stopped and is no longer recommended",-1),Z=e("blockquote",null,[e("p",null,"Hook Frameworks")],-1),$=e("thead",null,[e("tr",null,[e("th",null,"Name"),e("th",null,"ST"),e("th",null,"Description")])],-1),ee={href:"https://github.com/LSPosed/LSPlant",target:"_blank",rel:"noopener noreferrer"},te=e("td",null,"⭕",-1),oe={href:"https://github.com/Aliucord/hook",target:"_blank",rel:"noopener noreferrer"},le={href:"https://github.com/canyie/pine",target:"_blank",rel:"noopener noreferrer"},ne=e("td",null,"⭕",-1),se=e("td",null,"Theoretical support (not tested by developer)",-1),re={href:"https://github.com/asLody/SandHook",target:"_blank",rel:"noopener noreferrer"},de=e("td",null,"❎",-1),ue=e("td",null,"The latests Android are not supported, you need to integrated the Rovo89 Xposed API yourself",-1),ae={href:"https://github.com/asLody/whale",target:"_blank",rel:"noopener noreferrer"},ie=e("td",null,"❎",-1),he=e("td",null,"The latests Android are not supported, you need to integrated the Rovo89 Xposed API yourself",-1),ce={href:"https://github.com/PAGalaxyLab/YAHFA",target:"_blank",rel:"noopener noreferrer"},_e=e("td",null,"❎",-1),pe=e("td",null,"The latests Android are not supported, you need to integrated the Rovo89 Xposed API yourself",-1),fe={href:"https://github.com/turing-technician/FastHook",target:"_blank",rel:"noopener noreferrer"},be=e("td",null,"❎",-1),me=e("td",null,"Maintenance has stopped and is no longer recommended",-1),ke={href:"https://github.com/tiann/epic",target:"_blank",rel:"noopener noreferrer"},ge=e("td",null,"❎",-1),Ae=e("td",null,"Maintenance has stopped and is no longer recommended",-1),ye=e("blockquote",null,[e("p",null,"Hook APIs")],-1),Pe=e("thead",null,[e("tr",null,[e("th",null,"Name"),e("th",null,"ST"),e("th",null,"Description")])],-1),ve={href:"https://api.xposed.info/",target:"_blank",rel:"noopener noreferrer"},He=e("td",null,"✅",-1),Se=e("td",null,"Stable use in multiple scenarios",-1),Ie={href:"https://github.com/libxposed",target:"_blank",rel:"noopener noreferrer"},Xe=e("td",null,"❎",-1),xe=e("td",null,[t("Will be supported on "),e("code",null,"YukiHookAPI"),t(),e("code",null,"2.0.0")],-1);function Le(Te,Ne){const o=s("ExternalLinkIcon");return r(),d("div",null,[a,i,h,e("table",null,[c,e("tbody",null,[e("tr",null,[_,p,e("td",null,[t("Will use "),e("a",f,[t("New Xposed Module Config Plan"),l(o)]),t(" on "),b,t(),m])]),k,g])]),A,e("table",null,[y,e("tbody",null,[e("tr",null,[P,v,e("td",null,[t("Completely deprecated, recommended to migrate to "),e("a",H,[t("KavaRef"),l(o)]),t(", planned "),S,t(),I,t(" version removed")])]),X,x,L,T,N])]),M,e("table",null,[R,e("tbody",null,[e("tr",null,[e("td",null,[e("a",w,[t("LSPosed"),l(o)])]),D,E]),e("tr",null,[e("td",null,[e("a",F,[t("LSPatch"),l(o)])]),C,Y]),e("tr",null,[e("td",null,[e("a",j,[t("EdXposed"),l(o)])]),q,B]),e("tr",null,[e("td",null,[e("a",V,[t("Dreamland"),l(o)])]),W,K]),e("tr",null,[e("td",null,[e("a",G,[t("TaiChi"),l(o)])]),z,J]),e("tr",null,[e("td",null,[e("a",O,[t("Xposed"),l(o)])]),Q,U])])]),Z,e("table",null,[$,e("tbody",null,[e("tr",null,[e("td",null,[e("a",ee,[t("LSPlant"),l(o)])]),te,e("td",null,[t("Please visit "),e("a",oe,[t("AliuHook"),l(o)])])]),e("tr",null,[e("td",null,[e("a",le,[t("Pine"),l(o)])]),ne,se]),e("tr",null,[e("td",null,[e("a",re,[t("SandHook"),l(o)])]),de,ue]),e("tr",null,[e("td",null,[e("a",ae,[t("Whale"),l(o)])]),ie,he]),e("tr",null,[e("td",null,[e("a",ce,[t("YAHFA"),l(o)])]),_e,pe]),e("tr",null,[e("td",null,[e("a",fe,[t("FastHook"),l(o)])]),be,me]),e("tr",null,[e("td",null,[e("a",ke,[t("Epic"),l(o)])]),ge,Ae])])]),ye,e("table",null,[Pe,e("tbody",null,[e("tr",null,[e("td",null,[e("a",ve,[t("Rovo89 Xposed API"),l(o)])]),He,Se]),e("tr",null,[e("td",null,[e("a",Ie,[t("Modern Xposed API"),l(o)])]),Xe,xe])])])])}const Re=n(u,[["render",Le],["__file","supportive.html.vue"]]);export{Re as default}; diff --git a/assets/supportive.html-DFnCbU7r.js b/assets/supportive.html-DFnCbU7r.js new file mode 100644 index 00000000..3d64817d --- /dev/null +++ b/assets/supportive.html-DFnCbU7r.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-4f5c6182","path":"/zh-cn/guide/supportive.html","title":"支持性","lang":"zh-CN","frontmatter":{},"headers":[],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":5}]},"filePathRelative":"zh-cn/guide/supportive.md"}');export{e as data}; diff --git a/assets/supportive.html-bOj3zBC_.js b/assets/supportive.html-bOj3zBC_.js new file mode 100644 index 00000000..f6c8d973 --- /dev/null +++ b/assets/supportive.html-bOj3zBC_.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-68fd81d0","path":"/en/guide/supportive.html","title":"Supportive","lang":"en-US","frontmatter":{},"headers":[],"git":{"updatedTime":1750064706000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":5}]},"filePathRelative":"en/guide/supportive.md"}');export{e as data}; diff --git a/assets/xposed-channel.html-B7eDf6ix.js b/assets/xposed-channel.html-B7eDf6ix.js new file mode 100644 index 00000000..32b85355 --- /dev/null +++ b/assets/xposed-channel.html-B7eDf6ix.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-598546c6","path":"/zh-cn/api/special-features/xposed-channel.html","title":"Xposed 模块与宿主通讯桥","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"基本用法","slug":"基本用法","link":"#基本用法","children":[]},{"level":2,"title":"判断模块与宿主版本是否匹配","slug":"判断模块与宿主版本是否匹配","link":"#判断模块与宿主版本是否匹配","children":[]},{"level":2,"title":"回调事件响应的规则","slug":"回调事件响应的规则","link":"#回调事件响应的规则","children":[]},{"level":2,"title":"安全性说明","slug":"安全性说明","link":"#安全性说明","children":[]}],"git":{"updatedTime":1680895145000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":5}]},"filePathRelative":"zh-cn/api/special-features/xposed-channel.md"}');export{e as data}; diff --git a/assets/xposed-channel.html-BeC6v_Qb.js b/assets/xposed-channel.html-BeC6v_Qb.js new file mode 100644 index 00000000..87bdddd4 --- /dev/null +++ b/assets/xposed-channel.html-BeC6v_Qb.js @@ -0,0 +1,118 @@ +import{_ as s,o as n,c as a,a as l}from"./app-BpUB8-Q8.js";const e={},o=l(`# Xposed 模块与宿主通讯桥
这是一个使用系统无序广播在模块与宿主之间发送和接收数据的解决方案。
需要满足的条件
模块与宿主需要保持存活状态,否则无法建立通讯。
# 基本用法
这里描述了
wait
与put
方法的基本使用方法。通过使用
dataChannel
来实现模块与宿主之间的通讯桥,原理为发送接收系统无序广播。模块示例如下
// 从指定包名的宿主获取 +dataChannel(packageName = "com.example.demo").wait<String>(key = "key_from_host") { value -> + // Your code here. +} +// 发送给指定包名的宿主 +dataChannel(packageName = "com.example.demo").put(key = "key_from_module", value = "I am module") +
宿主示例如下
// 从模块获取 +dataChannel.wait<String>(key = "key_from_module") { value -> + // Your code here. +} +// 发送给模块 +dataChannel.put(key = "key_from_host", value = "I am host") +
你可以不设置
dataChannel
的value
来达到仅通知模块或宿主回调wait
方法。模块示例如下
// 从指定包名的宿主获取 +dataChannel(packageName = "com.example.demo").wait(key = "listener_from_host") { + // Your code here. +} +// 发送给指定包名的宿主 +dataChannel(packageName = "com.example.demo").put(key = "listener_from_module") +
宿主示例如下
// 从模块获取 +dataChannel.wait(key = "listener_from_module") { + // Your code here. +} +// 发送给模块 +dataChannel.put(key = "listener_from_host") +
特别注意
接收方需要保持存活状态才能收到通讯数据。
小提示
更多功能请参考 YukiHookDataChannel。
# 判断模块与宿主版本是否匹配
通过通讯桥功能,
YukiHookAPI
还为你提供了在用户更新模块后,判断模块是否与宿主版本匹配的解决方案。我们只需要调用
checkingVersionEquals
方法,即可实现这个功能。在模块与宿主中可进行双向判断。
你可以在模块中判断指定包名的宿主是否与当前模块的版本匹配。
示例如下
// 从指定包名的宿主获取 +dataChannel(packageName = "com.example.demo").checkingVersionEquals { isEquals -> + // Your code here. +} +
你还可以在宿主中判断是否自身与当前模块的版本匹配。
示例如下
// 从模块获取 +dataChannel.checkingVersionEquals { isEquals -> + // Your code here. +} +
方法回调的条件
宿主、模块保持存活状态,并在激活模块后重启了作用域中的 Hook 目标宿主对象。
小提示
更多功能请参考 YukiHookDataChannel。
# 回调事件响应的规则
这里只列出了在模块中使用的例子,在同一个宿主中相同的
key
始终不允许重复创建,但不同的宿主中允许存在相同的key
。特别注意
在模块和宿主中,每一个 dataChannel 对应的 key 的回调事件都不允许重复创建,若重复,之前的回调事件会被新增加的回调事件替换,若在模块中使用,在同一个 Activity 中不可以重复,不同的 Activity 中相同的 key 允许重复。
示例如下
class MainActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + // 回调事件 A + dataChannel(packageName = "com.example.demo1").wait(key = "test_key") { + // Your code here. + } + // 回调事件 B + dataChannel(packageName = "com.example.demo1").wait(key = "test_key") { + // Your code here. + } + // 回调事件 C + dataChannel(packageName = "com.example.demo1").wait(key = "other_test_key") { + // Your code here. + } + // 回调事件 D + dataChannel(packageName = "com.example.demo2").wait(key = "other_test_key") { + // Your code here. + } + } +} + +class OtherActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + // 回调事件 E + dataChannel(packageName = "com.example.demo1").wait(key = "test_key") { + // Your code here. + } + // 回调事件 F + dataChannel(packageName = "com.example.demo2").wait(key = "test_key") { + // Your code here. + } + } +} +
在上述示例中,虽然回调事件 A 与 B 是同一个宿主中的回调事件,但是它们的
key
相同,所以回调事件 A 会被回调事件 B 替换掉。回调事件 C 的
key
不与其它重复,虽然回调事件 D 的key
与回调事件 C 相同,但是它们的宿主不同,所以可以同时存在。回调事件 E 在另一个 Activity 中,回调事件 F 与回调事件 E 的
key
虽然相同,但它们也不是同一个宿主,所以可以同时存在。综上所述,最终回调事件 B、C、D、E、F 都可被创建成功。
兼容性说明
在过往历史版本的 API 中不同的宿主设置相同的 key 会造成只有最后一个事件回调,但是最新版本更正了这一问题,请确保你使用的是最新的 API 版本。
特别注意
一个相同 key 的回调事件只会回调当前模块正在显示的 Activity 中注册的回调事件,例如上述中的 test_key,如果 OtherActivity 正在显示,那么 MainActivity 中的 test_key 就不会被回调。
相同的 key 在同一个 Activity 不同的 Fragment 中注册 dataChannel,它们依然会在当前 Activity 中同时被回调。
在模块中,你可以在 Activity、Application 以及 Service 等地方使用 dataChannel,在 Activity 以外的地方使用时每个回调事件都会即时回调,此时你可以使用 ChannelPriority 进行管理。
若要在 Fragment 中使用 dataChannel,请使用 activity?.dataChannel(...)。
如果你希望在同一个 Activity 中手动设置每个回调事件的响应优先级 (条件),你可以使用
ChannelPriority
。例如,你正在使用一个 Activity 绑定多个 Fragment 的情况,这将能够解决这个问题。
示例如下
open class BaseFragment : Fragment() { + + /** 标识当前 Fragment 处于 onResume 生命周期 */ + var isResume = false + + override fun onResume() { + super.onResume() + isResume = true + } + + override fun onPause() { + super.onPause() + isResume = false + } + + override fun onStop() { + super.onStop() + isResume = false + } +} + +class FragmentA : BaseFragment() { + + // 省略部分装载代码 + // ... + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + // 使用自定义的 isResume 结合 isVisible 条件判断当前 Fragment 正处于显示状态 + activity?.dataChannel(packageName = "com.example.demo1") + ?.wait(key = "test_key", ChannelPriority { isResume && isVisible }) { + // Your code here. + } + } +} + +class FragmentB : BaseFragment() { + + // 省略部分装载代码 + // ... + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + // 使用自定义的 isResume 结合 isVisible 条件判断当前 Fragment 正处于显示状态 + activity?.dataChannel(packageName = "com.example.demo2") + ?.wait(key = "test_key", ChannelPriority { isResume && isVisible }) { + // Your code here. + } + } +} +
# 安全性说明
在模块环境中,你只能接收指定包名的宿主发送的通讯数据且只能发送给指定包名的宿主,系统框架除外。
`,47),p=[o];function c(t,r){return n(),a("div",null,p)}const y=s(e,[["render",c],["__file","xposed-channel.html.vue"]]);export{y as default}; diff --git a/assets/xposed-channel.html-DWoHNeKf.js b/assets/xposed-channel.html-DWoHNeKf.js new file mode 100644 index 00000000..85e200cd --- /dev/null +++ b/assets/xposed-channel.html-DWoHNeKf.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-2e6ad66c","path":"/en/api/special-features/xposed-channel.html","title":"Xposed Module and Host Channel","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"Basic Usage","slug":"basic-usage","link":"#basic-usage","children":[]},{"level":2,"title":"Determine Module App and Host App Version Match","slug":"determine-module-app-and-host-app-version-match","link":"#determine-module-app-and-host-app-version-match","children":[]},{"level":2,"title":"Rules for Callback Event Response","slug":"rules-for-callback-event-response","link":"#rules-for-callback-event-response","children":[]},{"level":2,"title":"Security Instructions","slug":"security-instructions","link":"#security-instructions","children":[]}],"git":{"updatedTime":1680895145000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":5}]},"filePathRelative":"en/api/special-features/xposed-channel.md"}');export{e as data}; diff --git a/assets/xposed-channel.html-DZ4m7tlI.js b/assets/xposed-channel.html-DZ4m7tlI.js new file mode 100644 index 00000000..8ca8547d --- /dev/null +++ b/assets/xposed-channel.html-DZ4m7tlI.js @@ -0,0 +1,120 @@ +import{_ as s,o as n,c as a,a as e}from"./app-BpUB8-Q8.js";const l={},o=e(`特别注意
为了进一步防止广播滥用,通讯数据中 API 会自动指定宿主和模块的包名,防止其它 APP 监听并利用广播做出超限行为。
# Xposed Module and Host Channel
This is a solution that uses system out-of-order broadcasting to send and receive data between the Module App and the Host App.
Condition that needs to be met
The Module App and the Host App need to remain alive, otherwise communication cannot be established.
# Basic Usage
The basic usage of the
wait
andput
methods is described here.By using
dataChannel
to realize the communication bridge between the Module App and the Host App, the principle is to send and receive system out-of-order broadcasts.The Module App example is as follows
// Get from the Host App of the specified package name +dataChannel(packageName = "com.example.demo").wait<String>(key = "key_from_host") { value -> + // Your code here. +} +// Send to the Host App with the specified package name +dataChannel(packageName = "com.example.demo").put(key = "key_from_module", value = "I am module") +
The Host App example is as follows
// Get from the Module App +dataChannel.wait<String>(key = "key_from_module") { value -> + // Your code here. +} +// Send to the Module App +dataChannel.put(key = "key_from_host", value = "I am host") +
You can leave the
value
ofdataChannel
unset to only notify the Module App or Host App to call back thewait
method.The Module App example is as follows
// Get from the Host App of the specified package name +dataChannel(packageName = "com.example.demo").wait(key = "listener_from_host") { + // Your code here. +} +// Send to the Host App with the specified package name +dataChannel(packageName = "com.example.demo").put(key = "listener_from_module") +
The Host App example is as follows
// Get from the Module App +dataChannel.wait(key = "listener_from_module") { + // Your code here. +} +// Send to the Module App +dataChannel.put(key = "listener_from_host") +
Pay Attention
The receiver needs to stay alive to receive the communication data.
Tips
For more functions, please refer to YukiHookDataChannel.
# Determine Module App and Host App Version Match
Through the communication bridge function,
YukiHookAPI
also provides a solution for you to determine whether the Module App matches the Host App version after the user updates the Module App.We only need to call the
checkingVersionEquals
method to achieve this function.Bidirectional judgment can be performed between the Module App and the Host App.
You can check in the Module App whether the Host App of the specified package name matches the version of the current Module App.
The following example
// Get from the Host App of the specified package name +dataChannel(packageName = "com.example.demo").checkingVersionEquals { isEquals -> + // Your code here. +} +
You can also determine in the Host App whether it matches the current Module App version.
The following example
// Get from the Module App +dataChannel.checkingVersionEquals { isEquals -> + // Your code here. +} +
Condition of method callback
The Host App and Module App must be stay alive, and after activating the Module App restart the Hook target Host App object in scope.
Tips
For more functions, please refer to YukiHookDataChannel.
# Rules for Callback Event Response
Only the examples used in Module App are listed here.
The same
key
in same Host App is always not allowed to be created repeatedly, but the samekey
is allowed in different Host Apps.Pay Attention
In the Module App and Host App, each key callback event corresponding to dataChannel is not allowed to be repeatedly created, if repeated, the previous callback event will be replaced by the newly added callback event.
When used in the Module App, it cannot be repeated in the same Activity, and the same key in different Activity is allowed to be repeated.
The following example
class MainActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + // Callback event A + dataChannel(packageName = "com.example.demo1").wait(key = "test_key") { + // Your code here. + } + // Callback event B + dataChannel(packageName = "com.example.demo1").wait(key = "test_key") { + // Your code here. + } + // Callback event C + dataChannel(packageName = "com.example.demo1").wait(key = "other_test_key") { + // Your code here. + } + // Callback event D + dataChannel(packageName = "com.example.demo2").wait(key = "other_test_key") { + // Your code here. + } + } +} + +class OtherActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + // Callback event E + dataChannel(packageName = "com.example.demo1").wait(key = "test_key") { + // Your code here. + } + // Callback event F + dataChannel(packageName = "com.example.demo2").wait(key = "test_key") { + // Your code here. + } + } +} +
In the above example, although callback events A and B are callback events in the same Host App, their
key
is the same, so callback event A will be replaced by callback event B.The
key
of callback event C is not duplicated with others.Although the
key
of callback event D is the same as that of callback event C, their Host Apps are different, so they can exist at the same time.Callback event E is in another Activity, although the
key
of callback event F and callback event E is the same, but they are not the same Host App, so they can exist at the same time.In summary, the final callback events B, C, D, E, and F can all be created successfully.
Compatibility Notes
Setting the same key on different Host Apps in previous historical versions of the API would result in only the last event callback, but the latest version has corrected this problem, please make sure you are using the latest API version.
Pay Attention
A callback event with the same key will only call back the callback event registered in the Activity that the current Module App is displaying, such as test_key in the above, if OtherActivity is being displayed, then test_key in MainActivity will not be called back.
The same key registers dataChannel in the same Activity but different Fragment, they will still be called back in the current Activity at the same time.
In a Module App, you can use dataChannel in Activity, Application and Service, when used in places other than Activity, each callback event will instant callback, at which point you can use ChannelPriority to manage.
If you want to use dataChannel in Fragment, use activity?.dataChannel(...).
If you want to manually set the response priority (condition) of each callback event in the same Activity, you can use
ChannelPriority
.For example, if you are using one Activity binding multiple Fragment cases, this will be able to solve this problem.
The following example
open class BaseFragment : Fragment() { + + /** Identify that the current Fragment is in the onResume lifecycle */ + var isResume = false + + override fun onResume() { + super. onResume() + isResume = true + } + + override fun onPause() { + super. onPause() + isResume = false + } + + override fun onStop() { + super. onStop() + isResume = false + } +} + +class FragmentA : BaseFragment() { + + // Omit part of initialization code + //... + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + // Use the custom isResume combined with the isVisible condition + // To judge that the current Fragment is in the displayed state + activity?.dataChannel(packageName = "com.example.demo1") + ?.wait(key = "test_key", ChannelPriority { isResume && isVisible }) { + // Your code here. + } + } +} + +class FragmentB : BaseFragment() { + + // Omit part of initialization code + //... + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + // Use the custom isResume combined with the isVisible condition + // To judge that the current Fragment is in the displayed state + activity?.dataChannel(packageName = "com.example.demo2") + ?.wait(key = "test_key", ChannelPriority { isResume && isVisible }) { + // Your code here. + } + } +} +
# Security Instructions
In the module environment, you can only receive the communication data sent by the Host App of the specified package name and can only send to the Host App of the specified package name, except for System Framework.
`,49),p=[o];function t(c,i){return n(),a("div",null,p)}const d=s(l,[["render",t],["__file","xposed-channel.html.vue"]]);export{d as default}; diff --git a/assets/xposed-storage.html-ByKfNh6r.js b/assets/xposed-storage.html-ByKfNh6r.js new file mode 100644 index 00000000..003b6ee9 --- /dev/null +++ b/assets/xposed-storage.html-ByKfNh6r.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-68bebbf4","path":"/en/api/special-features/xposed-storage.html","title":"Xposed Module Data Storage","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"Use in Activity","slug":"use-in-activity","link":"#use-in-activity","children":[]},{"level":2,"title":"Use in PreferenceFragment","slug":"use-in-preferencefragment","link":"#use-in-preferencefragment","children":[]},{"level":2,"title":"Use Native Storage","slug":"use-native-storage","link":"#use-native-storage","children":[]}],"git":{"updatedTime":1681673705000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":3}]},"filePathRelative":"en/api/special-features/xposed-storage.md"}');export{e as data}; diff --git a/assets/xposed-storage.html-CFhC-RoM.js b/assets/xposed-storage.html-CFhC-RoM.js new file mode 100644 index 00000000..4f88148d --- /dev/null +++ b/assets/xposed-storage.html-CFhC-RoM.js @@ -0,0 +1,38 @@ +import{_ as s,o as a,c as n,a as e}from"./app-BpUB8-Q8.js";const o={},l=e(`Pay Attention
In order to further prevent broadcast abuse, the API in the communication data will automatically specify the package name of the Host App and Module App to prevent other apps from monitoring and using broadcast to make overrun behaviors.
# Xposed 模块数据存储
这是一个自动对接
SharedPreferences
和XSharedPreferences
的高效模块数据存储解决方案。我们需要存储模块的数据,以供宿主调用,这个时候会遇到原生
Sp
存储的数据互通阻碍。原生的
Xposed
给我们提供了一个XSharedPreferences
用于读取模块的Sp
数据。# 在 Activity 中使用
这里描述了在
Activity
中装载YukiHookPrefsBridge
的场景。通常情况下我们可以这样在 Hook APP (宿主) 内对其进行初始化。
示例如下
XSharedPreferences(BuildConfig.APPLICATION_ID) +
有没有方便快捷的解决方案呢,此时你就可以使用
YukiHookAPI
的扩展能力快速实现这个功能。当你在模块中存储数据的时候,若当前处于
Activity
内,可以使用如下方法。示例如下
prefs().edit { putString("test_name", "saved_value") } +
当你在 Hook APP (宿主) 中读取数据时,可以使用如下方法。
示例如下
val testName = prefs.getString("test_name", "default_value") +
你不需要考虑传入模块的包名以及一系列复杂的权限配置,一切都交给
YukiHookPrefsBridge
来处理。若要实现存储的区域划分,你可以指定每个
prefs
文件的名称。在模块的
Activity
中这样使用。示例如下
// 推荐用法 +prefs("specify_file_name").edit { putString("test_name", "saved_value") } +// 也可以这样用 +prefs().name("specify_file_name").edit { putString("test_name", "saved_value") } +
在 Hook APP (宿主) 中这样读取。
示例如下
// 推荐用法 +val testName = prefs("specify_file_name").getString("test_name", "default_value") +// 也可以这样用 +val testName = prefs.name("specify_file_name").getString("test_name", "default_value") +
若你的项目中有大量的固定数据需要存储和读取,推荐使用
PrefsData
来创建模板。通过上面的示例,你可以调用
edit
方法使用以下两种方式来批量存储数据。示例如下
// <方案 1> +prefs().edit { + putString("test_name_1", "saved_value_1") + putString("test_name_2", "saved_value_2") + putString("test_name_3", "saved_value_3") +} +// <方案 2> +prefs().edit() + .putString("test_name_1", "saved_value_1") + .putString("test_name_2", "saved_value_2") + .putString("test_name_3", "saved_value_3") + .apply() +
小提示
更多功能请参考 YukiHookPrefsBridge、PrefsData。
# 在 PreferenceFragment 中使用
这里描述了在
PreferenceFragment
中装载YukiHookPrefsBridge
的场景。若你的模块使用了
PreferenceFragmentCompat
,你现在可以将其继承类开始迁移到ModulePreferenceFragment
。特别注意
你必须继承 ModulePreferenceFragment 才能实现 YukiHookPrefsBridge 的模块存储功能。
小提示
更多功能请参考 ModulePreferenceFragment。
# 使用原生方式存储
在模块环境中
YukiHookPrefsBridge
默认会将数据存储到模块自己的私有目录 (或 Hook Framework 提供的共享目录) 中。在宿主环境中使用
YukiHookPrefsBridge
默认会读取模块自己的私有目录 (或 Hook Framework 提供的共享目录) 中的数据。如果你想直接将数据存储到模块或宿主当前环境自身的私有目录,你可以使用
native
方法。例如模块的目录是
.../com.demo.test.module/shared_prefs
,宿主的目录是.../com.demo.test.host/shared_prefs
。以下是在
Activity
中的用法。示例如下
// 存储私有数据 +prefs().native().edit { putBoolean("isolation_data", true) } +// 读取私有数据 +val privateData = prefs().native().getBoolean("isolation_data") +// 存储共享数据 +prefs().edit { putBoolean("public_data", true) } +// 读取共享数据 +val publicData = prefs().getBoolean("public_data") +
以下是在
PackageParam
中的用法。示例如下
// 存储私有数据 +prefs.native().edit { putBoolean("isolation_data", true) } +// 读取私有数据 +val privateData = prefs.native().getBoolean("isolation_data") +// 读取共享数据 +val publicData = prefs.getBoolean("public_data") +
使用
native
方法后,无论在Activity
还是PackageParam
中都会将数据在对应环境的私有目录中存储、读取,数据相互隔离。`,47),p=[l];function t(c,r){return a(),n("div",null,p)}const d=s(o,[["render",t],["__file","xposed-storage.html.vue"]]);export{d as default}; diff --git a/assets/xposed-storage.html-CZy1SL3y.js b/assets/xposed-storage.html-CZy1SL3y.js new file mode 100644 index 00000000..486c5b28 --- /dev/null +++ b/assets/xposed-storage.html-CZy1SL3y.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-0d914225","path":"/zh-cn/api/special-features/xposed-storage.html","title":"Xposed 模块数据存储","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"在 Activity 中使用","slug":"在-activity-中使用","link":"#在-activity-中使用","children":[]},{"level":2,"title":"在 PreferenceFragment 中使用","slug":"在-preferencefragment-中使用","link":"#在-preferencefragment-中使用","children":[]},{"level":2,"title":"使用原生方式存储","slug":"使用原生方式存储","link":"#使用原生方式存储","children":[]}],"git":{"updatedTime":1681673705000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":3}]},"filePathRelative":"zh-cn/api/special-features/xposed-storage.md"}');export{e as data}; diff --git a/assets/xposed-storage.html-DYzzLHun.js b/assets/xposed-storage.html-DYzzLHun.js new file mode 100644 index 00000000..d5cf963a --- /dev/null +++ b/assets/xposed-storage.html-DYzzLHun.js @@ -0,0 +1,38 @@ +import{_ as s,o as e,c as a,a as n}from"./app-BpUB8-Q8.js";const o={},l=n(`小提示
更多功能请参考 YukiHookPrefsBridge。
# Xposed Module Data Storage
This is an efficient Module App data storage solution that automatically connects
SharedPreferences
andXSharedPreferences
.We need to store the data of the Module App for the Host App to call.
At this time, we will encounter the data exchange obstacle of the native
Sp
storage.The native
Xposed
provides us with aXSharedPreferences
for reading theSp
data of the Module App.# Use in Activity
Loading
YukiHookPrefsBridge
inActivity
is described here.Usually we can initialize it in Host App like this.
The following example
XSharedPreferences(BuildConfig.APPLICATION_ID) +
Is there a convenient and quick solution?
At this point, you can use the extension capability of
YukiHookAPI
to quickly implement this function.When you store data in a Module App, you can use the following methods if you are currently in an
Activity
.The following example
prefs().edit { putString("test_name", "saved_value") } +
When you read data in a Host App, you can use the following methods.
The following example
val testName = prefs.getString("test_name", "default_value") +
You don't need to consider the module package name and a series of complicated permission configurations, everything is handled by
YukiHookPrefsBridge
.To achieve localization of storage, you can specify the name of each
prefs
file.This is used in the
Activity
of the Module App.The following example
// Recommended usage +prefs("specify_file_name").edit { putString("test_name", "saved_value") } +// Can also be used like this +prefs().name("specify_file_name").edit { putString("test_name", "saved_value") } +
Read like this in Host App.
The following example
// Recommended usage +val testName = prefs("specify_file_name").getString("test_name", "default_value") +// Can also be used like this +val testName = prefs.name("specify_file_name").getString("test_name", "default_value") +
If your project has a lot of fixed data that needs to be stored and read, it is recommended to use
PrefsData
to create templates.Through the above example, you can call the
edit
method to store data in batches in the following two ways.The following example
// <Scenario 1> +prefs().edit { + putString("test_name_1", "saved_value_1") + putString("test_name_2", "saved_value_2") + putString("test_name_3", "saved_value_3") +} +// <Scenario 2> +prefs(). edit() + .putString("test_name_1", "saved_value_1") + .putString("test_name_2", "saved_value_2") + .putString("test_name_3", "saved_value_3") + .apply() +
Tips
For more functions, please refer to YukiHookPrefsBridge, PrefsData.
# Use in PreferenceFragment
Loading
YukiHookPrefsBridge
inPreferenceFragment
is described here.If your Module App uses
PreferenceFragmentCompat
, you can now start migrating its extendsModulePreferenceFragment
.Pay Attention
You must extends ModulePreferenceFragment to implement the module storage function of YukiHookPrefsBridge.
Tips
For more functions, please refer to ModulePreferenceFragment.
# Use Native Storage
In the Module environment,
YukiHookPrefsBridge
will store data in the Module App's own private directory (or the shared directory provided by Hook Framework) by default.Using
YukiHookPrefsBridge
in the Host environment will read the data in the Module App's own private directory (or the shared directory provided by Hook Framework) by default.If you want to store data directly into a Module App or Host App's own private directory, you can use the
native
method.For example, the directory of the Module App is
.../com.demo.test.module/shared_prefs
, and the directory of the Host App is.../com.demo.test.host/shared_prefs
.The following is the usage in
Activity
.The following example
// Store private data +prefs().native().edit { putBoolean("isolation_data", true) } +// Read private data +val privateData = prefs().native().getBoolean("isolation_data") +// Store shared data +prefs().edit { putBoolean("public_data", true) } +// Read shared data +val publicData = prefs().getBoolean("public_data") +
The following is the usage in
PackageParam
.The following example
// Store private data +prefs.native().edit { putBoolean("isolation_data", true) } +// Read private data +val privateData = prefs.native().getBoolean("isolation_data") +// Read shared data +val publicData = prefs.getBoolean("public_data") +
After using the
native
method, no matter inActivity
orPackageParam
, the data will be stored and read in the private directory of the corresponding environment, and the data will be isolated from each other.`,49),t=[l];function p(r,c){return e(),a("div",null,t)}const d=s(o,[["render",p],["__file","xposed-storage.html.vue"]]);export{d as default}; diff --git a/assets/xposed-using.html-7rTJRpMs.js b/assets/xposed-using.html-7rTJRpMs.js new file mode 100644 index 00000000..2dc48f80 --- /dev/null +++ b/assets/xposed-using.html-7rTJRpMs.js @@ -0,0 +1,88 @@ +import{_ as s,o as e,c as a,a as n}from"./app-BpUB8-Q8.js";const o={},l=n(`Tips
For more functions, please refer to YukiHookPrefsBridge.
# Use as Xposed Module Configs
Here are the related configuration methods used by
YukiHookAPI
as an Xposed Module.# Dependency Configs
As an Xposed Module,
YukiHookAPI
provides an automatic builder.You need to integrate the latest version of the
com.highcapable.yukihookapi:ksp-xposed
dependency in your build script.# Custom Automatic Builder
You can configure how
YukiHookAPI
will generate thexposed_init
entry point.# InjectYukiHookWithXposed Annotation
annotation class InjectYukiHookWithXposed( + val sourcePath: String, + val modulePackageName: String, + val entryClassName: String, + val isUsingXposedModuleStatus: Boolean, + val isUsingResourcesHook: Boolean +) +
The
@InjectYukiHookWithXposed
annotation is an important annotation to mark the entry point of a Module App's Hook.Pay Attention
The Class of the @InjectYukiHookWithXposed annotation must implements IYukiHookXposedInit interface.
All Class tags in your current project can only exist once, if there are multiple declaration automatic builder will throw an exception at compile time, you can customize its related parameters.
# sourcePath Parameter
The
sourcePath
parameter determines the important identifier for the automatic builder to automatically find and match your current project path.The content of this parameter is a relative path match, and the default parameter is
src/main
.Pay Attention
If your project is not in ../src/main.. or you set the project path manually using sourceSets, you need to set the sourcePath parameter manually, otherwise the automatic builder will not recognize your project path and will throw an exception at compile time.
The following example
@InjectYukiHookWithXposed(sourcePath = "src/custom") +
The file path separator used by
sourcePath
will be automatically recognized according toWindows
andUnix
, either/
or\\
can be used.# modulePackageName Parameter
modulePackageName
is theapplicationId
of your current project, which is your module package name (the final generated application package name).If left blank or not filled, the automatic builder will analyze and generate the current project file.
Notice
If you want to use the module package name to be automatically generated, you need to ensure that your project namespace has any of the following definitions in AndroidManifest.xml, build.gradle or build.gradle.kts.
Pay Attention
In Android Gradle Plugin 8+ versions, you need to manually enable buildConfig in the project's build.gradle or build.gradle.kts.
Groovy DSL
android { + buildFeatures { + buildConfig true + } +} +
Kotlin DSL
android { + buildFeatures { + buildConfig = true + } +} +
Example namespace
com.example.demo
, any one of the following definitions.The following definitions are for reference only, usually as long as your project can generate the
BuildConfig.java
file normally, no additional operations are required.
AndroidManifest.xml
example<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.demo"> +
build.gradle
exampleandroid { + namespace 'com.example.demo' +} +
build.gradle.kts
exampleandroid { + namespace = "com.example.demo" +} +
If your module package name is automatically generated by unconventional means, or you think it is necessary to manually define the module package name, then you can directly set the
modulePackageName
parameter.The following example
@InjectYukiHookWithXposed(modulePackageName = "com.example.demo") +
Pay Attention
Please do not fill in BuildConfig.APPLICATION_ID in modulePackageName, this will get an empty string during compilation, depending on the behavior of the Android Gradle Plugin.
As long as you customize the
modulePackageName
parameter, you will get a warning at compile time.The following example
You set the customize module package name to "com.example.demo", please check for yourself if it is correct +
Notice
In addition to the format of the manually defined module package name, the automatic builder will no longer check whether the module package name is correct, and you need to confirm its validity by yourself.
# entryClassName Parameter
entryClassName
determines how the automatic builder generates the entry class name inxposed_init
.By default, it will use your entry class package name to insert the
_YukiHookXposedInit
suffix for generation.Suppose this is your entry class.
The following example
@InjectYukiHookWithXposed +object HookEntry : IYukiHookXposedInit +
The Xposed entry class is handled as follows.
The following example
class HookEntry_YukiHookXposedInit : IXposedHookZygoteInit, IXposedHookLoadPackage, ... +
The compiled class name structure is as follows.
The following example
...hook.HookEntry ← Your entry class +...hook.HookEntry_Impl ← Auto-generated Impl class +...hook.HookEntry_YukiHookXposedInit ← Automatically generated Xposed entry class +
We now define the entry class name as
HookXposedEntry
.The following example
@InjectYukiHookWithXposed(entryClassName = "HookXposedEntry") +object HookEntry : IYukiHookXposedInit +
The Xposed entry class is handled as follows.
The following example
class HookXposedEntry : IXposedHookZygoteInit, IXposedHookLoadPackage, ... +
The compiled class name structure is as follows.
The following example
...hook.HookEntry ← Your entry class +...hook.HookEntry_Impl ← Auto-generated Impl class +...hook.HookXposedEntry ← Automatically generated Xposed entry class +
Tips
The entry class can be defined using class or object, but it is recommended to use object definition to ensure that each injected process is a single instance.
Pay Attention
The entryClassName you define must not be the same as the class name in xposed_init, otherwise the automatic builder throws an exception at compile time.
# isUsingXposedModuleStatus Parameter
isUsingXposedModuleStatus
determines whether the automatic builder generates relevant code for status functions such as Xposed Module activation, this feature is enabled by default.After generation, you will be able to use the related functions of
YukiHookAPI.Status
in the Module App's process.If you do not want to generate related code, you can manually turn off this feature, which will only take effect for the Module App's process.
# isUsingResourcesHook Parameter
isUsingResourcesHook
determines whether the automatic builder generates relevant code for the Resources Hook, this feature is not enabled by default.By default the generated entry class will look like this.
The following example
class _YukiHookXposedInit : IXposedHookZygoteInit, IXposedHookLoadPackage { + + override fun initZygote(sparam: IXposedHookZygoteInit.StartupParam?) { + // ... + } + + override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) { + // ... + } +} +
If your current project need to use Resources Hook, you can set
isUsingResourcesHook = true
to enable automatic generation.Notice
This feature will no longer be enabled by default after version 1.2.0, please enable it manually if you want to use it.
The following example
@InjectYukiHookWithXposed(isUsingResourcesHook = true) +
The resulting entry class after enabled will look like the following.
The following example
class _YukiHookXposedInit : IXposedHookZygoteInit, IXposedHookLoadPackage, IXposedHookInitPackageResources { + + override fun initZygote(sparam: IXposedHookZygoteInit.StartupParam?) { + // ... + } + + override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) { + // ... + } + + override fun handleInitPackageResources(resparam: XC_InitPackageResources.InitPackageResourcesParam?) { + // ... + } +} +
Tips
Since the Xposed entry class is dynamically generated by YukiHookAPI, it will generate the following two files at the same time.
assets/xposed_init
resources/META-INF/yukihookapi_init
If you are using Git code control system, you can add these two files to .gitignore file.
# IYukiHookXposedInit Interface
The
IYukiHookXposedInit
interface that your Hook entry class must implements it, which is the entry point for your Module App to start hooking.Tips
For more functions, please refer to IYukiHookXposedInit.
When your Module App is loaded by Xposed, the
onHook
method will be called back, you need to start usingYukiHookAPI
in this method.The basic calling process is
_YukiHookXposedInit
→IYukiHookXposedInit.onXposedEvent
→IYukiHookXposedInit.onInit
→IYukiHookXposedInit.onHook
For details, please refer to API Basic Configs.
# Native Xposed API Events
If your current Xposed Module uses third-party resources, but may not be able to transfer them in a short time, you can use
onXposedEvent
to monitor all loading events of the native Xposed API.The following example
@InjectYukiHookWithXposed +object HookEntry : IYukiHookXposedInit { + + override fun onHook() { + // Your code here. + } + + override fun onXposedEvent() { + // Listen to the loading events of the native Xposed API + YukiXposedEvent.events { + onInitZygote { + // The it object is [StartupParam] + } + onHandleLoadPackage { + // The it object is [LoadPackageParam] + } + onHandleInitPackageResources { + // The it object is [InitPackageResourcesParam] + } + } + } +} +
onXposedEvent
andonHook
methods exist completely independently and do not affect each other. You can continue to useYukiHookAPI
in theonHook
method.`,91),t=[l];function p(i,c){return e(),a("div",null,t)}const d=s(o,[["render",p],["__file","xposed-using.html.vue"]]);export{d as default}; diff --git a/assets/xposed-using.html-B9LNrU2W.js b/assets/xposed-using.html-B9LNrU2W.js new file mode 100644 index 00000000..b67ae951 --- /dev/null +++ b/assets/xposed-using.html-B9LNrU2W.js @@ -0,0 +1,88 @@ +import{_ as s,o as a,c as n,a as o}from"./app-BpUB8-Q8.js";const e={},l=o(`Tips
For more functions, please refer to the IYukiHookXposedInit.onXposedEvent method.
# 作为 Xposed 模块使用的相关配置
这里介绍了
YukiHookAPI
作为 Xposed 模块使用的相关配置方法。# 依赖配置
作为 Xposed 模块,
YukiHookAPI
提供了一个自动处理程序。你需要在你的构建脚本中集成
com.highcapable.yukihookapi:ksp-xposed
依赖的最新版本。# 自定义处理程序
你可以对
YukiHookAPI
将如何生成xposed_init
入口进行相关配置。# InjectYukiHookWithXposed 注解
annotation class InjectYukiHookWithXposed( + val sourcePath: String, + val modulePackageName: String, + val entryClassName: String, + val isUsingXposedModuleStatus: Boolean, + val isUsingResourcesHook: Boolean +) +
@InjectYukiHookWithXposed
注解是一个标记模块 Hook 入口的重要注解。特别注意
@InjectYukiHookWithXposed 注解的 Class 必须实现 IYukiHookXposedInit 接口。
在你当前项目中的所有 Class 标记中只能存在一次,若存在多个声明自动处理程序会在编译时抛出异常,你可以自定义其相关参数。
# sourcePath 参数
sourcePath
参数决定了自动处理程序自动查找并匹配你当前项目路径的重要标识,此参数的内容为相对路径匹配,默认参数为src/main
。特别注意
如果你的项目不在 ../src/main.. 或你手动使用 sourceSets 设置了项目路径,你就需要手动设置 sourcePath 参数,否则自动处理程序将无法识别你的项目路径并会在编译时抛出异常。
示例如下
@InjectYukiHookWithXposed(sourcePath = "src/custom") +
sourcePath
使用的文件路径分隔符写法根据Windows
和Unix
将自动进行识别,使用/
或\\
均可。# modulePackageName 参数
modulePackageName
是你当前项目的applicationId
,也就是你的模块包名 (最终生成的应用包名),留空或不填时自动处理程序将对当前项目文件进行分析并生成。注意
若你想使用模块包名自动生成,你需要确保你的项目命名空间在 AndroidManifest.xml、build.gradle 或 build.gradle.kts 中存在如下任意定义方式。
特别注意
在 Android Gradle Plugin 8+ 版本中,你需要手动在项目的 build.gradle 或 build.gradle.kts 中启用 buildConfig。
Groovy DSL
android { + buildFeatures { + buildConfig true + } +} +
Kotlin DSL
android { + buildFeatures { + buildConfig = true + } +} +
示例命名空间
com.example.demo
,以下定义方式任选其一。以下定义方式仅供参考,通常情况下只要你的项目能够正常生成
BuildConfig.java
文件,就不需要做额外操作。
AndroidManifest.xml
示例<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.demo"> +
build.gradle
示例android { + namespace 'com.example.demo' +} +
build.gradle.kts
示例android { + namespace = "com.example.demo" +} +
若你的模块包名是非常规手段进行自动生成的,或你认为有必要手动定义模块包名,那么你可以直接设置
modulePackageName
的参数。示例如下
@InjectYukiHookWithXposed(modulePackageName = "com.example.demo") +
特别注意
请不要在 modulePackageName 中填写 BuildConfig.APPLICATION_ID,这会在编译过程中获取到空字符串,这取决于 Android Gradle Plugin 的行为。
只要你自定义了
modulePackageName
的参数,你就会在编译时收到警告。示例如下
You set the customize module package name to "com.example.demo", please check for yourself if it is correct +
注意
手动定义的模块包名除了格式之外,自动处理程序将不会再检查模块包名是否正确,需要你自行确认其有效性。
# entryClassName 参数
entryClassName
决定了自动处理程序如何生成xposed_init
中的入口类名,默认会使用你的入口类包名插入_YukiHookXposedInit
后缀进行生成。假设这是你的入口类。
示例如下
@InjectYukiHookWithXposed +object HookEntry : IYukiHookXposedInit +
Xposed 入口类处理如下。
示例如下
class HookEntry_YukiHookXposedInit : IXposedHookZygoteInit, IXposedHookLoadPackage, ... +
编译后的类名结构如下。
示例如下
...hook.HookEntry ← 你的入口类 +...hook.HookEntry_Impl ← 自动生成的 Impl 类 +...hook.HookEntry_YukiHookXposedInit ← 自动生成的 Xposed 入口类 +
我们现在定义入口类名称为
HookXposedEntry
。示例如下
@InjectYukiHookWithXposed(entryClassName = "HookXposedEntry") +object HookEntry : IYukiHookXposedInit +
Xposed 入口类处理如下。
示例如下
class HookXposedEntry : IXposedHookZygoteInit, IXposedHookLoadPackage, ... +
编译后的类名结构如下。
示例如下
...hook.HookEntry ← 你的入口类 +...hook.HookEntry_Impl ← 自动生成的 Impl 类 +...hook.HookXposedEntry ← 自动生成的 Xposed 入口类 +
小提示
入口类可以使用 class 或 object 定义,但是建议使用 object 定义来保证每一个注入的进程都是单例运行。
特别注意
你定义的 entryClassName 不可与 xposed_init 中的类名相同,否则自动处理程序会在编译时抛出异常。
# isUsingXposedModuleStatus 参数
isUsingXposedModuleStatus
决定了自动处理程序是否生成针对 Xposed 模块激活等状态功能的相关代码,此功能默认启用。生成后你将可以在模块进程中使用
YukiHookAPI.Status
的相关功能。如果你不希望生成相关代码,你可以手动关闭此功能,仅对模块进程生效。
# isUsingResourcesHook 参数
isUsingResourcesHook
决定了自动处理程序是否生成针对 Resources Hook 的相关代码,此功能默认不启用。默认情况下生成的入口类将为如下所示。
示例如下
class _YukiHookXposedInit : IXposedHookZygoteInit, IXposedHookLoadPackage { + + override fun initZygote(sparam: IXposedHookZygoteInit.StartupParam?) { + // ... + } + + override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) { + // ... + } +} +
若你当前的项目需要用到 Resources Hook,可以设置
isUsingResourcesHook = true
来启用自动生成。注意
此功能在 1.2.0 版本后将不再默认启用,如需使用请手动启用。
示例如下
@InjectYukiHookWithXposed(isUsingResourcesHook = true) +
启用后生成的入口类将为如下所示。
示例如下
class _YukiHookXposedInit : IXposedHookZygoteInit, IXposedHookLoadPackage, IXposedHookInitPackageResources { + + override fun initZygote(sparam: IXposedHookZygoteInit.StartupParam?) { + // ... + } + + override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) { + // ... + } + + override fun handleInitPackageResources(resparam: XC_InitPackageResources.InitPackageResourcesParam?) { + // ... + } +} +
小提示
由于 Xposed 入口类是被 YukiHookAPI 动态生成的,它会同时生成如下两个文件。
assets/xposed_init
resources/META-INF/yukihookapi_init
如果你正在使用 Git 代码控制系统,你可以将这两个文件添加到 .gitignore 文件中。
# IYukiHookXposedInit 接口
IYukiHookXposedInit
接口为你的 Hook 入口类必须实现的接口,这是你的模块开始 Hook 的起点。小提示
更多功能请参考 IYukiHookXposedInit。
当你的模块被 Xposed 装载后,
onHook
方法将会被回调,你需要在此方法中开始使用YukiHookAPI
。基本的调用流程为
_YukiHookXposedInit
→IYukiHookXposedInit.onXposedEvent
→IYukiHookXposedInit.onInit
→IYukiHookXposedInit.onHook
详情请参考 API 基本配置。
# 原生 Xposed API 事件
若你当前的 Xposed 模块使用了第三方的资源,但是短时间内可能无法转移它们,此时,你可以使用
onXposedEvent
实现监听原生 Xposed API 的全部装载事件。示例如下
@InjectYukiHookWithXposed +object HookEntry : IYukiHookXposedInit { + + override fun onHook() { + // Your code here. + } + + override fun onXposedEvent() { + // 监听原生 Xposed API 的装载事件 + YukiXposedEvent.events { + onInitZygote { + // it 对象即 [StartupParam] + } + onHandleLoadPackage { + // it 对象即 [LoadPackageParam] + } + onHandleInitPackageResources { + // it 对象即 [InitPackageResourcesParam] + } + } + } +} +
onXposedEvent
与onHook
方法完全独立存在,互不影响,你可以继续在onHook
方法中使用YukiHookAPI
。`,88),p=[l];function c(t,i){return a(),n("div",null,p)}const d=s(e,[["render",c],["__file","xposed-using.html.vue"]]);export{d as default}; diff --git a/assets/xposed-using.html-CgLVQrdV.js b/assets/xposed-using.html-CgLVQrdV.js new file mode 100644 index 00000000..4ca8fa00 --- /dev/null +++ b/assets/xposed-using.html-CgLVQrdV.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-24e71de7","path":"/en/config/xposed-using.html","title":"Use as Xposed Module Configs","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"Dependency Configs","slug":"dependency-configs","link":"#dependency-configs","children":[]},{"level":2,"title":"Custom Automatic Builder","slug":"custom-automatic-builder","link":"#custom-automatic-builder","children":[{"level":3,"title":"InjectYukiHookWithXposed Annotation","slug":"injectyukihookwithxposed-annotation","link":"#injectyukihookwithxposed-annotation","children":[]},{"level":3,"title":"IYukiHookXposedInit Interface","slug":"iyukihookxposedinit-interface","link":"#iyukihookxposedinit-interface","children":[]}]},{"level":2,"title":"Native Xposed API Events","slug":"native-xposed-api-events","link":"#native-xposed-api-events","children":[]}],"git":{"updatedTime":1696443325000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":9}]},"filePathRelative":"en/config/xposed-using.md"}');export{e as data}; diff --git a/assets/xposed-using.html-sNzVArkO.js b/assets/xposed-using.html-sNzVArkO.js new file mode 100644 index 00000000..749de41b --- /dev/null +++ b/assets/xposed-using.html-sNzVArkO.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-af73b3d0","path":"/zh-cn/config/xposed-using.html","title":"作为 Xposed 模块使用的相关配置","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"依赖配置","slug":"依赖配置","link":"#依赖配置","children":[]},{"level":2,"title":"自定义处理程序","slug":"自定义处理程序","link":"#自定义处理程序","children":[{"level":3,"title":"InjectYukiHookWithXposed 注解","slug":"injectyukihookwithxposed-注解","link":"#injectyukihookwithxposed-注解","children":[]},{"level":3,"title":"IYukiHookXposedInit 接口","slug":"iyukihookxposedinit-接口","link":"#iyukihookxposedinit-接口","children":[]}]},{"level":2,"title":"原生 Xposed API 事件","slug":"原生-xposed-api-事件","link":"#原生-xposed-api-事件","children":[]}],"git":{"updatedTime":1696443325000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":9}]},"filePathRelative":"zh-cn/config/xposed-using.md"}');export{e as data}; diff --git a/assets/yukihookapi-projectbuilder.html-0qjforhM.js b/assets/yukihookapi-projectbuilder.html-0qjforhM.js new file mode 100644 index 00000000..0d385b94 --- /dev/null +++ b/assets/yukihookapi-projectbuilder.html-0qjforhM.js @@ -0,0 +1 @@ +import{_ as n,r as i,o as c,c as s,b as t,d as e,e as a,a as r}from"./app-BpUB8-Q8.js";const l="/YukiHookAPI/images/yukihookapi-projectbuilder-en.png",d={},u=r('小提示
更多功能请参考 IYukiHookXposedInit.onXposedEvent 方法。
# YukiHookAPI Project Builder
This is an automatic building tool for Xposed Modules using
YukiHookAPI
as the core.Implementing automated search relies on quickly building an Android project template that includes a Xposed Module environment.
# Get Project
This project is open source and free, and will be maintained continuously according to your usage.
The original version may have imperfections or bugs. We welcome to your feedback.
',7),h={href:"https://github.com/HighCapable/YukiHookAPI-ProjectBuilder",target:"_blank",rel:"noopener noreferrer"},p={href:"https://github.com/HighCapable/YukiHookAPI-ProjectBuilder/releases",target:"_blank",rel:"noopener noreferrer"},g=r('Notice
The project builder will be maintained before the release of the first
2.0.0
version ofYukiHookAPI
. This project will be officially deprecated after the new version is released.# Usage
Here contains the basic usage and function explanation.
# Basic Usage
The software use process requires your device connected to the Internet.
After starting the software, simply configure the project you want to create, click the button in the lower right corner or select Project > Run Build from the menu bar to start the task.
After waiting for the automatic dependency search to complete, you can configure the project dependencies. It is recommended to use the latest dependencies to ensure the stability of the project, and the build tools only support the latest dependencies.
Select the folder where you need to create the project. After starting, the project will be created in the location you selected, and wait for the whole process to complete and the project will be created.
# Config Template
Config template is an extension function, you can select menu bar Project > Config Template > New Template.
And then, you can create a template with the current config, and you can re-create it from Saved Template next time Load the template to restore the current config.
# Multilingual Support
The software language follows the current system, and you can manually select the software interface language in the Language column of the menu bar.
',9);function f(m,b){const o=i("ExternalLinkIcon");return c(),s("div",null,[u,t("p",null,[e("Project Address "),t("a",h,[e("YukiHookAPI-ProjectBuilder"),a(o)]),e("。")]),t("p",null,[e("If you want to download directly, you can "),t("a",p,[e("click here"),a(o)]),e(" to go to the Release address.")]),g])}const y=n(d,[["render",f],["__file","yukihookapi-projectbuilder.html.vue"]]);export{y as default}; diff --git a/assets/yukihookapi-projectbuilder.html-Bq3KEpgx.js b/assets/yukihookapi-projectbuilder.html-Bq3KEpgx.js new file mode 100644 index 00000000..0ad816a6 --- /dev/null +++ b/assets/yukihookapi-projectbuilder.html-Bq3KEpgx.js @@ -0,0 +1 @@ +import{_ as i,r as n,o as s,c,b as o,d as e,e as a,a as t}from"./app-BpUB8-Q8.js";const d="/YukiHookAPI/images/yukihookapi-projectbuilder-zh-cn.png",h={},l=t('# YukiHookAPI 构建工具
这是一个使用
YukiHookAPI
作为核心的 Xposed 模块自动构建工具。实现自动化搜索依赖快速搭建一个包含 Xposed 模块环境的 Android 项目模板。
# 获取项目
本项目完全开源免费,且会根据大家的使用情况持续维护,初代版本可能存在不完善或 BUG,欢迎反馈。
',6),p={href:"https://github.com/HighCapable/YukiHookAPI-ProjectBuilder",target:"_blank",rel:"noopener noreferrer"},u={href:"https://github.com/HighCapable/YukiHookAPI-ProjectBuilder/releases",target:"_blank",rel:"noopener noreferrer"},k=t('注意
项目构建器将会在
YukiHookAPI
发布第一个2.0.0
版本之前做最后的维护,在新的版本发布后,这个项目将正式弃用。# 使用方法
这里包含了基本的使用方法和功能讲解。
# 基本用法
软件使用过程需要当前设备已连接互联网,若项目依赖无法搜索请尝试 科学上网 。
启动软件后,对你期望创建的项目进行简单配置,点击右下角的 按钮 或菜单栏选择 项目 > 开始创建 即可开始任务。
等待依赖自动搜索完成后,你可以对项目依赖进行配置,建议使用最新依赖保证项目的稳定性,构建工具也仅对最新依赖进行支持。
选择你需要创建项目的目录,开始后项目会在你选择的位置中创建,并等待整个过程完成,项目就创建好了。
# 配置模板
配置模板是一个扩展功能,你可以选择菜单栏 项目 > 配置模板 > 新建模板,即可使用当前填写的配置创建一份模板,下次可以从 已保存的模板 中重新载入模板,即可还原当前配置。
# 多语言支持
软件语言跟随当前系统,你可以在菜单栏 语言 (Language) 一栏手动选择软件的界面语言。
',8);function g(_,b){const r=n("ExternalLinkIcon");return s(),c("div",null,[l,o("p",null,[e("项目地址 "),o("a",p,[e("YukiHookAPI-ProjectBuilder"),a(r)]),e("。")]),o("p",null,[e("若你想直接下载可以 "),o("a",u,[e("点击这里"),a(r)]),e(" 前往 Release 发布地址。")]),k])}const m=i(h,[["render",g],["__file","yukihookapi-projectbuilder.html.vue"]]);export{m as default}; diff --git a/assets/yukihookapi-projectbuilder.html-DnghHaiT.js b/assets/yukihookapi-projectbuilder.html-DnghHaiT.js new file mode 100644 index 00000000..40dbf4e7 --- /dev/null +++ b/assets/yukihookapi-projectbuilder.html-DnghHaiT.js @@ -0,0 +1 @@ +const l=JSON.parse('{"key":"v-a2fab4d6","path":"/zh-cn/tools/yukihookapi-projectbuilder.html","title":"YukiHookAPI 构建工具","lang":"zh-CN","frontmatter":{},"headers":[{"level":2,"title":"获取项目","slug":"获取项目","link":"#获取项目","children":[]},{"level":2,"title":"使用方法","slug":"使用方法","link":"#使用方法","children":[{"level":3,"title":"基本用法","slug":"基本用法","link":"#基本用法","children":[]},{"level":3,"title":"配置模板","slug":"配置模板","link":"#配置模板","children":[]},{"level":3,"title":"多语言支持","slug":"多语言支持","link":"#多语言支持","children":[]}]}],"git":{"updatedTime":1750845595000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":3}]},"filePathRelative":"zh-cn/tools/yukihookapi-projectbuilder.md"}');export{l as data}; diff --git a/assets/yukihookapi-projectbuilder.html-xbo0Krpt.js b/assets/yukihookapi-projectbuilder.html-xbo0Krpt.js new file mode 100644 index 00000000..ae478c02 --- /dev/null +++ b/assets/yukihookapi-projectbuilder.html-xbo0Krpt.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-55c11626","path":"/en/tools/yukihookapi-projectbuilder.html","title":"YukiHookAPI Project Builder","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"Get Project","slug":"get-project","link":"#get-project","children":[]},{"level":2,"title":"Usage","slug":"usage","link":"#usage","children":[{"level":3,"title":"Basic Usage","slug":"basic-usage","link":"#basic-usage","children":[]},{"level":3,"title":"Config Template","slug":"config-template","link":"#config-template","children":[]},{"level":3,"title":"Multilingual Support","slug":"multilingual-support","link":"#multilingual-support","children":[]}]}],"git":{"updatedTime":1750845595000,"contributors":[{"name":"fankesyooni","email":"qzmmcn@163.com","commits":3}]},"filePathRelative":"en/tools/yukihookapi-projectbuilder.md"}');export{e as data}; diff --git a/en/about/about.html b/en/about/about.html new file mode 100644 index 00000000..3ef146d5 --- /dev/null +++ b/en/about/about.html @@ -0,0 +1,49 @@ + + + + + + + + +About This Document | Yuki Hook API + + + + + ++ + + diff --git a/en/about/changelog.html b/en/about/changelog.html new file mode 100644 index 00000000..f38572c0 --- /dev/null +++ b/en/about/changelog.html @@ -0,0 +1,34 @@ + + + + + + + + +Yuki Hook API
About This Document
This document is powered by VuePress.
License
Apache License Version 2.0 + +Copyright (C) 2019 HighCapable + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +
Copyright © 2019 HighCapable
Changelog | Yuki Hook API + + + + + ++ + + diff --git a/en/about/contacts.html b/en/about/contacts.html new file mode 100644 index 00000000..6165e792 --- /dev/null +++ b/en/about/contacts.html @@ -0,0 +1,34 @@ + + + + + + + + +Yuki Hook API
Changelog
The version update history of
YukiHookAPI
is recorded here.Pay Attention
We will only maintain the latest API version, if you are using an outdate API version, you voluntarily renounce any possibility of maintenance.
Notice
To avoid translation time consumption, Changelog will use Google Translation from Chinese to English, please refer to the original text for actual reference.
Time zone of version release date: UTC+8
latest
1.3.0 | 2024.06.25
- This is a major update, please refer to Migrate to YukiHookAPI 1.3.x
- The reflection API of
YukiHookAPI
is deprecated, please move to the brand new KavaRef- The limitation of duplicate Hooks has been deprecated, now you can repeat the same method of the Hook
- Deprecated
,ModuleAppActivity
, please useModuleAppCompatActivity
ModuleActivity
to create your own proxyActivity
YLog
is now allowed to passmsg
into any object and will be automatically converted to a string for printingFreeReflection
has been deprecated and has now switched to AndroidHiddenApiBypassstale
1.2.1 | 2024.06.20
- Catch exceptions in singleton Hooker to prevent it from blocking the entire process
- Add automatic use of "`" in the automatic handler to fix the situation where Kotlin keywords are package names, thanks to Fengning Zhu for PR
- Adapt to Kotlin 2.0.0+, fix the problem that it cannot be compiled during automatic processing, thanks to xihan123 for PR
stale
1.2.0 | 2023.10.07
- The license agreement has been changed from
MIT
toApache-2.0
, subsequent versions will be distributed under this license agreement, you should change the relevant license agreement after using this version- This is a breaking update, please refer to Migrate to YukiHookAPI 1.2.x for details
- Adapted to Android 14, thanks to BlueCat300 for PR
- Fixed
findAllInterfaces
related issues, thanks to buffcow for PR- Fixed the delayed callback problem in the Hook process, thanks to cesaryuan for his Issue
- Added support for Resources Hook related functions, please refer to this Issue for details
- Added
YukiHookAPI.TAG
- Deprecated
,YukiHookAPI.API_VERSION_NAME
, merged intoYukiHookAPI.API_VERSION_CODE
YukiHookAPI.VERSION
- Added
YukiHookAPI.TAG
- Deprecated
,YukiHookAPI.API_VERSION_NAME
, merged intoYukiHookAPI.API_VERSION_CODE
YukiHookAPI.VERSION
- Deprecated
method inuseDangerousOperation
YukiMemberHookCreator
- Deprecated
function ininstanceClass
YukiMemberHookCreator
, it is no longer recommended- Modify
instanceClass
inHookParam
to be a null safe return value type- Detach all Hook objects created using
injectMember
toLegacyCreator
- Modify
appClassLoader
inPackageParam
to be a null safe return value type- Refactor all
logger...
methods to new usageYLog
- Removed the
-->
style behind the print log function- Fixed and improved the problem that the module package name cannot be obtained through KSP after using
namespace
- Functions such as whether to enable module activation status have now been moved to the
InjectYukiHookWithXposed
annotation- Detached FreeReflection will no longer be automatically generated and will be automatically imported as a dependency
- Added a warning log that will be automatically printed when the same Hook method is repeated
- The
findClass(...)
method inPackageParam
is obsolete, please migrate to the"...".toClass()
method- The
String.hook { ... }
method inPackageParam
is obsolete, and it is recommended to use a new method for HookAppLifecycle
can now be created repeatedly in different Hookers- The old version of Hook priority writing is obsolete and migrated to
YukiHookPriority
- Removed the
tag
function in the Hook process- Refactored
remendy
functionality in find methods, which now prints exceptions in steps- The multi-method find result type is changed from
HashSet
toMutableList
- Added
method()
,constructor()
,field()
to directly obtain all object functions in the classconstructor()
no longer behaves likeconstructor { emptyParam() }
- Added
lazyClass
andlazyClassOrNull
methods to lazily loadClass
outdate
1.1.11 | 2023.04.25
- Fixed a critical issue since
1.1.5
version where theMember
cache did not take effect and persistent storage eventually caused app out of memory (OOM), thanks to Art-Chen- Remove the direct cache function of
Member
and deprecated, keep the cache function ofYukiReflection.Configs.isEnableMemberCache
Class
- Modified finder to
Sequence
, optimize the finding speed and performance ofMember
- Remove the
YukiHookPrefsBridge
's direct key-value cache function and removedLruCache
related functions- Deprecated
YukiHookAPI.Configs.isEnablePrefsBridgeCache
- Deprecated
,direct
functions inclearCache
YukiHookPrefsBridge
outdate
1.1.10 | 2023.04.21
- The
Activity
proxy function adds the function of specifying a separate proxyActivity
for each proxiedActivity
- Fixed problem that the
contains
andall
methods inYukiHookPrefsBridge
did not judge thenative
function- Integrate the cache function in
YukiHookPrefsBridge
intoPreferencesCacheManager
and useLruCache
as a key-value pair cache- Modify
YukiHookPrefsBridge
key-value pair caching function to take effect in all environments (Module Apps, Host Apps)- Modify part of
HashMap
used for caching toArrayMap
to reduce memory consumption- Fix some other possible problems
outdate
1.1.9 | 2023.04.17
- Change the type of dependent library from Java Library (jar) to Android Library (aar)
- Remove the inspection function of internal methods and parameters through Hook or reflection API
- Fixed the problem that
YukiHookDataChannel
automatically segmented data sending function could not work normally (exception would still be thrown)- Added the ability to manually modify the maximum data byte size allowed by
YukiHookDataChannel
to be sent at one time according to the limitations of the target device- Remove the restriction that
YukiHookDataChannel
can only be used in moduleActivity
, now you can use it anywhere- Modify and standardize the broadcast Action name used by
YukiHookDataChannel
- Fix the problem that
BadParcelableException
occurs whenYukiHookDataChannel
has different modules with the same host- Added
ExecutorType
, you can get the type of known Hook Framework throughYukiHookAPI.Status.Executor.type
renamed toYukiHookModulePrefs
YukiHookPrefsBridge
- Modify
YukiHookPrefsBridge
to be implemented as a non-singleton, as a singleton may cause data confusion- Deprecated
method, please move toContext.modulePrefs(...)
Context.prefs(...)
YukiHookPrefsBridge
addsnative
method, which supports storing private data in modules and hosts directly as native storage- Integrate the storage method in
YukiHookPrefsBridge
toYukiHookPrefsBridge.Editor
, please useedit
method to store dataYukiHookPrefsBridge
addscontains
method- Cache dynamically created proxy objects in
YukiHookPrefsBridge
, try to fix problems that may cause OOM in the host and modules- Modify the proxy class of the
Activity
proxy function to be dynamically generated to prevent conflicts caused by injecting different modules into the host- Fixed some other possible problems
outdate
1.1.8 | 2023.02.01
- Fixed the problem that the underlying Hook method cannot update the modified state synchronously when modifying parameters such as
result
during callback, thanks to the Issue of Yongzheng Lai- Move the entry class name file automatically generated by
YukiHookAPI
fromassets/yukihookapi_init
toresources/META-INF/yukihookapi_init
- When only printing the exception stack, the
msg
parameter is allowed to be empty and themsg
parameter can not be set, and the log with themsg
parameter left blank will not be logged unless the exception stack is not empty- Fixed the bug that the log printed by the exception that occurs in the body of the Hook callback method has no specific method information
HookParam
addsinstanceOrNull
variable and method, which can be used on the premise that the Hook instance is not sure whether it is empty to prevent the Hook instance from being empty and throw an exception- Decoupled all hookers in
Member
lookup functionality toMemberBaseFinder.MemberHookerManager
- Modified the usage of
by
condition inYukiMemberHookCreator
, now you can reuseby
method to set multiple conditions- Removed wrong
Class
object declaration in Androidtype
- The
registerReceiver
method inPackageParam.AppLifecycle
adds the function of directly usingIntentFilter
to create a system broadcast listener- Fixed the problem that there may be multiple registration lifecycles in
PackageParam.AppLifecycle
- Revert: The 1.1.7 version has been withdrawn due to a serious problem, please update to this version directly (the update log is the same as version 1.1.7)
outdate
1.1.6 | 2023.01.21
- Fixed the serious problem that
ClassLoader
does not match afterPackageParam
keeps a single instance when there may be multiple package names in the same process when Xposed Module is loaded- When the package name is not distinguished when there are multiple package names in the same process, stop loading the singleton child Hooker and print a warning message
- Fixed the problem that the number of parameters is incorrect when methods such as
HookParam.callOriginal
,HookParam.invokeOriginal
call the original method- Modify the method parameter name
param
of reflection calls inMethodFinder
,ConstructorFinder
,ReflectionFactory
toargs
- Added the function of judging the parameters of the entry class constructor in the automatic processing program of the Xposed Module, the entry class needs to ensure that it does not have any constructor parameters
outdate
1.1.5 | 2023.01.13
- Standardize and optimize the overall code style
- Privatized some APIs called internally
- The underlying API interface is decoupled as a whole to prepare for compatibility with more Hook Frameworks
- Move some of the functions integrated in the API to
ksp-xposed
dependencies (decoupling), and the separate introduction ofapi
dependencies will no longer contain references to functions such as third-party libraries- Documentation Quick Start page added instructions on when
YukiHookAPI.Configs.isDebug
needs to be closed- Standardize Java Primitive Types in type definitions and sync update to docs
- Java
type
addsNumberClass
type- Improved (Xposed) Host environment recognition
- Take over all exceptions after loading the Xposed Module, if an exception occurs, it will automatically intercept and print the error log
- Modify the
Class
that does not exist in the lower Android system version (Android 5.0) in the type definition to be an empty safe type- Adapt and support native Xposed, the minimum recommended version is Android 7.0
- Added support for Hook entry class declared as
object
type (singleton)- Fixed the problem that the system below Android 8 does not support the
Executable
type, causing the Hook to fail- Fixed the problem of reporting an error when using the
Activity
proxy function for systems below Android 9 and limit the minimum supported version of this function to Android 7.0- Added the prohibition of resource injection and
Activity
proxy function injection into the current module's own instance process to prevent problems- Fixed a serious error that the return value of a method in the Hook process is not consistent with the target's inherited class and interface.
- Fixed the problem that the object is empty when calling
HookParam.callOriginal
andHookParam.invokeOriginal
when the current Hook instance object is static- Optimize the function of judging the Tai Chi activation method and update the relevant instructions of the document synchronously
- Obsolete
,YukiHookAPI.Status.executorName
, please move toYukiHookAPI.Status.executorVersion
YukiHookAPI.Status.Executor
- Adapted the
YukiHookAPI.Status.Executor.name
name display function of some third-party Hook Frameworks- Added
Class.extends
,Class.implements
and other methods, which can more conveniently judge the inheritance and interface relationship of the currentClass
- Added generic methods of the same name as
Class.toClass
,Class.toClassOrNull
and other related methods, you can use generics to constrain the instance object type of knownClass
- Modify the return value of the
classOf<T>
method to the generic typeT
to constrain the instance object type of the knownClass
- Added
initialize
parameter ofClass
related extension method, which can control whether to initialize its static method block at the same time when gettingClass
object- Added
param { ... }
,type { ... }
and other usages in the variable, method, and construction method search functions, which can add more specific conditional judgments to the searched objects- The
loadApp
method ofPackageParam
adds theisExcludeSelf
parameter, which can be used to exclude Hook-related functions from injecting into the module's own instance process- The
onAppLifecycle
method ofPackageParam
adds theisOnFailureThrowToApp
parameter, which can directly throw the exception that occurs in the lifecycle method body to the host- Modify
appClassLoader
inPackageParam
to be a modifiable variable, which can dynamically set theClassLoader
used by the host in the Hook process- Added
dataExtra
function inHookParam
, which can be used to temporarily store the data in the Hook method body- Obsolete
,isRunInNewXShareMode
inisXSharePrefsReadable
YukiHookModulePrefs
, merged intoisPreferencesAvailable
Class.allFields
,Class.allMethods
and other related methods add theisAccessible
parameter, which can control when the member object can be set as an accessible type- Fixed the problem that only the last method body will be called back when receiving the same key-value data in an Activity when there are multiple hosts in
YukiHookDataChannel
- Added
priority
parameter inwait
and other related methods ofYukiHookDataChannel
, you can pass inChannelPriority
to customize the conditions for callback data resultsYukiHookDataChannel
adds the function of automatically usingChannelDataWrapper
type wrapper when sending data, which improves the user experience and enhances data protectionYukiHookDataChannel
has added the function of limiting the maximum byte size of data sent at one time to prevent the app from crashing due to excessive dataYukiHookDataChannel
has added the function of automatically segmenting when the sent data is too large, only supportsList
,Map
,Set
,String
typesYukiHookLogger
adds thecontents
method and thedata
parameter ofsaveToFile
, which can be passed in custom debug log data for formatting or saving to a file- Fixed the problem that the debug log data package name processed by
YukiHookLogger
may be incorrect in the (Xposed) Host environment- Fixed the problem that the package name may be incorrect on some systems (in some system apps) when the Xposed Module loads the Resource Hook event
outdate
1.1.4 | 2022.10.04
- Fixed the issue that
YukiHookDataChannel
may not respond to broadcast events in the system framework, reproduced in A13- Fixed the issue that
YukiHookDataChannel
could not communicate with Module App in Host App for multiple versions- Added
obtainLoggerInMemoryData
method inYukiHookDataChannel
to share debug log data between module and host- Modify the type of
YukiHookLogger.inMemoryData
toArrayList
and changeYukiLoggerData
todata class
- Fixed
YukiLoggerData
printing blank when the package name is empty in the module- Added
loadApp
,loadZygote
,loadSystem
,withProcess
multi-parameter methods of the same name inPackageParam
- Fixed some possible bugs
outdate
1.1.3 | 2022.09.30
- Fixed a fatal bug where the Hook entry class name could not be customized
- Added some code notes in
LoggerFactory
and updated special features documentationoutdate
1.1.2 | 2022.09.30
- Documentation Basic Knowledge page add a friend link to the English version
- Fixed
YukiBaseHooker
comments in English code note link errors- Fixed
ClassCastException
inModuleClassLoader
- Fixed and standardize some code notes
- Added
ModuleClassLoader
exclusion list function, you can useexcludeHostClasses
andexcludeModuleClasses
methods to customize the exclusion list- Added
YukiLoggerData
real-time log data class, you can get the log array in real time throughYukiHookLogger.inMemoryData
- Added
ClassLoader.listOfClasses
method, which can directly get allClass
in the currentDex
outdate
1.1.1 | 2022.09.28
- Fixed the problem of wrong document friend links in Basic Knowledge page
- Fixed document
favicon
not showing up- Fixed bug in
DexClassFinder
search conditionsoutdate
1.1.0 | 2022.09.28
- This is a major version update, please refer to API Document and Special Features for the changes and usage mentioned in the changelog
- Change the help documentation framework to VuePress
- Unify and standardize the terms and nouns in the document, for example, "query" is always changed to "find",
XposedHelper
is misspelled and changed toXposedHelpers
- Documentation Basic Knowledge page to add friend links, Simplified Chinese only
- Convert
Class
andMethod
of Hook App Demo to Java to provide better demo effect- Fixed code comment naming in Hook Module Demo
- Refactored a lot of low-level Hook logic and the docking method of Xposed API
- Removed
HookParamWrapper
, it now interfaces directly withYukiBridgeFactory
- Moved methods in section
YukiHookBridge
toAppParasitics
- Removed
HookParam.args
and the underlying direct connection methodsetArgs
, directly get and set the object of the current array- Optimized automatic handler to merge referenced
jar
intostub
project- Fixed the problem that the module package name cannot be correctly matched when multi-project packaging, and modify the module package name matching logic of the automatic handler, thanks to 5ec1cff for the feedback and solutions provided
- Internal closure processing for the methods of API private tool classes to avoid polluting the top-level namespace
- Fixed
Creater
naming toCreator
for all reflection and Hook classes- Added
YukiHookAPI.Status.compiledTimestamp
function, which can get the compilation completion timestamp when used as an Xposed module- Added
YukiHookAPI.Status.isXposedEnvironment
function, which can determine whether the current (Xposed) host environment or module environment is- The debug logging function has been overhauled, and functions such as
YukiHookAPI.Configs.debugTag
have been merged intoYukiHookLogger.Configs
- The debug log can be added to specify the printing method as
XposedBridge.log
orLogd
- The package name of the current host and the current user ID are added to the debug log by default for debugging, you can change it yourself in the
debugLog
configuration- Added
generic
function to reflect and call generics, you can use it inClass
orCurrentClass
- obsolete the
buildOfAny
method, now use thebuildOf
method directly (without generics) to use the constructor to create a new object and get the resultAny
- Fixed the issue of null pointer exception when using
hasExtends
CurrentClass
added non-lambda method of callingCurrentClass
addsname
andsimpleName
functions- Completely rewrite the core method of
ReflectionTool
, sorting and classifying different search conditions- Fixed the problem that
Member
obtained by directly callingdeclared
inReflectionTool
throws an exception- Fixed
UndefinedType
inReflectionTool
is not correctly judged inMethod
andConstructor
conditions- Added a friendly prompt method when the reflection search result is abnormal, which can specifically locate the problem that
Member
cannot be found under specified conditions- Added
VagueType
condition inMethod
andConstructor
for reflection search, which can be used inparam
condition to ignore parameters you don't want to fill in- Added
paramCount { ... }
condition inMethod
andConstructor
of reflection search, now you can directly getit
in it to customize your judgment condition- The
current
method is added to theFieldFinder
result, which can directly create a call space for the result instance- Modified the
modifiers
condition andname
condition in the reflection lookup function, now you need to return aBoolean
at the end of the method body to make the condition trueas*
function inModifierRules
renamed tois*
, thanks to Kitsune suggestion- Added
RemedyPlan
feature inFieldFinder
- Added
Class
fuzzy search function (Beta) inDex
, you can now directly usesearchClass
function to fuzzy searchClass
with specified conditions- Added multiple search function in reflection search, you can use relative search conditions to obtain multiple search results at the same time, thanks to AA and Kitsune for suggestions
- Fixed the problem that the object obtained by
appClassLoader
is incorrect in system applications in some systems, thanks to Luckyzyx for the feedback- Modified the calling method of
XposedBridge.invokeOriginalMethod
and addedoriginal
function inMethodFinder.Result.Instance
- Fixed the problem of wrong value of
getStringSet
method inYukiHookModulePrefs
and optimize the code style, thanks to Teddy_Zhu PR- Modify
YukiHookModulePrefs
to intercept exceptions that may not exist inXSharePreference
- Fixed the problem that
YukiHookDataChannel
could not be successfully registered in some third-party ROM system frameworks- Secured
YukiHookDataChannel
, now it can only communicate between modules from the specified package name and the host- Added automatic hook
SharedPreferences
to fix the problem that file permissions are not0664
in some systems, thanks to 5ec1cff for the feedback and implementation code provided- Added
YukiHookAPI.Configs.isEnableHookSharedPreferences
function, which is disabled by default and can be enabled if the permission ofSharedPreferences
is incorrect- Fixed the bug that the no-parameter construction method cannot be found when searching for
Constructor
without filling in the search conditions, thanks B5 KAKA for the feedback- Detach
Result
instances located inmethod
,constructor
ininjectMember
toProcess
- Added the
useDangerousOperation
method in the Hook process, which will automatically stop the Hook and print an error after the function in the Hook Dangerous List is not declared- Added module resource injection and
Activity
proxy functions, you can callinjectModuleAppResources
andregisterModuleAppActivities
to use- Added
ModuleContextThemeWrapper
function, you can callapplyModuleTheme
to create theContext
of a module in anyActivity
- Added
ClassLoader.onLoadClass
function, which can be used to listen for events when theloadClass
method ofClassLoader
is called- obsolete
classOf
andclazz
extension methods, addtoClass
andtoClassOrNull
usage, please move to the new method nowVariousClass
adds agetOrNull
method, which can returnnull
instead of throwing an exception when it can't matchClass
- Removed
isUseAppClassLoader
parameter inPackageParam.hook
, changed it toisForceUseAbsolute
and automatically matched the targetClass
PackageParam
addssystemContext
function, you can call this function at any time to get a persistentContext
- no longer expose any methods in
HookClass
- Added
throwToApp
function inHookParam
, which can throw exceptions directly to the host- The
onFailureThrowToApp
function is added to the Hook callback, which can be directly thrown to the host when an exception occurs- Modified the printing logic of the debug log, the time-consuming records in the reflection search function will only be printed during the Hook process
- Added the function of removing Hook in the Hook process, you can use the
remove
andremoveSelf
methods to remove the hook- Fixed the issue that caused the host to throw an exception when ReplaceHook failed, and now it is modified to call the original method to ensure the normal operation of the host function
- Added the function of checking the return value of the method in the Hook process. If the return value does not match, it will automatically throw an exception or print an error according to the situation
- Added
array
type to Resources Hook, thanks to PR of GSWXXN- Moved
me.weishu.reflection
tothirdparty
to prevent conflicting dependencies of the same name introduced at the same time- Remove the exception thrown when the Hook method body is empty, and modify it to print the warning log
- Modify the exception handling logic of
AppLifecycle
and throw it directly to the host when an exception occurs- Updated Demo API version to 33
outdate
1.0.92 | 2022.05.31
- Fixed the naming method of callback in a large number of methods
- Changed the solution to fix the problem that
YukiHookDataChannel
cannot call back the currentActivity
broadcast on devices lower than Android 12- The
InjectYukiHookWithXposed
annotation adds theisUsingResourcesHook
function, now you can selectively disable the dependency interface that automatically generatesIXposedHookInitPackageResources
outdate
1.0.91 | 2022.05.29
- Fixed the
ClassLoader
error when the customized system of some devices is booted in the LSPosed environment, thanks to Luckyzyx for the feedback- Fixed
YukiHookDataChannel
not being able to call back the currentActivity
broadcast on ZUI and systems below Android 12- Integrate the
YukiHookModuleStatus
function intoYukiHookAPI.Status
, rewrite a lot of methods, now you can judge the status information such as module activation in the module and the host in both directionsoutdate
1.0.90 | 2022.05.27
- Fixed
YukiHookDataChannel
crashing when the module sets the listener callback- Fixed
YukiHookDataChannel
still calling back when not in currentActivity
- Remove the default value of
YukiHookDataChannel
callback event, no callback- Removed
YukiHookModulePrefs
warning printed if XShare is unreadable- Added the
isXSharePrefsReadable
method inYukiHookModulePrefs
to determine whether the current XShare is availableoutdate
1.0.89 | 2022.05.26
- Fixed the problem that
YukiHookDataChannel
cannot be repeatedly set to monitor, and added the function of repeating response in differentActivity
modules and automatically followingActivity
to destroy the monitor function- Added
YukiHookDataChannel
repeated listening use case description document- Add the
onAlreadyHooked
method to determine whether the current method is repeated Hook- Modify part of the logic of repeatedly adding HashMap, remove the
putIfAbsent
method, allow to override the addition- Fixed several possible bugs
outdate
1.0.88 | 2022.05.25
- Fully decoupled from Xposed API
- Added
android
type intype
- Separate
YukiHookModuleStatus
from auto-generated code and addisEnableHookModuleStatus
switch, it is up to you to enable or not- Internal closure processing for the constructors of a large number of classes in the API
- Set
YukiHookModulePrefs
to run as a singleton to prevent repeated creation and waste of system resources- Fixed the bug that Hook cannot be nested since version
1.0.80
, and optimize the related functions of nested Hook- Modify the Hooker storage scheme from HashSet to HashMap to prevent the problem of repeatedly adding Hookers
- Modify the core implementation method of Hook, add duplicate checking to avoid repeating the Hook multiple callbacks to the
HookParam
methodMethodFinder
andFieldFinder
add the function of finding fuzzy methods and variable names, you can callname { ... }
to set search conditions, and support regular expressions- Optimize and modify the way to get
appContext
to reduce the possibility of getting empty- Modify the print
TAG
oflogger
in the automatically generated code to default to your custom name, which is convenient for debugging- Optimize the
Hooker
implementation ofYukiHookBridge
to improve Hook performancePackageParam
adds theonAppLifecycle
method, which can natively monitor the life cycle of the host and implement the registration system broadcast function- Added
YukiHookDataChannel
function to communicate using system out-of-order broadcast while the module and the host remain aliveYukiHookDataChannel
adds thecheckingVersionEquals
method, which can be monitored to verify that the host has not updated the version mismatch problem after the module is updated- Added Java version example in the example code of
demo-module
for reference onlyoutdate
1.0.87 | 2022.05.10
- Added
refreshModuleAppResources
function to adapt Resources refresh when the language region, font size, resolution changes, etc.- Added
isEnableModuleAppResourcesCache
function, you can set whether to automatically cache the resources of the current moduleoutdate
1.0.86 | 2022.05.06
- Fixed the problem of continuous error reporting during
initZygote
when Resources Hook is not supported, reproduced in ZUI/LSPosed CI(1.8.3-6550)- Optimize and handle exceptions for Resources Hook, only print errors and warnings if they are used and not supported
outdate
1.0.85 | 2022.05.04
- Fixed a serious problem of not being able to hook the system framework, since
1.0.80
- Added in the debug log to distinguish the package name loaded by
initZygote
asandroid-zygote
,packageName
keepsandroid
unchangedoutdate
1.0.83 | 2022.05.04
- Fixed
YukiHookModuleStatus
reporting a lot of errors afterloadSystem
- Added
android
type intype
- Updated example descriptions in help documentation
outdate
1.0.82 | 2022.05.04
- Fixed a concept confusion error, distinguishing the relationship between
initZygote
and the system framework, there are problems with the previous comments and documentation, I am very sorryPackageParam
addsloadSystem
method, no need to writeloadApp(name = "android")
to hook the system frameworkoutdate
1.0.81 | 2022.05.04
- Fixed the problem that the method and constructor that cannot be found in the Hook method body still output the error log after setting the condition using the
by
method- Added a global log to display the package name of the current Hook APP during the execution of the Hook, and fixed a problem with the printing style of the error log
outdate
1.0.80 | 2022.05.01
- The
InjectYukiHookWithXposed
annotation adds theentryClassName
function, which can customize the generatedxposed_init
entry class namerenamed toYukiHookXposedInitProxy
IYukiHookXposedInit
, the original interface name has been invalidated and will be deleted directly in subsequent versions- Added
initZygote
and Resources Hook functions to support Hook Layout- Added
onXposedEvent
method to listen to all events of native Xposed API- Perform
inline
processing on the lambda of the Hook function to avoid generating excessively broken anonymous classes and improve the running performance after compilation- Fixed
PrefsData
compiled method body copy is too large- Added
XSharePreference
readability test, which will automatically print a warning log if it failsPackageParam
addsappResources
,moduleAppResources
,moduleAppFilePath
functionsloadApp
ofPackageParam
adds the function of not writingname
, and all APPs are filtered by defaultPackageParam
adds theloadZygote
method, which can directly hook the system frameworkPackageParam
addedresources().hook
function- Optimization method, construction method, variable search function, the error log that cannot be found will display the set query conditions first
- Added
hasExtends
extension method to determine whether the currentClass
has an inheritance relationship- Added
isSupportResourcesHook
function to determine whether resource hooks are currently supported (Resources Hook)current
function addssuperClass
method to call superclass- New
superClass
query conditions for search methods, construction methods and variables, you can continue to search in the parent classYukiHookAPI
lots of methods are decoupled from Xposed API- Added native Hook priority function of Xposed API
- Fixed the problem that
isFirstApplication
may be inaccurate- Block the problem that MiuiCatcherPatch repeatedly calls the Hook entry method on the MIUI system
- Optimize Hook entry calling method to avoid multiple calls due to Hook Framework issues
- Fixed the problem that Hook
ClassLoader
causes Hook to freeze, thanks to WankkoRee for the feedback- Improve the performance after the
XC_Callback
interface is connected- Java
type
addedClassLoader
type- Optimize the API help documentation, fix the problem that the page may be continuously cached
outdate
1.0.78 | 2022.04.18
YukiHookModulePrefs
addsisRunInNewXShareMode
method, which can be used to determine whether the module is currently inNew XSharePreference
mode- Fixed
YukiHookModulePrefs
working inNew XSharePreference
mode- Added
ModulePreferenceFragment
, now you can completely replacePreferenceFragmentCompat
and start using the new functionality- Adapt the Sp data storage solution of
PreferenceFragmentCompat
, thanks to mahoshojoHCG for feedback- Update autohandlers and Kotlin dependencies to the latest version
- Fixed some bugs in documentation and code comments
outdate
1.0.77 | 2022.04.15
YukiHookModulePrefs
addedclear
method, thanks to WankkoRee for the suggestionYukiHookModulePrefs
addedgetStringSet
,putStringSet
,all
methods- Added
any
method toargs
ofHookParam
- Added
ModuleApplication
, which can be inherited in modules to achieve more functions- Connect all
findClass
functions to the Xposed API, and continue to use nativeClassLoader
in non-hosted environments- Fixed some possible bugs
outdate
1.0.75 | 2022.04.13
- Corrected the logic recognition part of the automatic handler, thanks to ApeaSuperz contribution
- Fixed an issue where the reference to a doc comment was not changed
firstArgs
andlastArgs
methods have been removed fromHookParam
, now you can useargs().first()
andargs().last()
instead of it- Removed default parameter
index = 0
inargs()
inHookParam
, now you can useargs().first()
orargs(index = 0)
to replace it- The
result
function inHookParam
adds generic matching, now you can useresult<T>
to match the known return value type of your target method- The
emptyParam
condition is added to the method and constructor query function, and the misunderstanding of the query condition that needs to be paid attention to in the document has been improved- Added
android
type intype
outdate
1.0.73 | 2022.04.10
- Fixed some Chinese translation errors in documents, thanks to WankkoRee for their contributions
- Fixed the problem that
XC_LoadPackage.LoadPackageParam
throws an exception when the content is empty in some cases, thanks to Luckyzyx for the feedback- Fixed some known bugs and improve Hook stability
outdate
1.0.72 | 2022.04.09
- Update API documentation to new address
- Add
appContext
function toPackageParam
- Fixed some known bugs and improve Hook stability
outdate
1.0.71 | 2022.04.04
- Fixed a serious issue that would stop the Hook from throwing an exception when VariousClass could not be matched
outdate
1.0.70 | 2022.04.04
- Fixed
instanceClass
reporting an error after being called in a static instance- Add
isUseAppClassLoader
function in Hook process, thanks to WankkoRee for feedback- Added the
withProcess
function, which can be hooked according to the currently specified process of the APP- Fixed critical logic errors in lookup methods, constructor classes and variables
- Fixed the problem that the abnormal output cannot be ignored when the Hook target class does not exist
- Fixed the problem that the Hook could not take effect due to the fast loading of the APP startup method in some cases
- Fixed
allMethods
not throwing an exception when it is not hooked to a method, thanks to WankkoRee for the feedback- Added Hook status monitoring function, thanks to WankkoRee for the suggestion
- Modify the way the Xposed entry is injected into the class, and redefine the definition domain of the API
- Added obfuscated method and variable lookup function, you can use different types of filter
index
to locate the specified method and variable, thanks to WankkoRee for the ideas provided- When looking for methods and variables, multiple types are allowed, such as the class name declared by
String
andVariousClass
- Add a new
current
function, which can build a reflection method operation space for any class, and easily call and modify the methods and variables in it- Fixed a lot of bugs in the hook process, thanks to WankkoRee for contributing to this project
outdate
1.0.69 | 2022.03.30
- Added and improved annotations for some method functions
- Added more example Hook content in Demo
- Fixed the issue that only the last one takes effect when
allMethods
is used multiple times in a Hook instance, thanks to WankkoRee for the feedbackoutdate
1.0.68 | 2022.03.29
- Added new use case and LSPosed scope in Demo
- Added
Member
lookup cache and lookup cache configuration switches- Removed and modified
MethodFinder
,FieldFinder
andHookParam
related method calls- Add more
cast
types inFinder
and supportcast
as array- Overall performance and stability improvements
- Fixed bugs that may exist in the previous version
outdate
1.0.67 | 2022.03.27
- Added three
modifiers
functions inFinder
, which can filterstatic
,native
,public
,abstract
and many other description types- When searching for methods and constructors, the method parameter type can be blurred to a specified number for searching
- Added
hasModifiers
extension forMember
- Added
give
method inMethodFinder
andConstructorFinder
to get primitive types- Added
PrefsData
template function inYukiHookModulePrefs
- Completely refactored method, constructor and variable lookup scheme
- Optimized code comments and fixed possible bugs
outdate
1.0.66 | 2022.03.25
- Fixed a serious bug in
MethodFinder
- Added
args
call method inhookParam
- Fixed other possible problems and fix some class annotation problems
outdate
1.0.65 | 2022.03.25
- Republished version to fix the incorrect new version of the Maven repository due to cache issues
- Added
MethodFinder
andFieldFinder
new return value calling methods- Fixed possible problems and fix possible problems during the use of Tai Chi
- Fixed possible problems with auto-generated Xposed entry classes
- Added
android
type and Java type intype
outdate
1.0.6 | 2022.03.20
- Fixed
YukiHookModulePrefs
being ignored every time after usingdirect
once to ignore cache- Added new API, abolished the traditional usage of
isActive
to judge module activation- Fixed the issue of printing debug logs when using the API in a non-Xposed environment
- Fixed log output issue and unintercepted exception issue when looking for
Field
- Decoupling Xposed API in
ReflectionUtils
- Added
YukiHookModuleStatus
method name confusion to reduce the size of module generation- The welcome message will no longer be printed when loading the module's own Hook
- Fixed some bugs that still exist in the previous version
outdate
1.0.55 | 2022.03.18
- Fixed an annotation error
- Temporarily fix a bug
- Added a large number of
android
types intype
and a small number of Java types- Fixed compatibility issues between new and old Kotlin APIs
outdate
1.0.5 | 2022.03.18
- Fixed the problem that the welcome message was printed multiple times in the case of the old version of the LSPosed framework
- Added
onInit
method to configureYukiHookAPI
- Added
executorName
andexecutorVersion
to get the name and version number of the current hook framework- Added
by
method to set the timing and condition of HookYukiHookModulePrefs
adds a controllable key-value cache, which can dynamically update data when the host is running- Fixed some possible bugs
outdate
1.0.4 | 2022.03.06
- Fixed LSPosed cannot find
XposedBridge
after enabling "Only module classloader can use Xposed API" option in latest version- Added constant version name and version number for
YukiHookAPI
- Added
hasField
method andisAllowPrintingLogs
configuration parameter- Added
isDebug
to enable the API to automatically print the welcome message to test whether the module is validoutdate
1.0.3 | 2022.03.02
- Fixed a potential exception not intercepted BUG
- Added
ignoredError
function- Added
android
type intype
- Added
ClassNotFound
function after listening tohook
outdate
1.0.2 | 2022.02.18
- Fixed the problem that the project path cannot be found under Windows
- Remove part of reflection API, merge into
BaseFinder
for integration- Add a method to create Hook directly using string
outdate
1.0.1 | 2022.02.15
RemedyPlan
addsonFind
function- Integrate and modify some reflection API code
- Added Java type in
type
- Fixed the issue that ignored errors still output in the console
outdate
1.0 | 2022.02.14
- The first version is submitted to Maven
Contact Us | Yuki Hook API + + + + + ++ + + diff --git a/en/about/future.html b/en/about/future.html new file mode 100644 index 00000000..20587f97 --- /dev/null +++ b/en/about/future.html @@ -0,0 +1,34 @@ + + + + + + + + +Yuki Hook API
Contact Us
If you have any questions during usage, or have any constructive suggestions, you can contact us.
Join our developers group.
Find me on Twitter @fankesyooni.
Help with Maintenance
Thank you for choosing and using
YukiHookAPI
.If you have code-related suggestions and requests, you can submit a Pull Request on GitHub.
Looking Toward the Future | Yuki Hook API + + + + + ++ + + diff --git a/en/api/home.html b/en/api/home.html new file mode 100644 index 00000000..557cd522 --- /dev/null +++ b/en/api/home.html @@ -0,0 +1,34 @@ + + + + + + + + +Yuki Hook API
Looking Toward the Future
The future is bright and uncertain, let us look forward to the future development space of
YukiHookAPI
.Unresolved Issues
Here are the unresolved issues with
YukiHookAPI
.YukiHookPrefsBridge
Currently only supports LSPosed perfectly, other Xposed Framework need to downgrade the module target api.
TaiChi may not be supported at all, and TaiChi needs a lower target api to adapt on high-version systems.
Some Xposed Module developers currently choose the Hook target app self's SharedPreferences storage solution to solve the module settings sharing problem.
In the later period, the permissions of the Android system will become more and more strict, and
selinux
is a big problem currently facing, which needs to be discussed and studied.Updated on 2023.10.06
LSPosed has now experimentally launched Modern Xposed API, which uses Service to communicate with modules, which will solve the problem of module data storage.
In order to ensure the compatibility of most modules, YukiHookAPI plans to use a customized ContentProvider to realize data exchange between the Module App and the Host App in the future, so stay tuned.
Future Plans
Features that
YukiHookAPI
may add later are included here.Lite Version Supported for Standalone Use
If you like the Reflection API of
YukiHookAPI
, but your project may not need related Hook functions.Well here is some good news for you:
The core Reflection API ofYukiHookAPI
has been decoupled into YukiReflection project, which can now be used in any Android project.The
YukiReflection
project has been deprecated due to many unsolved black box issues, so we no longer recommend anyone to use it. Please now migrate to the brand new design KavaRef.To be Discussed
At present, the API only supports binding to xposed_init through the automatic builder.
If you don't like the automatic builder, you must implement the module loading entry yourself.
In the future, the Lite version with only API functions will be launched according to the number of people required.
You can submit issues with us.
We have provided the Xposed native API listening interface, you can find or view the implementation method of the Demo here.
Milestone Plan
The plans below have been published in
issues
on GitHub, and you can view the progress of each project.All functions are expected to be completed in
2.0.0
version, so stay tuned.Document Introduce | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/YukiHookAPI.html b/en/api/public/com/highcapable/yukihookapi/YukiHookAPI.html new file mode 100644 index 00000000..2407f1cf --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/YukiHookAPI.html @@ -0,0 +1,126 @@ + + + + + + + + +Yuki Hook API
Document Introduce
The document here will synchronize the relevant usage of the latest API version, please keep
YukiHookAPI
as the latest version to use the latest version of the function.Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
. If you encounter unsolvable problems, you can contact us via Contact Us.Function Description
The function description mainly introduces the related usage and purpose of the current API.
Function Example Description
The function examples mainly show the basic usage examples of the current API for reference.
Change Record Description
The function of the first version will be marked as
v<version>
first
;New function added later will be marked as
v<version>
added
;Later modified function will be appended as
v<version>
modified
;Later deprecated function will be marked as
v<version>
deprecated
and strikethrough;Later removed function will be marked as
v<version>
removed
and strikethrough.Related Symbols Description
kt Kotlin Static File
annotation Annotation Class
interface Interface Class
object Class (Singleton)
class Class
field Field or
get
/set
method or read-onlyget
methodmethod Method
enum Enum constant
ext-field Extension field (global)
ext-method Extension method (global)
i-ext-field Extension field (internal)
i-ext-method Extension method (internal)
YukiHookAPI - object | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/annotation/xposed/InjectYukiHookWithXposed.html b/en/api/public/com/highcapable/yukihookapi/annotation/xposed/InjectYukiHookWithXposed.html new file mode 100644 index 00000000..2013bbbe --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/annotation/xposed/InjectYukiHookWithXposed.html @@ -0,0 +1,41 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- object
YukiHookAPIobject YukiHookAPI +
Change Records
v1.0
first
Function Illustrate
这是
YukiHookAPI
的 API 调用总类,Hook 相关功能的开始、Hook 相关功能的配置都在这里。- field
TAGconst val TAG: String +
Change Records
v1.2.0
added
Function Illustrate
获取当前
YukiHookAPI
的名称 (标签)。- field
VERSIONconst val VERSION: String +
Change Records
v1.2.0
added
Function Illustrate
获取当前
YukiHookAPI
的版本。API_VERSION_NAME - field
Change Records
v1.0.4
added
v1.2.0
deprecated
不再区分版本名称和版本号,请迁移到
VERSION
API_VERSION_CODE - field
Change Records
v1.0.4
added
v1.2.0
deprecated
不再区分版本名称和版本号,请迁移到
VERSION
executorName - field
Change Records
v1.0.5
added
v1.0.91
removed
请迁移到
Status.Executor.name
executorVersion - field
Change Records
v1.0.5
added
v1.0.91
removed
请迁移到
Status.Executor.apiLevel
、Status.Executor.versionName
、Status.Executor.versionCode
- object
Statusobject Status +
Change Records
v1.0.91
added
Function Illustrate
当前
YukiHookAPI
的状态。- field
compiledTimestampval compiledTimestamp: Long +
Change Records
v1.1.0
added
Function Illustrate
获取项目编译完成的时间戳 (当前本地时间)。
- field
isXposedEnvironmentval isXposedEnvironment: Boolean +
Change Records
v1.1.0
added
Function Illustrate
获取当前是否为 (Xposed) 宿主环境。
executorName - field
Change Records
v1.0.91
added
v1.1.5
deprecated
请迁移到
Executor.name
executorVersion - field
Change Records
v1.0.91
added
v1.1.5
deprecated
请迁移到
Executor.apiLevel
、Executor.versionName
、Executor.versionCode
- field
isModuleActiveval isModuleActive: Boolean +
Change Records
v1.0.91
added
Function Illustrate
判断模块是否在 Xposed 或太极、无极中激活。
Notice
在模块环境中你需要将 Application 继承于 ModuleApplication。
在模块环境中需要启用 InjectYukiHookWithXposed.isUsingXposedModuleStatus。
在 (Xposed) 宿主环境中仅返回非 isTaiChiModuleActive 的激活状态。
- field
isXposedModuleActiveval isXposedModuleActive: Boolean +
Change Records
v1.0.91
added
Function Illustrate
仅判断模块是否在 Xposed 中激活。
Notice
在模块环境中需要启用 InjectYukiHookWithXposed.isUsingXposedModuleStatus。
在 (Xposed) 宿主环境中始终返回 true。
- field
isTaiChiModuleActiveval isTaiChiModuleActive: Boolean +
Change Records
v1.0.91
added
Function Illustrate
仅判断模块是否在太极、无极中激活。
Notice
在模块环境中你需要将 Application 继承于 ModuleApplication。
在 (Xposed) 宿主环境中始终返回 false。
- field
isSupportResourcesHookval isSupportResourcesHook: Boolean +
Change Records
v1.0.91
added
Function Illustrate
判断当前 Hook Framework 是否支持资源钩子 (Resources Hook)。
Notice
在模块环境中需要启用 InjectYukiHookWithXposed.isUsingXposedModuleStatus。
在 (Xposed) 宿主环境中可能会延迟等待事件回调后才会返回 true。
请注意你需要确保 InjectYukiHookWithXposed.isUsingResourcesHook 已启用,否则始终返回 false。
- object
Executorobject Executor +
Change Records
v1.1.5
added
Function Illustrate
当前
YukiHookAPI
使用的 Hook Framework 相关信息。- field
nameval name: String +
Change Records
v1.1.5
added
Function Illustrate
获取当前 Hook Framework 名称。
Notice
在模块环境中需要启用 InjectYukiHookWithXposed.isUsingXposedModuleStatus。
- field
typeval type: ExecutorType +
Change Records
v1.1.9
added
Function Illustrate
获取当前 Hook Framework 类型。
Notice
在模块环境中需要启用 InjectYukiHookWithXposed.isUsingXposedModuleStatus。
- field
apiLevelval apiLevel: Int +
Change Records
v1.1.5
added
Function Illustrate
获取当前 Hook Framework 的 API 版本。
Notice
在模块环境中需要启用 InjectYukiHookWithXposed.isUsingXposedModuleStatus。
- field
versionNameval versionName: String +
Change Records
v1.1.5
added
Function Illustrate
获取当前 Hook Framework 版本名称。
Notice
在模块环境中需要启用 InjectYukiHookWithXposed.isUsingXposedModuleStatus。
- field
versionCodeval versionCode: Int +
Change Records
v1.1.5
added
Function Illustrate
获取当前 Hook Framework 版本号。
Notice
在模块环境中需要启用 InjectYukiHookWithXposed.isUsingXposedModuleStatus。
- object
Configsobject Configs +
Change Records
v1.0
first
Function Illustrate
对 API 相关功能的配置类。
- method
debugLoginline fun debugLog(initiate: YLog.Configs.() -> Unit) +
Change Records
v1.1.0
added
Function Illustrate
配置
YLog.Configs
相关参数。debugTag - field
Change Records
v1.0
first
v1.1.0
deprecated
请迁移到
YLog.Configs.tag
- field
isDebugvar isDebug: Boolean +
Change Records
v1.0
first
Function Illustrate
是否启用 Debug 模式。
默认不启用,启用后模块将会向
Logcat
和 (Xposed) 宿主环境中的日志功能打印详细的 Hook 日志,关闭后仅会打印E
级别的日志。isAllowPrintingLogs - field
Change Records
v1.0.4
added
v1.1.0
deprecated
请迁移到
YLog.Configs.isEnable
isEnableModulePrefsCache - field
Change Records
v1.0.5
added
v1.1.9
deprecated
请迁移到
isEnablePrefsBridgeCache
isEnablePrefsBridgeCache - field
Change Records
v1.1.9
added
v1.1.11
deprecated
键值的直接缓存功能已被移除,因为其存在内存溢出 (OOM) 问题
- field
isEnableModuleAppResourcesCachevar isEnableModuleAppResourcesCache: Boolean +
Change Records
v1.0.87
added
Function Illustrate
是否启用当前 Xposed 模块自身
Resources
缓存功能。为防止内存复用过高问题,此功能默认启用。
你可以手动调用
PackageParam.refreshModuleAppResources
来刷新缓存。Notice
关闭后每次使用 PackageParam.moduleAppResources 都会重新创建,可能会造成运行缓慢。
isEnableHookModuleStatus - field
变更记录
v1.0.88
added
v1.2.0
deprecated
请手动迁移到
InjectYukiHookWithXposed.isUsingXposedModuleStatus
- field
isEnableHookSharedPreferencesvar isEnableHookSharedPreferences: Boolean +
Change Records
v1.1.0
added
Function Illustrate
是否启用 Hook
SharedPreferences
。启用后将在模块启动时强制将
SharedPreferences
文件权限调整为Context.MODE_WORLD_READABLE
(0664)。Notice
这是一个可选的实验性功能,此功能默认不启用。
仅用于修复某些系统可能会出现在启用了 New XSharedPreferences 后依然出现文件权限错误问题,若你能正常使用 YukiHookPrefsBridge 就不建议启用此功能。
- field
isEnableDataChannelvar isEnableDataChannel: Boolean +
Change Records
v1.0.88
added
Function Illustrate
是否启用当前 Xposed 模块与宿主交互的
YukiHookDataChannel
功能。请确保 Xposed 模块的
Application
继承于ModuleApplication
才能有效。此功能默认启用,关闭后将不会在功能初始化的时候装载
YukiHookDataChannel
。isEnableMemberCache - field
Change Records
v1.0.68
added
v1.1.11
deprecated
Member
的直接缓存功能已被移除,因为其存在内存溢出 (OOM) 问题- method
configsinline fun configs(initiate: Configs.() -> Unit) +
Change Records
v1.0
first
v1.0.80
modified
将方法体进行 inline
Function Illustrate
对
Configs
类实现了一个 lambda 方法体。你可以轻松地调用它进行配置。
Function Example
你可以在 Hook 入口类的
onInit
方法中调用configs
方法和debugLog
方法完成对 API 的功能配置,实时生效。The following example
object HookEntry : IYukiHookXposedInit { + + override fun onInit() { + YukiHookAPI.configs { + debugLog { + tag = "YukiHookAPI" + isEnable = true + isRecord = false + elements(TAG, PRIORITY, PACKAGE_NAME, USER_ID) + } + isDebug = BuildConfig.DEBUG + isEnableModuleAppResourcesCache = true + isEnableHookModuleStatus = true + isEnableHookSharedPreferences = false + isEnableDataChannel = true + } + } + + override fun onHook() { + // Your code here. + } +} +
若觉得上面的写法不美观,你还可以写得更加简洁。
The following example
object HookEntry : IYukiHookXposedInit { + + override fun onInit() = configs { + debugLog { + tag = "YukiHookAPI" + isEnable = true + isRecord = false + elements(TAG, PRIORITY, PACKAGE_NAME, USER_ID) + } + isDebug = BuildConfig.DEBUG + isEnableModuleAppResourcesCache = true + isEnableHookModuleStatus = true + isEnableHookSharedPreferences = false + isEnableDataChannel = true + } + + override fun onHook() { + // Your code here. + } +} +
你也可以不通过
configs
和debugLog
方法,直接进行配置。The following example
object HookEntry : IYukiHookXposedInit { + + override fun onInit() { + YLog.Configs.tag = "YukiHookAPI" + YLog.Configs.isEnable = true + YLog.Configs.isRecord = false + YLog.Configs.elements( + YLog.Configs.TAG, + YLog.Configs.PRIORITY, + YLog.Configs.PACKAGE_NAME, + YLog.Configs.USER_ID + ) + YukiHookAPI.Configs.isDebug = BuildConfig.DEBUG + YukiHookAPI.Configs.isEnableModuleAppResourcesCache = true + YukiHookAPI.InjectYukiHookWithXposed.isUsingXposedModuleStatus = true + YukiHookAPI.Configs.isEnableHookSharedPreferences = false + YukiHookAPI.Configs.isEnableDataChannel = true + } + + override fun onHook() { + // Your code here. + } +} +
- method
encasefun encase(initiate: PackageParam.() -> Unit) +
fun encase(vararg hooker: YukiBaseHooker) +
fun encase(baseContext: Context?, initiate: PackageParam.() -> Unit) +
fun encase(baseContext: Context?, vararg hooker: YukiBaseHooker) +
Change Records
v1.0
first
Function Illustrate
装载 Hook 入口的核心方法。
Function Example
详情请参考
InjectYukiHookWithXposed - annotation | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/bean/CurrentClass.html b/en/api/public/com/highcapable/yukihookapi/hook/bean/CurrentClass.html new file mode 100644 index 00000000..92cacfed --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/bean/CurrentClass.html @@ -0,0 +1,49 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- annotation
InjectYukiHookWithXposedannotation class InjectYukiHookWithXposed( + val sourcePath: String, + val modulePackageName: String, + val entryClassName: String, + val isUsingXposedModuleStatus: Boolean, + val isUsingResourcesHook: Boolean +) +
Change Records
v1.0
first
v1.0.80
modified
新增
entryClassName
参数
v1.0.92
modified
新增
isUsingResourcesHook
参数
v1.2.0
modified
新增
isUsingXposedModuleStatus
参数Function Illustrate
标识
YukiHookAPI
注入 Xposed 入口的类注解。Function Example
CurrentClass - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/bean/GenericClass.html b/en/api/public/com/highcapable/yukihookapi/hook/bean/GenericClass.html new file mode 100644 index 00000000..d3f18cc9 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/bean/GenericClass.html @@ -0,0 +1,37 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
CurrentClassclass CurrentClass internal constructor(private val classSet: Class<*>, internal val instance: Any) +
Change Records
v1.0.70
added
v1.1.0
modified
调整了构造方法的参数名称
Function Illustrate
当前实例的类操作对象。
- field
nameval name: String +
Change Records
v1.1.0
added
Function Illustrate
获得当前
classSet
的Class.getName
。- field
simpleNameval simpleName: String +
Change Records
v1.1.0
added
Function Illustrate
获得当前
classSet
的Class.getSimpleName
。- method
genericfun generic(): GenericClass? +
Change Records
v1.1.0
added
Function Illustrate
获得当前实例中的泛型父类。
如果当前实例不存在泛型将返回
null
。- method
genericinline fun generic(initiate: GenericClass.() -> Unit): GenericClass? +
Change Records
v1.1.0
added
Function Illustrate
获得当前实例中的泛型父类。
如果当前实例不存在泛型将返回
null
。- method
superClassfun superClass(): SuperClass +
Change Records
v1.0.80
added
Function Illustrate
调用父类实例。
- method
fieldinline fun field(initiate: FieldConditions): FieldFinder.Result.Instance +
Change Records
v1.0.70
added
Function Illustrate
调用当前实例中的变量。
- method
methodinline fun method(initiate: MethodConditions): MethodFinder.Result.Instance +
Change Records
v1.0.70
added
Function Illustrate
调用当前实例中的方法。
- class
SuperClassinner class SuperClass internal constructor(private val superClassSet: Class<*>) +
Change Records
v1.0.80
added
v1.1.0
modified
新增
superClassSet
参数Function Illustrate
当前类的父类实例的类操作对象。
- field
nameval name: String +
Change Records
v1.1.0
added
Function Illustrate
获得当前
classSet
中父类的Class.getName
。- field
simpleNameval simpleName: String +
Change Records
v1.1.0
added
Function Illustrate
获得当前
classSet
中父类的Class.getSimpleName
。- method
genericfun generic(): GenericClass? +
Change Records
v1.1.0
added
Function Illustrate
获得当前实例父类中的泛型父类。
如果当前实例不存在泛型将返回
null
。- method
genericinline fun generic(initiate: GenericClass.() -> Unit): GenericClass? +
Change Records
v1.1.0
added
Function Illustrate
获得当前实例父类中的泛型父类。
如果当前实例不存在泛型将返回
null
。- method
fieldinline fun field(initiate: FieldConditions): FieldFinder.Result.Instance +
Change Records
v1.0.80
added
Function Illustrate
调用父类实例中的变量。
- method
methodinline fun method(initiate: MethodConditions): MethodFinder.Result.Instance +
Change Records
v1.0.80
added
Function Illustrate
调用父类实例中的方法。
GenericClass - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/bean/HookClass.html b/en/api/public/com/highcapable/yukihookapi/hook/bean/HookClass.html new file mode 100644 index 00000000..1d003330 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/bean/HookClass.html @@ -0,0 +1,35 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
GenericClassclass GenericClass internal constructor(private val type: ParameterizedType) +
Change Records
v1.1.0
added
Function Illustrate
当前
Class
的泛型父类操作对象。- method
argumentfun argument(index: Int): Class<*>? +
inline fun <reified T> argument(index: Int): Class<T>? +
Change Records
v1.1.0
added
v1.1.5
modified
新增泛型返回值
Class<T>
方法
v1.2.0
modified
方法的返回值可为
null
Function Illustrate
获得泛型参数数组下标的
Class
实例。Notice
在运行时局部变量的泛型会被擦除,获取不到时将会返回 null。
HookClass - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/bean/HookResources.html b/en/api/public/com/highcapable/yukihookapi/hook/bean/HookResources.html new file mode 100644 index 00000000..b6372809 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/bean/HookResources.html @@ -0,0 +1,35 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
HookClassclass HookClass internal constructor(internal var instance: Class<*>?, internal var name: String, internal var throwable: Throwable?) +
Change Records
v1.0
first
v1.1.0
modified
HookClass
相关功能不再对外开放Function Illustrate
创建一个当前 Hook 的
Class
接管类。
instance
为实例,name
为实例完整包名,throwable
为找不到实例的时候抛出的异常。HookResources - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/bean/VariousClass.html b/en/api/public/com/highcapable/yukihookapi/hook/bean/VariousClass.html new file mode 100644 index 00000000..ddc3d464 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/bean/VariousClass.html @@ -0,0 +1,37 @@ + + + + + + + + +Yuki Hook API
Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
HookResourcesclass HookResources internal constructor(var instance: YukiResources?) +
Change Records
v1.0.80
added
Function Illustrate
创建一个当前 Hook 的
YukiResources
接管类。VariousClass - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/core/YukiMemberHookCreator.html b/en/api/public/com/highcapable/yukihookapi/hook/core/YukiMemberHookCreator.html new file mode 100644 index 00000000..5592e8b6 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/core/YukiMemberHookCreator.html @@ -0,0 +1,69 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
VariousClassclass VariousClass(private vararg val name: String) +
Change Records
v1.0
first
v1.1.5
modified
私有化
name
参数并设置为不可修改Function Illustrate
这是一个不确定性
Class
类名装载器,通过name
装载Class
名称数组。- method
getfun get(loader: ClassLoader? = null, initialize: Boolean): Class<*> +
Change Records
v1.0.70
added
v1.1.5
modified
新增
initialize
参数Function Illustrate
获取匹配的实体类。
使用当前
loader
装载目标Class
。- method
getOrNullfun getOrNull(loader: ClassLoader? = null, initialize: Boolean): Class<*>? +
Change Records
v1.1.0
added
v1.1.5
modified
新增
initialize
参数Function Illustrate
获取匹配的实体类。
使用当前
loader
装载目标Class
。匹配不到
Class
会返回null
,不会抛出异常。YukiMemberHookCreator - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/core/YukiResourcesHookCreator.html b/en/api/public/com/highcapable/yukihookapi/hook/core/YukiResourcesHookCreator.html new file mode 100644 index 00000000..9c4691b6 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/core/YukiResourcesHookCreator.html @@ -0,0 +1,130 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
YukiMemberHookCreatorclass YukiMemberHookCreator internal constructor(private val packageParam: PackageParam, private val hookClass: HookClass) +
Change Records
v1.0
first
v1.0.80
modified
对
hookClass
进行 inline 处理
v1.1.0
modified
修正拼写错误的 Creater 命名到 Creator
v1.1.5
modified
私有化构造方法
Function Illustrate
YukiHookAPI
的Member
核心 Hook 实现类。PRIORITY_DEFAULT - field
Change Records
v1.0.80
added
v1.2.0
deprecated
请迁移到
YukiHookPriority
PRIORITY_LOWEST - field
Change Records
v1.0.80
added
v1.2.0
deprecated
请迁移到
YukiHookPriority
PRIORITY_HIGHEST - field
Change Records
v1.0.80
added
v1.2.0
deprecated
请迁移到
YukiHookPriority
instanceClass - field
Change Records
v1.0
first
v1.0.2
modified
更名为thisClass
instanceClass
v1.2.0
deprecated
不再推荐使用
injectMember - method
Change Records
v1.0
first
v1.0.80
modified
将方法体进行 inline
增加
priority
Hook 优先级
v1.2.0
deprecated
请迁移到另一个
injectMember
- method
injectMemberinline fun injectMember(priority: YukiHookPriority, initiate: MemberHookCreator.LegacyCreator.() -> Unit): MemberHookCreator.Result +
Change Records
v1.2.0
added
Function Illustrate
注入要 Hook 的
Method
、Constructor
。useDangerousOperation - method
Change Records
v1.1.0
added
v1.2.0
deprecated
此功能已被弃用
- class
MemberHookCreatorinner class MemberHookCreator internal constructor(private val priority: YukiHookPriority, private val hookMode: HookMode) +
Change Records
v1.0
first
v1.0.80
modified
增加
priority
Hook 优先级
v1.0.81
modified
增加
packageName
当前 Hook 的 APP 包名
v1.1.0
modified
移除
packageName
修正拼写错误的 Creater 命名到 Creator
v1.2.0
modified
移除
tag
priority
类型由Int
变更为YukiHookPriority
增加
hookMode
Hook 模式Function Illustrate
Hook 核心功能实现类,查找和处理需要 Hook 的
Method
、Constructor
。- method
beforefun before(initiate: HookParam.() -> Unit): HookCallback +
Change Records
v1.2.0
added
Function Illustrate
在
Member
执行完成前 Hook。- method
afterfun after(initiate: HookParam.() -> Unit): HookCallback +
Change Records
v1.2.0
added
Function Illustrate
在
Member
执行完成后 Hook。- method
replaceAnyfun replaceAny(initiate: HookParam.() -> Any?) +
Change Records
v1.0
first
Function Illustrate
拦截并替换此
Member
内容,给出返回值。- method
replaceUnitfun replaceUnit(initiate: HookParam.() -> Unit) +
Change Records
v1.0
first
Function Illustrate
拦截并替换此
Member
内容,没有返回值,可以称为Void
。- method
replaceTofun replaceTo(any: Any?) +
Change Records
v1.0
first
Function Illustrate
拦截并替
Member
返回值。- method
replaceToTruefun replaceToTrue() +
Change Records
v1.0
first
Function Illustrate
拦截并替换
Member
返回值为true
。Pay Attention
确保替换 Member 的返回对象为 Boolean。
- method
replaceToFalsefun replaceToFalse() +
Change Records
v1.0
first
Function Illustrate
拦截并替换
Member
返回值为false
。Pay Attention
确保替换 Member 的返回对象为 Boolean。
- method
interceptfun intercept() +
Change Records
v1.0
first
Function Illustrate
拦截此
Member
。这将会禁止此
Member
执行并返回null
。Pay Attention
例如 Int、Long、Boolean 常量返回值的 Member 一旦被设置为 null 可能会造成 Hook APP 抛出异常。
- method
removeSelffun removeSelf(result: (Boolean) -> Unit) +
Change Records
v1.1.0
added
Function Illustrate
移除当前注入的 Hook
Method
、Constructor
(解除 Hook)。Pay Attention
你只能在 Hook 回调方法中使用此功能。
- class
LegacyCreatorinner class LegacyCreator internal constructor() +
Change Records
v1.2.0
added
Function Illustrate
使用
injectMember
创建的 Hook 核心功能实现类 (旧版本)。Notice
大部分旧版 API 已被迁移至此处,将不再特殊说明其中包含的旧版 API。
- class
HookCallbackinner class HookCallback internal constructor() +
Change Records
v1.1.0
added
Function Illustrate
Hook 方法体回调实现类。
- method
onFailureThrowToAppfun onFailureThrowToApp() +
Change Records
v1.1.0
added
Function Illustrate
当回调方法体内发生异常时将异常抛出给当前 Hook APP。
- class
Resultinner class Result internal constructor() +
Change Records
v1.0
first
Function Illustrate
监听 Hook 结果实现类。
- method
resultinline fun result(initiate: Result.() -> Unit): Result +
Change Records
v1.0
first
v1.0.5
modified
修改为failures
result
v1.0.80
modified
将方法体进行 inline
Function Illustrate
创建监听失败事件方法体。
- method
byinline fun by(condition: () -> Boolean): Result +
Change Records
v1.0.5
added
v1.0.80
modified
将方法体进行 inline
Function Illustrate
添加执行 Hook 需要满足的条件,不满足条件将直接停止 Hook。
- method
onHookedfun onHooked(result: (Member) -> Unit): Result +
Change Records
v1.0.70
added
Function Illustrate
监听
members
Hook 成功的回调方法。在首次 Hook 成功后回调。
在重复 Hook 时会回调
onAlreadyHooked
。- method
onAlreadyHookedfun onAlreadyHooked(result: (Member) -> Unit): Result +
Change Records
v1.0.89
added
Function Illustrate
监听
members
重复 Hook 的回调方法。Notice
同一个 hookClass 中的同一个 members 不会被 API 重复 Hook,若由于各种原因重复 Hook 会回调此方法。
- method
onNoSuchMemberFailurefun onNoSuchMemberFailure(result: (Throwable) -> Unit): Result +
Change Records
v1.0.5
added
Function Illustrate
监听
members
不存在发生错误的回调方法。- method
onConductFailurefun onConductFailure(result: (HookParam, Throwable) -> Unit): Result +
Change Records
v1.0
first
Function Illustrate
监听 Hook 进行过程中发生错误的回调方法。
- method
onHookingFailurefun onHookingFailure(result: (Throwable) -> Unit): Result +
Change Records
v1.0
first
Function Illustrate
监听 Hook 开始时发生的错误的回调方法。
- method
onAllFailurefun onAllFailure(result: (Throwable) -> Unit): Result +
Change Records
v1.0
first
Function Illustrate
监听全部 Hook 过程发生错误的回调方法。
- method
ignoredNoSuchMemberFailurefun ignoredNoSuchMemberFailure(): Result +
Change Records
v1.0.5
added
Function Illustrate
忽略
members
不存在发生的错误。- method
ignoredConductFailurefun ignoredConductFailure(): Result +
Change Records
v1.0
first
Function Illustrate
忽略 Hook 进行过程中发生的错误。
- method
ignoredHookingFailurefun ignoredHookingFailure(): Result +
Change Records
v1.0
first
Function Illustrate
忽略 Hook 开始时发生的错误。
- method
ignoredAllFailurefun ignoredAllFailure(): Result +
Change Records
v1.0
first
Function Illustrate
忽略全部 Hook 过程发生的错误。
- method
removefun remove(result: (Boolean) -> Unit) +
Change Records
v1.1.0
added
Function Illustrate
移除当前注入的 Hook
Method
、Constructor
(解除 Hook)。Notice
你只能在 Hook 成功后才能解除 Hook,可监听 onHooked 事件。
- class
Resultinner class Result internal constructor() +
Change Records
v1.0.3
added
Function Illustrate
监听全部 Hook 结果实现类。
- method
resultinline fun result(initiate: Result.() -> Unit): Result +
Change Records
v1.0.3
added
v1.0.5
modified
修改为failures
result
v1.0.80
modified
将方法体进行 inline
Function Illustrate
创建监听事件方法体。
- method
byinline fun by(condition: () -> Boolean): Result +
Change Records
v1.0.5
added
v1.0.80
modified
将方法体进行 inline
Function Illustrate
添加执行 Hook 需要满足的条件,不满足条件将直接停止 Hook。
- method
onPrepareHookfun onPrepareHook(callback: () -> Unit): Result +
Change Records
v1.0.70
added
Function Illustrate
监听
hookClass
存在时准备开始 Hook 的操作。- method
onHookClassNotFoundFailurefun onHookClassNotFoundFailure(result: (Throwable) -> Unit): Result +
Change Records
v1.0.3
added
Function Illustrate
监听
hookClass
找不到时发生错误的回调方法。- method
ignoredHookClassNotFoundFailurefun ignoredHookClassNotFoundFailure(): Result +
Change Records
v1.0.3
added
Function Illustrate
忽略
hookClass
找不到时出现的错误。YukiResourcesHookCreator - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/core/api/compat/type/ExecutorType.html b/en/api/public/com/highcapable/yukihookapi/hook/core/api/compat/type/ExecutorType.html new file mode 100644 index 00000000..33c20702 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/core/api/compat/type/ExecutorType.html @@ -0,0 +1,41 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
YukiResourcesHookCreatorclass YukiResourcesHookCreator internal constructor(internal val packageParam: PackageParam, internal val hookResources: HookResources) +
Change Records
v1.0.80
added
v1.1.0
modified
修正拼写错误的 Creater 命名到 Creator
v1.1.5
modified
私有化构造方法
Function Illustrate
YukiHookAPI
的Resources
核心 Hook 实现类。- method
injectResourceinline fun injectResource(tag: String, initiate: ResourceHookCreator.() -> Unit): ResourceHookCreator.Result +
Change Records
v1.0.80
added
Function Illustrate
注入要 Hook 的 Resources。
Function Example
你可以注入任意 Resources,使用
injectResource
即可创建一个Hook
对象。The following example
injectResource { + // Your code here. +} +
你还可以自定义
tag
,方便你在调试的时候能够区分你的Hook
对象。The following example
injectResource(tag = "KuriharaYuki") { + // Your code here. +} +
- class
ResourcesHookCreatorinner class ResourcesHookCreator internal constructor(private val tag: String) +
Change Records
v1.0.80
added
v1.1.0
modified
移除
packageName
修正拼写错误的 Creater 命名到 Creator
Function Illustrate
Hook 核心功能实现类。
查找和处理需要 Hook 的 Resources。
- field
resourceIdvar resourceId: Int +
Change Records
v1.0.80
added
Function Illustrate
直接设置需要替换的 Resources Id。
Notice
不建议使用此方法设置目标需要 Hook 的 Resources Id,你可以使用 conditions 方法。
Function Example
你可以直接设置并指定目标 Hook APP 的 Resources Id。
The following example
injectResource { + resourceId = 0x7f060001.toInt() + replaceTo(...) +} +
- method
conditionsinline fun conditions(initiate: ConditionFinder.() -> Unit) +
Change Records
v1.0.80
added
Function Illustrate
设置 Resources 查找条件。
若你设置了
resourceId
则此方法将不会被使用。Function Example
你可参考 ConditionFinder 查看详细用法。
The following example
injectResource { + conditions { + name = "test_string" + string() + } + replaceTo(...) +} +
- method
replaceTofun replaceTo(any: Any) +
Change Records
v1.0.80
added
Function Illustrate
替换指定 Resources 为指定的值。
Function Example
你可以替换找到的 Resources 为你想要的值,可以是
String
、Drawable
等。比如我们要替换一个找到的字符串 Resources。
The following example
injectResource { + conditions { + name = "test_string" + string() + } + replaceTo("replace string") +} +
或是替换为一个
Drawable
,你无需对目标 Resources 实现fwd
方法或DrawableLoader
。The following example
injectResource { + conditions { + name = "test_drawable" + drawable() + } + replaceTo(ColorDrawable(Color.RED)) +} +
- method
replaceToTruefun replaceToTrue() +
Change Records
v1.0.80
added
Function Illustrate
替换指定 Resources 为
true
。Pay Attention
确保目标替换 Resources 的类型为 Boolean。
- method
replaceToFalsefun replaceToFalse() +
Change Records
v1.0.80
added
Function Illustrate
替换指定 Resources 为
false
。Pay Attention
确保目标替换 Resources 的类型为 Boolean。
- method
replaceToModuleResourcefun replaceToModuleResource(resId: Int) +
Change Records
v1.0.80
added
Function Illustrate
替换为当前 Xposed 模块的 Resources。
你可以直接使用模块的
R.string.xxx
、R.mipmap.xxx
、R.drawable.xxx
替换 Hook APP 的 Resources。Function Example
使用此方法可非常方便地使用当前模块的 Resources 去替换目标 Hook APP 的 Resources。
这个过程你无需对目标 Resources 实现
fwd
方法。比如我们要替换一个字符串。
The following example
injectResource { + conditions { + name = "test_string" + string() + } + replaceToModuleResource(R.string.module_string) +} +
还可以替换一些复杂的 Resources,比如
xml
创建的drawable
。The following example
injectResource { + conditions { + name = "test_drawable" + drawable() + } + replaceToModuleResource(R.drawable.module_drawable) +} +
- method
replaceTofun replaceTo(result: (original: Any) -> Any?) +
Change Records
v1.2.0
added
Function Illustrate
替换指定 Resources 为指定的值。
Notice
此方法只支持部分类型,例如 String、Boolean。
此方法不支持在 HookEntryType.ZYGOTE 时使用。
- method
replaceToModuleResourcefun replaceToModuleResource(result: (original: Any) -> Int) +
Change Records
v1.2.0
added
Function Illustrate
替换为当前 Xposed 模块的 Resources。
你可以直接使用模块的
R.string.xxx
、R.mipmap.xxx
、R.drawable.xxx
替换 Hook APP 的 Resources。Notice
此方法只支持部分类型,例如 String、Boolean。
此方法不支持在 HookEntryType.ZYGOTE 时使用。
- method
injectAsLayoutfun injectAsLayout(initiate: YukiResources.LayoutInflatedParam.() -> Unit) +
Change Records
v1.0.80
added
Function Illustrate
作为装载的布局注入。
Function Example
你可以直接注入一个布局监听并修改它的内部
View
。The following example
injectResource { + conditions { + name = "activity_main" + layout() + } + injectAsLayout { + findViewByIdentifier<View>(name = "test_view")?.isVisible = false + findViewByIdentifier<TextView>(name = "test_text_view")?.text = "Hook this" + } +} +
你还可以通过
currentView
拿到Context
。The following example
injectResource { + conditions { + name = "activity_main" + layout() + } + injectAsLayout { + Toast.makeText(currentView.context, "Hook this", Toast.LENGTH_SHORT).show() + } +} +
- class
ConditionFinderinner class ConditionFinder internal constructor() +
Change Records
v1.0.80
added
Function Illustrate
Resources 查找条件实现类。
- field
namevar name: String +
Change Records
v1.0.80
added
Function Illustrate
设置 Resources 名称。
- method
animfun anim() +
Change Records
v1.0.80
added
Function Illustrate
设置 Resources 类型为动画。
- method
animatorfun animator() +
Change Records
v1.0.80
added
Function Illustrate
设置 Resources 类型为属性动画。
- method
boolfun bool() +
Change Records
v1.0.80
added
Function Illustrate
设置 Resources 类型为布朗(Boolean)。
- method
colorfun color() +
Change Records
v1.0.80
added
Function Illustrate
设置 Resources 类型为颜色(Color)。
- method
dimenfun dimen() +
Change Records
v1.0.80
added
Function Illustrate
设置 Resources 类型为尺寸(Dimention)。
- method
drawablefun drawable() +
Change Records
v1.0.80
added
Function Illustrate
设置 Resources 类型为 Drawable。
- method
integerfun integer() +
Change Records
v1.0.80
added
Function Illustrate
设置 Resources 类型为整型(Integer)。
- method
layoutfun layout() +
Change Records
v1.0.80
added
Function Illustrate
设置 Resources 类型为布局(Layout)。
- method
pluralsfun plurals() +
Change Records
v1.0.80
added
Function Illustrate
设置 Resources 类型为 Plurals。
- method
stringfun string() +
Change Records
v1.0.80
added
Function Illustrate
设置 Resources 类型为字符串(String)。
- method
xmlfun xml() +
Change Records
v1.0.80
added
Function Illustrate
设置 Resources 类型为 Xml。
- method
mipmapfun mipmap() +
Change Records
v1.0.80
added
Function Illustrate
设置 Resources 类型为位图(Mipmap)。
- method
arrayfun array() +
Change Records
v1.1.0
added
Function Illustrate
设置 Resources 类型为数组(Array)。
- class
Resultinner class Result internal constructor() +
Change Records
v1.0.80
added
Function Illustrate
监听全部 Hook 结果实现类,可在这里处理失败事件监听。
- method
resultinline fun result(initiate: Result.() -> Unit): Result +
Change Records
v1.0.80
added
Function Illustrate
创建监听事件方法体。
- method
byinline fun by(condition: () -> Boolean): Result +
Change Records
v1.0.80
added
Function Illustrate
添加执行 Hook 需要满足的条件,不满足条件将直接停止 Hook。
- method
onHookingFailurefun onHookingFailure(result: (Throwable) -> Unit): Result +
Change Records
v1.0.80
added
Function Illustrate
监听 Hook 过程发生错误的回调方法。
- method
ignoredHookingFailurefun ignoredHookingFailure(): Result +
Change Records
v1.0.80
added
Function Illustrate
忽略 Hook 过程出现的错误。
ExecutorType - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/core/api/priority/YukiHookPriority.html b/en/api/public/com/highcapable/yukihookapi/hook/core/api/priority/YukiHookPriority.html new file mode 100644 index 00000000..1f2342a5 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/core/api/priority/YukiHookPriority.html @@ -0,0 +1,38 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
ExecutorTypeenum class ExecutorType +
Change Records
v1.1.9
added
Function Illustrate
Hook Framework 类型定义。
定义了目前已知使用频率较高的 Hook Framework。
后期根据 Hook Framework 特征和使用情况将会继续添加新的类型。
无法识别的 Hook Framework 将被定义为
UNKNOWN
。- enum
UNKNOWNUNKNOWN +
Change Records
v1.1.9
added
Function Illustrate
未知类型。
- enum
XPOSEDXPOSED +
Change Records
v1.1.9
added
Function Illustrate
原版、第三方 Xposed。
- enum
LSPOSED_LSPATCHLSPOSED_LSPATCH +
Change Records
v1.1.9
added
Function Illustrate
LSPosed、LSPatch。
- enum
ED_XPOSEDED_XPOSED +
Change Records
v1.1.9
added
Function Illustrate
EdXposed。
- enum
TAICHI_XPOSEDTAICHI_XPOSED +
Change Records
v1.1.9
added
Function Illustrate
TaiChi (太极)。
- enum
BUG_XPOSEDBUG_XPOSED +
Change Records
v1.1.9
added
Function Illustrate
BugXposed (应用转生)。
YukiHookPriority - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/BaseFinder.html b/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/BaseFinder.html new file mode 100644 index 00000000..a12ad9f9 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/BaseFinder.html @@ -0,0 +1,42 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
YukiHookPriorityenum class YukiHookPriority +
Change Records
v1.1.5
added
v1.2.0
modified
移除
internal
对外公开Function Illustrate
Hook 回调优先级配置类。
- enum
DEFAULTDEFAULT +
Change Records
v1.1.5
added
Function Illustrate
默认 Hook 回调优先级。
- enum
LOWESTLOWEST +
Change Records
v1.1.5
added
Function Illustrate
延迟回调 Hook 方法结果。
- enum
HIGHESTHIGHEST +
Change Records
v1.1.5
added
Function Illustrate
更快回调 Hook 方法结果。
BaseFinder - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/CountRules.html b/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/CountRules.html new file mode 100644 index 00000000..d2e1a132 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/CountRules.html @@ -0,0 +1,39 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
BaseFinderabstract class BaseFinder +
Change Records
v1.0.70
added
v1.1.0
modified
分离原始命名
BaseFinder
中的部分方法与参数到MemberBaseFinder
Function Illustrate
这是
Class
与Member
查找类功能的基本类实现。- class
BaseFinder.IndexTypeConditioninner class IndexTypeCondition internal constructor(private val type: IndexConfigType) +
Change Records
v1.0.70
added
Function Illustrate
字节码下标筛选实现类。
- method
indexfun index(num: Int) +
Change Records
v1.0.70
added
Function Illustrate
设置下标。
若
index
小于零则为倒序,此时可以使用IndexTypeConditionSort.reverse
方法实现。可使用
IndexTypeConditionSort.first
和IndexTypeConditionSort.last
设置首位和末位筛选条件。- method
indexfun index(): IndexTypeConditionSort +
Change Records
v1.0.70
added
Function Illustrate
得到下标。
- class
IndexTypeConditionSortinner class IndexTypeConditionSort internal constructor() +
Change Records
v1.0.70
added
Function Illustrate
字节码下标排序实现类。
- method
firstfun first() +
Change Records
v1.0.70
added
Function Illustrate
设置满足条件的第一个。
- method
lastfun last() +
Change Records
v1.0.70
added
Function Illustrate
设置满足条件的最后一个。
- method
reversefun reverse(num: Int) +
Change Records
v1.0.70
added
Function Illustrate
设置倒序下标。
CountRules - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/ModifierRules.html b/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/ModifierRules.html new file mode 100644 index 00000000..688eef93 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/ModifierRules.html @@ -0,0 +1,47 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
CountRulesclass CountRules private constructor() +
Change Records
v1.1.0
added
Function Illustrate
这是一个模糊
Class
、Member
数组 (下标) 个数条件实现类。可对 R8 混淆后的
Class
、Member
进行更加详细的定位。- i-ext-method
Int.isZerofun Int.isZero(): Boolean +
Change Records
v1.1.0
added
Function Illustrate
是否为 0。
- i-ext-method
Int.moreThanfun Int.moreThan(count: Int): Boolean +
Change Records
v1.1.0
added
Function Illustrate
大于
count
。- i-ext-method
Int.lessThanfun Int.lessThan(count: Int): Boolean +
Change Records
v1.1.0
added
Function Illustrate
小于
count
。- i-ext-method
Int.inIntervalfun Int.inInterval(countRange: IntRange): Boolean +
Change Records
v1.1.0
added
Function Illustrate
在
countRange
区间 A ≤ this ≤ B。ModifierRules - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/NameRules.html b/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/NameRules.html new file mode 100644 index 00000000..54bc47e3 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/NameRules.html @@ -0,0 +1,42 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
ModifierRulesclass ModifierRules private constructor() +
Change Records
v1.0.67
added
v1.1.0
modified
新增
Class
的描述符判断作为 lambda 整体判断条件使用
移动到 base 包名
私有化构造方法
Function Illustrate
这是一个
Class
、Member
描述符条件实现类。可对 R8 混淆后的
Class
、Member
进行更加详细的定位。- i-ext-field
isPublicval isPublic: Boolean +
Change Records
v1.0.67
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
Class
、Member
类型是否包含public
。- i-ext-field
isPrivateval isPrivate: Boolean +
Change Records
v1.0.67
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
Class
、Member
类型是否包含private
。- i-ext-field
isProtectedval isProtected: Boolean +
Change Records
v1.0.67
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
Class
、Member
类型是否包含protected
。- i-ext-field
isStaticval isStatic: Boolean +
Change Records
v1.0.67
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
Class
、Member
类型是否包含static
。对于任意的静态
Class
、Member
可添加此描述进行确定。Notice
Kotlin → Jvm 后的 object 类中的方法并不是静态的。
- i-ext-field
isFinalval isFinal: Boolean +
Change Records
v1.0.67
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
Class
、Member
类型是否包含final
。Notice
Kotlin → Jvm 后没有 open 符号标识的 Class、Member 和没有任何关联的 Class、Member 都将为 final。
- i-ext-field
isSynchronizedval isSynchronized: Boolean +
Change Records
v1.0.67
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
Class
、Member
类型是否包含synchronized
。- i-ext-field
isVolatileval isVolatile: Boolean +
Change Records
v1.0.67
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
Field
类型是否包含volatile
。- i-ext-field
isTransientval isTransient: Boolean +
Change Records
v1.0.67
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
Field
类型是否包含transient
。- i-ext-field
isNativeval isNative: Boolean +
Change Records
v1.0.67
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
Method
类型是否包含native
。对于任意 JNI 对接的
Method
可添加此描述进行确定。- i-ext-field
isInterfaceval isInterface: Boolean +
Change Records
v1.0.67
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
Class
类型是否包含interface
。- i-ext-field
isAbstractval isAbstract: Boolean +
Change Records
v1.0.67
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
Class
、Member
类型是否包含abstract
。对于任意的抽象
Class
、Member
可添加此描述进行确定。- i-ext-field
isStrictval isStrict: Boolean +
Change Records
v1.0.67
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
Class
、Member
类型是否包含strictfp
。NameRules - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/ObjectRules.html b/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/ObjectRules.html new file mode 100644 index 00000000..76c67356 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/core/finder/base/rules/ObjectRules.html @@ -0,0 +1,35 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
NameRulesclass NameRules private constructor() +
Change Records
v1.0.88
added
v1.1.0
modified
更名为NameConditions
NameRules
作为 lambda 整体判断条件使用
移动到 base 包名
私有化构造方法
Function Illustrate
这是一个模糊
Class
、Member
名称条件实现类。可对 R8 混淆后的
Class
、Member
进行更加详细的定位。- i-ext-method
String.isSyntheticfun String.isSynthetic(index: Int): Boolean +
Change Records
v1.0.88
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
是否为匿名类的主类调用对象。
- i-ext-method
String.isOnlySymbolsfun String.isOnlySymbols(): Boolean +
Change Records
v1.0.88
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
是否只有符号。
- i-ext-method
String.isOnlyLettersfun String.isOnlyLetters(): Boolean +
Change Records
v1.0.88
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
是否只有字母。
- i-ext-method
String.isOnlyNumbersfun String.isOnlyNumbers(): Boolean +
Change Records
v1.0.88
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
是否只有数字。
- i-ext-method
String.isOnlyLettersNumbersfun String.isOnlyLettersNumbers(): Boolean +
Change Records
v1.0.88
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
是否只有字母或数字。
- i-ext-method
String.isOnlyLowercasefun String.isOnlyLowercase(): Boolean +
Change Records
v1.0.88
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
是否只有小写字母。
在没有其它条件的情况下设置此条件允许判断对象存在字母以外的字符。
- i-ext-method
String.isOnlyUppercasefun String.isOnlyUppercase(): Boolean +
Change Records
v1.0.88
added
v1.1.0
modified
统一合并到扩展方法并改名
Function Illustrate
是否只有大写字母。
在没有其它条件的情况下设置此条件允许判断对象存在字母以外的字符。
ObjectRules - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/DexClassFinder.html b/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/DexClassFinder.html new file mode 100644 index 00000000..fbc6ba4f --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/DexClassFinder.html @@ -0,0 +1,78 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
ObjectRulesclass ObjectRules private constructor(private val instance: Any) +
Change Records
v1.1.5
added
Function Illustrate
这是一个任意对象条件实现类。
可对 R8 混淆后的
Class
、Member
进行更加详细的定位。DexClassFinder - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/ConstructorRules.html b/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/ConstructorRules.html new file mode 100644 index 00000000..0651456a --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/ConstructorRules.html @@ -0,0 +1,42 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
DexClassFinderclass DexClassFinder internal constructor( + internal var name: String, + internal var async: Boolean, + override val loaderSet: ClassLoader? +) : ClassBaseFinder +
Change Records
v1.1.0
added
Function Illustrate
Class
查找类。可使用
BaseDexClassLoader
通过指定条件查找指定Class
或一组Class
。Notice
此功能尚在实验阶段,性能与稳定性可能仍然存在问题,使用过程遇到问题请向我们报告并帮助我们改进。
- object
companion objectChange Records
v1.1.0
added
- method
clearCachefun clearCache(context: Context?, versionName: String?, versionCode: Long?) +
Change Records
v1.1.0
added
Function Illustrate
清除当前
DexClassFinder
的Class
缓存。适用于全部通过 ClassLoader.searchClass 或 PackageParam.searchClass 获取的
DexClassFinder
。- field
fullNamevar fullName: String +
Change Records
v1.1.0
added
Function Illustrate
设置
Class
完整名称。只会查找匹配到的
Class.getName
。例如
com.demo.Test
需要填写com.demo.Test
。- field
simpleNamevar simpleName: String +
Change Records
v1.1.0
added
Function Illustrate
设置
Class
简单名称。只会查找匹配到的
Class.getSimpleName
。例如
com.demo.Test
只需要填写Test
。对于匿名类例如
com.demo.Test$InnerTest
会为空,此时你可以使用 singleName。- field
singleNamevar singleName: String +
Change Records
v1.1.0
added
Function Illustrate
设置
Class
独立名称。设置后将首先使用
Class.getSimpleName
,若为空则会使用Class.getName
进行处理。例如
com.demo.Test
只需要填写Test
。对于匿名类例如
com.demo.Test$InnerTest
只需要填写Test$InnerTest
。- method
fromfun from(vararg name: String): FromPackageRules +
Change Records
v1.1.0
added
Function Illustrate
设置在指定包名范围查找当前
Class
。设置后仅会在当前
name
开头匹配的包名路径下进行查找,可提升查找速度。例如 ↓
com.demo.test
com.demo.test.demo
Notice
建议设置此参数指定查找范围,否则 Class 过多时将会非常慢。
- method
modifiersfun modifiers(conditions: ModifierConditions) +
Change Records
v1.1.0
added
Function Illustrate
设置
Class
标识符筛选条件。可不设置筛选条件。
- method
fullNamefun fullName(value: String): ClassNameRules +
Change Records
v1.1.0
added
Function Illustrate
设置
Class
完整名称。只会查找匹配到的
Class.getName
。例如
com.demo.Test
需要填写com.demo.Test
。- method
simpleNamefun simpleName(value: String): ClassNameRules +
Change Records
v1.1.0
added
Function Illustrate
设置
Class
简单名称。只会查找匹配到的
Class.getSimpleName
。例如
com.demo.Test
只需要填写Test
。对于匿名类例如
com.demo.Test$InnerTest 会为空
,此时你可以使用 singleName。- method
singleNamefun singleName(value: String): ClassNameRules +
Change Records
v1.1.0
added
Function Illustrate
设置
Class
独立名称。设置后将首先使用
Class.getSimpleName
,若为空则会使用Class.getName
进行处理。例如
com.demo.Test
只需要填写Test
。对于匿名类例如
com.demo.Test$InnerTest
只需要填写Test$InnerTest
。- method
fullNamefun fullName(conditions: NameConditions) +
Change Records
v1.1.0
added
Function Illustrate
设置
Class
完整名称条件。只会查找匹配到的
Class.getName
。- method
simpleNamefun simpleName(conditions: NameConditions) +
Change Records
v1.1.0
added
Function Illustrate
设置
Class
简单名称条件。只会查找匹配到的
Class.getSimpleName
。- method
singleNamefun singleName(conditions: NameConditions) +
Change Records
v1.1.0
added
Function Illustrate
设置
Class
独立名称条件。设置后将首先使用
Class.getSimpleName
,若为空则会使用Class.getName
进行处理。- method
extendsinline fun <reified T> extends() +
Change Records
v1.1.0
added
Function Illustrate
设置
Class
继承的父类。- method
extendsfun extends(vararg name: String) +
Change Records
v1.1.0
added
Function Illustrate
设置
Class
继承的父类。会同时查找
name
中所有匹配的父类。- method
implementsinline fun <reified T> implements() +
Change Records
v1.1.0
added
Function Illustrate
设置
Class
实现的接口类。- method
implementsfun implements(vararg name: String) +
Change Records
v1.1.0
added
Function Illustrate
设置
Class
实现的接口类。会同时查找
name
中所有匹配的接口类。- method
anonymousfun anonymous() +
Change Records
v1.1.0
added
Function Illustrate
标识
Class
为匿名类。例如
com.demo.Test$1
或com.demo.Test$InnerTest
。标识后你可以使用 enclosing 来进一步指定匿名类的 (封闭类) 主类。
- method
noExtendsfun noExtends() +
Change Records
v1.1.0
added
Function Illustrate
设置
Class
没有任何继承。此时
Class
只应该继承于Any
。Notice
设置此条件后 extends 将失效。
- method
noImplementsfun noImplements() +
Change Records
v1.1.0
added
Function Illustrate
设置
Class
没有任何接口。Notice
设置此条件后 implements 将失效。
- method
noSuperfun noSuper() +
Change Records
v1.1.0
added
Function Illustrate
设置
Class
没有任何继承与接口。此时
Class
只应该继承于Any
。Notice
设置此条件后 extends 与 implements 将失效。
- method
enclosinginline fun <reified T> enclosing() +
Change Records
v1.1.0
added
Function Illustrate
设置
Class
匿名类的 (封闭类) 主类。- method
enclosingfun enclosing(vararg name: String) +
Change Records
v1.1.0
added
Function Illustrate
设置
Class
匿名类的 (封闭类) 主类。会同时查找
name
中所有匹配的 (封闭类) 主类。- class
FromPackageRulesinner class FromPackageRules internal constructor(private val packages: MutableList<ClassRulesData.PackageRulesData>) +
Change Records
v1.1.0
added
Function Illustrate
包名范围名称过滤匹配条件实现类。
- method
absolutefun absolute() +
Change Records
v1.1.0
added
Function Illustrate
设置包名绝对匹配。
例如有如下包名 ↓
com.demo.test.a
com.demo.test.a.b
com.demo.test.active
若包名条件为
com.demo.test.a
则绝对匹配仅能匹配到第一个。相反地,不设置以上示例会全部匹配。
- class
ClassNameRulesinner class ClassNameRules internal constructor(private val name: ClassRulesData.NameRulesData) +
Change Records
v1.1.0
added
Function Illustrate
类名匹配条件实现类。
- method
optionalfun optional() +
Change Records
v1.1.0
added
Function Illustrate
设置类名可选。
例如有如下类名 ↓
com.demo.Test
fullName /Test
simpleName
defpackage.a
fullName /a
simpleName这两个类名都是同一个类,但是在有些版本中被混淆有些版本没有。
此时可设置类名为
com.demo.Test
fullName /Test
simpleName。这样就可在完全匹配类名情况下使用类名而忽略其它查找条件,否则忽略此条件继续使用其它查找条件。
- method
memberinline fun member(initiate: MemberRules.() -> Unit): MemberRulesResult +
Change Records
v1.1.0
added
Function Illustrate
设置
Class
满足的Member
条件。- method
fieldinline fun field(initiate: FieldRules.() -> Unit): MemberRulesResult +
Change Records
v1.1.0
added
Function Illustrate
设置
Class
满足的Field
条件。- method
methodinline fun method(initiate: MethodRules.() -> Unit): MemberRulesResult +
Change Records
v1.1.0
added
Function Illustrate
设置
Class
满足的Method
条件。- method
constructorinline fun constructor(initiate: ConstructorRules.() -> Unit): MemberRulesResult +
Change Records
v1.1.0
added
Function Illustrate
设置
Class
满足的Constructor
条件。- class
Resultinner class Result internal constructor(internal var isNotFound: Boolean, internal var throwable: Throwable?) : BaseResult +
Change Records
v1.1.0
added
Function Illustrate
Class
查找结果实现类。- method
resultinline fun result(initiate: Result.() -> Unit): Result +
Change Records
v1.1.0
added
Function Illustrate
创建监听结果事件方法体。
- method
getfun get(): Class<*>? +
Change Records
v1.1.0
added
Function Illustrate
得到
Class
本身。若有多个
Class
结果只会返回第一个。在查找条件找不到任何结果的时候将返回
null
。若你设置了
async
请使用 wait 方法。- method
allfun all(): MutableList<Class<*>> +
Change Records
v1.1.0
added
v1.2.0
modified
返回值类型由
HashSet
修改为MutableList
Function Illustrate
得到
Class
本身数组。返回全部查找条件匹配的多个
Class
实例。在查找条件找不到任何结果的时候将返回空的
MutableList
。若你设置了
async
请使用 waitAll 方法。- method
allfun all(result: (Class<*>) -> Unit): Result +
Change Records
v1.1.0
added
Function Illustrate
得到
Class
本身数组 (依次遍历)。回调全部查找条件匹配的多个
Class
实例。在查找条件找不到任何结果的时候将不会执行。
若你设置了
async
请使用 waitAll 方法。- method
waitfun wait(result: (Class<*>?) -> Unit): Result +
Change Records
v1.1.0
added
Function Illustrate
得到
Class
本身 (异步)。若有多个
Class
结果只会回调第一个。在查找条件找不到任何结果的时候将回调 null。
你需要设置
async
后此方法才会被回调,否则请使用 get 方法。- method
waitAllfun waitAll(result: (MutableList<Class<*>>) -> Unit): Result +
Change Records
v1.1.0
added
v1.2.0
modified
result
类型由HashSet
修改为MutableList
Function Illustrate
得到
Class
本身数组 (异步)。回调全部查找条件匹配的多个
Class
实例。在查找条件找不到任何结果的时候将回调空的
MutableList
。你需要设置
async
后此方法才会被回调,否则请使用 all 方法。- method
onNoClassDefFoundErrorfun onNoClassDefFoundError(result: (Throwable) -> Unit): Result +
Change Records
v1.1.0
added
Function Illustrate
监听找不到
Class
时。- method
ignoredfun ignored(): Result +
Change Records
v1.1.0
added
Function Illustrate
忽略异常并停止打印任何错误日志。
此时若要监听异常结果,你需要手动实现 onNoClassDefFoundError 方法。
ConstructorRules - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/FieldRules.html b/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/FieldRules.html new file mode 100644 index 00000000..c6cf2dd1 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/FieldRules.html @@ -0,0 +1,40 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
ConstructorRulesclass ConstructorRules internal constructor(private val rulesData: ConstructorRulesData) : BaseRules +
Change Records
v1.1.0
added
Function Illustrate
Constructor
查找条件实现类。- field
paramCountvar paramCount: Int +
Change Records
v1.1.0
added
Function Illustrate
设置
Constructor
参数个数。你可以不使用
param
指定参数类型而是仅使用此变量指定参数个数。若参数个数小于零则忽略并使用
param
。- method
modifiersfun modifiers(conditions: ModifierConditions) +
Change Records
v1.1.0
added
Function Illustrate
设置
Constructor
标识符筛选条件。可不设置筛选条件。
- method
emptyParamfun emptyParam() +
Change Records
v1.1.0
added
Function Illustrate
设置
Constructor
空参数、无参数。- method
paramfun param(vararg paramType: Any) +
Change Records
v1.1.0
added
Function Illustrate
设置
Constructor
参数。如果同时使用了
paramCount
则paramType
的数量必须与paramCount
完全匹配。如果
Constructor
中存在一些无意义又很长的类型,你可以使用VagueType
来替代它。Pay Attention
无参 Constructor 请使用 emptyParam 设置查找条件。
有参 Constructor 必须使用此方法设定参数或使用 paramCount 指定个数。
- method
paramfun param(conditions: ObjectsConditions) +
Change Records
v1.1.5
added
Function Illustrate
设置
Constructor
参数条件。Pay Attention
无参 Constructor 请使用 emptyParam 设置查找条件。
有参 Constructor 必须使用此方法设定参数或使用 paramCount 指定个数。
- method
paramCountfun paramCount(numRange: IntRange) +
Change Records
v1.1.0
added
Function Illustrate
设置
Constructor
参数个数范围。你可以不使用
param
指定参数类型而是仅使用此方法指定参数个数范围。- method
paramCountfun paramCount(conditions: CountConditions) +
Change Records
v1.1.0
added
Function Illustrate
设置
Constructor
参数个数条件。你可以不使用
param
指定参数类型而是仅使用此方法指定参数个数条件。FieldRules - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/MemberRules.html b/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/MemberRules.html new file mode 100644 index 00000000..9583cd06 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/MemberRules.html @@ -0,0 +1,36 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
FieldRulesclass FieldRules internal constructor(private val rulesData: FieldRulesData) : BaseRules +
Change Records
v1.1.0
added
Function Illustrate
Field
查找条件实现类。- field
namevar name: String +
Change Records
v1.1.0
added
Function Illustrate
设置
Field
名称。- field
typevar type: Any? +
Change Records
v1.1.0
added
Function Illustrate
设置
Field
类型。可不填写类型。
- method
modifiersfun modifiers(conditions: ModifierConditions) +
Change Records
v1.1.0
added
Function Illustrate
设置
Field
标识符筛选条件。可不设置筛选条件。
- method
namefun name(conditions: NameConditions) +
Change Records
v1.1.0
added
Function Illustrate
设置
Field
名称条件。- method
typefun type(conditions: ObjectConditions) +
Change Records
v1.1.5
added
Function Illustrate
设置
Field
类型条件。可不填写类型。
MemberRules - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/MethodRules.html b/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/MethodRules.html new file mode 100644 index 00000000..83d5b229 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/MethodRules.html @@ -0,0 +1,46 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
MemberRulesclass MemberRules internal constructor(private val rulesData: MemberRulesData) : BaseRules +
Change Records
v1.1.0
added
Function Illustrate
Member
查找条件实现类。- method
modifiersfun modifiers(conditions: ModifierConditions) +
Change Records
v1.1.0
added
Function Illustrate
设置
Member
标识符筛选条件。可不设置筛选条件。
MethodRules - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/result/MemberRulesResult.html b/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/result/MemberRulesResult.html new file mode 100644 index 00000000..53ba1c7d --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/core/finder/classes/rules/result/MemberRulesResult.html @@ -0,0 +1,39 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
MethodRulesclass MethodRules internal constructor(private val rulesData: MethodRulesData) : BaseRules +
Change Records
v1.1.0
added
Function Illustrate
Method
查找条件实现类。- field
namevar name: String +
Change Records
v1.1.0
added
Function Illustrate
设置
Method
名称。- field
paramCountvar paramCount: Int +
Change Records
v1.1.0
added
Function Illustrate
设置
Method
参数个数。你可以不使用
param
指定参数类型而是仅使用此变量指定参数个数。若参数个数小于零则忽略并使用
param
。- field
returnTypevar returnType: Any? +
Change Records
v1.1.0
added
Function Illustrate
设置
Method
返回值。可不填写返回值。
- method
modifiersfun modifiers(conditions: ModifierConditions) +
Change Records
v1.1.0
added
Function Illustrate
设置
Method
标识符筛选条件。可不设置筛选条件。
- method
emptyParamfun emptyParam() +
Change Records
v1.1.0
added
Function Illustrate
设置
Method
空参数、无参数。- method
paramfun param(vararg paramType: Any) +
Change Records
v1.1.0
added
Function Illustrate
设置
Method
参数。如果同时使用了
paramCount
则paramType
的数量必须与paramCount
完全匹配。如果
Method
中存在一些无意义又很长的类型,你可以使用VagueType
来替代它。Pay Attention
无参 Method 请使用 emptyParam 设置查找条件。
有参 Method 必须使用此方法设定参数或使用 paramCount 指定个数。
- method
paramfun param(conditions: ObjectsConditions) +
Change Records
v1.1.5
added
Function Illustrate
设置
Method
参数条件。Pay Attention
无参 Method 请使用 emptyParam 设置查找条件。
有参 Method 必须使用此方法设定参数或使用 paramCount 指定个数。
- method
namefun name(conditions: NameConditions) +
Change Records
v1.1.0
added
Function Illustrate
设置
Method
名称条件。- method
paramCountfun paramCount(numRange: IntRange) +
Change Records
v1.1.0
added
Function Illustrate
设置
Method
参数个数范围。你可以不使用
param
指定参数类型而是仅使用此方法指定参数个数范围。- method
paramCountfun paramCount(conditions: CountConditions) +
Change Records
v1.1.0
added
Function Illustrate
设置
Method
参数个数条件。你可以不使用
param
指定参数类型而是仅使用此方法指定参数个数条件。- method
returnTypefun returnType(conditions: ObjectConditions) +
Change Records
v1.1.5
added
Function Illustrate
设置
Method
返回值条件。可不填写返回值。
MemberRulesResult - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/core/finder/members/ConstructorFinder.html b/en/api/public/com/highcapable/yukihookapi/hook/core/finder/members/ConstructorFinder.html new file mode 100644 index 00000000..89b2d6ae --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/core/finder/members/ConstructorFinder.html @@ -0,0 +1,121 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
MemberRulesResultclass MemberRulesResult internal constructor(private val rulesData: MemberRulesData) +
Change Records
v1.1.0
added
Function Illustrate
当前
Member
查找条件结果实现类。- method
nonefun none(): MemberRulesResult +
Change Records
v1.1.0
added
Function Illustrate
设置当前
Member
在查找条件中个数为0
。- method
countfun count(num: Int): MemberRulesResult +
Change Records
v1.1.0
added
Function Illustrate
设置当前
Member
在查找条件中需要全部匹配的个数。- method
countfun count(numRange: IntRange): MemberRulesResult +
Change Records
v1.1.0
added
Function Illustrate
设置当前
Member
在查找条件中需要全部匹配的个数范围。- method
countfun count(conditions: CountConditions): MemberRulesResult +
Change Records
v1.1.0
added
Function Illustrate
设置当前
Member
在查找条件中需要全部匹配的个数条件。ConstructorFinder - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/core/finder/members/FieldFinder.html b/en/api/public/com/highcapable/yukihookapi/hook/core/finder/members/FieldFinder.html new file mode 100644 index 00000000..d6edfeba --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/core/finder/members/FieldFinder.html @@ -0,0 +1,117 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
ConstructorFinderclass ConstructorFinder internal constructor(override val classSet: Class<*>) : MemberBaseFinder +
Change Records
v1.0
first
v1.0.2
modified
合并到
BaseFinder
v1.1.0
modified
合并到
MemberBaseFinder
v1.1.8
modified
移动
hookInstance
参数到MemberBaseFinder.MemberHookerManager
Function Illustrate
Constructor
查找类。可通过指定类型查找指定
Constructor
或一组Constructor
。- field
paramCountvar paramCount: Int +
Change Records
v1.0.67
added
Function Illustrate
设置
Constructor
参数个数。你可以不使用
param
指定参数类型而是仅使用此变量指定参数个数。若参数个数小于零则忽略并使用
param
。- method
modifiersfun modifiers(conditions: ModifierConditions): IndexTypeCondition +
Change Records
v1.0.67
added
v1.0.80
modified
将方法体进行 inline
v1.1.0
modified
合并到
ModifierConditions
Function Illustrate
设置
Constructor
标识符筛选条件。可不设置筛选条件,默认模糊查找并取第一个匹配的
Constructor
。Pay Attention
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
- method
emptyParamfun emptyParam(): IndexTypeCondition +
Change Records
v1.0.75
added
Function Illustrate
设置
Constructor
空参数、无参数。- method
paramfun param(vararg paramType: Any): IndexTypeCondition +
Change Records
v1.0
first
Function Illustrate
设置
Constructor
参数。如果同时使用了
paramCount
则paramType
的数量必须与paramCount
完全匹配。如果
Constructor
中存在一些无意义又很长的类型,你可以使用 VagueType 来替代它。Pay Attention
无参 Constructor 请使用 emptyParam 设置查找条件。
有参 Constructor 必须使用此方法设定参数或使用 paramCount 指定个数。
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
- method
paramfun param(conditions: ObjectsConditions): IndexTypeCondition +
Change Records
v1.1.5
added
Function Illustrate
设置
Constructor
参数条件。Pay Attention
无参 Constructor 请使用 emptyParam 设置查找条件。
有参 Constructor 必须使用此方法设定参数或使用 paramCount 指定个数。
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
- method
paramCountfun paramCount(num: Int): IndexTypeCondition +
Change Records
v1.0.70
added
Function Illustrate
设置
Constructor
参数个数。你可以不使用
param
指定参数类型而是仅使用此方法指定参数个数。若参数个数小于零则忽略并使用
param
。Pay Attention
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
- method
paramCountfun paramCount(numRange: IntRange): IndexTypeCondition +
Change Records
v1.1.0
added
Function Illustrate
设置
Constructor
参数个数范围。你可以不使用
param
指定参数类型而是仅使用此方法指定参数个数范围。Pay Attention
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
- method
paramCountfun paramCount(conditions: CountConditions): IndexTypeCondition +
Change Records
v1.1.0
added
Function Illustrate
设置
Constructor
参数个数条件。你可以不使用
param
指定参数类型而是仅使用此方法指定参数个数条件。Pay Attention
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
- method
superClassfun superClass(isOnlySuperClass: Boolean) +
Change Records
v1.0.80
added
Function Illustrate
设置在
classSet
的所有父类中查找当前Constructor
。Notice
若当前 classSet 的父类较多可能会耗时,API 会自动循环到父类继承是 Any 前的最后一个类。
- class
RemedyPlaninner class RemedyPlan internal constructor() +
Change Records
v1.0
first
Function Illustrate
Constructor
重查找实现类,可累计失败次数直到查找成功。- method
constructorinline fun constructor(initiate: ConstructorConditions) +
Change Records
v1.0
first
v1.0.80
modified
将方法体进行 inline
Function Illustrate
创建需要重新查找的
Constructor
。你可以添加多个备选
Constructor
,直到成功为止,若最后依然失败,将停止查找并输出错误日志。- class
Resultinner class Result internal constructor() +
Change Records
v1.0.1
added
Function Illustrate
RemedyPlan
结果实现类。- method
onFindfun onFind(initiate: MutableList<Constructor<*>>.() -> Unit) +
Change Records
v1.0.1
added
v1.1.0
modified
initiate
参数Constructor
变为HashSet<Constructor>
v1.2.0
modified
initiate
类型由HashSet
修改为MutableList
Function Illustrate
当在
RemedyPlan
中找到结果时。Function Example
你可以方便地对重查找的
Constructor
实现onFind
方法。The following example
constructor { + // Your code here. +}.onFind { + // Your code here. +} +
- class
Processinner class Process internal constructor(internal val isNoSuch: Boolean, internal val throwable: Throwable?) : BaseResult +
Change Records
v1.1.0
added
Function Illustrate
Constructor
查找结果处理类,为hookManager
提供。- method
resultinline fun result(initiate: Process.() -> Unit): Process +
Change Records
v1.1.0
added
Function Illustrate
创建监听结果事件方法体。
Function Example
你可以使用 lambda 形式创建
Result
类。The following example
constructor { + // Your code here. +}.result { + all() + remedys {} + onNoSuchConstructor {} +} +
- method
allfun all(): Process +
Change Records
v1.1.0
added
Function Illustrate
设置全部查找条件匹配的多个
Constructor
实例结果到hookManager
。- method
remedysinline fun remedys(initiate: RemedyPlan.() -> Unit): Result +
Change Records
v1.1.0
added
Function Illustrate
创建
Constructor
重查找功能。Function Example
当你遇到一种
Constructor
可能存在不同形式的存在时,可以使用RemedyPlan
重新查找它,而没有必要使用onNoSuchConstructor
捕获异常二次查找Constructor
。若第一次查找失败了,你还可以在这里继续添加此方法体直到成功为止。
The following example
constructor { + // Your code here. +}.remedys { + constructor { + // Your code here. + } + constructor { + // Your code here. + } +} +
- method
onNoSuchConstructorinline fun onNoSuchConstructor(result: (Throwable) -> Unit): Result +
Change Records
v1.1.0
added
Function Illustrate
监听找不到
Constructor
时。只会返回第一次的错误信息,不会返回
RemedyPlan
的错误信息。- class
Resultinner class Result internal constructor(internal val isNoSuch: Boolean, internal val throwable: Throwable?) : BaseResult +
Change Records
v1.0
first
v1.1.0
modified
继承到接口
BaseResult
Function Illustrate
Constructor
查找结果实现类。- method
resultinline fun result(initiate: Result.() -> Unit): Result +
Change Records
v1.0
first
v1.0.80
modified
将方法体进行 inline
Function Illustrate
创建监听结果事件方法体。
Function Example
你可以使用 lambda 形式创建
Result
类。The following example
constructor { + // Your code here. +}.result { + get().call() + all() + remedys {} + onNoSuchConstructor {} +} +
- method
getfun get(): Instance +
Change Records
v1.0.2
added
Function Illustrate
获得
Constructor
实例处理类。若有多个
Constructor
结果只会返回第一个。Pay Attention
若你设置了 remedys 请使用 wait 回调结果方法。
Function Example
你可以通过获得方法所在实例来执行构造方法创建新的实例对象。
The following example
constructor { + // Your code here. +}.get().call() +
你可以
cast
构造方法为指定类型的实例对象。The following example
constructor { + // Your code here. +}.get().newInstance<TestClass>() +
Pay Attention
若构造方法含有参数则后方参数必填。
The following example
constructor { + // Your code here. +}.get().newInstance<TestClass>("param1", "param2") +
- method
allfun all(): MutableList<Instance> +
Change Records
v1.1.0
added
v1.2.0
modified
返回值类型由
ArrayList
修改为MutableList
Function Illustrate
获得
Constructor
实例处理类数组。返回全部查找条件匹配的多个
Constructor
实例结果。Function Example
你可以通过此方法来获得当前条件结果中匹配的全部
Constructor
。The following example
constructor { + // Your code here. +}.all().forEach { instance -> + instance.call(...) +} +
- method
givefun give(): Constructor<*>? +
Change Records
v1.0.67
added
Function Illustrate
得到
Constructor
本身。若有多个
Constructor
结果只会返回第一个。在查找条件找不到任何结果的时候将返回
null
。- method
giveAllfun giveAll(): MutableList<Constructor<*>> +
Change Records
v1.1.0
added
v1.2.0
modified
返回值类型由
HashSet
修改为MutableList
Function Illustrate
得到
Constructor
本身数组。返回全部查找条件匹配的多个
Constructor
实例。在查找条件找不到任何结果的时候将返回空的
MutableList
。- method
waitfun wait(initiate: Instance.() -> Unit) +
Change Records
v1.0.2
added
Function Illustrate
获得
Constructor
实例处理类,配合RemedyPlan
使用。若有多个
Constructor
结果只会返回第一个。Pay Attention
若你设置了 remedys 必须使用此方法才能获得结果。
若你没有设置 remedys 此方法将不会被回调。
- method
waitAllfun waitAll(initiate: MutableList<Instance>.() -> Unit) +
Change Records
v1.1.0
added
v1.2.0
modified
initiate
类型由ArrayList
修改为MutableList
Function Illustrate
获得
Constructor
实例处理类数组,配合RemedyPlan
使用。返回全部查找条件匹配的多个
Constructor
实例结果。Pay Attention
若你设置了 remedys 必须使用此方法才能获得结果。
若你没有设置 remedys 此方法将不会被回调。
- method
remedysinline fun remedys(initiate: RemedyPlan.() -> Unit): Result +
Change Records
v1.0
first
v1.0.80
modified
将方法体进行 inline
Function Illustrate
创建
Constructor
重查找功能。Function Example
当你遇到一种
Constructor
可能存在不同形式的存在时,可以使用RemedyPlan
重新查找它,而没有必要使用onNoSuchConstructor
捕获异常二次查找Constructor
。若第一次查找失败了,你还可以在这里继续添加此方法体直到成功为止。
The following example
constructor { + // Your code here. +}.remedys { + constructor { + // Your code here. + } + constructor { + // Your code here. + } +} +
- method
onNoSuchConstructorinline fun onNoSuchConstructor(result: (Throwable) -> Unit): Result +
Change Records
v1.0
first
v1.0.80
modified
将方法体进行 inline
Function Illustrate
监听找不到
Constructor
时。只会返回第一次的错误信息,不会返回
RemedyPlan
的错误信息。- method
ignoredfun ignored(): Result +
Change Records
v1.1.0
added
Function Illustrate
忽略异常并停止打印任何错误日志。
若
MemberBaseFinder.MemberHookerManager.isNotIgnoredNoSuchMemberFailure
为false
则自动忽略。Notice
此时若要监听异常结果,你需要手动实现 onNoSuchConstructor 方法。
ignoredError - method
Change Records
v1.0.3
added
v1.1.0
deprecated
请迁移到新方法
ignored()
- class
Instanceinner class Instance internal constructor(private val constructor: Constructor<*>?) +
Change Records
v1.0.2
added
v1.1.0
modified
新增
constructor
参数Function Illustrate
Constructor
实例处理类。- method
callfun call(vararg args: Any?): Any? +
Change Records
v1.0.2
added
v1.1.6
modified
修改参数命名
param
为args
Function Illustrate
执行
Constructor
创建目标实例,不指定目标实例类型。- method
newInstancefun <T> newInstance(vararg args: Any?): T? +
Change Records
v1.0.2
added
v1.1.6
modified
修改参数命名
param
为args
Function Illustrate
执行
Constructor
创建目标实例 ,指定T
目标实例类型。FieldFinder - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/core/finder/members/MethodFinder.html b/en/api/public/com/highcapable/yukihookapi/hook/core/finder/members/MethodFinder.html new file mode 100644 index 00000000..1b63a731 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/core/finder/members/MethodFinder.html @@ -0,0 +1,137 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
FieldFinderclass FieldFinder internal constructor(override val classSet: Class<*>?) : MemberBaseFinder +
Change Records
v1.0
first
v1.0.2
modified
合并到
BaseFinder
v1.1.0
modified
合并到
MemberBaseFinder
v1.1.8
modified
移动
hookInstance
参数到MemberBaseFinder.MemberHookerManager
Function Illustrate
Field
查找类。可通过指定类型查找指定
Field
或一组Field
。classSet - field
Change Records
v1.0
first
v1.0.2
移除
- field
namevar name: String +
Change Records
v1.0
first
v1.0.70
modified
允许不填写名称
Function Illustrate
设置
Field
名称。Pay Attention
若不填写名称则必须存在一个其它条件。
- field
typevar type: Any? +
Change Records
v1.0
first
Function Illustrate
设置
Field
类型。可不填写类型。
- method
modifiersfun modifiers(conditions: ModifierConditions): IndexTypeCondition +
Change Records
v1.0.67
added
v1.0.80
modified
将方法体进行 inline
v1.1.0
modified
合并到
ModifierConditions
Function Illustrate
设置
Field
标识符筛选条件。可不设置筛选条件。
Pay Attention
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
- method
orderfun order(): IndexTypeCondition +
Change Records
v1.0.70
added
Function Illustrate
顺序筛选字节码的下标。
- method
namefun name(value: String): IndexTypeCondition +
Change Records
v1.0.70
added
Function Illustrate
设置
Field
名称。Pay Attention
若不填写名称则必须存在一个其它条件。
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
- method
namefun name(conditions: NameConditions): IndexTypeCondition +
Change Records
v1.0.88
added
v1.1.0
modified
合并到
NameConditions
Function Illustrate
设置
Field
名称条件。Pay Attention
若不填写名称则必须存在一个其它条件。
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
- method
typefun type(value: Any): IndexTypeCondition +
Change Records
v1.0.70
added
Function Illustrate
设置
Field
类型。可不填写类型。
Pay Attention
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
- method
typefun type(conditions: ObjectConditions): IndexTypeCondition +
Change Records
v1.1.5
added
Function Illustrate
设置
Field
类型条件。可不填写类型。
Pay Attention
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
- method
superClassfun superClass(isOnlySuperClass: Boolean) +
Change Records
v1.0.80
added
Function Illustrate
设置在
classSet
的所有父类中查找当前Field
。Notice
若当前 classSet 的父类较多可能会耗时,API 会自动循环到父类继承是 Any 前的最后一个类。
- class
RemedyPlaninner class RemedyPlan internal constructor() +
Change Records
v1.1.0
added
Function Illustrate
Field
重查找实现类,可累计失败次数直到查找成功。- method
fieldinline fun field(initiate: FieldConditions): Result +
Change Records
v1.1.0
added
Function Illustrate
创建需要重新查找的
Field
。你可以添加多个备选
Field
,直到成功为止,若最后依然失败,将停止查找并输出错误日志。- class
Resultinner class Result internal constructor() +
Change Records
v1.1.0
added
Function Illustrate
RemedyPlan
结果实现类。- method
onFindfun onFind(initiate: MutableList<Field>.() -> Unit) +
Change Records
v1.1.0
added
v1.2.0
modified
initiate
类型由HashSet
修改为MutableList
Function Illustrate
当在
RemedyPlan
中找到结果时。功能示例
你可以方便地对重查找的
Field
实现onFind
方法。示例如下
field { + // Your code here. +}.onFind { + // Your code here. +} +
- class
Resultinner class Result internal constructor(internal val isNoSuch: Boolean, internal val throwable: Throwable?) : BaseResult +
Change Records
v1.0
first
v1.1.0
modified
继承到接口
BaseResult
Function Illustrate
Field
查找结果实现类。- method
resultinline fun result(initiate: Result.() -> Unit): Result +
Change Records
v1.0
first
v1.0.80
modified
将方法体进行 inline
Function Illustrate
创建监听结果事件方法体。
功能示例
你可以使用 lambda 形式创建
Result
类。示例如下
field { + // Your code here. +}.result { + get(instance).set("something") + get(instance).string() + get(instance).cast<CustomClass>() + get().boolean() + all(instance) + give() + giveAll() + onNoSuchField {} +} +
- method
getfun get(instance: Any?): Instance +
Change Records
v1.0
first
Function Illustrate
获得
Field
实例处理类。若有多个
Field
结果只会返回第一个。功能示例
你可以轻松地得到
Field
的实例以及使用它进行设置实例。示例如下
field { + // Your code here. +}.get(instance).set("something") +
如果你取到的是静态
Field
,可以不需要设置实例。示例如下
field { + // Your code here. +}.get().set("something") +
- method
allfun all(instance: Any?): MutableList<Instance> +
Change Records
v1.1.0
added
v1.2.0
modified
返回值类型由
ArrayList
修改为MutableList
Function Illustrate
获得
Field
实例处理类数组。返回全部查找条件匹配的多个
Field
实例结果。功能示例
你可以通过此方法来获得当前条件结果中匹配的全部
Field
,其Field
所在实例用法与get
相同。示例如下
field { + // Your code here. +}.all(instance).forEach { instance -> + instance.self +} +
- method
givefun give(): Field? +
Change Records
v1.0
first
Function Illustrate
得到
Field
本身。若有多个 Field 结果只会返回第一个。
在查找条件找不到任何结果的时候将返回
null
。- method
giveAllfun giveAll(): MutableList<Field> +
Change Records
v1.1.0
added
v1.2.0
modified
返回值类型由
HashSet
修改为MutableList
Function Illustrate
得到
Field
本身数组。返回全部查找条件匹配的多个
Field
实例。在查找条件找不到任何结果的时候将返回空的
MutableList
。- method
waitfun wait(instance: Any?, initiate: Instance.() -> Unit) +
Change Records
v1.1.0
added
Function Illustrate
获得
Field
实例处理类,配合RemedyPlan
使用。若有多个
Field
结果只会返回第一个。Pay Attention
若你设置了 remedys 必须使用此方法才能获得结果。
若你没有设置 remedys 此方法将不会被回调。
- method
waitAllfun waitAll(instance: Any?, initiate: MutableList<Instance>.() -> Unit) +
Change Records
v1.1.0
added
v1.2.0
modified
initiate
类型由ArrayList
修改为MutableList
Function Illustrate
获得
Field
实例处理类数组,配合RemedyPlan
使用。返回全部查找条件匹配的多个
Field
实例结果。Pay Attention
若你设置了 remedys 必须使用此方法才能获得结果。
若你没有设置 remedys 此方法将不会被回调。
- method
remedysinline fun remedys(initiate: RemedyPlan.() -> Unit): Result +
Change Records
v1.1.0
added
Function Illustrate
创建
Field
重查找功能。功能示例
当你遇到一种
Field
可能存在不同形式的存在时,可以使用RemedyPlan
重新查找它,而没有必要使用onNoSuchField
捕获异常二次查找Field
。若第一次查找失败了,你还可以在这里继续添加此方法体直到成功为止。
示例如下
field { + // Your code here. +}.remedys { + field { + // Your code here. + } + field { + // Your code here. + } +} +
- method
onNoSuchFieldfun onNoSuchField(result: (Throwable) -> Unit): Result +
Change Records
v1.0
first
Function Illustrate
监听找不到
Field
时。- method
ignoredfun ignored(): Result +
Change Records
v1.1.0
added
Function Illustrate
忽略异常并停止打印任何错误日志。
若
MemberBaseFinder.MemberHookerManager.isNotIgnoredNoSuchMemberFailure
为false
则自动忽略。Notice
此时若要监听异常结果,你需要手动实现 onNoSuchField 方法。
ignoredError - method
Change Records
v1.0.3
added
v1.1.0
deprecated
请迁移到新方法
ignored()
- class
Instanceinner class Instance internal constructor(private val instance: Any?, private val field: Field?) +
Change Records
v1.0
first
v1.1.0
modified
新增
field
参数不再对外公开
self
参数Function Illustrate
Field
实例变量处理类。self - field
Change Records
v1.0
first
v1.1.0
移除
请直接使用
any
方法得到Field
自身的实例化对象- method
currentfun current(ignored: Boolean): CurrentClass? +
inline fun current(ignored: Boolean, initiate: CurrentClass.() -> Unit): Any? +
Change Records
v1.1.0
added
Function Illustrate
获得当前
Field
自身self
实例的类操作对象CurrentClass
。- method
castfun <T> cast(): T? +
Change Records
v1.0
first
v1.0.68
modified
修改
为of
cast
移动方法到
Instance
Function Illustrate
得到当前
Field
实例。- method
bytefun byte(): Byte? +
Change Records
v1.0.68
added
Function Illustrate
得到当前
Field
Byte 实例。- method
intfun int(): Int +
Change Records
v1.0.65
added
v1.0.68
modified
修改
为ofInt
int
移动方法到
Instance
Function Illustrate
得到当前
Field
Int 实例。- method
longfun long(): Long +
Change Records
v1.0.65
added
v1.0.68
modified
修改
为ofLong
long
移动方法到
Instance
Function Illustrate
得到当前
Field
Long 实例。- method
shortfun short(): Short +
Change Records
v1.0.65
added
v1.0.68
modified
修改
为ofShort
short
移动方法到
Instance
Function Illustrate
得到当前
Field
Short 实例。- method
doublefun double(): Double +
Change Records
v1.0.65
added
v1.0.68
modified
修改
为ofDouble
double
移动方法到
Instance
Function Illustrate
得到当前
Field
Double 实例。- method
floatfun float(): Float +
Change Records
v1.0.65
added
v1.0.68
modified
修改
为ofFloat
float
移动方法到
Instance
Function Illustrate
得到当前
Field
Float 实例。- method
stringfun string(): String +
Change Records
v1.0.65
added
v1.0.68
modified
修改
为ofString
string
移动方法到
Instance
Function Illustrate
得到当前
Field
String 实例。- method
charfun char(): Char +
Change Records
v1.0.68
added
Function Illustrate
得到当前
Field
Char 实例。- method
booleanfun boolean(): Boolean +
Change Records
v1.0.65
added
v1.0.68
modified
修改
为ofBoolean
boolean
移动方法到
Instance
Function Illustrate
得到当前
Field
Boolean 实例。- method
anyfun any(): Any? +
Change Records
v1.0.65
added
v1.0.68
modified
修改
为ofAny
any
移动方法到
Instance
Function Illustrate
得到当前
Field
Any 实例。- method
arrayinline fun <reified T> array(): Array<T> +
Change Records
v1.0.68
added
Function Illustrate
得到当前
Field
Array 实例。- method
listinline fun <reified T> list(): List<T> +
Change Records
v1.0.68
added
Function Illustrate
得到当前
Field
List 实例。- method
setfun set(any: Any?) +
Change Records
v1.0
first
Function Illustrate
设置当前
Field
实例。- method
setTruefun setTrue() +
Change Records
v1.0
first
Function Illustrate
设置当前
Field
实例为true
。Pay Attention
请确保实例对象类型为 Boolean。
- method
setFalsefun setFalse() +
Change Records
v1.0
first
Function Illustrate
设置当前
Field
实例为false
。Pay Attention
请确保实例对象类型为 Boolean。
- method
setNullfun setNull() +
Change Records
v1.0
first
Function Illustrate
设置当前
Field
实例为null
。MethodFinder - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/entity/YukiBaseHooker.html b/en/api/public/com/highcapable/yukihookapi/hook/entity/YukiBaseHooker.html new file mode 100644 index 00000000..726b2906 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/entity/YukiBaseHooker.html @@ -0,0 +1,36 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
MethodFinderclass MethodFinder internal constructor(override val classSet: Class<*>) : MemberBaseFinder +
Change Records
v1.0
first
v1.0.2
modified
合并到
BaseFinder
v1.1.0
modified
合并到
MemberBaseFinder
v1.1.8
modified
移动
hookInstance
参数到MemberBaseFinder.MemberHookerManager
Function Illustrate
Method
查找类。可通过指定类型查找指定
Method
或一组Method
。- field
namevar name: String +
Change Records
v1.0
first
v1.0.70
modified
允许不填写名称
Function Illustrate
设置
Method
名称。Pay Attention
若不填写名称则必须存在一个其它条件。
- field
paramCountvar paramCount: Int +
Change Records
v1.0.67
added
Function Illustrate
设置
Method
参数个数。你可以不使用
param
指定参数类型而是仅使用此变量指定参数个数。若参数个数小于零则忽略并使用
param
。- field
returnTypevar returnType: Any? +
Change Records
v1.0
first
Function Illustrate
设置
Method
返回值,可不填写返回值。- method
modifiersfun modifiers(conditions: ModifierConditions): IndexTypeCondition +
Change Records
v1.0.67
added
v1.0.80
modified
将方法体进行 inline
v1.1.0
modified
合并到
ModifierConditions
Function Illustrate
设置
Method
标识符筛选条件。可不设置筛选条件。
Pay Attention
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
- method
emptyParamfun emptyParam(): IndexTypeCondition +
Change Records
v1.0.75
added
Function Illustrate
设置
Method
空参数、无参数。- method
paramfun param(vararg paramType: Any): IndexTypeCondition +
Change Records
v1.0
first
Function Illustrate
设置
Method
参数。如果同时使用了
paramCount
则paramType
的数量必须与paramCount
完全匹配。如果
Method
中存在一些无意义又很长的类型,你可以使用 VagueType 来替代它。Pay Attention
无参 Method 请使用 emptyParam 设置查找条件。
有参 Method 必须使用此方法设定参数或使用 paramCount 指定个数。
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
- method
paramfun param(conditions: ObjectsConditions): IndexTypeCondition +
Change Records
v1.1.5
added
Function Illustrate
设置
Method
参数条件。Pay Attention
无参 Method 请使用 emptyParam 设置查找条件。
有参 Method 必须使用此方法设定参数或使用 paramCount 指定个数。
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
- method
orderfun order(): IndexTypeCondition +
Change Records
v1.0.70
added
Function Illustrate
顺序筛选字节码的下标。
- method
namefun name(value: String): IndexTypeCondition +
Change Records
v1.0.70
added
Function Illustrate
设置
Method
名称。Pay Attention
若不填写名称则必须存在一个其它条件。
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
- method
namefun name(conditions: NameConditions): IndexTypeCondition +
Change Records
v1.0.88
added
v1.1.0
modified
合并到
NameConditions
Function Illustrate
设置
Method
名称条件。Pay Attention
若不填写名称则必须存在一个其它条件。
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
- method
paramCountfun paramCount(num: Int): IndexTypeCondition +
Change Records
v1.0.70
added
Function Illustrate
设置
Method
参数个数。你可以不使用
param
指定参数类型而是仅使用此方法指定参数个数。若参数个数小于零则忽略并使用
param
。Pay Attention
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
- method
paramCountfun paramCount(numRange: IntRange): IndexTypeCondition +
Change Records
v1.1.0
added
Function Illustrate
设置
Method
参数个数范围。你可以不使用
param
指定参数类型而是仅使用此方法指定参数个数范围。Pay Attention
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
- method
paramCountfun paramCount(conditions: CountConditions): IndexTypeCondition +
Change Records
v1.1.0
added
Function Illustrate
设置
Method
参数个数条件。你可以不使用
param
指定参数类型而是仅使用此方法指定参数个数条件。Pay Attention
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
- method
returnTypefun returnType(value: Any): IndexTypeCondition +
Change Records
v1.0.70
added
Function Illustrate
设置
Method
返回值。可不填写返回值。
Pay Attention
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
- method
returnTypefun returnType(conditions: ObjectConditions): IndexTypeCondition +
Change Records
v1.1.5
added
Function Illustrate
设置
Method
返回值条件。可不填写返回值。
Pay Attention
存在多个 IndexTypeCondition 时除了 order 只会生效最后一个。
- method
superClassfun superClass(isOnlySuperClass: Boolean) +
Change Records
v1.0.80
added
Function Illustrate
设置在
classSet
的所有父类中查找当前Method
。Notice
若当前 classSet 的父类较多可能会耗时,API 会自动循环到父类继承是 Any 前的最后一个类。
- class
RemedyPlaninner class RemedyPlan internal constructor() +
Change Records
v1.0
first
Function Illustrate
Method
重查找实现类,可累计失败次数直到查找成功。- method
methodinline fun method(initiate: MethodConditions): Result +
Change Records
v1.0
first
v1.0.80
modified
将方法体进行 inline
Function Illustrate
创建需要重新查找的
Method
。你可以添加多个备选
Method
,直到成功为止,若最后依然失败,将停止查找并输出错误日志。- class
Resultinner class Result internal constructor() +
Change Records
v1.0.1
added
Function Illustrate
RemedyPlan
结果实现类。- method
onFindfun onFind(initiate: MutableList<Method>.() -> Unit) +
Change Records
v1.0.1
added
v1.1.0
modified
initiate
参数Method
变为HashSet<Method>
v1.2.0
modified
initiate
类型由HashSet
修改为MutableList
Function Illustrate
当在
RemedyPlan
中找到结果时。Function Example
你可以方便地对重查找的
Method
实现onFind
方法。The following example
method { + // Your code here. +}.onFind { + // Your code here. +} +
- class
Processinner class Process internal constructor(internal val isNoSuch: Boolean, internal val throwable: Throwable?) : BaseResult +
Change Records
v1.1.0
added
Function Illustrate
Method
查找结果处理类,为hookManager
提供。- method
resultinline fun result(initiate: Process.() -> Unit): Process +
Change Records
v1.1.0
added
Function Illustrate
创建监听结果事件方法体。
Function Example
你可以使用 lambda 形式创建
Result
类。The following example
method { + // Your code here. +}.result { + all() + remedys {} + onNoSuchMethod {} +} +
- method
allfun all(): Process +
Change Records
v1.1.0
added
Function Illustrate
设置全部查找条件匹配的多个
Method
实例结果到hookManager
。- method
remedysinline fun remedys(initiate: RemedyPlan.() -> Unit): Result +
Change Records
v1.1.0
added
Function Illustrate
创建
Method
重查找功能。Function Example
当你遇到一种
Method
可能存在不同形式的存在时,可以使用RemedyPlan
重新查找它,而没有必要使用onNoSuchMethod
捕获异常二次查找Method
。若第一次查找失败了,你还可以在这里继续添加此方法体直到成功为止。
The following example
method { + // Your code here. +}.remedys { + method { + // Your code here. + } + method { + // Your code here. + } +} +
- method
onNoSuchMethodinline fun onNoSuchMethod(result: (Throwable) -> Unit): Result +
Change Records
v1.1.0
added
Function Illustrate
监听找不到
Method
时。只会返回第一次的错误信息,不会返回
RemedyPlan
的错误信息。- class
Resultinner class Result internal constructor(internal val isNoSuch: Boolean, private val throwable: Throwable?) : BaseResult +
Change Records
v1.0
first
v1.1.0
modified
继承到接口
BaseResult
Function Illustrate
Method
查找结果实现类。- method
resultinline fun result(initiate: Result.() -> Unit): Result +
Change Records
v1.0
first
v1.0.80
modified
将方法体进行 inline
Function Illustrate
创建监听结果事件方法体。
Function Example
你可以使用 lambda 形式创建
Result
类。The following example
method { + // Your code here. +}.result { + get(instance).call() + all(instance) + remedys {} + onNoSuchMethod {} +} +
- method
getfun get(instance: Any?): Instance +
Change Records
v1.0.2
added
Function Illustrate
获得
Method
实例处理类。若有多个
Method
结果只会返回第一个。Pay Attention
若你设置了 remedys 请使用 wait 回调结果方法。
Function Example
你可以通过获得方法所在实例来执行
Method
。The following example
method { + // Your code here. +}.get(instance).call() +
若当前为静态方法,你可以不设置实例。
The following example
method { + // Your code here. +}.get().call() +
- method
allfun all(instance: Any?): MutableList<Instance> +
Change Records
v1.1.0
added
v1.2.0
modified
返回值类型由
ArrayList
修改为MutableList
Function Illustrate
获得
Method
实例处理类数组。返回全部查找条件匹配的多个
Method
实例结果。Function Example
你可以通过此方法来获得当前条件结果中匹配的全部
Method
,其方法所在实例用法与get
相同。The following example
method { + // Your code here. +}.all(instance).forEach { instance -> + instance.call(...) +} +
- method
givefun give(): Method? +
Change Records
v1.0.67
added
Function Illustrate
得到
Method
本身。若有多个
Method
结果只会返回第一个。在查找条件找不到任何结果的时候将返回
null
。- method
giveAllfun giveAll(): MutableList<Method> +
Change Records
v1.1.0
added
v1.2.0
modified
返回值类型由
HashSet
修改为MutableList
Function Illustrate
得到
Method
本身数组。返回全部查找条件匹配的多个
Method
实例。在查找条件找不到任何结果的时候将返回空的
MutableList
。- method
waitfun wait(instance: Any?, initiate: Instance.() -> Unit) +
Change Records
v1.0.2
added
Function Illustrate
获得
Method
实例处理类,配合RemedyPlan
使用。若有多个
Method
结果只会返回第一个。Pay Attention
若你设置了 remedys 必须使用此方法才能获得结果。
若你没有设置 remedys 此方法将不会被回调。
- method
waitAllfun waitAll(instance: Any?, initiate: MutableList<Instance>.() -> Unit) +
Change Records
v1.1.0
added
v1.2.0
modified
initiate
类型由ArrayList
修改为MutableList
Function Illustrate
获得
Method
实例处理类数组,配合RemedyPlan
使用。返回全部查找条件匹配的多个
Method
实例结果。Pay Attention
若你设置了 remedys 必须使用此方法才能获得结果。
若你没有设置 remedys 此方法将不会被回调。
- method
remedysinline fun remedys(initiate: RemedyPlan.() -> Unit): Result +
Change Records
v1.0
first
v1.0.80
modified
将方法体进行 inline
Function Illustrate
创建
Method
重查找功能。Function Example
当你遇到一种
Method
可能存在不同形式的存在时,可以使用RemedyPlan
重新查找它,而没有必要使用onNoSuchMethod
捕获异常二次查找Method
。若第一次查找失败了,你还可以在这里继续添加此方法体直到成功为止。
The following example
method { + // Your code here. +}.remedys { + method { + // Your code here. + } + method { + // Your code here. + } +} +
- method
onNoSuchMethodinline fun onNoSuchMethod(result: (Throwable) -> Unit): Result +
Change Records
v1.0
first
v1.0.80
modified
将方法体进行 inline
Function Illustrate
监听找不到
Method
时。只会返回第一次的错误信息,不会返回
RemedyPlan
的错误信息。- method
ignoredfun ignored(): Result +
Change Records
v1.1.0
added
Function Illustrate
忽略异常并停止打印任何错误日志。
若
MemberBaseFinder.MemberHookerManager.isNotIgnoredNoSuchMemberFailure
为false
则自动忽略。Notice
此时若要监听异常结果,你需要手动实现 onNoSuchMethod 方法。
ignoredError - method
Change Records
v1.0.3
added
v1.1.0
deprecated
请迁移到新方法
ignored()
- class
Instanceinner class Instance internal constructor(private val instance: Any?, private val method: Method?) +
Change Records
v1.0.2
added
v1.1.0
modified
新增
method
参数Function Illustrate
Method
实例处理类。- method
originalfun original(): Instance +
Change Records
v1.1.0
added
Function Illustrate
标识需要调用当前
Method
未经 Hook 的原始方法。若当前
Method
并未 Hook 则会使用原始的Method.invoke
方法调用。Pay Attention
你只能在 (Xposed) 宿主环境中使用此功能。
- method
callfun call(vararg args: Any?): Any? +
Change Records
v1.0.2
added
v1.1.6
modified
修改参数命名
param
为args
Function Illustrate
执行
Method
,不指定返回值类型。- method
invokefun <T> invoke(vararg args: Any?): T? +
Change Records
v1.0.2
added
v1.1.6
modified
修改参数命名
param
为args
Function Illustrate
执行
Method
,指定T
返回值类型。- method
bytefun byte(vararg args: Any?): Byte? +
Change Records
v1.0.68
added
v1.1.6
modified
修改参数命名
param
为args
Function Illustrate
执行
Method
,指定 Byte 返回值类型。- method
intfun int(vararg args: Any?): Int +
Change Records
v1.0.65
added
v1.0.68
modified
修改
为callInt
int
v1.1.6
modified
修改参数命名
param
为args
Function Illustrate
执行
Method
,指定 Int 返回值类型。- method
longfun long(vararg args: Any?): Long +
Change Records
v1.0.65
added
v1.0.68
modified
修改
为callLong
long
v1.1.6
modified
修改参数命名
param
为args
Function Illustrate
执行
Method
,指定 Long 返回值类型。- method
shortfun short(vararg args: Any?): Short +
Change Records
v1.0.65
added
v1.0.68
modified
修改
为callShort
short
v1.1.6
modified
修改参数命名
param
为args
Function Illustrate
执行
Method
,指定 Short 返回值类型。- method
doublefun double(vararg args: Any?): Double +
Change Records
v1.0.65
added
v1.0.68
modified
修改
为callDouble
double
v1.1.6
modified
修改参数命名
param
为args
Function Illustrate
执行
Method
,指定 Double 返回值类型。- method
floatfun float(vararg args: Any?): Float +
Change Records
v1.0.65
added
v1.0.68
modified
修改
为callFloat
float
v1.1.6
modified
修改参数命名
param
为args
Function Illustrate
执行
Method
,指定 Float 返回值类型。- method
stringfun string(vararg args: Any?): String +
Change Records
v1.0.65
added
v1.0.68
modified
修改
为callString
string
v1.1.6
modified
修改参数命名
param
为args
Function Illustrate
执行
Method
,指定 String 返回值类型。- method
charfun char(vararg args: Any?): Char +
Change Records
v1.0.68
added
v1.1.6
modified
修改参数命名
param
为args
Function Illustrate
执行
Method
,指定 Char 返回值类型。- method
booleanfun boolean(vararg args: Any?): Boolean +
Change Records
v1.0.65
added
v1.0.68
modified
修改
为callBoolean
boolean
v1.1.6
modified
修改参数命名
param
为args
Function Illustrate
执行
Method
,指定 Boolean 返回值类型。- method
arrayinline fun <reified T> array(vararg args: Any?): Array<T> +
Change Records
v1.0.68
added
v1.1.6
modified
修改参数命名
param
为args
Function Illustrate
执行
Method
,指定 Array 返回值类型。- method
listinline fun <reified T> list(vararg args: Any?): List<T> +
Change Records
v1.0.68
added
v1.1.6
modified
修改参数命名
param
为args
Function Illustrate
执行
Method
,指定 List 返回值类型。YukiBaseHooker - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.html b/en/api/public/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.html new file mode 100644 index 00000000..a7535604 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.html @@ -0,0 +1,153 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
YukiBaseHookerabstract class YukiBaseHooker : PackageParam() +
Change Records
v1.0
first
Function Illustrate
YukiHookAPI
的子类 Hooker 实现。- method
onHookfun onHook() +
Change Records
v1.0
first
Function Illustrate
子类 Hook 开始。
ReflectionFactory - kt | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/factory/YukiHookFactory.html b/en/api/public/com/highcapable/yukihookapi/hook/factory/YukiHookFactory.html new file mode 100644 index 00000000..e1c1e8df --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/factory/YukiHookFactory.html @@ -0,0 +1,44 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- kt
ReflectionFactoryChange Records
v1.0
first
Function Illustrate
这是自定义
Member
和Class
相关功能的查找匹配以及invoke
的封装类。- class
MembersTypeenum class MembersType +
Change Records
v1.1.0
added
Function Illustrate
定义一个
Class
中的Member
类型- enum
ALLALL +
Change Records
v1.1.0
added
Function Illustrate
全部
Method
与Constructor
。- enum
METHODMETHOD +
Change Records
v1.1.0
added
Function Illustrate
全部
Method
。- enum
CONSTRUCTORCONSTRUCTOR +
Change Records
v1.1.0
added
Function Illustrate
全部
Constructor
。- class
LazyClassopen class LazyClass<T> internal constructor( + private val instance: Any, + private val initialize: Boolean, + private val loader: ClassLoaderInitializer? +) +
Change Records
v1.2.0
added
Function Illustrate
懒装载
Class
实例。- ext-method
ClassLoader.listOfClassesfun ClassLoader.listOfClasses(): List<String> +
Change Records
v1.1.2
added
Function Illustrate
写出当前
ClassLoader
下所有Class
名称数组。- ext-method
ClassLoader.searchClassinline fun ClassLoader.searchClass(name: String, async: Boolean, initiate: ClassConditions): DexClassFinder.Result +
Change Records
v1.1.0
added
Function Illustrate
通过当前
ClassLoader
按指定条件查找并得到 Dex 中的Class
。Pay Attention
此方法在 Class 数量过多及查找条件复杂时会非常耗时。
建议启用 async 或设置 name 参数,name 参数将在 Hook APP (宿主) 不同版本中自动进行本地缓存以提升效率。
此功能尚在实验阶段,性能与稳定性可能仍然存在问题,使用过程遇到问题请向我们报告并帮助我们改进。
- ext-method
ClassLoader.onLoadClassfun ClassLoader.onLoadClass(result: (Class<*>) -> Unit) +
Change Records
v1.1.0
added
Function Illustrate
监听当前
ClassLoader
的ClassLoader.loadClass
方法装载。Pay Attention
只有当前 ClassLoader 有主动使用 ClassLoader.loadClass 事件时才能被捕获。
这是一个实验性功能,一般情况下不会用到此方法,不保证不会发生错误。
只能在 (Xposed) 宿主环境使用此功能,其它环境下使用将不生效且会打印警告信息。
Function Example
针对一些使用特定
ClassLoader
装载Class
的宿主应用,你可以使用此方法来监听Class
加载情况。Notice
为了防止发生问题,你需要得到一个存在的 ClassLoader 实例来使用此功能。
比如我们在
PackageParam
中使用appClassLoader
。The following example
appClassLoader.onLoadClass { clazz -> + // 得到 clazz 即加载对象 + clazz... // 这里进行你需要的操作 +} +
或使用你得到的存在的
ClassLoader
实例,可以通过 Hook 获取。The following example
val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader +customClassLoader?.onLoadClass { clazz -> + // ... +} +
在判断到这个
Class
被装载成功时,开始执行你的 Hook 功能。The following example
val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader +customClassLoader?.onLoadClass { clazz -> + if(clazz.name == /** 你需要的 Class 名称 */) { + clazz.hook { + // ... + } + } +} +
hookClass - field
Change Records
v1.0
first
v1.1.0
removed
HookClass
相关功能不再对外开放normalClass - field
Change Records
v1.0
first
v1.1.0
removed
HookClass
相关功能不再对外开放hasClass - field
Change Records
v1.0
first
v1.1.0
removed
请直接使用
hasClass()
无参方法- ext-field
Class.hasExtendsval Class<*>.hasExtends: Boolean +
Change Records
v1.0.80
added
Function Illustrate
当前
Class
是否有继承关系,父类是Any
将被认为没有继承关系。- ext-method
Class?.extendsinfix fun Class<*>?.extends(other: Class<*>?): Boolean +
Change Records
v1.1.5
added
Function Illustrate
当前
Class
是否继承于other
。如果当前
Class
就是other
也会返回true
。如果当前
Class
为null
或other
为null
会返回false
。Function Example
你可以使用此方法来判断两个
Class
是否存在继承关系。The following example
// 假设下面这两个 Class 就是你需要判断的 Class +val classA: Class<*>? +val classB: Class<*>? +// 判断 A 是否继承于 B +if (classA extends classB) { + // Your code here. +} +
- ext-method
Class?.notExtendsinfix fun Class<*>?.notExtends(other: Class<*>?): Boolean +
Change Records
v1.1.5
added
Function Illustrate
当前
Class
是否不继承于other
。此方法相当于
extends
的反向判断。Function Example
你可以使用此方法来判断两个
Class
是否不存在继承关系。The following example
// 假设下面这两个 Class 就是你需要判断的 Class +val classA: Class<*>? +val classB: Class<*>? +// 判断 A 是否不继承于 B +if (classA notExtends classB) { + // Your code here. +} +
- ext-method
Class?.implementsinfix fun Class<*>?.implements(other: Class<*>?): Boolean +
Change Records
v1.1.5
added
Function Illustrate
当前
Class
是否实现了other
接口类。如果当前
Class
为null
或other
为null
会返回false
。Function Example
你可以使用此方法来判断两个
Class
是否存在依赖关系。The following example
// 假设下面这两个 Class 就是你需要判断的 Class +val classA: Class<*>? +val classB: Class<*>? +// 判断 A 是否实现了 B 接口类 +if (classA implements classB) { + // Your code here. +} +
- ext-method
Class?.notImplementsinfix fun Class<*>?.notImplements(other: Class<*>?): Boolean +
Change Records
v1.1.5
added
Function Illustrate
当前
Class
是否未实现other
接口类。此方法相当于
implements
的反向判断。Function Example
你可以使用此方法来判断两个
Class
是否不存在依赖关系。The following example
// 假设下面这两个 Class 就是你需要判断的 Class +val classA: Class<*>? +val classB: Class<*>? +// 判断 A 是否未实现 B 接口类 +if (classA notImplements classB) { + // Your code here. +} +
- ext-method
Class.toJavaPrimitiveTypefun Class<*>.toJavaPrimitiveType(): Class<*> +
Change Records
v1.1.5
added
Function Illustrate
自动转换当前
Class
为 Java 原始类型 (Primitive Type)。如果当前
Class
为 Java 或 Kotlin 基本类型将自动执行类型转换。当前能够自动转换的基本类型如下。
kotlin.Unit
java.lang.Void
java.lang.Boolean
java.lang.Integer
java.lang.Float
java.lang.Double
java.lang.Long
java.lang.Short
java.lang.Character
java.lang.Byte
classOf - method
Change Records
v1.0
first
v1.1.0
deprecated
请转到
toClass(...)
方法- ext-method
String.toClassfun String.toClass(loader: ClassLoader?, initialize: Boolean): Class<*> +
inline fun <reified T> String.toClass(loader: ClassLoader?, initialize: Boolean): Class<T> +
Change Records
v1.1.0
added
v1.1.5
modified
新增泛型返回值
Class<T>
方法新增
initialize
参数Function Illustrate
通过字符串类名转换为
loader
中的实体类。Function Example
你可以直接填写你要查找的目标
Class
,必须在默认ClassLoader
下存在。The following example
"com.example.demo.DemoClass".toClass() +
你还可以自定义
Class
所在的ClassLoader
。The following example
val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader +"com.example.demo.DemoClass".toClass(customClassLoader) +
你还可以指定
Class
的目标类型。The following example
// 指定的 DemoClass 必须存在或为可访问的 stub +"com.example.demo.DemoClass".toClass<DemoClass>() +
你还可以设置在获取到这个
Class
时是否自动执行其默认的静态方法块,默认情况下不会执行。The following example
// 获取并执行 DemoClass 默认的静态方法块 +"com.example.demo.DemoClass".toClass(initialize = true) +
默认的静态方法块在 Java 中使用如下方式定义。
The following example
public class DemoClass { + + static { + // 这里是静态方法块的内容 + } + + public DemoClass() { + // ... + } +} +
- ext-method
String.toClassOrNullfun String.toClassOrNull(loader: ClassLoader?, initialize: Boolean): Class<*>? +
inline fun <reified T> String.toClassOrNull(loader: ClassLoader?, initialize: Boolean): Class<T>? +
Change Records
v1.1.0
added
v1.1.5
modified
新增泛型返回值
Class<T>
方法新增
initialize
参数Function Illustrate
通过字符串类名转换为
loader
中的实体类。找不到
Class
会返回null
,不会抛出异常。Function Example
用法请参考 String.toClass 方法。
- method
classOfinline fun <reified T> classOf(loader: ClassLoader?, initialize: Boolean): Class<T> +
Change Records
v1.1.0
added
v1.1.5
modified
将返回类型由
Class<*>
cast 为Class<T>
新增
initialize
参数Function Illustrate
通过
T
得到其Class
实例并转换为实体类。Function Example
我们要获取一个
Class
在 Kotlin 下不通过反射时应该这样做。The following example
DemoClass::class.java +
现在,你可以直接
cast
一个实例并获取它的Class
对象,必须在当前ClassLoader
下存在。The following example
classOf<DemoClass>() +
若目标存在的
Class
为stub
,通过这种方式,你还可以自定义Class
所在的ClassLoader
。The following example
val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader +classOf<DemoClass>(customClassLoader) +
- method
lazyClassfun lazyClass(name: String, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.NonNull<Any> +
inline fun <reified T> lazyClass(name: String, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.NonNull<T> +
fun lazyClass(variousClass: VariousClass, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.NonNull<Any> +
Change Records
v1.2.0
added
Function Illustrate
懒装载
Class
。- method
lazyClassOrNullfun lazyClassOrNull(name: String, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.Nullable<Any> +
inline fun <reified T> lazyClassOrNull(name: String, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.Nullable<T> +
fun lazyClassOrNull(variousClass: VariousClass, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.Nullable<Any> +
Change Records
v1.2.0
added
Function Illustrate
懒装载
Class
。- ext-method
String.hasClassfun String.hasClass(loader: ClassLoader?): Boolean +
Change Records
v1.0
first
v1.1.0
modified
支持直接使用空参数方法使用默认
ClassLoader
进行判断Function Illustrate
通过字符串类名使用指定的
ClassLoader
查找是否存在。Function Example
你可以轻松的使用此方法判断字符串中的类是否存在,效果等同于直接使用
Class.forName
。The following example
if("com.example.demo.DemoClass".hasClass()) { + // Your code here. +} +
填入方法中的
loader
参数可判断指定的ClassLoader
中的Class
是否存在。The following example
val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader +if("com.example.demo.DemoClass".hasClass(customClassLoader)) { + // Your code here. +} +
- ext-method
Class.hasFieldinline fun Class<*>.hasField(initiate: FieldConditions): Boolean +
Change Records
v1.0.4
added
v1.0.67
modified
合并到
FieldFinder
v1.0.80
modified
将方法体进行 inline
Function Illustrate
查找变量是否存在。
- ext-method
Class.hasMethodinline fun Class<*>.hasMethod(initiate: MethodConditions): Boolean +
Change Records
v1.0
first
v1.0.1
modified
新增
returnType
参数
v1.0.67
modified
合并到
MethodFinder
v1.0.80
modified
将方法体进行 inline
Function Illustrate
查找方法是否存在。
- ext-method
Class.hasConstructorinline fun Class<*>.hasConstructor(initiate: ConstructorConditions): Boolean +
Change Records
v1.0.2
added
v1.0.67
modified
合并到
ConstructorFinder
v1.0.80
modified
将方法体进行 inline
Function Illustrate
查找构造方法是否存在。
- ext-method
Member.hasModifiersinline fun Member.hasModifiers(conditions: ModifierConditions): Boolean +
Change Records
v1.0.67
added
v1.0.80
modified
将方法体进行 inline
v1.1.0
modified
合并到
ModifierConditions
Function Illustrate
查找
Member
中匹配的描述符。- ext-method
Class.hasModifiersinline fun Class<*>.hasModifiers(conditions: ModifierConditions): Boolean +
Change Records
v1.1.0
added
Function Illustrate
查找
Class
中匹配的描述符。obtainStaticFieldAny - method
Change Records
v1.0
first
v1.0.1
removed
obtainFieldAny - method
Change Records
v1.0
first
v1.0.1
removed
modifyStaticField - method
Change Records
v1.0
first
v1.0.1
removed
modifyField - method
Change Records
v1.0
first
v1.0.1
removed
- ext-method
Class.fieldinline fun Class<*>.field(initiate: FieldConditions): FieldFinder.Result +
Change Records
v1.0.2
added
v1.0.80
modified
将方法体进行 inline
Function Illustrate
查找并得到变量。
- ext-method
Class.methodinline fun Class<*>.method(initiate: MethodConditions): MethodFinder.Result +
Change Records
v1.0
first
v1.0.1
modified
更名为obtainMethod
method
新增
returnType
参数
v1.0.2
modified
合并到
MethodFinder
方法体
v1.0.80
modified
将方法体进行 inline
Function Illustrate
查找并得到方法。
- ext-method
Class.constructorinline fun Class<*>.constructor(initiate: ConstructorConditions): ConstructorFinder.Result +
Change Records
v1.0
first
v1.0.1
modified
更名为obtainConstructor
constructor
v1.0.2
modified
合并到
ConstructorFinder
方法体
v1.0.80
modified
将方法体进行 inline
Function Illustrate
查找并得到构造方法。
callStatic - method
Change Records
v1.0
first
v1.0.1
modified
更名为invokeStatic
callStatic
v1.0.2
removed
call - method
Change Records
v1.0
first
v1.0.1
modified
更名为invokeAny
call
v1.0.2
removed
- ext-method
Class.genericfun Class<*>.generic(): GenericClass? +
Change Records
v1.1.0
added
Function Illustrate
获得当前
Class
的泛型父类。如果当前实例不存在泛型将返回
null
。- ext-method
Class.genericinline fun Class<*>.generic(initiate: GenericClass.() -> Unit): GenericClass? +
Change Records
v1.1.0
added
Function Illustrate
获得当前
Class
的泛型父类。如果当前实例不存在泛型将返回
null
。- ext-method
Any.currentinline fun <reified T : Any> T.current(ignored: Boolean): CurrentClass +
inline fun <reified T : Any> T.current(ignored: Boolean, initiate: CurrentClass.() -> Unit): T +
Change Records
v1.0.70
added
v1.1.0
added
新增
ignored
参数,可以忽略在CurrentClass
中出现的异常新增不使用
current { ... }
调用域直接使用current()
得到实例的类操作对象Function Illustrate
获得当前实例的类操作对象。
Class.buildOfAny - ext-method
Change Records
v1.0.70
added
v1.0.80
modified
将方法体进行 inline
v1.1.0
deprecated
请迁移到
buildOf
方法- ext-method
Class.buildOfinline fun Class<*>.buildOf(vararg args: Any?, initiate: ConstructorConditions): Any? +
inline fun <T> Class<*>.buildOf(vararg args: Any?, initiate: ConstructorConditions): T? +
Change Records
v1.0.70
added
v1.0.80
modified
将方法体进行 inline
v1.1.0
modified
加入无泛型方法
buildOf
v1.1.6
modified
修改参数命名
param
为args
Function Illustrate
通过构造方法创建新实例,指定类型
T
或任意类型Any
。- ext-method
Class.allMethodsinline fun Class<*>.allMethods(isAccessible: Boolean, result: (index: Int, method: Method) -> Unit) +
Change Records
v1.0.70
added
v1.0.80
modified
将方法体进行 inline
v1.1.5
modified
新增
isAccessible
参数Function Illustrate
遍历当前类中的所有方法。
- ext-method
Class.allConstructorsinline fun Class<*>.allConstructors(isAccessible: Boolean, result: (index: Int, constructor: Constructor<*>) -> Unit) +
Change Records
v1.0.70
added
v1.0.80
modified
将方法体进行 inline
v1.1.5
modified
新增
isAccessible
参数Function Illustrate
遍历当前类中的所有构造方法。
- ext-method
Class.allFieldsinline fun Class<*>.allFields(isAccessible: Boolean, result: (index: Int, field: Field) -> Unit) +
Change Records
v1.0.70
added
v1.0.80
modified
将方法体进行 inline
v1.1.5
modified
新增
isAccessible
参数Function Illustrate
遍历当前类中的所有变量。
YukiHookFactory - kt | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/log/YLog.html b/en/api/public/com/highcapable/yukihookapi/hook/log/YLog.html new file mode 100644 index 00000000..a966f4cd --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/log/YLog.html @@ -0,0 +1,62 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- kt
YukiHookFactoryChange Records
v1.0
first
v1.0.80
modified
合并到
IYukiHookXposedInit
,将方法体进行 inlineFunction Illustrate
这是
YukiHookAPI
相关 lambda 方法的封装类以及部分 API 用法。- ext-method
IYukiHookXposedInit.configsinline fun IYukiHookXposedInit.configs(initiate: YukiHookAPI.Configs.() -> Unit) +
Change Records
v1.0.1
added
v1.0.80
modified
合并到
IYukiHookXposedInit
Function Illustrate
在
IYukiHookXposedInit
中配置Configs
。- ext-method
IYukiHookXposedInit.encasefun IYukiHookXposedInit.encase(initiate: PackageParam.() -> Unit) +
fun IYukiHookXposedInit.encase(vararg hooker: YukiBaseHooker) +
Change Records
v1.0
first
v1.0.80
modified
合并到
IYukiHookXposedInit
Function Illustrate
在
IYukiHookXposedInit
中调用YukiHookAPI
。Context.modulePrefs - ext-field
Change Records
v1.0
first
v1.1.9
deprecated
请迁移到
prefs
方法Context.modulePrefs - ext-method
Change Records
v1.0
first
v1.1.9
deprecated
请迁移到
prefs
方法- ext-method
Context.prefsfun Context.prefs(name: String): YukiHookPrefsBridge +
Change Records
v1.1.9
added
Function Illustrate
创建
YukiHookPrefsBridge
对象。可以同时在模块与 (Xposed) 宿主环境中使用。
如果你想在 (Xposed) 宿主环境将数据存入当前宿主的私有空间,请使用
YukiHookPrefsBridge.native
方法。在未声明任何条件的情况下 (Xposed) 宿主环境默认读取模块中的数据。
- ext-method
Context.dataChannelfun Context.dataChannel(packageName: String): YukiHookDataChannel.NameSpace +
Change Records
v1.0.88
added
Function Illustrate
获取
YukiHookDataChannel
对象。Pay Attention
只能在模块环境使用此功能,其它环境下使用将不起作用。
- ext-field
Context.processNameval Context.processName: String +
Change Records
v1.0
first
Function Illustrate
获取当前进程名称。
- ext-method
Context+Resources.injectModuleAppResourcesfun Context.injectModuleAppResources() +
fun Resources.injectModuleAppResources() +
Change Records
v1.1.0
added
Function Illustrate
向 Hook APP (宿主)
Context
或Resources
注入当前 Xposed 模块的资源。注入成功后,你就可以直接使用例如
ImageView.setImageResource
或Resources.getString
装载当前 Xposed 模块的资源 ID。注入的资源作用域仅限当前
Context
或Resources
,你需要在每个用到宿主Context
或Resources
的地方重复调用此方法进行注入才能使用。Pay Attention
只能在 (Xposed) 宿主环境使用此功能,其它环境下使用将不生效且会打印警告信息。
- ext-method
Context.registerModuleAppActivitiesfun Context.registerModuleAppActivities(proxy: Any?) +
Change Records
v1.1.0
added
v1.1.5
modified
加入最低 API 版本限制
Function Illustrate
向 Hook APP (宿主) 注册当前 Xposed 模块的
Activity
。注册成功后,你就可以直接使用
Context.startActivity
来启动未在宿主中注册的Activity
。使用此方法会在未注册的
Activity
在 Hook APP (宿主) 中启动时自动调用injectModuleAppResources
注入当前 Xposed 模块的资源。你要将需要在宿主启动的
Activity
继承于ModuleAppActivity
或ModuleAppCompatActivity
。Pay Attention
只能在 (Xposed) 宿主环境使用此功能,其它环境下使用将不生效且会打印警告信息。
最低支持 Android 7.0 (API 24)。
- ext-method
Context.applyModuleThemefun Context.applyModuleTheme(theme: Int, configuration: Configuration?): ModuleContextThemeWrapper +
Change Records
v1.1.0
added
Function Illustrate
生成一个
ContextThemeWrapper
代理以应用当前 Xposed 模块的主题资源。在 Hook APP (宿主) 中使用此方法会自动调用
injectModuleAppResources
注入当前 Xposed 模块的资源。如果在 Hook APP (宿主) 中使用此方法发生
ClassCastException
,请手动设置configuration
。isSupportResourcesHook - field
Change Records
v1.0.80
added
v1.0.91
removed
请迁移到
YukiHookAPI.Status.isSupportResourcesHook
isModuleActive - field
Change Records
v1.0.6
added
v1.0.91
removed
请迁移到
YukiHookAPI.Status.isModuleActive
isXposedModuleActive - field
Change Records
v1.0.6
added
v1.0.91
removed
请迁移到
YukiHookAPI.Status.isXposedModuleActive
isTaiChiModuleActive - field
Change Records
v1.0
first
v1.0.91
removed
请迁移到
YukiHookAPI.Status.isTaiChiModuleActive
YukiHookModuleStatus - class
Change Records
v1.0
first
v1.0.91
deprecated
请迁移到
YukiHookAPI.Status
YLog - object | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/log/data/YLogData.html b/en/api/public/com/highcapable/yukihookapi/hook/log/data/YLogData.html new file mode 100644 index 00000000..b573bc44 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/log/data/YLogData.html @@ -0,0 +1,44 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- object
YLogobject YLog +
Change Records
v1.2.0
added
Function Illustrate
全局 Log 管理类。
- field
inMemoryDataval inMemoryData: MutableList<YLogData> +
Change Records
v1.2.0
added
Function Illustrate
当前全部已记录的日志数据。
Pay Attention
获取到的日志数据在 Hook APP (宿主) 及模块进程中是相互隔离的。
- field
contentsval contents: String +
Change Records
v1.2.0
added
Function Illustrate
获取当前日志文件内容。
如果当前没有已记录的日志会返回空字符串。
Pay Attention
获取到的日志数据在 Hook APP (宿主) 及模块进程中是相互隔离的。
- method
contentsfun contents(data: List<YLogData>): String +
Change Records
v1.2.0
added
Function Illustrate
获取、格式化当前日志文件内容。
如果当前没有已记录的日志 (
data
为空) 会返回空字符串。Pay Attention
获取到的日志数据在 Hook APP (宿主) 及模块进程中是相互隔离的。
- method
clearfun clear() +
Change Records
v1.2.0
added
Function Illustrate
清除全部已记录的日志。
你也可以直接获取 inMemoryData 来清除。
Pay Attention
获取到的日志数据在 Hook APP (宿主) 及模块进程中是相互隔离的。
- method
saveToFilefun saveToFile(fileName: String, data: List<YLogData>) +
Change Records
v1.2.0
added
Function Illustrate
保存当前日志到文件。
若当前未开启
Configs.isRecord
或记录为空则不会进行任何操作。日志文件会追加到
fileName
的文件结尾,若文件不存在会自动创建。Pay Attention
文件读写权限取决于当前宿主、模块已获取的权限。
- object
Configsobject Configs +
Change Records
v1.2.0
added
Function Illustrate
配置
YLog
。- field
TAGconst val TAG: Int +
Change Records
v1.2.0
added
Function Illustrate
标签。
- field
PRIORITYconst val PRIORITY: Int +
Change Records
v1.2.0
added
Function Illustrate
优先级。
- field
PACKAGE_NAMEconst val PACKAGE_NAME: Int +
Change Records
v1.2.0
added
Function Illustrate
当前宿主的包名。
- field
USER_IDconst val USER_ID: Int +
Change Records
v1.2.0
added
Function Illustrate
当前宿主的用户 ID (主用户不显示)。
- field
tagvar tag: String +
Change Records
v1.2.0
added
Function Illustrate
这是一个调试日志的全局标识。
默认文案为
YukiHookAPI
。你可以修改为你自己的文案。
- field
isEnablevar isEnable: Boolean +
Change Records
v1.2.0
added
Function Illustrate
是否启用调试日志的输出功能。
关闭后将会停用
YukiHookAPI
对全部日志的输出。但是不影响当你手动调用下面这些方法输出日志。
debug
、info
、warn
、error
。当
isEnable
关闭后YukiHookAPI.Configs.isDebug
也将同时关闭。- field
isRecordvar isRecord: Boolean +
Change Records
v1.2.0
added
Function Illustrate
是否启用调试日志的记录功能。
开启后将会在内存中记录全部可用的日志和异常堆栈。
需要同时启用 isEnable 才能有效。
Pay Attention
过量的日志可能会导致宿主运行缓慢或造成频繁 GC。
开启后你可以调用 YLog.saveToFile 实时保存日志到文件或使用 YLog.contents 获取实时日志文件。
- method
elementsfun elements(vararg item: Int) +
Change Records
v1.2.0
added
Function Illustrate
自定义调试日志对外显示的元素。
只对日志记录和 (Xposed) 宿主环境的日志生效。
日志元素的排列将按照你在
item
中设置的顺序进行显示。你还可以留空
item
以不显示除日志内容外的全部元素。可用的元素有:
TAG
、PRIORITY
、PACKAGE_NAME
、USER_ID
。功能示例
打印的日志样式将按照你设置的排列顺序和元素内容进行。
示例如下
elements(TAG, PRIORITY, PACKAGE_NAME, USER_ID) +
以上内容定义的日志将显示为如下样式。
示例如下
[YukiHookAPI][D][com.demo.test][999]--> This is a log +
如果我们调整元素顺序以及减少个数,那么结果又会不一样。
示例如下
elements(PACKAGE_NAME, USER_ID, PRIORITY) +
以上内容定义的日志将显示为如下样式。
示例如下
[com.demo.test][999][D]--> This is a log +
- method
debugfun debug(msg: String, e: Throwable?, tag: String, env: EnvType) +
Change Records
v1.2.0
added
Function Illustrate
打印 Debug 级别 Log。
- method
infofun info(msg: String, e: Throwable?, tag: String, env: EnvType) +
Change Records
v1.2.0
added
Function Illustrate
打印 Info 级别 Log。
- method
warnfun warn(msg: String, e: Throwable?, tag: String, env: EnvType) +
Change Records
v1.2.0
added
Function Illustrate
打印 Warn 级别 Log。
- method
errorfun error(msg: String, e: Throwable?, tag: String, env: EnvType) +
Change Records
v1.2.0
added
Function Illustrate
打印 Error 级别 Log。
- class
EnvTypeenum class EnvType +
Change Records
v1.2.0
added
Function Illustrate
需要打印的日志环境类型。
决定于模块与 (Xposed) 宿主环境使用的打印方式。
- enum
LOGDLOGD +
Change Records
v1.2.0
added
Function Illustrate
仅使用
android.util.Log
。- enum
XPOSED_ENVIRONMENTXPOSED_ENVIRONMENT +
Change Records
v1.2.0
added
Function Illustrate
仅在 (Xposed) 宿主环境使用。
Pay Attention
只能在 (Xposed) 宿主环境中使用,模块环境将不生效。
- enum
SCOPESCOPE +
Change Records
v1.2.0
added
Function Illustrate
分区使用。
(Xposed) 宿主环境仅使用
XPOSED_ENVIRONMENT
。模块环境仅使用
LOGD
。- enum
BOTHBOTH +
Change Records
v1.2.0
added
Function Illustrate
同时使用。
(Xposed) 宿主环境使用
LOGD
与XPOSED_ENVIRONMENT
。模块环境仅使用
LOGD
。LoggerFactory - kt
Change Records
v1.0
first
v1.2.0
deprecated
请迁移到
YLog
YLogData - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/param/HookParam.html b/en/api/public/com/highcapable/yukihookapi/hook/param/HookParam.html new file mode 100644 index 00000000..4c88e374 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/param/HookParam.html @@ -0,0 +1,121 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
YLogDatadata class YLogData internal constructor( + var timestamp: Long, + var time: String, + var tag: String, + var priority: String, + var packageName: String, + var userId: Int, + var msg: String, + var throwable: Throwable? +) : Serializable +
Change Records
v1.2.0
added
Function Illustrate
调试日志数据实现类。
HookParam - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/param/PackageParam.html b/en/api/public/com/highcapable/yukihookapi/hook/param/PackageParam.html new file mode 100644 index 00000000..51f6ea38 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/param/PackageParam.html @@ -0,0 +1,162 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
HookParamclass HookParam private constructor( + private val creatorInstance: YukiMemberHookCreator, + private var paramId: String, + private var param: YukiHookCallback.Param? +) +
Change Records
v1.0
first
v1.1.0
modified
移动
HookParamWrapper
到YukiHookCallback.Param
修正拼写错误的 creater 命名到 creator
v1.1.5
modified
新增
paramId
参数
v1.2.0
modified
不再开放构造方法
Function Illustrate
Hook 方法、构造方法的目标对象实现类。
- field
argsval args: Array<Any?> +
Change Records
在
v1.0
添加Function Illustrate
获取当前 Hook 对象
member
或constructor
的参数对象数组。这里的数组每项类型默认为
Any
,你可以使用args
方法来实现ArgsModifyer.cast
功能。firstArgs - field
Change Records
v1.0
first
v1.0.75
removed
请使用
args(index = 0)
或args().first()
lastArgs - field
Change Records
v1.0
first
v1.0.75
removed
请使用
args().last()
- field
instanceval instance: Any +
Change Records
v1.0
first
Function Illustrate
获取当前 Hook 实例的对象。
Pay Attention
如果你当前 Hook 的对象是一个静态,那么它将不存在实例的对象。
如果你不确定当前实例的对象是否为
null
,你可以使用instanceOrNull
。- field
instanceOrNullval instanceOrNull: Any? +
Change Records
v1.1.8
added
Function Illustrate
获取当前 Hook 实例的对象。
Pay Attention
如果你当前 Hook 的对象是一个静态,那么它将不存在实例的对象。
- field
instanceClassval instanceClass: Class<*>? +
Change Records
v1.0
first
v1.2.0
modified
加入可空类型 (空安全)
Function Illustrate
获取当前 Hook 实例的类对象。
Pay Attention
如果你当前 Hook 的对象是一个静态,那么它将不存在实例的对象。
- field
memberval member: Member +
Change Records
v1.1.0
added
Function Illustrate
获取当前 Hook 对象的
Member
。在不确定
Member
类型为Method
或Constructor
时可以使用此方法。- field
methodval method: Method +
Change Records
v1.0
first
Function Illustrate
获取当前 Hook 对象的方法。
- field
constructorval constructor: Constructor +
Change Records
v1.0
first
Function Illustrate
获取当前 Hook 对象的构造方法。
- field
resultvar result: Any? +
Change Records
v1.0
first
Function Illustrate
获取、设置当前 Hook 对象的
method
或constructor
的返回值。- field
dataExtraval dataExtra: Bundle +
Change Records
v1.1.5
added
Function Illustrate
获取当前回调方法体范围内的数据存储实例。
- field
hasThrowableval hasThrowable: Boolean +
Change Records
v1.1.0
added
Function Illustrate
判断是否存在设置过的方法调用抛出异常。
- field
throwableval throwable: Throwable? +
Change Records
v1.1.0
added
Function Illustrate
获取设置的方法调用抛出异常。
- i-ext-method
Throwable.throwToAppfun Throwable.throwToApp() +
Change Records
v1.1.0
added
Function Illustrate
向 Hook APP 抛出异常。
使用
hasThrowable
判断当前是否存在被抛出的异常。使用
throwable
获取当前设置的方法调用抛出异常。仅会在回调方法的
MemberHookCreator.before
或MemberHookCreator.after
中生效。Pay Attention
设置后会同时执行 resultNull 方法并将异常抛出给当前 Hook APP。
Function Example
Hook 过程中的异常仅会作用于 (Xposed) 宿主环境,目标 Hook APP 不会受到影响。
若想将异常抛给 Hook APP,可以直接使用如下方法。
The following example
hook { + before { + RuntimeException("Test Exception").throwToApp() + } +} +
Pay Attention
向 Hook APP 抛出异常会对其暴露被 Hook 的事实,是不安全的,容易被检测,请按实际场景合理使用。
- method
resultinline fun <reified T> result(): T? +
Change Records
v1.0.75
added
Function Illustrate
获取当前 Hook 对象的
method
或constructor
的返回值T
。firstArg - method
Change Records
v1.0.66
added
v1.0.75
removed
lastArgs - method
Change Records
v1.0.66
added
v1.0.75
removed
- method
instanceinline fun <reified T> instance(): T +
Change Records
v1.0
first
Function Illustrate
获取当前 Hook 实例的对象
T
。Function Example
你可以通过
instance
方法轻松使用泛型cast
为目标对象的类型。The following example
instance<Activity>().finish() +
- method
instanceOrNullinline fun <reified T> instanceOrNull(): T? +
Function Illustrate
v1.1.8
added
Function Illustrate
获取当前 Hook 实例的对象
T
。Function Example
用法请参考 instance 方法。
- method
argsfun args(): ArgsIndexCondition +
Change Records
v1.0.75
added
Function Illustrate
获取当前 Hook 对象的
method
或constructor
的参数数组下标实例化类。- method
argsfun args(index: Int): ArgsModifyer +
Change Records
v1.0
first
v1.0.75
modified
默认值
index = 0
移动到新的使用方法args().first()
Function Illustrate
获取当前 Hook 对象的
method
或constructor
的参数实例化对象类。Function Example
你可以通过
args
方法修改当前 Hook 实例的方法、构造方法的参数内容。你可以直接使用
set
方法设置param
为你的目标实例,接受Any
类型。Pay Attention
请确保 param 类型为你的目标实例类型。
The following example
args(index = 0).set("modify the value") +
你可以这样直接设置第一位
param
的值。The following example
args().first().set("modify the value") +
你还可以直接设置最后一位
param
的值。The following example
args().last().set("modify the value") +
你还可以使用
setNull
方法设置param
为空。The following example
args(index = 1).setNull() +
你还可以使用
setTrue
方法设置param
为true
。Pay Attention
请确保 param 类型为 Boolean。
The following example
args(index = 1).setTrue() +
你还可以使用
setFalse
方法设置param
为false
。Pay Attention
请确保 param 类型为 Boolean。
The following example
args(index = 1).setFalse() +
- method
callOriginalfun callOriginal(): Any? +
fun <T> callOriginal(): T? +
Change Records
v1.1.0
added
Function Illustrate
执行原始
Member
。调用自身未进行 Hook 的原始
Member
并调用原始参数执行。功能实例
此方法可以
invoke
原始未经 Hook 的Member
对象,取决于原始Member
的参数。调用自身原始的方法不会再经过当前
before
、after
以及replaceUnit
、replaceAny
。比如我们 Hook 的这个方法被这样调用
test("test value")
,使用此方法会调用其中的"test value"
作为参数。The following example
method { + name = "test" + param(StringClass) + returnType = StringClass +}.hook { + after { + // <方案1> 不使用泛型,不获取方法执行结果,调用将使用原方法传入的 args 自动传参 + callOriginal() + // <方案2> 使用泛型,已知方法执行结果参数类型进行 cast + // 假设返回值为 String,失败会返回 null,调用将使用原方法传入的 args 自动传参 + val value = callOriginal<String>() + } +} +
- method
invokeOriginalfun invokeOriginal(vararg args: Any?): Any? +
fun <T> invokeOriginal(vararg args: Any?): T? +
Change Records
v1.0
first
v1.1.0
modified
不再需要使用
member.invokeOriginal
进行调用Function Illustrate
执行原始
Member
。调用自身未进行 Hook 的原始
Member
并自定义args
执行。功能实例
此方法可以
invoke
原始未经 Hook 的Member
对象,可自定义需要调用的参数内容。调用自身原始的方法不会再经过当前
before
、after
以及replaceUnit
、replaceAny
。比如我们 Hook 的这个方法被这样调用
test("test value")
,使用此方法可自定义其中的args
作为参数。The following example
method { + name = "test" + param(StringClass) + returnType = StringClass +}.hook { + after { + // <方案1> 不使用泛型,不获取方法执行结果 + invokeOriginal("test value") + // <方案2> 使用泛型,已知方法执行结果参数类型进行 cast,假设返回值为 String,失败会返回 null + val value = invokeOriginal<String>("test value") + } +} +
- method
resultTruefun resultTrue() +
Change Records
v1.0
first
Function Illustrate
设置当前 Hook 对象方法的
result
返回值为true
。Pay Attention
请确保 result 类型为 Boolean。
- method
resultFalsefun resultFalse() +
Change Records
v1.0
first
Function Illustrate
设置当前 Hook 对象方法的
result
返回值为false
。Pay Attention
请确保 result 类型为 Boolean。
- method
resultNullfun resultNull() +
Change Records
v1.0
first
Function Illustrate
Notice
此方法将强制设置 Hook 对象方法的 result 为 null。
- class
ArgsIndexConditioninner class ArgsIndexCondition internal constructor() +
Change Records
v1.0.75
added
Function Illustrate
对方法参数的数组下标进行实例化类。
- method
firstfun first(): ArgsModifyer +
Change Records
v1.0.75
added
Function Illustrate
获取当前 Hook 对象的
method
或constructor
的参数数组第一位。- method
lastfun last(): ArgsModifyer +
Change Records
v1.0.75
added
Function Illustrate
获取当前 Hook 对象的
method
或constructor
的参数数组最后一位。- class
ArgsModifyerinner class ArgsModifyer internal constructor(private val index: Int) +
Change Records
v1.0
first
Function Illustrate
对方法参数的修改进行实例化类。
- method
castfun <T> cast(): T? +
Change Records
v1.0.66
added
v1.0.68
modified
修改
为of
cast
Function Illustrate
得到方法参数的实例对象
T
。- method
bytefun byte(): Byte? +
Change Records
v1.0.68
added
Function Illustrate
得到方法参数的实例对象 Byte。
- method
intfun int(): Int +
Change Records
v1.0.66
added
v1.0.68
modified
修改
为ofInt
int
Function Illustrate
得到方法参数的实例对象 Int。
- method
longfun long(): Long +
Change Records
v1.0.66
added
v1.0.68
modified
修改
为ofLong
long
Function Illustrate
得到方法参数的实例对象 Long。
- method
shortfun short(): Short +
Change Records
v1.0.66
added
v1.0.68
modified
修改
为ofShort
short
Function Illustrate
得到方法参数的实例对象 Short。
- method
doublefun double(): Double +
Change Records
v1.0.66
added
v1.0.68
modified
修改
为ofDouble
double
Function Illustrate
得到方法参数的实例对象 Double。
- method
floatfun float(): Float +
Change Records
v1.0.66
added
v1.0.68
modified
修改
为ofFloat
float
Function Illustrate
得到方法参数的实例对象 Float。
- method
stringfun string(): String +
Change Records
v1.0.66
added
v1.0.68
modified
修改
为ofString
string
Function Illustrate
得到方法参数的实例对象 String。
- method
charfun char(): Char +
Change Records
v1.0.68
added
Function Illustrate
得到方法参数的实例对象 Char。
- method
booleanfun boolean(): Boolean +
Change Records
v1.0.66
added
v1.0.68
modified
修改
为ofBoolean
boolean
Function Illustrate
得到方法参数的实例对象 Boolean。
- method
anyfun any(): Any? +
Change Records
v1.0.77
added
Function Illustrate
得到方法参数的实例对象 Any。
- method
arrayinline fun <reified T> array(): Array<T> +
Change Records
v1.0.68
added
Function Illustrate
得到方法参数的实例对象 Array。
- method
listinline fun <reified T> list(): List<T> +
Change Records
v1.0.68
added
Function Illustrate
得到方法参数的实例对象 List。
- method
setfun <T> set(any: T?) +
Change Records
v1.0
first
Function Illustrate
设置方法参数的实例对象。
- method
setNullfun setNull() +
Change Records
v1.0
first
Function Illustrate
设置方法参数的实例对象为
null
。- method
setTruefun setTrue() +
Change Records
v1.0
first
Function Illustrate
设置方法参数的实例对象为
true
。Pay Attention
请确保目标对象的类型是 Boolean。
- method
setFalsefun setFalse() +
Change Records
v1.0
first
Function Illustrate
设置方法参数的实例对象为
false
。Pay Attention
请确保目标对象的类型是 Boolean。
PackageParam - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/type/android/ComponentTypeFactory.html b/en/api/public/com/highcapable/yukihookapi/hook/type/android/ComponentTypeFactory.html new file mode 100644 index 00000000..d53833f3 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/type/android/ComponentTypeFactory.html @@ -0,0 +1,34 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
pageClass: code-page
- class
PackageParamopen class PackageParam internal constructor(internal var wrapper: PackageParamWrapper?) +
Change Records
v1.0
first
Function Illustrate
装载 Hook 的目标 APP 入口对象实现类。
- field
appClassLoadervar appClassLoader:ClassLoader? +
Change Records
v1.0
first
v1.1.5
modified
可以动态修改此变量的值
v1.2.0
modified
加入可空类型 (空安全)
Function Illustrate
获取、设置当前 Hook APP 的
ClassLoader
。你可以在这里手动设置当前 Hook APP 的
ClassLoader
,默认情况下会自动获取。Pay Attention
如果设置了错误或无效的 ClassLoader 会造成功能异常,请谨慎操作。
- field
appInfoval appInfo: ApplicationInfo +
Change Records
v1.0
first
Function Illustrate
获取当前 Hook APP 的
ApplicationInfo
。- field
appUserIdval appUserId: Int +
Change Records
v1.1.0
added
Function Illustrate
获取当前 Hook APP 的用户 ID。
机主为
0
,应用双开 (分身) 或工作资料因系统环境不同 ID 也各不相同。- field
appContextval appContext: Application? +
Change Records
v1.0.72
added
v1.1.0
modified
加入可空类型 (空安全)
Function Illustrate
获取当前 Hook APP 的
Application
。Pay Attention
首次装载可能是空的,请延迟一段时间再获取或使用 onAppLifecycle 监听来完成。
- field
appResourcesval appResources:Resources? +
Change Records
v1.0.80
added
v1.1.0
modified
加入可空类型 (空安全)
Function Illustrate
获取当前 Hook APP 的 Resources。
Pay Attention
你只能在 HookResources.hook 方法体内或 appContext 装载完毕时进行调用。
- field
systemContextval systemContext: Context +
Change Records
v1.1.0
added
Function Illustrate
获取当前系统框架的
Context
。- field
processNameval processName: String +
Change Records
v1.0
first
Function Illustrate
获取当前 Hook APP 的进程名称。
- field
packageNameval packageName: String +
Change Records
v1.0
first
Function Illustrate
获取当前 Hook APP 的包名。
- field
isFirstApplicationval isFirstApplication: Boolean +
Change Records
v1.0
first
Function Illustrate
获取当前 Hook APP 是否为第一个
Application
。- field
mainProcessNameval mainProcessName: String +
Change Records
v1.0.70
added
Function Illustrate
获取当前 Hook APP 的主进程名称。
其对应的就是
packageName
。- field
moduleAppFilePathval moduleAppFilePath: String +
Change Records
v1.0.80
added
Function Illustrate
获取当前 Xposed 模块自身 APK 文件路径。
Pay Attention
作为 Hook API 装载时无法使用,会获取到空字符串。
- field
moduleAppResourcesval moduleAppResources: YukiModuleResources +
Change Records
v1.0.80
added
Function Illustrate
获取当前 Xposed 模块自身
Resources
。Pay Attention
作为 Hook API 或不支持的 Hook Framework 装载时无法使用,会抛出异常。
- field
prefsval prefs: YukiHookPrefsBridge +
Change Records
v1.0
first
Function Illustrate
创建
YukiHookPrefsBridge
对象。Pay Attention
作为 Hook API 装载时无法使用,会抛出异常。
- method
prefsfun prefs(name: String): YukiHookPrefsBridge +
Change Records
v1.0
first
v1.0.80
modified
将方法体进行 inline
Function Illustrate
创建
YukiHookPrefsBridge
对象。你可以通过
name
来自定义 Sp 存储的名称。Pay Attention
作为 Hook API 装载时无法使用,会抛出异常。
- field
dataChannelval dataChannel: YukiHookDataChannel.NameSpace +
Change Records
v1.0.88
added
Function Illustrate
获取
YukiHookDataChannel
对象。Pay Attention
作为 Hook API 装载时无法使用,会抛出异常。
- method
resourcesfun resources(): HookResources +
Change Records
v1.0.80
added
Function Illustrate
获得当前 Hook APP 的
YukiResources
对象。请调用
HookResources.hook
方法开始 Hook。- method
refreshModuleAppResourcesfun refreshModuleAppResources() +
Change Records
v1.0.87
added
Function Illustrate
刷新当前 Xposed 模块自身
Resources
。- method
onAppLifecycleinline fun onAppLifecycle(isOnFailureThrowToApp: Boolean, initiate: AppLifecycle.() -> Unit) +
Change Records
v1.0.88
added
v1.1.5
modified
新增
isOnFailureThrowToApp
参数,可选择将异常在 (Xposed) 宿主环境打印而不是抛出给宿主Function Illustrate
监听当前 Hook APP 生命周期装载事件。
Notice
在 loadZygote 中不会被装载,仅会在 loadSystem、loadApp 中装载。
作为 Hook API 装载时请使用原生的 Application 实现生命周期监听。
- method
loadAppinline fun loadApp(name: String, initiate: PackageParam.() -> Unit) +
fun loadApp(name: String, hooker: YukiBaseHooker) +
inline fun loadApp(vararg name: String, initiate: PackageParam.() -> Unit) +
fun loadApp(name: String, vararg hooker: YukiBaseHooker) +
inline fun loadApp(isExcludeSelf: Boolean, initiate: PackageParam.() -> Unit) +
fun loadApp(isExcludeSelf: Boolean, hooker: YukiBaseHooker) +
fun loadApp(isExcludeSelf: Boolean, vararg hooker: YukiBaseHooker) +
Change Records
v1.0
first
v1.0.80
modified
将方法体进行 inline
v1.1.4
modified
新增两个方法,可以同时装载多个 APP 与子 Hooker
v1.1.5
modified
新增三个方法,可以使用参数
isExcludeSelf
排除模块自身Function Illustrate
装载并 Hook 指定、全部包名的 APP。
name
为 APP 的包名,后方的两个参数一个可作为 lambda 方法体使用,一个可以直接装载子 Hooker。装载并 Hook 指定、全部包名的 APP。
若要装载 APP Zygote 事件,请使用
loadZygote
。若要 Hook 系统框架,请使用
loadSystem
。Function Example
你可以使用
loadApp
的 lambda 方法体形式或直接装载一个 Hooker。The following example
// 使用 lambda +loadApp(name = "com.example.test") { + // Your code here. +} +// 使用 Hooker +loadApp(name = "com.example.test", CustomHooker) +
若不指定
name
参数,则此方法体默认会过滤当前系统中全部可被 Hook 的 APP。The following example
// 使用 lambda +loadApp { + // Your code here. +} +// 使用 Hooker +loadApp(hooker = CustomHooker) +
若要在全部可被 Hook 的 APP 中过滤掉模块自身,你只需加入
isExcludeSelf = true
。The following example
// 使用 lambda +loadApp(isExcludeSelf = true) { + // Your code here. +} +// 使用 Hooker +loadApp(isExcludeSelf = true, hooker = CustomHooker) +
若想要同时装载多个需要 Hook 的 APP,可以直接使用如下方式。
The following example
// 同时装载多个需要 Hook 的 APP +loadApp("com.example.test", "com.example.next") { + // Your code here. +} +
若想要同时装载多个子 Hooker,可以直接使用如下方式,但此时只能指定一个需要 Hook 的 APP。
The following example
// 同时装载多个子 Hooker +loadApp("com.example.test", CustomHooker1, CustomHooker2) +
- method
loadZygoteinline fun loadZygote(initiate: PackageParam.() -> Unit) +
fun loadZygote(hooker: YukiBaseHooker) +
fun loadZygote(vararg hooker: YukiBaseHooker) +
Change Records
v1.0.80
added
v1.1.4
modified
新增一个方法,可以同时装载多个子 Hooker
Function Illustrate
装载 APP Zygote 事件。
方法中的两个参数一个可作为 lambda 方法体使用,一个可以直接装载子 Hooker。
- method
loadSysteminline fun loadSystem(initiate: PackageParam.() -> Unit) +
fun loadSystem(hooker: YukiBaseHooker) +
fun loadSystem(vararg hooker: YukiBaseHooker) +
Change Records
v1.0.82
added
v1.1.4
modified
新增一个方法,可以同时装载多个子 Hooker
Function Illustrate
装载并 Hook 系统框架。
方法中的两个参数一个可作为 lambda 方法体使用,一个可以直接装载子 Hooker。
- method
withProcessinline fun withProcess(name: String, initiate: PackageParam.() -> Unit) +
fun withProcess(name: String, hooker: YukiBaseHooker) +
fun withProcess(vararg name: String, hooker: YukiBaseHooker) +
fun withProcess(name: String, vararg hooker: YukiBaseHooker) +
Change Records
v1.0.70
added
v1.1.4
modified
新增两个方法,可以同时装载多个进程与子 Hooker
Function Illustrate
装载并 Hook APP 的指定进程。
name
为 APP 的进程名称,后方的两个参数一个可作为 lambda 方法体使用,一个可以直接装载子 Hooker。- method
loadHookerfun loadHooker(hooker: YukiBaseHooker) +
Change Records
v1.0
first
Function Illustrate
装载 Hook 子类。
你可以填入
hooker
在 Hooker 中继续装载 Hooker。- method
searchClassinline fun searchClass(name: String, async: Boolean, initiate: ClassConditions): DexClassFinder.Result +
Change Records
v1.1.0
added
Function Illustrate
通过
appClassLoader
按指定条件查找并得到当前 Hook APP Dex 中的Class
。Pay Attention
此方法在 Class 数量过多及查找条件复杂时会非常耗时。
建议启用 async 或设置 name 参数,name 参数将在 Hook APP (宿主) 不同版本中自动进行本地缓存以提升效率。
此功能尚在实验阶段,性能与稳定性可能仍然存在问题,使用过程遇到问题请向我们报告并帮助我们改进。
String+VariousClass.clazz - i-ext-field
Change Records
v1.0
first
v1.1.0
deprecated
请迁移到
toClass(...)
方法String.hasClass - i-ext-field
Change Records
v1.0
first
v1.1.0
deprecated
请迁移到
hasClass(...)
方法- i-ext-method
String+VariousClass.toClassfun String.toClass(loader: ClassLoader?, initialize: Boolean): Class<*> +
inline fun <reified T> String.toClass(loader: ClassLoader?, initialize: Boolean): Class<T> +
fun VariousClass.toClass(loader: ClassLoader?, initialize: Boolean): Class<*> +
Change Records
v1.1.0
added
v1.1.5
modified
新增泛型返回值
Class<T>
方法新增
initialize
参数Function Illustrate
通过字符串类名、
VariousClass
转换为loader
中的实体类。默认使用当前
appClassLoader
装载目标Class
。Function Example
你可以轻松地将
String
类型的Class
包名转为Class
实例。The following example
"com.example.demo.DemoClass".toClass() +
你还可以向
loader
参数传入你自定义的ClassLoader
。The following example
val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader +"com.example.demo.DemoClass".toClass(customClassLoader) +
你还可以指定
Class
的目标类型。The following example
// 指定的 DemoClass 必须存在或为可访问的 stub +"com.example.demo.DemoClass".toClass<DemoClass>() +
你还可以设置在获取到这个
Class
时是否自动执行其默认的静态方法块,默认情况下不会执行。The following example
// 获取并执行 DemoClass 默认的静态方法块 +"com.example.demo.DemoClass".toClass(initialize = true) +
默认的静态方法块在 Java 中使用如下方式定义。
The following example
public class DemoClass { + + static { + // 这里是静态方法块的内容 + } + + public DemoClass() { + // ... + } +} +
你还可以创建一个
VariousClass
,并转换为实体类。
VariousClass
会枚举所有设置的Class
并最终获得第一个存在的Class
。The following example
VariousClass("com.example.demo.DemoClass1", "com.example.demo.DemoClass2").toClass() +
同样地,你还可以向
loader
参数传入你自定义的ClassLoader
。The following example
val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader +VariousClass("com.example.demo.DemoClass1", "com.example.demo.DemoClass2").toClass(customClassLoader) +
- i-ext-method
String+VariousClass.toClassOrNullfun String.toClassOrNull(loader: ClassLoader?, initialize: Boolean): Class<*>? +
inline fun <reified T> String.toClassOrNull(loader: ClassLoader?, initialize: Boolean): Class<T>? +
fun VariousClass.toClassOrNull(loader: ClassLoader?, initialize: Boolean): Class<*>? +
Change Records
v1.1.0
added
v1.1.5
modified
新增泛型返回值
Class<T>
方法新增
initialize
参数Function Illustrate
通过字符串类名、
VariousClass
转换为loader
中的实体类。默认使用当前
appClassLoader
装载目标Class
。找不到
Class
会返回null
,不会抛出异常。Function Example
用法请参考 String+VariousClass.toClass 方法。
- method
lazyClassfun lazyClass(name: String, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.NonNull<Any> +
inline fun <reified T> lazyClass(name: String, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.NonNull<T> +
fun lazyClass(variousClass: VariousClass, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.NonNull<Any> +
Change Records
v1.2.0
added
Function Illustrate
懒装载
Class
。- method
lazyClassOrNullfun lazyClassOrNull(name: String, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.Nullable<Any> +
inline fun <reified T> lazyClassOrNull(name: String, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.Nullable<T> +
fun lazyClassOrNull(variousClass: VariousClass, initialize: Boolean, loader: ClassLoaderInitializer?): LazyClass.Nullable<Any> +
Change Records
v1.2.0
added
Function Illustrate
懒装载
Class
。- i-ext-method
String.hasClassfun String.hasClass(loader: ClassLoader?): Boolean +
Change Records
v1.1.0
added
Function Illustrate
通过字符串类名查找是否存在。
默认使用当前
appClassLoader
装载目标Class
。Function Example
你可以轻松的使用此方法判断字符串中的类是否存在。
The following example
if("com.example.demo.DemoClass".hasClass()) { + // Your code here. +} +
你还可以自定义其中的
loader
参数,默认为appClassLoader
。The following example
val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader +if("com.example.demo.DemoClass".hasClass(customClassLoader)) { + // Your code here. +} +
findClass - method
Change Records
v1.0
first
v1.0.1
modified
移除了
方法findClass(various: VariousClass)
v1.1.0
modified
新增
loader
参数
v1.2.0
deprecated
请直接使用
String.toClass(...)
或VariousClass(...)
- i-ext-method
Class+VariousClass+HookClass.hookinline fun Class<*>.hook(isForceUseAbsolute: Boolean, initiate: YukiMemberHookCreator.() -> Unit): YukiMemberHookCreator.Result +
inline fun VariousClass.hook(initiate: YukiMemberHookCreator.() -> Unit): YukiMemberHookCreator.Result +
inline fun HookClass.hook(initiate: YukiMemberHookCreator.() -> Unit): YukiMemberHookCreator.Result +
Change Records
v1.0
first
v1.0.1
modified
新增
VariousClass
的直接调用hook
方法
v1.0.2
modified
新增
String
的直接调用hook
方法
v1.0.3
modified
新增
YukiMemberHookCreator.Result
返回值
v1.0.70
modified
新增
isUseAppClassLoader
参数
v1.0.80
modified
将方法体进行 inline
v1.1.0
modified
移除了
参数isUseAppClassLoader
添加了
isForceUseAbsolute
参数到Class.hook
方法
v1.2.0
modified
作废了
方法String.hook
Function Illustrate
Hook 方法、构造方法。
- i-ext-method
Member+BaseFinder.BaseResult.hookinline fun Member.hook(priority: YukiHookPriority): YukiMemberHookCreator.MemberHookCreator +
inline fun Member.hook(priority: YukiHookPriority, initiate: YukiMemberHookCreator.MemberHookCreator.() -> Unit): YukiMemberHookCreator.MemberHookCreator.Result +
inline fun BaseFinder.BaseResult.hook(priority: YukiHookPriority): YukiMemberHookCreator.MemberHookCreator +
inline fun BaseFinder.BaseResult.hook(priority: YukiHookPriority, initiate: YukiMemberHookCreator.MemberHookCreator.() -> Unit): YukiMemberHookCreator.MemberHookCreator.Result +
Change Records
v1.2.0
added
Function Illustrate
直接 Hook 方法、构造方法。
Notice
此功能尚在实验阶段,在 1.x.x 版本将暂定于此,在 2.0.0 版本将完全合并到新 API。
- i-ext-method
Array<Member>+List<Member>+BaseFinder.BaseResult.hookAllinline fun Array<Member>.hookAll(priority: YukiHookPriority): YukiMemberHookCreator.MemberHookCreator +
inline fun Array<Member>.hookAll(priority: YukiHookPriority, initiate: YukiMemberHookCreator.MemberHookCreator.() -> Unit): YukiMemberHookCreator.MemberHookCreator.Result +
inline fun List<Member>.hookAll(priority: YukiHookPriority): YukiMemberHookCreator.MemberHookCreator +
inline fun List<Member>.hookAll(priority: YukiHookPriority, initiate: YukiMemberHookCreator.MemberHookCreator.() -> Unit): YukiMemberHookCreator.MemberHookCreator.Result +
inline fun BaseFinder.BaseResult.hookAll(priority: YukiHookPriority): YukiMemberHookCreator.MemberHookCreator +
inline fun BaseFinder.BaseResult.hookAll(priority: YukiHookPriority, initiate: YukiMemberHookCreator.MemberHookCreator.() -> Unit): YukiMemberHookCreator.MemberHookCreator.Result +
Change Records
v1.2.0
added
Function Illustrate
直接 Hook 方法、构造方法 (批量)。
Notice
此功能尚在实验阶段,在 1.x.x 版本将暂定于此,在 2.0.0 版本将完全合并到新 API。
- i-ext-method
HookResources.hookinline fun HookResources.hook(initiate: YukiResourcesHookCreator.() -> Unit) +
Change Records
v1.0.80
added
Function Illustrate
Hook APP 的 Resources。
Pay Attention
此功能将不再默认启用,如需启用,请手动设置 InjectYukiHookWithXposed.isUsingResourcesHook。
Function Example
Resources Hook 为固定用法,获取
resources
对象,然后调用hook
方法开始 Hook。The following example
resources().hook { + // Your code here. +} +
Pay Attention
这是固定用法,为了防止发生问题,你不可手动实现任何 HookResources 实例执行 hook 调用。
将 Resources 的 Hook 设置为这样是为了与
String.toClass(...).hook
做到统一,使得调用起来逻辑不会混乱。- class
AppLifecycleinner class AppLifecycle internal constructor(private val isOnFailureThrowToApp: Boolean) +
Change Records
v1.0.88
added
v1.1.5
modified
新增
isOnFailureThrowToApp
参数,可选择将异常在 (Xposed) 宿主环境打印而不是抛出给宿主Function Illustrate
当前 Hook APP 的生命周期实例处理类。
- method
attachBaseContextfun attachBaseContext(result: (baseContext: Context, hasCalledSuper: Boolean) -> Unit) +
Change Records
v1.0.88
added
Function Illustrate
监听当前 Hook APP 装载
Application.attachBaseContext
。- method
onCreatefun onCreate(initiate: Application.() -> Unit) +
Change Records
v1.0.88
added
Function Illustrate
监听当前 Hook APP 装载
Application.onCreate
。- method
onTerminatefun onTerminate(initiate: Application.() -> Unit) +
Change Records
v1.0.88
added
Function Illustrate
监听当前 Hook APP 装载
Application.onTerminate
。- method
onLowMemoryfun onLowMemory(initiate: Application.() -> Unit) +
Change Records
v1.0.88
added
Function Illustrate
监听当前 Hook APP 装载
Application.onLowMemory
。- method
onTrimMemoryfun onTrimMemory(result: (self: Application, level: Int) -> Unit) +
Change Records
v1.0.88
added
Function Illustrate
监听当前 Hook APP 装载
Application.onTrimMemory
。- method
onConfigurationChangedfun onConfigurationChanged(result: (self: Application, config: Configuration) -> Unit) +
Change Records
v1.0.88
added
Function Illustrate
监听当前 Hook APP 装载
Application.onConfigurationChanged
。- method
registerReceiverfun registerReceiver(vararg action: String, result: (context: Context, intent: Intent) -> Unit) +
fun registerReceiver(filter: IntentFilter, result: (context: Context, intent: Intent) -> Unit) +
Change Records
v1.0.88
added
v1.1.8
modified
新增直接使用
IntentFilter
注册系统广播监听Function Illustrate
注册系统广播监听。
ComponentTypeFactory - kt | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/type/android/GraphicsTypeFactory.html b/en/api/public/com/highcapable/yukihookapi/hook/type/android/GraphicsTypeFactory.html new file mode 100644 index 00000000..f91e0ae1 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/type/android/GraphicsTypeFactory.html @@ -0,0 +1,34 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- kt
ComponentTypeFactoryChange Records
v1.0
first
Function Illustrate
这是一个预置反射类型的常量类,主要为
Android
相关组件的Class
内容,跟随版本更新会逐一进行增加。详情可 点击这里 进行查看。
GraphicsTypeFactory - kt | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/type/android/ViewTypeFactory.html b/en/api/public/com/highcapable/yukihookapi/hook/type/android/ViewTypeFactory.html new file mode 100644 index 00000000..994c4db8 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/type/android/ViewTypeFactory.html @@ -0,0 +1,34 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- kt
GraphicsTypeFactoryChange Records
v1.0
first
Function Illustrate
这是一个预置反射类型的常量类,主要为
Android
相关Graphics
的Class
内容,跟随版本更新会逐一进行增加。详情可 点击这里 进行查看。
ViewTypeFactory - kt | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/type/defined/DefinedTypeFactory.html b/en/api/public/com/highcapable/yukihookapi/hook/type/defined/DefinedTypeFactory.html new file mode 100644 index 00000000..f547d359 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/type/defined/DefinedTypeFactory.html @@ -0,0 +1,35 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- kt
ViewTypeFactoryChange Records
v1.0
first
Function Illustrate
这是一个预置反射类型的常量类,主要为
Android
相关Widget
的Class
内容,跟随版本更新会逐一进行增加。详情可 点击这里 进行查看。
DefinedTypeFactory - kt | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/type/java/VariableTypeFactory.html b/en/api/public/com/highcapable/yukihookapi/hook/type/java/VariableTypeFactory.html new file mode 100644 index 00000000..e45ff607 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/type/java/VariableTypeFactory.html @@ -0,0 +1,34 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- kt
DefinedTypeFactoryChange Records
v1.1.0
added
Function Illustrate
这是一个内部类型的定义常量类,主要用于反射 API 相关用法的延伸。
- field
VagueTypeval VagueType: Class<*> +
Change Records
v1.1.0
added
Function Illustrate
得到模糊类型。
VariableTypeFactory - kt | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/xposed/application/ModuleApplication.html b/en/api/public/com/highcapable/yukihookapi/hook/xposed/application/ModuleApplication.html new file mode 100644 index 00000000..2b4ca001 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/xposed/application/ModuleApplication.html @@ -0,0 +1,50 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- kt
VariableTypeFactoryChange Records
v1.0
first
Function Illustrate
这是一个预置反射类型的常量类,主要为 Java 相关基本变量类型的
Class
内容,跟随版本更新会逐一进行增加。详情可 点击这里 进行查看。
ModuleApplication - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/event/YukiXposedEvent.html b/en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/event/YukiXposedEvent.html new file mode 100644 index 00000000..aefb22e8 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/event/YukiXposedEvent.html @@ -0,0 +1,39 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
ModuleApplicationopen class ModuleApplication: Application() +
Change Records
v1.0.77
added
Function Illustrate
这是对使用
YukiHookAPI
Xposed 模块实现中的一个扩展功能。在你的 Xposed 模块的
Application
中继承此类。或在
AndroidManifest.xml
的application
标签中指定此类。目前可实现功能如下
全局共享模块中静态的
appContext
在模块与宿主中装载
YukiHookAPI.Config
以确保YukiHookAPI.Configs.debugTag
不需要重复定义在模块与宿主中使用
YukiHookDataChannel
进行通讯在模块中使用系统隐藏 API,核心技术引用了开源项目 FreeReflection
在模块中使用
YukiHookAPI.Status.isTaiChiModuleActive
判断太极、无极激活状态Function Example
将此类继承到你的自定义
Application
上。The following example
package com.demo + +class MyApplication: ModuleApplication() { + + override fun onCreate() { + super.onCreate() + } +} +
在
AndroidManifest.xml
的application
标签中指定自定义的Application
。The following example
<application + android:name="com.demo.MyApplication" + ...> +
如果你不需要自定义
Application
可以直接将ModuleApplication
设置到AndroidManifest.xml
的application
标签中。The following example
<application + android:name="com.highcapable.yukihookapi.hook.xposed.application.ModuleApplication" + ...> +
- field
appContextval appContext: ModuleApplication +
Change Records
v1.0.77
added
Function Illustrate
获取全局静态
Application
实例。YukiXposedEvent - object | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiModuleResources.html b/en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiModuleResources.html new file mode 100644 index 00000000..dd86dfb7 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiModuleResources.html @@ -0,0 +1,36 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- object
YukiXposedEventobject YukiXposedEvent +
Change Records
v1.0.80
first
Function Illustrate
实现对原生 Xposed API 的装载事件监听。
- method
eventsinline fun events(initiate: YukiXposedEvent.() -> Unit) +
Change Records
v1.0.80
added
Function Illustrate
对
YukiXposedEvent
创建一个方法体。- method
onInitZygotefun onInitZygote(result: (StartupParam) -> Unit) +
Change Records
v1.0.80
added
Function Illustrate
设置 initZygote 事件监听。
- method
onHandleLoadPackagefun onHandleLoadPackage(result: (LoadPackageParam) -> Unit) +
Change Records
v1.0.80
added
Function Illustrate
设置 handleLoadPackage 事件监听。
- method
onHandleInitPackageResourcesfun onHandleInitPackageResources(result: (InitPackageResourcesParam) -> Unit) +
Change Records
v1.0.80
added
Function Illustrate
设置 handleInitPackageResources 事件监听。
YukiModuleResources - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResForwarder.html b/en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResForwarder.html new file mode 100644 index 00000000..2c7b68bf --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResForwarder.html @@ -0,0 +1,37 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
YukiModuleResourcesclass YukiModuleResources private constructor(private val baseInstance: XModuleResources) : Resources +
Change Records
v1.0.80
added
Function Illustrate
对接
XModuleResources
的中间层实例。- method
fwdfun fwd(resId: Int): YukiResForwarder +
Change Records
v1.0.80
added
Function Illustrate
对接
XModuleResources.fwd
方法。创建
YukiResForwarder
与XResForwarder
实例。YukiResForwarder - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResources.html b/en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResources.html new file mode 100644 index 00000000..5eb46efb --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/xposed/bridge/resources/YukiResources.html @@ -0,0 +1,40 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
YukiResForwarderclass YukiResForwarder private constructor(private val baseInstance: XResForwarder) +
Change Records
v1.0.80
added
Function Illustrate
对接
XResForwarder
的中间层实例。instance - field
Change Records
v1.0.80
added
v1.1.0
deprecated
不再对外公开
instance
参数- field
idval id: Int +
Change Records
v1.0.80
added
Function Illustrate
获得当前 APP 的 Resources Id。
- field
resourcesval resources: Resources +
Change Records
v1.0.80
added
Function Illustrate
获得当前 APP 的 Resources。
YukiResources - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/xposed/channel/YukiHookDataChannel.html b/en/api/public/com/highcapable/yukihookapi/hook/xposed/channel/YukiHookDataChannel.html new file mode 100644 index 00000000..f7c034e8 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/xposed/channel/YukiHookDataChannel.html @@ -0,0 +1,49 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
YukiResourcesclass YukiResources private constructor(private val baseInstance: XResources) : Resources +
Change Records
v1.0.80
added
Function Illustrate
对接
XResources
的中间层实例。- class
LayoutInflatedParamclass LayoutInflatedParam(private val baseParam: XC_LayoutInflated.LayoutInflatedParam) +
Change Records
v1.0.80
added
Function Illustrate
装载 Hook APP 的目标布局 Resources 实现类。
- field
variantNameval variantName: String +
Change Records
v1.0.80
added
Function Illustrate
获取当前被 Hook 的布局装载目录名称。
例如:
layout
、layout-land
、layout-sw600dp
。- field
currentViewval currentView: View +
Change Records
v1.0.80
added
Function Illustrate
获取当前被 Hook 的布局实例。
- method
findViewByIdentifierinline fun <reified T : View> View.findViewByIdentifier(name: String): T? +
inline fun <reified T : View> findViewByIdentifier(name: String): T? +
Change Records
v1.0.80
added
Function Illustrate
使用 Identifier 查找 Hook APP 指定 Id 的
View
。扩展方法可以使用 Identifier 查找 Hook APP 当前装载布局中指定 Id 的
View
。YukiHookDataChannel - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/xposed/channel/data/ChannelData.html b/en/api/public/com/highcapable/yukihookapi/hook/xposed/channel/data/ChannelData.html new file mode 100644 index 00000000..ce8815cd --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/xposed/channel/data/ChannelData.html @@ -0,0 +1,56 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
YukiHookDataChannelclass YukiHookDataChannel private constructor() +
Change Records
v1.0.88
added
Function Illustrate
实现 Xposed 模块的数据通讯桥。
通过模块与宿主相互注册
BroadcastReceiver
来实现数据的交互。模块需要将
Application
继承于ModuleApplication
来实现此功能。Pay Attention
模块与宿主需要保持存活状态,否则无法建立通讯。
- class
NameSpaceinner class NameSpace internal constructor(private val context: Context?, private val packageName: String) +
Change Records
v1.0.88
added
v1.0.90
modified
新增
isSecure
参数
v1.1.9
modified
移除
isSecure
参数Function Illustrate
YukiHookDataChannel
命名空间。- method
withinline fun with(initiate: NameSpace.() -> Unit): NameSpace +
Change Records
v1.0.88
added
Function Illustrate
创建一个调用空间。
- field
dataMaxByteSizevar dataMaxByteSize: Int +
Change Records
v1.1.9
added
Function Illustrate
YukiHookDataChannel
允许发送的最大数据字节大小。默认为
500 KB (500 * 1024)
,详情请参考receiverDataMaxByteSize
的注释。最小不能低于
100 KB (100 * 1024)
,否则会被重新设置为100 KB (100 * 1024)
。设置后将在全局生效,直到当前进程结束。
超出最大数据字节大小后的数据将被自动分段发送。
Pay Attention
请谨慎调整此参数,如果超出了系统能够允许的大小会引发 TransactionTooLargeException 异常。
- field
dataMaxByteCompressionFactorvar dataMaxByteCompressionFactor: Int +
Change Records
v1.1.9
added
Function Illustrate
YukiHookDataChannel
允许发送的最大数据字节大小倍数 (分段数据)。默认为
3
,详情请参考receiverDataMaxByteCompressionFactor
的注释。最小不能低于
2
,否则会被重新设置为2
。设置后将在全局生效,直到当前进程结束。
超出最大数据字节大小后的数据将按照此倍数自动划分
receiverDataMaxByteSize
的大小。Pay Attention
请谨慎调整此参数,如果超出了系统能够允许的大小会引发 TransactionTooLargeException 异常。
- method
allowSendTooLargeDatafun allowSendTooLargeData(): NameSpace +
Change Records
v1.1.5
added
Function Illustrate
解除发送数据的大小限制并禁止开启分段发送功能。
仅会在每次调用时生效,下一次没有调用此方法则此功能将被自动关闭。
你还需要在整个调用域中声明注解
SendTooLargeChannelData
以消除警告。Pay Attention
若你不知道允许此功能会带来何种后果,请勿使用。
- method
putfun <T> put(key: String, value: T) +
fun <T> put(data: ChannelData<T>, value: T?) +
fun put(vararg data: ChannelData<*>) +
Change Records
v1.0.88
added
Function Illustrate
发送键值数据。
- method
putfun put(key: String) +
Change Records
v1.0.88
added
Function Illustrate
仅发送键值监听,使用默认值
VALUE_WAIT_FOR_LISTENER
发送键值数据。- method
waitfun <T> wait(key: String, priority: ChannelPriority?, result: (value: T) -> Unit) +
fun <T> wait(data: ChannelData<T>, priority: ChannelPriority?, result: (value: T) -> Unit) +
Change Records
v1.0.88
added
v1.0.90
modified
移除默认值
value
v1.1.5
modified
新增
priority
参数Function Illustrate
获取键值数据。
- method
waitfun wait(key: String, priority: ChannelPriority?, callback: () -> Unit) +
Change Records
v1.0.88
added
v1.1.5
modified
新增
priority
参数Function Illustrate
仅获取监听结果,不获取键值数据。
Pay Attention
仅限使用 VALUE_WAIT_FOR_LISTENER 发送的监听才能被接收。
- method
checkingVersionEqualsfun checkingVersionEquals(priority: ChannelPriority?, result: (Boolean) -> Unit) +
Change Records
v1.0.88
added
v1.1.5
modified
新增
priority
参数Function Illustrate
获取模块与宿主的版本是否匹配。
通过此方法可原生判断 Xposed 模块更新后宿主并未重新装载造成两者不匹配的情况。
- method
obtainLoggerInMemoryDatafun obtainLoggerInMemoryData(priority: ChannelPriority?, result: (List<YLogData>) -> Unit) +
Change Records
v1.1.4
added
v1.1.5
modified
新增
priority
参数Function Illustrate
获取模块与宿主之间的
List<YLogData>
数据。由于模块与宿主处于不同的进程,我们可以使用数据通讯桥访问各自的调试日志数据。
Pay Attention
模块与宿主必须启用 YLog.Configs.isRecord 才能获取到调试日志数据。
由于 Android 限制了数据传输大小的最大值,如果调试日志过多将会自动进行分段发送,数据越大速度越慢。
ChannelData - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/xposed/channel/priority/ChannelPriority.html b/en/api/public/com/highcapable/yukihookapi/hook/xposed/channel/priority/ChannelPriority.html new file mode 100644 index 00000000..7a70968b --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/xposed/channel/priority/ChannelPriority.html @@ -0,0 +1,35 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
ChannelDatadata class ChannelData<T>(var key: String, var value: T?) : Serializable +
Change Records
v1.0.88
added
v1.1.5
modified
实现了
Serializable
接口Function Illustrate
数据通讯桥键值构造类。
这个类是对
YukiHookDataChannel
的一个扩展用法。Function Example
建立一个模板类定义模块与宿主需要发送的键值数据。
The following example
object DataConst { + + val TEST_KV_DATA_1 = ChannelData("test_data_1", "defalut value") + val TEST_KV_DATA_2 = ChannelData("test_data_2", 0) +} +
键值数据定义后,你就可以方便地在模块和宿主中调用所需要发送的数据。
模块示例如下
// 从指定包名的宿主获取 +dataChannel(packageName = "com.example.demo").wait(DataConst.TEST_KV_DATA_1) { value -> + // Your code here. +} +// 发送给指定包名的宿主 - 未填写 value 时将使用模板提供的默认值 +dataChannel(packageName = "com.example.demo").put(DataConst.TEST_KV_DATA_1, value = "sending value") +
宿主示例如下
// 从模块获取 +dataChannel.wait(DataConst.TEST_KV_DATA_1) { value -> + // Your code here. +} +// 发送给模块 - 未填写 value 时将使用模板提供的默认值 +dataChannel.put(DataConst.TEST_KV_DATA_1, value = "sending value") +
你依然可以不使用模板定义的默认值,随时修改你的默认值。
The following example
// 获取 - 此时 value 取到的默认值将会是 2 - 并不是模板提供的 0 +dataChannel.wait(DataConst.TEST_KV_DATA_2, value = 2) { value -> + // Your code here. +} +
ChannelPriority - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/base/ModuleAppActivity.html b/en/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/base/ModuleAppActivity.html new file mode 100644 index 00000000..6772850b --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/base/ModuleAppActivity.html @@ -0,0 +1,36 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
ChannelPriorityclass ChannelPriority(private val conditions: () -> Boolean) +
Change Records
v1.1.5
added
Function Illustrate
数据通讯桥响应优先级构造类。
这个类是对
YukiHookDataChannel
的一个扩展用法。ModuleAppActivity - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/base/ModuleAppCompatActivity.html b/en/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/base/ModuleAppCompatActivity.html new file mode 100644 index 00000000..945856c4 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/activity/base/ModuleAppCompatActivity.html @@ -0,0 +1,37 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
ModuleAppActivityopen class ModuleAppActivity : Activity() +
Change Records
v1.1.0
added
Function Illustrate
代理
Activity
。继承于此类的
Activity
可以同时在宿主与模块中启动。在 (Xposed) 宿主环境需要在宿主启动时调用
Context.registerModuleAppActivities
进行注册。- field
proxyClassNameopen val proxyClassName: String +
Change Records
v1.1.10
added
Function Illustrate
设置当前代理的
Activity
类名。留空则使用
Context.registerModuleAppActivities
时设置的类名Pay Attention
代理的 Activity 类名必须存在于宿主的 AndroidMainifest 清单中。
ModuleAppCompatActivity - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/context/wrapper/ModuleContextThemeWrapper.html b/en/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/context/wrapper/ModuleContextThemeWrapper.html new file mode 100644 index 00000000..ed5f82b4 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/context/wrapper/ModuleContextThemeWrapper.html @@ -0,0 +1,36 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
ModuleAppCompatActivityopen class ModuleAppCompatActivity : AppCompatActivity() +
Change Records
v1.1.0
added
Function Illustrate
代理
AppCompatActivity
。继承于此类的
Activity
可以同时在宿主与模块中启动。在 (Xposed) 宿主环境需要在宿主启动时调用
Context.registerModuleAppActivities
进行注册。在 (Xposed) 宿主环境需要重写
moduleTheme
设置 AppCompat 主题,否则会无法启动。- field
moduleThemeopen val moduleTheme: Int +
Change Records
v1.1.0
added
Function Illustrate
设置当前代理的
Activity
主题。- field
proxyClassNameopen val proxyClassName: String +
Change Records
v1.1.10
added
Function Illustrate
设置当前代理的
Activity
类名。留空则使用
Context.registerModuleAppActivities
时设置的类名Pay Attention
代理的 Activity 类名必须存在于宿主的 AndroidMainifest 清单中。
ModuleContextThemeWrapper - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/reference/ModuleClassLoader.html b/en/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/reference/ModuleClassLoader.html new file mode 100644 index 00000000..dac05966 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/xposed/parasitic/reference/ModuleClassLoader.html @@ -0,0 +1,37 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
ModuleContextThemeWrapperclass ModuleContextThemeWrapper private constructor(baseContext: Context, theme: Int, configuration: Configuration?) : ContextThemeWrapper +
Change Records
v1.1.0
added
Function Illustrate
代理
ContextThemeWrapper
。通过包装,你可以轻松在 (Xposed) 宿主环境使用来自模块的主题资源。
- method
applyConfigurationfun applyConfiguration(initiate: Configuration.() -> Unit): ModuleContextThemeWrapper +
Change Records
v1.1.0
added
Function Illustrate
设置当前
ModuleContextThemeWrapper
的Configuration
。设置后会自动调用
Resources.updateConfiguration
。ModuleClassLoader - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookPrefsBridge.html b/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookPrefsBridge.html new file mode 100644 index 00000000..6c908338 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookPrefsBridge.html @@ -0,0 +1,67 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
ModuleClassLoaderclass ModuleClassLoader private constructor() : ClassLoader +
Change Records
v1.1.2
added
Function Illustrate
自动处理 (Xposed) 宿主环境与模块环境的
ClassLoader
。- object
companion objectChange Records
v1.1.2
added
- method
excludeHostClassesfun excludeHostClasses(vararg name: String) +
Change Records
v1.1.2
added
Function Illustrate
添加到 Hook APP (宿主)
Class
排除列表。排除列表中的
Class
将会使用宿主的ClassLoader
进行装载。Pay Attention
排除列表仅会在 (Xposed) 宿主环境生效。
- method
excludeModuleClassesfun excludeModuleClasses(vararg name: String) +
Change Records
v1.1.2
added
Function Illustrate
添加到模块
Class
排除列表。排除列表中的
Class
将会使用模块 (当前宿主环境的模块注入进程) 的ClassLoader
进行装载。Pay Attention
排除列表仅会在 (Xposed) 宿主环境生效。
YukiHookPrefsBridge - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData.html b/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData.html new file mode 100644 index 00000000..c4e77843 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData.html @@ -0,0 +1,51 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
YukiHookPrefsBridgeclass YukiHookPrefsBridge private constructor(private var context: Context?) +
Change Records
v1.0
first
v1.1.9
modified
更名为YukiHookModulePrefs
YukiHookPrefsBridge
Function Illustrate
YukiHookAPI
对SharedPreferences
、XSharedPreferences
的扩展存储桥实现。在不同环境智能选择存取使用的对象。
Pay Attention
模块与宿主之前共享数据存储为实验性功能,仅在 LSPosed 环境测试通过,EdXposed 理论也可以使用但不再推荐。
使用 LSPosed 环境请在
AndroidManifests.xml
中将xposedminversion
最低设置为93
。若你在按照规定配置后依然无法使用或出现文件权限错误问题,可以参考 isEnableHookSharedPreferences。
未使用 LSPosed 环境请将你的模块
API
降至26
以下,YukiHookAPI
将会尝试使用makeWorldReadable
但仍有可能不成功。太极请参阅 文件权限/配置/XSharedPreference。
对于在模块环境中使用
PreferenceFragmentCompat
,YukiHookAPI
提供了ModulePreferenceFragment
来实现同样的功能。Optional Configuration
若你不想将你的模块的
xposedminversion
最低设置为93
,你可以在AndroidManifest.xml
中添加xposedsharedprefs
来实现支持。The following example
<meta-data + android:name="xposedsharedprefs" + android:value="true"/> +
isXSharePrefsReadable - field
Change Records
v1.0.90
added
v1.1.5
deprecated
请迁移到
isPreferencesAvailable
isRunInNewXShareMode - field
Change Records
v1.0.78
added
v1.1.5
deprecated
请迁移到
isPreferencesAvailable
- field
isPreferencesAvailableval isPreferencesAvailable: Boolean +
Change Records
v1.1.5
added
Function Illustrate
获取当前
YukiHookPrefsBridge
的可用状态。在 (Xposed) 宿主环境中返回
XSharedPreferences
可用状态 (可读)。在模块环境中返回当前是否处于 New XSharedPreferences 模式 (可读可写)。
- method
namefun name(name: String): YukiHookPrefsBridge +
Change Records
v1.0
first
Function Illustrate
自定义 Sp 存储名称。
Function Example
在
Activity
中的使用方法。The following example
prefs("custom_name").getString("custom_key") +
在 (Xposed) 宿主环境
PackageParam
中的使用方法。The following example
prefs("custom_name").getString("custom_key") +
direct - method
Change Records
v1.0.5
added
v1.1.11
deprecated
键值的直接缓存功能已被移除,因为其存在内存溢出 (OOM) 问题
- method
nativefun native(): YukiHookPrefsBridge +
Change Records
v1.1.9
added
Function Illustrate
忽略当前环境直接使用
Context.getSharedPreferences
存取数据。- method
getStringfun getString(key: String, value: String): String +
Change Records
v1.0
first
Function Illustrate
获取
String
键值。- method
getStringSetfun getStringSet(key: String, value: Set<String>): Set<String> +
Change Records
v1.0.77
added
Function Illustrate
获取
Set<String>
键值。- method
getBooleanfun getBoolean(key: String, value: Boolean): Boolean +
Change Records
v1.0
first
Function Illustrate
获取
Boolean
键值。- method
getIntfun getInt(key: String, value: Int): Int +
Change Records
v1.0
first
Function Illustrate
获取
Int
键值。- method
getLongfun getLong(key: String, value: Long): Long +
Change Records
v1.0
first
Function Illustrate
获取
Long
键值。- method
getFloatfun getFloat(key: String, value: Float): Float +
Change Records
v1.0
first
Function Illustrate
获取
Float
键值。- method
containsfun contains(key: String): Boolean +
Change Records
v1.1.9
added
Function Illustrate
判断当前是否包含
key
键值的数据。智能识别对应环境读取键值数据。
- method
allfun all(): MutableMap<String, Any?> +
Change Records
v1.0.77
added
Function Illustrate
获取全部存储的键值数据。
智能识别对应环境读取键值数据。
Pay Attention
每次调用都会获取实时的数据,不受缓存控制,请勿在高并发场景中使用。
remove - method
Change Records
v1.0
first
v1.1.9
deprecated
请迁移到
edit
方法clear - method
Change Records
v1.0.77
added
v1.1.9
deprecated
请迁移到
edit
方法putString - method
Change Records
v1.0
first
v1.1.9
deprecated
请迁移到
edit
方法putStringSet - method
Change Records
v1.0.77
added
v1.1.9
deprecated
请迁移到
edit
方法putBoolean - method
Change Records
v1.0
first
v1.1.9
deprecated
请迁移到
edit
方法putInt - method
Change Records
v1.0
first
v1.1.9
deprecated
请迁移到
edit
方法putLong - method
Change Records
v1.0
first
v1.1.9
deprecated
请迁移到
edit
方法putFloat - method
Change Records
v1.0
first
v1.1.9
deprecated
请迁移到
edit
方法- method
getinline fun <reified T> get(prefs: PrefsData<T>, value: T): T +
Change Records
v1.0.67
added
Function Illustrate
智能获取指定类型的键值。
put - method
Change Records
v1.0.67
added
v1.1.9
deprecated
请迁移到
edit
方法- method
editfun edit(): Editor +
Change Records
v1.1.9
added
Function Illustrate
创建新的
Editor
。在模块环境中或启用了
isUsingNativeStorage
后使用。Notice
在 (Xposed) 宿主环境下只读,无法使用。
- method
editfun edit(initiate: Editor.() -> Unit) +
Change Records
v1.1.9
added
Function Illustrate
创建新的
Editor
。自动调用
Editor.apply
方法。在模块环境中或启用了
isUsingNativeStorage
后使用。Notice
在 (Xposed) 宿主环境下只读,无法使用。
clearCache - method
Change Records
v1.0.5
added
v1.1.11
deprecated
键值的直接缓存功能已被移除,因为其存在内存溢出 (OOM) 问题
- class
Editorinner class Editor internal constructor() +
Change Records
v1.1.9
added
Function Illustrate
YukiHookPrefsBridge
的存储代理类。请使用
edit
方法来获取Editor
。在模块环境中或启用了
isUsingNativeStorage
后使用。Notice
在 (Xposed) 宿主环境下只读,无法使用。
- method
removefun remove(key: String): Editor +
Change Records
v1.1.9
added
Function Illustrate
移除全部包含
key
的存储数据。- method
removeinline fun <reified T> remove(prefs: PrefsData<T>): Editor +
Change Records
v1.1.9
added
Function Illustrate
移除
PrefsData.key
的存储数据。- method
clearfun clear(): Editor +
Change Records
v1.1.9
added
Function Illustrate
移除全部存储数据。
- method
putStringfun putString(key: String, value: String): Editor +
Change Records
v1.1.9
added
Function Illustrate
存储
String
键值。- method
putStringSetfun putStringSet(key: String, value: Set<String>): Editor +
Change Records
v1.1.9
added
Function Illustrate
存储
Set<String>
键值。- method
putBooleanfun putBoolean(key: String, value: Boolean): Editor +
Change Records
v1.1.9
added
Function Illustrate
存储
Boolean
键值。- method
putIntfun putInt(key: String, value: Int): Editor +
Change Records
v1.1.9
added
Function Illustrate
存储
Int
键值。- method
putLongfun putLong(key: String, value: Long): Editor +
Change Records
v1.1.9
added
Function Illustrate
存储
Long
键值。- method
putFloatfun putFloat(key: String, value: Float): Editor +
Change Records
v1.1.9
added
Function Illustrate
存储
Float
键值。- method
putinline fun <reified T> put(prefs: PrefsData<T>, value: T): Editor +
Change Records
v1.1.9
added
Function Illustrate
智能存储指定类型的键值。
- method
commitfun commit(): Boolean +
Change Records
v1.1.9
added
Function Illustrate
提交更改 (同步)。
- method
applyfun apply() +
Change Records
v1.1.9
added
Function Illustrate
提交更改 (异步)。
PrefsData - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/ui/ModulePreferenceFragment.html b/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/ui/ModulePreferenceFragment.html new file mode 100644 index 00000000..372566c3 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/ui/ModulePreferenceFragment.html @@ -0,0 +1,55 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
PrefsDatadata class PrefsData<T>(var key: String, var value: T) : Serializable +
Change Records
v1.0.67
added
v1.1.5
modified
实现了
Serializable
接口Function Illustrate
键值对存储构造类。
这个类是对
YukiHookPrefsBridge
的一个扩展用法。Function Example
建立一个模板类定义模块与宿主需要使用的键值数据。
The following example
object DataConst { + + val TEST_KV_DATA_1 = PrefsData("test_data_1", "defalut value") + val TEST_KV_DATA_2 = PrefsData("test_data_2", false) + val TEST_KV_DATA_3 = PrefsData("test_data_3", 0) +} +
键值数据定义后,你就可以方便地在模块和宿主中调用所需要的数据。
模块示例如下
// 读取 +val data = prefs().get(DataConst.TEST_KV_DATA_1) +// 写入 +prefs().edit { put(DataConst.TEST_KV_DATA_1, "written value") } +
宿主示例如下
// 读取 String +val dataString = prefs.get(DataConst.TEST_KV_DATA_1) +// 读取 Boolean +val dataBoolean = prefs.get(DataConst.TEST_KV_DATA_2) +
你依然可以不使用模板定义的默认值,随时修改你的默认值。
The following example
// 读取 - 此时 data 取到的默认值将会是 2 - 并不是模板提供的 0 +val data = prefs.get(DataConst.TEST_KV_DATA_3, 2) +
ModulePreferenceFragment - class | Yuki Hook API + + + + + ++ + + diff --git a/en/api/public/com/highcapable/yukihookapi/hook/xposed/proxy/IYukiHookXposedInit.html b/en/api/public/com/highcapable/yukihookapi/hook/xposed/proxy/IYukiHookXposedInit.html new file mode 100644 index 00000000..b64b39e9 --- /dev/null +++ b/en/api/public/com/highcapable/yukihookapi/hook/xposed/proxy/IYukiHookXposedInit.html @@ -0,0 +1,38 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- class
ModulePreferenceFragmentabstract class ModulePreferenceFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedPreferenceChangeListener +
Change Records
v1.0.78
added
Function Illustrate
这是对使用
YukiHookAPI
Xposed 模块实现中的一个扩展功能。此类接管了
PreferenceFragmentCompat
并对其实现了 Sp 存储在 Xposed 模块中的全局可读可写。在你使用
PreferenceFragmentCompat
的实例中,将继承对象换成此类。然后请将重写方法由
onCreatePreferences
替换为onCreatePreferencesInModuleApp
即可。Function Example
使用
ModulePreferenceFragment
创建一个PreferenceFragmentCompat
对象。The following example
class SettingsFragment : ModulePreferenceFragment() { + + override fun onCreatePreferencesInModuleApp(savedInstanceState: Bundle?, rootKey: String?) { + setPreferencesFromResource(R.xml.settings_preferences, rootKey) + // Your code here. + } +} +
其余用法与
PreferenceFragmentCompat
保持一致。- method
onCreatePreferencesInModuleAppabstract fun onCreatePreferencesInModuleApp(savedInstanceState: Bundle?, rootKey: String?) +
Change Records
v1.0.78
added
Function Illustrate
对接原始方法
onCreatePreferences
。- method
onSharedPreferenceChangedoverride fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) +
Change Records
v1.0.78
added
Function Illustrate
实现了
SharedPreferences.OnSharedPreferenceChangeListener
的原生监听功能。Function Example
Notice
在使用 onSharedPreferenceChanged 时请保留 super 方法。
The following example
class SettingsFragment : ModulePreferenceFragment() { + + override fun onCreatePreferencesInModuleApp(savedInstanceState: Bundle?, rootKey: String?) { + // ... + } + + override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { + super.onSharedPreferenceChanged(sharedPreferences, key) + // Your code here. + } +} +
IYukiHookXposedInit - interface | Yuki Hook API + + + + + ++ + + diff --git a/en/api/special-features/host-inject.html b/en/api/special-features/host-inject.html new file mode 100644 index 00000000..931c4cd3 --- /dev/null +++ b/en/api/special-features/host-inject.html @@ -0,0 +1,189 @@ + + + + + + + + +Yuki Hook API
Notice
Due to maintenance costs, the
YukiHookAPI
will no longer update this document from version1.3.0
and switch to the API document automatically generated by the Dokka plugin in version2.0.0
.Notice
The English translation of this page has not been completed, you are welcome to contribute translations to us.
You can use the Chrome Translation Plugin to translate entire pages for reference.
- interface
IYukiHookXposedInitinterface IYukiHookXposedInit +
Change Records
v1.0
first
v1.0.80
modified
deprecated
作废了
名称但保留接口YukiHookXposedInitProxy
迁移到
IYukiHookXposedInit
新名称Function Illustrate
YukiHookAPI 的 Xposed 装载 API 调用接口。
- method
onInitfun onInit() +
Change Records
v1.0.5
added
Function Illustrate
配置
YukiHookAPI.Configs
的初始化方法。Pay Attention
在这里只能进行初始化配置,不能进行 Hook 操作。
此方法可选,你也可以选择不对 YukiHookAPI.Configs 进行配置。
- method
onHookfun onHook() +
Change Records
v1.0
first
Function Illustrate
Xposed API 的模块装载调用入口方法。
- method
onXposedEventfun onXposedEvent() +
Change Records
v1.0.80
added
Function Illustrate
监听 Xposed 原生装载事件。
若你的 Hook 事件中存在需要兼容的原生 Xposed 功能,可在这里实现。
请在这里使用 YukiXposedEvent 创建回调事件监听。
可监听的事件如下:
YukiXposedEvent.onInitZygote
YukiXposedEvent.onHandleLoadPackage
YukiXposedEvent.onHandleInitPackageResources
Pay Attention
此接口仅供监听和实现原生 Xposed API 的功能,请不要在这里操作 YukiHookAPI。
YukiHookXposedInitProxy - interface
Change Records
v1.0
first
v1.0.80
deprecated
请迁移到
IYukiHookXposedInit
Host Resource Injection Extension | Yuki Hook API + + + + + ++ + + diff --git a/en/api/special-features/host-lifecycle.html b/en/api/special-features/host-lifecycle.html new file mode 100644 index 00000000..b2c44808 --- /dev/null +++ b/en/api/special-features/host-lifecycle.html @@ -0,0 +1,84 @@ + + + + + + + + +Yuki Hook API
Host Resource Injection Extension
This is an extension that injects Module App's Resources,
Activity
components, andContext
topics into the Host App.Before using the following functions, in order to prevent Resource Id from conflicting with each other, you need to modify the Resource Id in the
build.gradle
of the current Xposed Module project.Kotlin DSL
android { + androidResources.additionalParameters += listOf("--allow-reserved-package-id", "--package-id", "0x64") +} +
Groovy DSL
android { + androidResources.additionalParameters += ['--allow-reserved-package-id', '--package-id', '0x64'] +} +
Notice
aaptOptions.additionalParameters in previous versions has been deprecated, please refer to the above writing method and keep your Android Gradle Plugin to the latest version.
The sample Resource Id value provided is for reference only, 0x7f cannot be used, the default is 0x64.
In order to prevent the existence of multiple Xposed Modules in the current Host App, it is recommended to customize your own Resource Id.
Inject Module App's Resources
After the Host App is hooked, we can directly inject the
Context
obtained in the Hooker into the current Module App's Resources.The following example
resolve().firstMethod { + name = "onCreate" + parameters(Bundle::class) +}.hook { + after { + instance<Activity>().also { + // <Scenario 1> Inject Module App's Resources through Context + it.injectModuleAppResources() + // <Scenario 2> Get the Host App's Resources directly and inject the Module App's Resources + it.resources.injectModuleAppResources() + // Use the Module App's Resource Id directly + it.getString(R.id.app_name) + } + } +} +
You can also inject current Module App's Resources directly in
AppLifecycle
.The following example
onAppLifecycle { + onCreate { + // Globally inject Module App's Resources, but only in the global lifecycle + // Methods like ImageView.setImageResource need to be injected separately in Activity + // <Scenario 1> Inject Module App's Resources through Context + injectModuleAppResources() + // <Scenario 2> Get the Host App's Resources directly and inject the Module App's Resources + resources.injectModuleAppResources() + // Use the Module App's Resource Id directly + getString(R.id.app_name) + } +} +
Tips
For more functions, please refer to the Context+Resources.injectModuleAppResources method.
Register Module App's Activity
When the
Activity
of all applications in the Android system starts, it needs to be registered inAndroidManifest.xml
.During the Hook process, if we want to directly start the unregistered
Activity
in the Module App through the Host App, what should we do?After the Host App is hooked, we can directly register the
Activity
proxy of the current Module App in theContext
obtained in the Hooker.The following example
resolve().firstMethod { + name = "onCreate" + parameters(Bundle::class) +}.hook { + after { + instance<Activity>().registerModuleAppActivities() + } +} +
You can also register the current Module App's
Activity
proxy directly inAppLifecycle
.The following example
onAppLifecycle { + onCreate { + registerModuleAppActivities() + } +} +
If the
proxy
parameter is not filled in, the API will automatically obtain the current Host App's launching entryActivity
for proxying according to the currentContext
.Usually, it works, but the above situation will fail in some apps, for example, some
Activity
will add launching parameters to the registration list, so we need to use another solution.If the unregistered
Activity
cannot be launched correctly, we can manually get the Host App'sAndroidManifest.xml
for analysis to get a registeredActivity
tag and get thename
.You need to choose an unneeded
Activity
that may not be used by the current Host App as a "puppet" to proxy it, which usually works.For example, we have found a suitable
Activity
that can be proxied.The following example
<activity + android:name="com.demo.test.activity.TestActivity" + ...> +
According to the
name
, we only need to add this parameter to the method for registration.The following example
registerModuleAppActivities(proxy = "com.demo.test.activity.TestActivity") +
Alternatively, if you write a
stub
for the Host App's class, you can register it directly through theClass
object.The following example
registerModuleAppActivities(TestActivity::class.java) +
After registration is completed, please implement the
ModuleActivity
interface using theActivity
module in the host-started module.These
Activity
(ies) now live seamlessly in the host without registration.We recommend that you create
BaseActivity
as the base class for all modulesActivity
.The following example
abstract class BaseActivity : AppCompatActivity(), ModuleActivity { + + // Set up AppCompat Theme (if currently is [AppCompatActivity]) + override val moduleTheme get() = R.style.YourAppTheme + + override fun getClassLoader() = delegate.getClassLoader() + + override fun onCreate(savedInstanceState: Bundle?) { + delegate.onCreate(savedInstanceState) + super.onCreate(savedInstanceState) + } + + override fun onConfigurationChanged(newConfig: Configuration) { + delegate.onConfigurationChanged(newConfig) + super.onConfigurationChanged(newConfig) + } + + override fun onRestoreInstanceState(savedInstanceState: Bundle) { + delegate.onRestoreInstanceState(savedInstanceState) + super.onRestoreInstanceState(savedInstanceState) + } +} +
Then inherit the
Activity
you want to implement inBaseActivity
.The following example
class HostTestActivity : BaseActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + // Module App's Resources have been injected automatically + // You can directly use xml to load the layout + setContentView(R.layout.activity_main) + } +} +
After all the above steps are completed, you can happily call
startActivity
anywhere in the (Xposed) Host environment where aContext
exists.The following example
val context: Context = ... // Assume this is your Context +context.startActivity(context, HostTestActivity::class.java) +
The
proxy
parameter we set in theregisterModuleAppActivities
method above is the default global proxyActivity
.If you need to specify a delegated
Activity
to use another Host App'sActivity
as a proxy, you can refer to the following method.The following example
class HostTestActivity : BaseActivity() { + + // Specify an additional proxy Activity class name + // Which must also exist in the Host App's AndroidManifest + override val proxyClassName get() = "com.demo.test.activity.OtherActivity" + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + // Module App's Resources have been injected automatically + // You can directly use xml to load the layout + setContentView(R.layout.activity_main) + } +} +
Tips
For more functions, please refer to the Context.registerModuleAppActivities method.
Create ContextThemeWrapper Proxy
Sometimes, we need to use
MaterialAlertDialogBuilder
to beautify our own dialogs in the Host App, but we can't create them without the AppCompat theme.
- Will got the following exception
The style on this component requires your app theme to be Theme.AppCompat (or a descendant). +
At this time, we want to use
MaterialAlertDialogBuilder
to create a dialog in the currentActivity
of the Host App being hooked, you can have the following methods.The following example
resolve().firstMethod { + name = "onCreate" + parameters(Bundle::class) +}.hook { + after { + // Use applyModuleTheme to create a theme resource in the current Module App + val appCompatContext = instance<Activity>().applyModuleTheme(R.style.Theme_AppCompat) + // Directly use this Context that wraps the Module App's theme to create a dialog + MaterialAlertDialogBuilder(appCompatContext) + .setTitle("AppCompat Theme Dialog") + .setMessage("I am an AppCompat theme dialog displayed in the Host App.") + .setPositiveButton("OK", null) + .show() + } +} +
You can also set the system (native) night mode and day mode on the current
Context
throughuiMode
.Which requires at least Android 10 and above system version support and the current theme contains night mode related elements.
The following example
resolve().firstMethod { + name = "onCreate" + parameters(Bundle::class) +}.hook { + after { + // Define the theme resource in the current Module App + var appCompatContext: ModuleContextThemeWrapper + // <Scenario 1> Get the Configuration object directly to set + appCompatContext = instance<Activity>() + .applyModuleTheme(R.style.Theme_AppCompat) + .applyConfiguration { uiMode = Configuration.UI_MODE_NIGHT_YES } + // <Scenario 2> Create a new Configuration object + // This solution will destroy the original font scaling and other settings in the current Host App + // You need to manually re-pass parameters such as densityDpi + appCompatContext = instance<Activity>().applyModuleTheme( + theme = R.style.Theme_AppCompat, + configuration = Configuration().apply { uiMode = Configuration.UI_MODE_NIGHT_YES } + ) + // Directly use this Context that wraps the Module App's theme to create a dialog + MaterialAlertDialogBuilder(appCompatContext) + .setTitle("AppCompat Theme Dialog") + .setMessage("I am an AppCompat theme dialog displayed in the Host App.") + .setPositiveButton("OK", null) + .show() + } +} +
This way, we can create dialogs in the Host App very simply using
MaterialAlertDialogBuilder
.Possible Problems
Because some androidx dependent libraries or custom themes used by some apps may interfere with the actual style of the current MaterialAlertDialog, such as the button style of the dialog.
You can refer to the Module App Demo in this case and see here is the sample code to fix this problem.
ClassCastException may occur when some apps are created, please manually specify a new Configuration instance to fix.
Tips
For more functions, please refer to the Context.applyModuleTheme method.
ClassLoader Conflict Problem
The content introduced on this page is to directly inject the resources of the Module App into the Host App.
Since the Module App and the Host App are not in the same process (the same APK), there may be a
ClassLoader
conflict.If a
ClassLoader
conflict occurs, you may encounter aClassCastException
.
YukiHookAPI
has solved the problem of possible conflicts by default, and you need to configure the exclusion list by yourself in other cases.The exclusion list determines whether these
Class
need to be loaded by the Module App or the Host App'sClassLoader
.The following example
// Exclude Class names belonging to the Host App +// They will be loaded by the Host App's ClassLoader +// The following content is for demonstration only +// DO NOT USE IT DIRECTLY, please refer to your actual situation +ModuleClassLoader.excludeHostClasses( + "androidx.core.app.ActivityCompat", + "com.demo.Test" +) +// Exclude Class names belonging to the Module App +// They will be loaded by the ClassLoader of the Module App (the current Hook process) +// The following content is for demonstration only +// DO NOT USE IT DIRECTLY, please refer to your actual situation +ModuleClassLoader.excludeModuleClasses( + "com.demo.entry.HookEntry", + "com.demo.controller.ModuleController" +) +
You need to set it before the method of injecting Module App's resources into the Host App is executed to take effect.
This function is only to solve the situation that
Class
with the same name may exist in the Host App and Module App, such as shared SDK and dependencies.In most cases, you will not use this function.
Tips
For more functions, please refer to ModuleClassLoader.
Host Lifecycle Extension | Yuki Hook API + + + + + ++ + + diff --git a/en/api/special-features/logger.html b/en/api/special-features/logger.html new file mode 100644 index 00000000..315bf1f3 --- /dev/null +++ b/en/api/special-features/logger.html @@ -0,0 +1,84 @@ + + + + + + + + +Yuki Hook API
Host Lifecycle Extension
This is an extension of the lifecycle of an automatic hooking Host App.
Listener Lifecycle
Implement the listening function by automating the lifecycle method of the Host App.
We need to listen to the startup and lifecycle methods of the Host App's
Application
, just use the following methods.The following example
loadApp(name = "com.example.demo") { + // Register lifecycle listeners + // Optional parameter: + // You can set isOnFailureThrowToApp = false + // So that the exception will not be thrown to the Host App to prevent the Host App from crashing + // The default is true + onAppLifecycle(isOnFailureThrowToApp = true) { + // You can implement lifecycle method listeners in Application here + attachBaseContext { baseContext, hasCalledSuper -> + // Determine whether + // The super.attachBaseContext(base) method has been executed by judging hasCalledSuper + // ... + } + onCreate { + // Get the current Application instance through this + // ... + } + onTerminate { + // Get the current Application instance through this + // ... + } + onLowMemory { + // Get the current Application instance through this + // ... + } + onTrimMemory { self, level -> + // Here you can judge whether the app has switched to the background + if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { + // ... + } + // ... + } + onConfigurationChanged { self, config -> + // ... + } + } +} +
Tips
For more functions, please refer to AppLifecycle.
Register System Broadcast
Register system broadcast through the
Application.onCreate
method to listening system broadcast.We can also register system broadcast in the Host App's
Application
.The following example
loadApp(name = "com.example.demo") { + // Register lifecycle listeners + onAppLifecycle { + // Broadcast listening when the registered user is unlocked + registerReceiver(Intent.ACTION_USER_PRESENT) { context, intent -> + // ... + } + // Register multiple broadcast listeners, will call back multiple times at the same time + registerReceiver(Intent.ACTION_PACKAGE_CHANGED, Intent.ACTION_TIME_TICK) { context, intent -> + // ... + } + } +} +
Tips
For more functions, please refer to AppLifecycle.
Debug Logs | Yuki Hook API + + + + + ++ + + diff --git a/en/api/special-features/reflection.html b/en/api/special-features/reflection.html new file mode 100644 index 00000000..5d0aa475 --- /dev/null +++ b/en/api/special-features/reflection.html @@ -0,0 +1,882 @@ + + + + + + + + +Yuki Hook API
Debug Logs
Log is the most important part of the debugging process,
YukiHookAPI
encapsulates a set of stable and efficient debugging log functions for developers.Tips
The logs of
KavaRef
can be managed separately by itself. For detailed configuration plans, you can refer to here, which will jump to theKavaRef
document.
YukiHookAPI
has taken over the logging function ofKavaRef
by default, and you can also configure the logging function ofKavaRef
yourself.Normal Logs
You can call
YLog.debug
,YLog.info
,YLog.warn
to print normal logs to the console.The usage method is as follows.
The following example
YLog.debug(msg = "This is a log") +
At this ponit,
YukiHookAPI
will callandroid.util.Log
and log function in (Xposed) Host environment to print this log at the same time.The default
TAG
of the log is the value you set inYLog.Configs.tag
.You can also customize this value dynamically, but it is not recommended to modify
TAG
easily to prevent logs from being filtered.The following example
YLog.debug(tag = "YukiHookAPI", msg = "This is a log") +
The printed result is as shown below.
The following example
[YukiHookAPI][D][host package name] This is a log +
You can also use
YLog.EnvType
to customize the type of log printing.You can choose to use
android.util.Log
or the log function in the (Xposed) Host environment to print logs.The default type is
YLog.EnvType.BOTH
, which means that both methods are used to print logs.For example we only use
android.util.Log
to print logs.The following example
YLog.debug(tag = "YukiHookAPI", msg = "This is a log", env = YLog.EnvType.LOGD) +
Or just use the log function that in the (Xposed) Host environment to print the log, this method can only be used in the (Xposed) Host environment.
The following example
YLog.debug(tag = "YukiHookAPI", msg = "This is a log", env = YLog.EnvType.XPOSED_ENVIRONMENT) +
If you want to intelligently distinguish the (Xposed) Host environment from the Module environment, you can write it in the following form.
The following example
YLog.debug(tag = "YukiHookAPI", msg = "This is a log", env = YLog.EnvType.SCOPE) +
In this way, the API will intelligently select the specified method type to print this log in different environments.
Tips
For more functions, please refer to YLog.debug, YLog.info and YLog.warn methods.
Error Logs
You can call
YLog.error
to printE
level logs to the console.The usage method is as follows.
The following example
YLog.error(msg = "This is an error") +
The error log is the highest level, regardless of whether you have filtered only
E
level logs.For error-level logging, you can also append an exception stack.
// Assume this is the exception that was thrown +val throwable = Throwable(...) +// Print log +YLog.error(msg = "This is an error", e = throwable) +
The printed result is as shown below.
The following example
[YukiHookAPI][E][host package name] This is an error +
At the same time, the log will help you print the entire exception stack.
The following example
java.lang.Throwable + at com.demo.Test.<init>(...) + at com.demo.Test.doTask(...) + at com.demo.Test.stop(...) + at com.demo.Test.init(...) + at a.a.a(...) + ... 3 more +
In the error log, you can also use
YLog.EnvType
to specify the method type currently used to print the log.Tips
For more functions, please refer to the YLog.error method.
Save Logs and Custom Elements
You can save all currently printed logs directly to a file using the
YLog.saveToFile
method.The following example
// Please note +// The saved file path must have read and write permissions +// Otherwise an exception will be thrown +YLog.saveToFile("/sdcard/Documents/debug_log.log") +
You can also use
YLog.contents
to get all the log file contents that have been printed so far.The following example
// Get the contents of all log files that have been printed so far +val fileContent = YLog.contents +
If you need an array of real-time log data structures, you can directly get the content of
YLog.inMemoryData
.The following example
// Get the currently printed real-time log data structure array +YLog.inMemoryData.forEach { + it.timestamp // Get timestamp + it.time // Get UTC time + it.priority // Get priority + it.msg // Get message + it.throwable // Get exception + // ... +} +
If you want to format or save the obtained custom log data to a file, you only need to use the following method.
The following example
// Assume this is the custom log data you get +val data: List<YLogData> +// Format log data to String +val dataString = YLog.contents(data) +// Save log data to file +// Please note +// The saved file path must have read and write permissions +// Otherwise an exception will be thrown +YLog.saveToFile("/sdcard/Documents/debug_log.log", data) +
Pay Attention
You need to enable YLog.Configs.isRecord to get the contents of YLog.inMemoryData.
The obtained log data is isolated from each other in the Host App and the Module App's process.
You can only get the corresponding log data in the corresponding process.
If you need to get these log data in real time anywhere, please refer to Xposed Module and Host Channel, Register Module App's Activity.
If you only want to get log data in real time through Module App or Host App, Please refer to the optional solution YukiHookDataChannel.obtainLoggerInMemoryData method.
You can also use
YLog.Configs.elements
to customize the elements that debug logs display externally.This function requires
YukiHookAPI.Configs
to be configured inonInit
of the Hook entry class.The following example
override fun onInit() = configs { + debugLog { + // ... + elements(TAG, PRIORITY, PACKAGE_NAME, USER_ID) + } + // ... +} +
Tips
For more functions, please refer to YLog.inMemoryData, YLog.contents, YLog.contents, YLog.saveToFile methods and YLog.Configs.
Reflection Extensions (Migrated) | Yuki Hook API + + + + + ++ + + diff --git a/en/api/special-features/xposed-channel.html b/en/api/special-features/xposed-channel.html new file mode 100644 index 00000000..25c3bedb --- /dev/null +++ b/en/api/special-features/xposed-channel.html @@ -0,0 +1,153 @@ + + + + + + + + +Yuki Hook API
Reflection Extensions (Migrated)
YukiHookAPI
encapsulates a set of reflection API with near-zero reflection writing for developers, which can almost completely replace the usage of reflection API in Java.
The core part of this functionality has been decoupled into the YukiReflection project, which can be used independently in any Java or Android project.
NowYukiReflection
is integrated intoYukiHookAPI
as a core dependency.
YukiHookAPI
adds related extensions for Hook functions on the basis ofYukiReflection
, and there is no need to introduce this dependency to useYukiHookAPI
.Notice
Starting with version
1.3.0
,YukiHookAPI
has moved its own reflection API partially to KavaRef, we no longer recommend the reflection API ofYukiHookAPI
itself, which have been marked as deprecated.The
YukiReflection
project has been deprecated due to many unsolved black box issues, and we no longer recommend anyone to use it.If you are still using the reflection API section of
YukiHookAPI
, please refer to the migration document here which will jump to theKavaRef
document.Class Extensions
Here are the extension functions related to the Class object itself.
Object Conversion
Suppose we want to get a
Class
that cannot be called directly.Normally, we can use the standard reflection API to find this
Class
.The following example
// Class in the default ClassLoader environment +var instance = Class.forName("com.demo.Test") +// Specify the Class in the ClassLoader environment +val customClassLoader: ClassLoader? = ... // Assume this is your ClassLoader +var instance = customClassLoader?.loadClass("com.demo.Test") +
This is probably not very friendly, and
YukiHookAPI
provides you with a syntactic sugar that can be used anywhere.The above writing can be written as
YukiHookAPI
as follows.The following example
// Get this Class directly +// If you are currently in the PackageParam environment, then you don't need to consider ClassLoader +var instance = "com.demo.Test".toClass() +// ClassLoader where the custom Class is located +val customClassLoader: ClassLoader? = ... // Assume this is your ClassLoader +var instance = "com.demo.Test".toClass(customClassLoader) +
If the current
Class
does not exist, using the above method will throw an exception.If you are not sure whether the
Class
exists, you can refer to the following solutions.The following example
// Get this Class directly +// If you are currently in the PackageParam environment, then you don't need to consider ClassLoader +// If not available, the result will be null but no exception will be thrown +var instance = "com.demo.Test".toClassOrNull() +// ClassLoader where the custom Class is located +val customClassLoader: ClassLoader? = ... // Assume this is your ClassLoader +// If not available, the result will be null but no exception will be thrown +var instance = "com.demo.Test".toClassOrNull(customClassLoader) +
We can also get an existing
Class
object by mapping.The following example
// Assume this Class can be obtained directly +var instance = classOf<Test>() +// We can also customize the ClassLoader where the Class is located, which is very effective for stubs +val customClassLoader: ClassLoader? = ... // Assume this is your ClassLoader +var instance = classOf<Test>(customClassLoader) +
Tips
For more functions, please refer to classOf, String.toClass, String.toClassOrNull, PackageParam → String+ VariousClass.toClass, PackageParam → String+VariousClass.toClassOrNull methods.
Lazy Loading
Suppose we want to get a
Class
that cannot be called directly, but we do not need thisClass
immediately.At this time, you can use
lazyClass
to complete this function.The following example
// Lazy loading of this Class +// If you are currently in a PackageParam environment, then you do not need to consider ClassLoader +val instance by lazyClass("com.demo.Test") +// Customize the ClassLoader where the Class is located +val customClassLoader: ClassLoader? = ... // Assume this is your ClassLoader +val instance by lazyClass("com.demo.Test") { customClassLoader } +// Call this Class at the appropriate time +instance.method { + // ... +} +
If the current
Class
does not exist, using the above method will throw an exception.If you are not sure whether
Class
exists, you can refer to the following solution.The following example
// Lazy loading of this Class +// If you are currently in a PackageParam environment, then you do not need to consider ClassLoader +// If not available, the result will be null but no exception will be thrown +val instance by lazyClassOrNull("com.demo.Test") +// Customize the ClassLoader where the Class is located +val customClassLoader: ClassLoader? = ... // Assume this is your ClassLoader +// If not available, the result will be null but no exception will be thrown +val instance by lazyClassOrNull("com.demo.Test") { customClassLoader } +// Call this Class at the appropriate time +instance?.method { + // ... +} +
Tips
For more functions, please refer to lazyClass, lazyClassOrNull, PackageParam → lazyClass, PackageParam → lazyClassOrNull methods.
Existential Judgment
Suppose we want to determine whether a
Class
exists.Usually, we can use the standard reflection API to find this
Class
to determine whether it exists by exception.The following example
// Class in the default ClassLoader environment +var isExist = try { + Class.forName("com.demo.Test") + true +} catch (_: Throwable) { + false +} +// Specify the Class in the ClassLoader environment +val customClassLoader: ClassLoader? = ... // Assume this is your ClassLoader +var isExist = try { + customClassLoader?.loadClass("com.demo.Test") + true +} catch (_: Throwable) { + false +} +
This is probably not very friendly, and
YukiHookAPI
provides you with a syntactic sugar that can be used anywhere.The above writing can be written as
YukiHookAPI
as follows.The following example
// Check if this class exists +// If you are currently in the PackageParam environment, then you don't need to consider ClassLoader +var isExist = "com.demo.Test".hasClass() +// ClassLoader where the custom Class is located +val customClassLoader: ClassLoader? = ... // Assume this is your ClassLoader +var isExist = "com.demo.Test".hasClass(customClassLoader) +
Tips
For more functions, please refer to String.hasClass, PackageParam → String.hasClass methods.
Beta
Vague SearchThe
Class
name in the Host App's Dex after being obfuscated by tools such as R8 will be difficult to distinguish.Its correct position is uncertain, and cannot be obtained directly through Object Conversion.
At this point, there is
DexClassFinder
, its role is to determine the instance of thisClass
by the bytecode features in theClass
that need to be searched.Notice
At present, the function of DexClassFinder is still in the experimental stage.
Since the search function is only implemented through the Java layer, the performance may not reach the optimal level when there are too many Host App's Class.
If something got wrong welcome to feedback.
Since it is a reflection-level API, currently it can only locate the specified Class through the characteristics of Class and Member, and cannot locate it by specifying the string and method content characteristics in the bytecode.
The speed of searching Class depends on the performance of the current device.
At present, the mainstream mobile processors are in the 3~10s range when the conditions are not complicated in the 10~15w number of Class, the fastest speed can reach within 25s under slightly complex conditions.
Please note that the more the same type Class is matched, the slower the speed.
Pay Attention
After YukiHookAPI 2.0.0 released, this function will be deprecated and will no longer be migrated to YukiReflection.We welcome all developers to start using DexKit, which is a high-performance runtime parsing library for Dex implemented in C++, which is more efficient than the Java layer in terms of performance, efficient and excellent, it is still in the development stage, your valuable suggestions are welcome.
Get Started
Below is a simple usage example.
Suppose the following
Class
is what we want, the names are obfuscated and may be different in each version.The following example
package com.demo; + +public class a extends Activity implements Serializable { + + public a(String var1) { + // ... + } + + private String a; + + private String b; + + private boolean a; + + protected void onCreate(Bundle var1) { + // ... + } + + private static void a(String var1) { + // ... + } + + private String a(boolean var1, String var2) { + // ... + } + + private void a() { + // ... + } + + public void a(boolean var1, a var2, b var3, String var4) { + // ... + } +} +
At this point, we want to get this
Class
, you can use theClassLoader.searchClass
method directly.In
PackageParam
you can use thesearchClass
method directly and it will automatically specify theappClassLoader
.Each of the conditions demonstrated below is optional, and the more complex the conditions, the more accurate the positioning and the worse the performance.
The following example
searchClass { + // Start the search from the specified package name range + // In actual use, you can specify multiple package name ranges at the same time + from("com.demo") + // Specify the result of getSimpleName of the current Class + // You can directly make logical judgments on this string + // Here we are not sure whether its name is a, we can only judge the length of the string + simpleName { it.length == 1 } + // Specify the inherited parent class object + // If it is an existing stub, it can be directly represented by generics + extends<Activity>() + // Specify the inherited parent class object + // Which can be written directly as the full class name + // And you can also specify multiple objects at the same time + extends("android.app.Activity") + // Specify the implemented interface + // If it exists stub, can be directly represented by generics + implements<Serializable>() + // Specify the implemented interface + // Which can be written directly as a full class name, or you can specify multiple at the same time + implements("java.io.Serializable") + // Specify the type and style of the constructor + // And the number count that exists in the current class + constructor { param(StringClass) }.count(num = 1) + // Specify the type and style of the variable + // And the number that exists in the current class count + field { type = StringClass }.count(num = 2) + // Specify the type and style of the variable + // And the number that exists in the current class count + field { type = BooleanType }.count(num = 1) + // Directly specify the number of all variables that exist in the current class count + field().count(num = 3) + // If you think the number of variables is indeterminate + // You can also use the following custom conditions + field().count(1..3) + field().count { it >= 3 } + // Specify the type and style of the method + // And the number that exists in the current class count + method { + name = "onCreate" + param(BundleClass) + }.count(num = 1) + // Specify the type and style of the method + // Specify the modifier, and the number count in the current class + method { + modifiers { isStatic && isPrivate } + param(StringClass) + returnType = UnitType + }.count(num = 1) + // Specify the type and style of the method + // Specify the modifier, and the number count in the current class + method { + modifiers { isPrivate && isStatic.not() } + param(BooleanType, StringClass) + returnType = StringClass + }.count(num = 1) + // Specify the type and style of the method + // Specify the modifier, and the number count in the current class + method { + modifiers { isPrivate && isStatic.not() } + emptyParam() + returnType = UnitType + }.count(num = 1) + // Specify the type and style of the method + // As well as the modifier and VagueType + // And the number count that exists in the current class + method { + modifiers { isPrivate && isStatic.not() } + param(BooleanType, VagueType, VagueType, StringClass) + returnType = UnitType + }.count(num = 1) + // Directly specify the number of all methods that exist in the current class count + method().count(num = 5) + // If you think the number of methods is uncertain, you can also use the following custom conditions + method().count(1..5) + method().count { it >= 5 } + // Directly specify the number of all members existing in the current class count + // Members include: Field, Method, Constructor + member().count(num = 9) + // There must be a static modifier in all members, you can add this condition like this + member { + modifiers { isStatic } + } +}.get() // Get the instance of this Class itself, if not found, it will return null +
Tips
The conditional usage of Field, Method, Constructor in the above usage is consistent with the related usage in Member Extensions, with only minor differences.
For more functions, please refer to MemberRules, FieldRules, MethodRules, ConstructorRules.
Asynchronous Search
By default,
DexClassFinder
will use synchronous mode to searchClass
, which will block the current thread until it finds or finds an exception.If the search takes too long, it may cause ANR problems to the Host App.
In response to the above problems, we can enable asynchronous, just add the parameter
async = true
, which will not require you to start a thread again, the API has already handled the related problems for you.Notice
For the asynchronous case you need to use the wait method to get the result, the get method will no longer work.
The following example
searchClass(async = true) { + // ... +}.wait { class1 -> + // Get asynchronous result +} +searchClass(async = true) { + // ... +}.wait { class2 -> + // Get asynchronous result +} +
In this way, our search process runs asynchronously, it will not block the main thread, and each search will be performed in a separate thread at the same time, which can achieve the effect of parallel tasks.
Local Cache
Since the search is performed again every time the Host App is reopened, this is a waste of repetitive performance when the Host App's version is unchanged.
At this point, we can locally cache the search results of the current Host App's version by specifying the
name
parameter.Next time, the found class name will be directly read from the local cache.
The local cache uses
SharedPreferences
, which will be saved to the Host App's data directory and will be re-cached after the Host App's version is updated.After enabling the local cache,
async = true
will be set at the same time, you don't need to set it manually.The following example
searchClass(name = "com.demo.class1") { + // ... +}.wait { class1 -> + // Get asynchronous result +} +searchClass(name = "com.demo.class2") { + // ... +}.wait { class2 -> + // Get asynchronous result +} +
If you want to clear the local cache manually, you can use the following method to clear the current version of the Host App's cache.
The following example
// Call it directly +// It may fail when the Host App's appContext is null, and a warning message will be printed on failure +DexClassFinder.clearCache() +// Called after listening to the lifecycle of the Host App +onAppLifecycle { + onCreate { + DexClassFinder.clearCache(context = this) + } +} +
You can also clear the Host App's cache for a specific version.
The following example
// Call it directly +// It may fail when the Host App's appContext is null, and a warning message will be printed on failure +DexClassFinder.clearCache(versionName = "1.0", versionCode = 1) +// Called after listening to the lifecycle of the Host App +onAppLifecycle { + onCreate { + DexClassFinder.clearCache(context = this, versionName = "1.0", versionCode = 1) + } +} +
Multiple Search
If you need to search a set of
Class
at the same time using a fixed condition, then you only need to use theall
orwaitAll
method to get the result.// Synchronous search, use all to get all the results found by the conditions +searchClass { + // ... +}.all().forEach { clazz -> + // Get each result +} +// Synchronous search, using all { ... } to iterate over each result +searchClass { + // ... +}.all { clazz -> + // Get each result +} +// Asynchronous search, use waitAll to get all the results found by the conditions +searchClass(async = true) { + // ... +}.waitAll { classes -> + classes.forEach { + // Get each result + } +} +
Tips
For more functions, please refer to ClassLoader.searchClass, PackageParam.searchClass methods.
Member Extensions
Here are the extension functions related to the Class bytecode member variables Field, Method, Constructor.
Tips
Member is the interface description object of Field, Method, Constructor, which is the general term for the bytecode members in Class in Java reflection.
Suppose there is such a
Class
.The following example
package com.demo; + +public class BaseTest { + + public BaseTest() { + // ... + } + + public BaseTest(boolean isInit) { + // ... + } + + private void doBaseTask(String taskName) { + // ... + } +} +
package com.demo; + +public class Test extends BaseTest { + + public Test() { + // ... + } + + public Test(boolean isInit) { + // ... + } + + private static TAG = "Test"; + + private BaseTest baseInstance; + + private String a; + + private boolean a; + + private boolean isTaskRunning = false; + + private static void init() { + // ... + } + + private void doTask(String taskName) { + // ... + } + + private void release(String taskName, Function<boolean, String> task, boolean isFinish) { + // ... + } + + private void stop() { + // ... + } + + private String getName() { + // ... + } + + private void b() { + // ... + } + + private void b(String a) { + // ... + } +} +
Find and Reflection
Suppose we want to get the
doTask
method ofTest
and execute it.Normally, we can use the standard reflection API to find this method.
The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using reflection API +Test::class.java + .getDeclaredMethod("doTask", String::class.java) + .apply { isAccessible = true } + .invoke(instance, "task_name") +
This is probably not very friendly, and
YukiHookAPI
provides you with a syntactic sugar that can be used anywhere.The above writing can be written as
YukiHookAPI
as follows.The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name = "doTask" + param(StringClass) +}.get(instance).call("task_name") +
Tips
For more features, please refer to MethodFinder.
Similarly, we need to get the
isTaskRunning
field can also be written as follows.The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.field { + name = "isTaskRunning" + type = BooleanType +}.get(instance).any() // Any instantiates an object of any type of Field +
Tips
For more features, please refer to FieldFinder.
Maybe you also want to get the current
Class
constructor, the same can be achieved.The following example
Test::class.java.constructor { + param(BooleanType) +}.get().call(true) // Can create a new instance +
If you want to get the no-argument constructor of
Class
, you can write it as follows.The following example
Test::class.java.constructor().get().call() // Create a new instance +
Tips
For more features, please refer to ConstructorFinder.
Optional Find Conditions
Suppose we want to get the
getName
method inClass
, which can be implemented as follows.The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name = "getName" + emptyParam() + returnType = StringClass +}.get(instance).string() // Get the result of the method +
Through observation, it is found that there is only one method named
getName
in thisClass
, so can we make it simpler?The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name = "getName" + emptyParam() +}.get(instance).string() // Get the result of the method +
Yes, you can refine your find criteria for methods that do not change exactly.
When using only
get
orwait
methods to get results,YukiHookAPI
will match the first found result in bytecode order by default.The problem comes again, this
Class
has arelease
method, but its method parameters are very long, and some types may not be directly available.Normally we would use
param(...)
to find this method, but is there an easier way.At this point, after determining the uniqueness of the method, you can use
paramCount
to find the method.The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name = "release" + // At this point + // We don't have to determine the specific type of method parameters, just write the number + paramCount = 3 +}.get(instance) // Get this method +
Although the above example can be successfully matched, it is not accurate.
At this time, you can also use
VagueType
to fill in the method parameter type that you do not want to fill in.The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name = "release" + // Use VagueType to fill in the type you don't want to fill in + // While ensuring that other types can match + param(StringClass, VagueType, BooleanType) +}.get(instance) // Get this method +
If you are not sure about the type of each parameter, you can create a conditional method body with the
param { ... }
method.The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name = "release" + // Get the it (Class) method parameter type array instance + // To only determine the known type and its position + param { it[0] == StringClass && it[2] == BooleanType } +}.get(instance) // Get this method +
Tips
Use param { ... } to create a conditional method body, where the variable it is the Class type array instance of the current method parameter, and you can freely use Class all objects and their methods in.
The condition at the end of the method body needs to return a Boolean, which is the final condition judgment result.
For more functions, please refer to FieldFinder.type, MethodFinder.param, MethodFinder.returnType, ConstructorFinder.param method.
Find in Super Class
You will notice that
Test
extendsBaseTest
, now we want to get thedoBaseTask
method ofBaseTest
, how do we do it without knowing the name of the super class?Referring to the above find conditions, we only need to add a
superClass
to the find conditions to achieve this function.The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name = "doBaseTask" + param(StringClass) + // Just add this condition + superClass() +}.get(instance).call("task_name") +
At this time, we can get this method in the super class.
superClass
has a parameterisOnlySuperClass
, when set totrue
, you can skip the currentClass
and only find the super class of the currentClass
.Since we now know that the
doBaseTask
method only exists in the super class, this condition can be added to save finding time.The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name = "doBaseTask" + param(StringClass) + // Add a find condition + superClass(isOnlySuperClass = true) +}.get(instance).call("task_name") +
At this time, we can also get this method in the super class.
Once
superClass
is set, it will automatically cycle backward to find out whether this method exists in all extends super classes, until it finds that the target has no super class (the extends isjava.lang.Object
).Tips
For more functions, please refer to MethodFinder.superClass, ConstructorFinder.superClass, FieldFinder.superClass methods.
Pay Attention
The currently founded Method can only find the Method of the current Class unless the superClass condition is specified, which is the default behavior of the Java Reflection API.
Vague Find
If we want to find a method name, but are not sure if it has changed in each release, we can use vague find.
Suppose we want to get the
doTask
method inClass
, which can be implemented as follows.The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name { + // Set name is case insensitive + it.equals("dotask", isIgnoreCase = true) + } + param(StringClass) +}.get(instance).call("task_name") +
Knowing that there is currently only one
doTask
method inClass
, we can also judge that the method name contains only the characters specified in it.The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name { + // Only contains oTas + it.contains("oTas") + } + param(StringClass) +}.get(instance).call("task_name") +
We can also judge based on the first and last strings.
The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name { + // Contains do at the beginning and Task at the end + it.startsWith("do") && it.endsWith("Task") + } + param(StringClass) +}.get(instance).call("task_name") +
By observing that this method name contains only letters, we can add a precise search condition.
The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name { + // Start with do, end with Task, just letters + it.startsWith("do") && it.endsWith("Task") && it.isOnlyLetters() + } + param(StringClass) +}.get(instance).call("task_name") +
Tips
Use name { ... } to create a conditional method body, where the variable it is the string of the current name, and you can freely use it in the extension method of NameRules function.
The condition at the end of the method body needs to return a Boolean, which is the final condition judgment result.
For more functions, please refer to FieldFinder.name, MethodFinder.name methods and NameRules.
Multiple Find
Sometimes, we may need to find a set of methods, constructors, and fields with the same characteristics in a
Class
.At this time, we can use relative condition matching to complete.
Based on the result of the find condition, we only need to replace
get
withall
to get all the bytecodes that match the condition.Suppose this time we want to get all methods in
Class
with the number of method parameters in the range1..3
, you can use the following implementation.The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + paramCount(1..3) +}.all(instance).forEach { instance -> + // Call and execute each method + instance.call(...) +} +
The above example can be perfectly matched to the following 3 methods.
private void doTask(String taskName)
private void release(String taskName, Function<boolean, String> task, boolean isFinish)
private void b(String a)
If you want to define the conditions for the range of the number of parameters more freely, you can use the following implementation.
The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + paramCount { it < 3 } +}.all(instance).forEach { instance -> + // Call and execute each method + instance.call(...) +} +
The above example can be perfectly matched to the following 6 methods.
private static void init()
private void doTask(String taskName)
private void stop(String a)
private void getName(String a)
private void b()
private void b(String a)
By observing that there are two methods named
b
inClass
, you can use the following implementation.The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name = "b" +}.all(instance).forEach { instance -> + // Call and execute each method + instance.call(...) +} +
The above example can be perfectly matched to the following 2 methods.
private void b()
private void b(String a)
Tips
Use paramCount { ... } to create a conditional method body, where the variable it is the integer of the current number of parameters, and you can use it freely in the extension method of CountRules function in it.
The condition at the end of the method body needs to return a Boolean, which is the final condition judgment result.
For more functions, please refer to MethodFinder.paramCount, ConstructorFinder.paramCount methods and CountRules.
Static Bytecode
Some methods and fields are statically implemented in
Class
, at this time, we can call them without passing in an instance.Suppose we want to get the contents of the static field
TAG
this time.The following example
Test::class.java.field { + name = "TAG" + type = StringClass +}.get().string() // The type of Field is string and can be cast directly +
Assuming that there is a non-static
TAG
field with the same name inClass
, what should I do at this time?Just add a filter.
The following example
Test::class.java.field { + name = "TAG" + type = StringClass + // This field to identify the lookup needs to be static + modifiers { isStatic } +}.get().string() // The type of Field is string and can be cast directly +
We can also call a static method called
init
.The following example
Test::class.java.method { + name = "init" + emptyParam() +}.get().call() +
Likewise, you can identify it as a static.
The following example
Test::class.java.method { + name = "init" + emptyParam() + // This method of identity find needs to be static + modifiers { isStatic } +}.get().call() +
Tips
Use modifiers { ... } to create a conditional method body, at which point you can freely use its functionality in ModifierRules.
The condition at the end of the method body needs to return a Boolean, which is the final condition judgment result.
For more functions, please refer to FieldFinder.modifiers, MethodFinder.modifiers, ConstructorFinder.modifiers methods and ModifierRules.
Obfuscated Bytecode
You may have noticed that the example
Class
given here has two obfuscated field names, both of which area
, how do we get them at this time?There are two options.
The first option is to determine the name and type of the field.
The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.field { + name = "a" + type = BooleanType +}.get(instance).any() // Get a field named a with type Boolean +
The second option is to determine where the type of the field is located.
The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.field { + type(BooleanType).index().first() +}.get(instance).any() // Get the first field of type Boolean +
In the above two cases, the corresponding field
private boolean a
can be obtained.Likewise, there are two obfuscated method names in this
Class
, both of which areb
.You can also have two options to get them.
The first option is to determine the method name and method parameters.
The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name = "b" + param(StringClass) +}.get(instance).call("test_string") // Get the method whose name is b and whose parameter is [String] +
The second option is to determine where the parameters of the method are located.
The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + param(StringClass).index().first() +}.get(instance).call("test_string") // Get the method whose first method parameter is [String] +
Since it is observed that this method is last in
Class
, then we have an alternative.The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + order().index().last() +}.get(instance).call("test_string") // Get the last method of the current Class +
Notice
Please try to avoid using order to filter bytecode subscripts, they may be indeterminate unless you are sure that its position in this Class must not change.
Directly Called
The methods of calling bytecode described above all need to use
get(instance)
to call the corresponding method.Is there a simpler way?
At this point, you can use the
current
method on any instance to create a call space.The following example
// Assume this is an instance of this Class +val instance = Test() +// Assume this Class is not directly available +instance.current { + // Execute the doTask method + method { + name = "doTask" + param(StringClass) + }.call("task_name") + // Execute the stop method + method { + name = "stop" + emptyParam() + }.call() + // Get name + val name = method { name = "getName" }.string() +} +
We can also use
superClass
to call methods of the currentClass
super class.The following example
// Assume this is an instance of this Class +val instance = Test() +// Assume this Class is not directly available +instance.current { + // Execute the doBaseTask method of the parent class + superClass().method { + name = "doBaseTask" + param(StringClass) + }.call("task_name") +} +
If you don't like to use a lambda to create the namespace of the current instance, you can use the
current()
method directly.The following example
// Assuming this is an instance of this Class, this Class cannot be obtained directly +val instance = Test() +// Execute the doTask method +instance + .current() + .method { + name = "doTask" + param(StringClass) + }.call("task_name") +// Execute the stop method +instance + .current() + .method { + name = "stop" + emptyParam() + }.call() +// Get name +val name = instance.current().method { name = "getName" }.string() +
Likewise, consecutive calls can be made between them, but inline calls are not allowed.
The following example
// Assume this is an instance of this Class +val instance = Test() +// Assume this Class is not directly available +instance.current { + method { + name = "doTask" + param(StringClass) + }.call("task_name") +}.current() + .method { + name = "stop" + emptyParam() + }.call() +// Note that because current() returns the CurrentClass object itself +// It CANNOT BE CALLED like the following +instance.current().current() +
For
Field
instances, there is also a convenience method that can directly get the object of the instance whereField
is located.The following example
// Assume this is an instance of this Class +val instance = Test() +// Assume this Class is not directly available +instance.current { + // <Plan 1> + field { + name = "baseInstance" + }.current { + method { + name = "doBaseTask" + param(StringClass) + }.call("task_name") + } + // <Plan 2> + field { + name = "baseInstance" + }.current() + ?.method { + name = "doBaseTask" + param(StringClass) + }?.call("task_name") +} +
Notice
The above current method is equivalent to calling the field { ... }.any()?.current() method in CurrentClass for you.
If there is no CurrentClass calling field, you need to use field { ... }.get(instance).current() to call it.
The problem comes again, I want to use reflection to create the following instance and call the method in it, how to do it?
The following example
Test(true).doTask("task_name") +
Usually, we can use the standard reflection API to call.
The following example
"com.demo.Test".toClass() + .getDeclaredConstructor(Boolean::class.java) + .apply { isAccessible = true } + .newInstance(true) + .apply { + javaClass + .getDeclaredMethod("doTask", String::class.java) + .apply { isAccessible = true } + .invoke(this, "task_name") + } +
But I feel that this approach is very troublesome.
Is there a more concise way to call it?
At this time, we can also use the
buildOf
method to create an instance.The following example
"com.demo.Test".toClass().buildOf(true) { param(BooleanType) }?.current { + method { + name = "doTask" + param(StringClass) + }.call("task_name") +} +
If you want the
buildOf
method to return the type of the current instance, you can include a type-generic declaration in it instead of usingas
tocast
the target type.In this case, the constructor of the instance itself is private, but the method inside is public, so we only need to create its constructor by reflection.
The following example
// Assume this Class can be obtained directly +val test = Test::class.java.buildOf<Test>(true) { param(BooleanType) } +test.doTask("task_name") +
Tips
For more functions, please refer to CurrentClass and Class.buildOf method.
Original Called
If you are using reflection to call a method that has been hooked, how do we call its original method?
The native
XposedBridge
provides us with aXposedBridge.invokeOriginalMethod
function.Now, in
YukiHookAPI
you can use the following method to implement this function conveniently.Suppose below is the
Class
we want to demonstrate.The following example
public class Test { + + public static String getString() { + return "Original"; + } +} +
Here's how the
getString
method in thisClass
Hooks.The following example
Test::class.java.method { + name = "getString" + emptyParam() + returnType = StringClass +}.hook { + replaceTo("Hooked") +} +
At this point, we use reflection to call this method, and we will get the result of Hook
"Hooked"
.The following example
// Result will be "Hooked" +val result = Test::class.java.method { + name = "getString" + emptyParam() + returnType = StringClass +}.get().string() +
If we want to get the original method and result of this method without hooking, we just need to add
original
to the result.The following example
// Result will be "Original" +val result = Test::class.java.method { + name = "getString" + emptyParam() + returnType = StringClass +}.get().original().string() +
Tips
For more functions, please refer to the MethodFinder.Result.original method.
Find Again
Suppose there are three different versions of
Class
, all of which are the sameClass
for different versions of this Host App.There is also a method
doTask
in it, assuming they function the same.The following example of version A
public class Test { + + public void doTask() { + // ... + } +} +
The following example of version B
public class Test { + + public void doTask(String taskName) { + // ... + } +} +
The following example of version C
public class Test { + + public void doTask(String taskName, int type) { + // ... + } +} +
We need to get this same functionality of the
doTask
method in a different version, how do we do it?At this point, you can use
RemedyPlan
to complete your needs.The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name = "doTask" + emptyParam() +}.remedys { + method { + name = "doTask" + param(StringClass) + }.onFind { + // Found logic can be implemented here + } + method { + name = "doTask" + param(StringClass, IntType) + }.onFind { + // Found logic can be implemented here + } +}.wait(instance) { + // Get the result of the method +} +
Pay Attention
The method lookup result using RemedyPlan can no longer use get to get method instance, you should use wait method.
Also, you can continue to use
RemedyPlan
while using Multiple Find.The following example
// Assume this is an instance of this Class +val instance = Test() +// Call and execute using YukiHookAPI +Test::class.java.method { + name = "doTask" + emptyParam() +}.remedys { + method { + name = "doTask" + paramCount(0..1) + }.onFind { + // Found logic can be implemented here + } + method { + name = "doTask" + paramCount(1..2) + }.onFind { + // Found logic can be implemented here + } +}.waitAll(instance) { + // Get the result of the method +} +
Tips
For more functions, please refer to MethodFinder.RemedyPlan, ConstructorFinder.RemedyPlan, FieldFinder.RemedyPlan .
Relative Matching
Suppose there is a
Class
with the same function in different versions of the Host App but only the name of theClass
is different.The following example of version A
public class ATest { + + public static void doTask() { + // ... + } +} +
The following example of version B
public class BTest { + + public static void doTask() { + // ... + } +} +
At this time, what should we do if we want to call the
doTask
method in thisClass
in each version?The usual practice is to check if
Class
exists.The following example
// First find this Class +val currentClass = + if("com.demo.ATest".hasClass()) "com.demo.ATest".toClass() else "com.demo.BTest".toClass() +// Then look for this method and call +currentClass.method { + name = "doTask" + emptyParam() +}.get().call() +
I feel that this solution is very inelegant and cumbersome, then
YukiHookAPI
provides you with a very convenientVariousClass
to solve this problem.Now, you can get this
Class
directly using the following methods.The following example
VariousClass("com.demo.ATest", "com.demo.BTest").get().method { + name = "doTask" + emptyParam() +}.get().call() +
If the current
Class
exists in the specifiedClassLoader
, you can fill in yourClassLoader
inget
.The following example
val customClassLoader: ClassLoader? = ... // Assume this is your ClassLoader +VariousClass("com.demo.ATest", "com.demo.BTest").get(customClassLoader).method { + name = "doTask" + emptyParam() +}.get().call() +
If you are not sure that all
Class
will be matched, you can use thegetOrNull
method.The following example
val customClassLoader: ClassLoader? = ... // Assume this is your ClassLoader +VariousClass("com.demo.ATest", "com.demo.BTest").getOrNull(customClassLoader)?.method { + name = "doTask" + emptyParam() +}?.get()?.call() +
If you are using the
Class
of the (Xposed) Host environment inPackageParam
, you can usetoClass()
to set it directly.The following example
VariousClass("com.demo.ATest", "com.demo.BTest").toClass().method { + name = "doTask" + emptyParam() +}.get().call() +
Tips
For more functions, please refer to VariousClass.
If it is used when creating a Hook, it can be more convenient, and it can also automatically intercept the exception that
Class
cannot be found.You can define this
Class
as a constant type to use.The following example
// Define constant type +val ABTestClass = VariousClass("com.demo.ATest", "com.demo.BTest") +// Use directly +ABTestClass.hook { + // Your code here. +} +
Calling Generics
In the process of reflection, we may encounter generic problems.
In the reflection processing of generics,
YukiHookAPI
also provides a syntactic sugar that can be used anywhere.For example we have the following generic class.
The following example
class TestGeneric<T, R> (t: T, r: R) { + + fun foo() { + // ... + } +} +
When we want to get a
Class
instance of the genericT
orR
in the currentClass
, only the following implementation is required.The following example
class TestGeneric<T, R> (t: T, r: R) { + + fun foo() { + // Get the operation object of the current instance + // Get the Class instance of T, in the 0th position of the parameter + // The default value can not be written + val tClass = current().generic()?.argument() + // Get the Class instance of R, in parameter 1 + val rClass = current().generic()?.argument(index = 1) + // You can also use the following syntax + current().generic { + // Get the Class instance of T + // In the 0th position of the parameter, the default value can be left blank + val tClass = argument() + // Get the Class instance of R, in parameter 1 + val rClass = argument(index = 1) + } + } +} +
When we want to call this
Class
externally, it can be implemented as follows.The following example
// Assume this is the Class of T +class TI { + + fun foo() { + // ... + } +} +// Assume this is an instance of T +val tInstance: TI? = ... +// Get the Class instance of T +// In the 0th position of the parameter, the default value can be left blank +// And get the method foo and call it +TestGeneric::class.java.generic()?.argument()?.method { + name = "foo" + emptyParam() +}?.get(tInstance)?.invoke<TI>() +
Tips
For more functions, please refer to CurrentClass.generic, Class.generic methods and GenericClass.
Pay Attention of Trap
Here are some misunderstandings that may be encountered during use for reference.
Restrictive Find Conditions
In find conditions you can only use
index
function once exceptorder
.The following example
method { + name = "test" + param(BooleanType).index(num = 2) + // Wrong usage, please keep only one index method + returnType(StringClass).index(num = 1) +} +
The following find conditions can be used without any problems.
The following example
method { + name = "test" + param(BooleanType).index(num = 2) + order().index(num = 1) +} +
Necessary Find Conditions
In common method find conditions, even methods without parameters need to set find conditions.
Suppose we have the following
Class
.The following example
public class TestFoo { + + public void foo(String string) { + // ... + } + + public void foo() { + // ... + } +} +
We want to get the
public void foo()
method, which can be written as follows.The following example
TestFoo::class.java.method { + name = "foo" +} +
However, the above example is wrong.
You will find two
foo
methods in thisClass
, one of which takes a method parameter.Since the above example does not set the find conditions for
param
, the result will be the first methodpublic void foo(String string)
that matches the name and matches the bytecode order, not the last method we need.This is a frequent error, without method parameters, you will lose the use of method parameter find conditions.
The correct usage is as follows.
The following example
TestFoo::class.java.method { + name = "foo" + // ✅ Correct usage, add detailed filter conditions + emptyParam() +} +
At this point, the above example will perfectly match the
public void foo()
method.Compatibility Notes
In the past historical versions of the API, it was allowed to match the method without writing the default matching no-parameter method, but the latest version has corrected this problem, please make sure that you are using the latest API version.
In the find conditions for constructors, even constructors without parameters need to set find conditions.
Suppose we have the following
Class
.The following example
public class TestFoo { + + public TestFoo() { + // ... + } +} +
To get the
public TestFoo()
constructor, we must write it in the following form.The following example
TestFoo::class.java.constructor { emptyParam() } +
The above example can successfully obtain the
public TestFoo()
constructor.If you write
constructor()
and missemptyParam()
, the result found at this time will be the first one in bytecode order, may not be parameterless.Compatibility Notes
In past historical versions of the API, if the constructor does not fill in any search parameters, the constructor will not be found directly.
This is a BUG and has been fixed in the latest version, please make sure you are using the latest API version.
API Behavior Changes
In 1.2.0 and later versions, the behavior of constructor() is no longer constructor { emptyParam() } but constructor {}, please pay attention to the behavior change reasonably adjust the find parameters.
No Find Conditions
Without setting find conditions, using
field()
,constructor()
,method()
will return all members under the currentClass
.Using
get(...)
orgive()
will only get the first bit in bytecode order.The following example
Test::class.java.field().get(...) +Test::class.java.method().give() +
If you want to get all members, you can use
all(...)
orgiveAll()
The following example
Test::class.java.field().all(...) +Test::class.java.method().giveAll() +
Compatibility Notes
In past historical versions of the API, failure to set find conditions will throw an exception.
This feature was added in 1.2.0 and later versions.
Bytecode Type
In the bytecode call result, the cast method can only specify the type corresponding to the bytecode.
For example we want to get a field of type
Boolean
and cast it toString
.The following is the wrong way to use it.
The following example
field { + name = "test" + type = BooleanType +}.get().string() // Wrong usage, must be cast to the bytecode target type +
The following is the correct way to use it.
The following example
field { + name = "test" + type = BooleanType +}.get().boolean().toString() // ✅ The correct way to use, get the type and then convert +
Common Type Extensions
When find methods and fields, we usually need to specify the type in find conditions.
The following example
field { + name = "test" + type = Boolean::class.javaPrimitiveType +} +
Expressing the type of
Boolean::class.javaPrimitiveType
in Kotlin is very long and inconvenient.Therefore,
YukiHookAPI
encapsulates common type calls for developers, including Android related types and Java common types and primitive type keywords.At this time, the above type can be written in the following form.
The following example
field { + name = "test" + type = BooleanType +} +
The primitive type keywords in common Java types have been encapsulated as Type(Class Name) + Type, such as
IntType
,FloatType
(their bytecode types areint
,float
).Correspondingly, array types also have convenient usage methods, assuming we want to get an array of type
String[]
.You need to write
java.lang.reflect.Array.newInstance(String::class.java, 0).javaClass
to get this type.Does it feel very troublesome, at this time we can use the method
ArrayClass(StringClass)
to get this type.At the same time, since
String
is a common type, you can also directly useStringArrayClass
to get this type.Some common methods found in Hook have their corresponding encapsulation types for use, in the format Type(Class Name) + Class.
For example, the Hook
onCreate
method needs to look up theBundle::class.java
type.The following example
method { + name = "onCreate" + param(BundleClass) +} +
The following are wrapper names for some special case types in Java represented in
YukiHookAPI
.
void
→UnitType
java.lang.Void
→UnitClass
java.lang.Object
→AnyClass
java.lang.Integer
→IntClass
java.lang.Character
→CharClass
Notice
Encapsulating types with Type(Class Name) + Type will and only be represented as Java primitive type keywords.
Since the concept of primitive types does not exist in Kotlin, they will all be defined as KClass.
There are 9 primitive type keywords in Java, of which 8 are primitive type, namely boolean, char, byte, short , int, float, long, double, of which the void type is a special case.
At the same time, they all have their own corresponding package types in Java, such as java.lang.Boolean, java.lang.Integer, these types are unequal, Please note the distinction.
Similarly, arrays also have corresponding wrapper types, which also need to be distinguished from Java primitive type keywords.
For example, the encapsulation type of byte[] is ByteArrayType or ArrayClass(ByteType), and the encapsulation type of Byte[] is ByteArrayClass or ArrayClass(ByteClass), these types are also unequal.
Tips
For more types, see ComponentTypeFactory, GraphicsTypeFactory, ViewTypeFactory, VariableTypeFactory.
At the same time, you are welcome to contribute more commonly used types.
Xposed Module and Host Channel | Yuki Hook API + + + + + ++ + + diff --git a/en/api/special-features/xposed-storage.html b/en/api/special-features/xposed-storage.html new file mode 100644 index 00000000..0dfe3bc2 --- /dev/null +++ b/en/api/special-features/xposed-storage.html @@ -0,0 +1,71 @@ + + + + + + + + +Yuki Hook API
Xposed Module and Host Channel
This is a solution that uses system out-of-order broadcasting to send and receive data between the Module App and the Host App.
Condition that needs to be met
The Module App and the Host App need to remain alive, otherwise communication cannot be established.
Basic Usage
The basic usage of the
wait
andput
methods is described here.By using
dataChannel
to realize the communication bridge between the Module App and the Host App, the principle is to send and receive system out-of-order broadcasts.The Module App example is as follows
// Get from the Host App of the specified package name +dataChannel(packageName = "com.example.demo").wait<String>(key = "key_from_host") { value -> + // Your code here. +} +// Send to the Host App with the specified package name +dataChannel(packageName = "com.example.demo").put(key = "key_from_module", value = "I am module") +
The Host App example is as follows
// Get from the Module App +dataChannel.wait<String>(key = "key_from_module") { value -> + // Your code here. +} +// Send to the Module App +dataChannel.put(key = "key_from_host", value = "I am host") +
You can leave the
value
ofdataChannel
unset to only notify the Module App or Host App to call back thewait
method.The Module App example is as follows
// Get from the Host App of the specified package name +dataChannel(packageName = "com.example.demo").wait(key = "listener_from_host") { + // Your code here. +} +// Send to the Host App with the specified package name +dataChannel(packageName = "com.example.demo").put(key = "listener_from_module") +
The Host App example is as follows
// Get from the Module App +dataChannel.wait(key = "listener_from_module") { + // Your code here. +} +// Send to the Module App +dataChannel.put(key = "listener_from_host") +
Pay Attention
The receiver needs to stay alive to receive the communication data.
Tips
For more functions, please refer to YukiHookDataChannel.
Determine Module App and Host App Version Match
Through the communication bridge function,
YukiHookAPI
also provides a solution for you to determine whether the Module App matches the Host App version after the user updates the Module App.We only need to call the
checkingVersionEquals
method to achieve this function.Bidirectional judgment can be performed between the Module App and the Host App.
You can check in the Module App whether the Host App of the specified package name matches the version of the current Module App.
The following example
// Get from the Host App of the specified package name +dataChannel(packageName = "com.example.demo").checkingVersionEquals { isEquals -> + // Your code here. +} +
You can also determine in the Host App whether it matches the current Module App version.
The following example
// Get from the Module App +dataChannel.checkingVersionEquals { isEquals -> + // Your code here. +} +
Condition of method callback
The Host App and Module App must be stay alive, and after activating the Module App restart the Hook target Host App object in scope.
Tips
For more functions, please refer to YukiHookDataChannel.
Rules for Callback Event Response
Only the examples used in Module App are listed here.
The same
key
in same Host App is always not allowed to be created repeatedly, but the samekey
is allowed in different Host Apps.Pay Attention
In the Module App and Host App, each key callback event corresponding to dataChannel is not allowed to be repeatedly created, if repeated, the previous callback event will be replaced by the newly added callback event.
When used in the Module App, it cannot be repeated in the same Activity, and the same key in different Activity is allowed to be repeated.
The following example
class MainActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + // Callback event A + dataChannel(packageName = "com.example.demo1").wait(key = "test_key") { + // Your code here. + } + // Callback event B + dataChannel(packageName = "com.example.demo1").wait(key = "test_key") { + // Your code here. + } + // Callback event C + dataChannel(packageName = "com.example.demo1").wait(key = "other_test_key") { + // Your code here. + } + // Callback event D + dataChannel(packageName = "com.example.demo2").wait(key = "other_test_key") { + // Your code here. + } + } +} + +class OtherActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + // Callback event E + dataChannel(packageName = "com.example.demo1").wait(key = "test_key") { + // Your code here. + } + // Callback event F + dataChannel(packageName = "com.example.demo2").wait(key = "test_key") { + // Your code here. + } + } +} +
In the above example, although callback events A and B are callback events in the same Host App, their
key
is the same, so callback event A will be replaced by callback event B.The
key
of callback event C is not duplicated with others.Although the
key
of callback event D is the same as that of callback event C, their Host Apps are different, so they can exist at the same time.Callback event E is in another Activity, although the
key
of callback event F and callback event E is the same, but they are not the same Host App, so they can exist at the same time.In summary, the final callback events B, C, D, E, and F can all be created successfully.
Compatibility Notes
Setting the same key on different Host Apps in previous historical versions of the API would result in only the last event callback, but the latest version has corrected this problem, please make sure you are using the latest API version.
Pay Attention
A callback event with the same key will only call back the callback event registered in the Activity that the current Module App is displaying, such as test_key in the above, if OtherActivity is being displayed, then test_key in MainActivity will not be called back.
The same key registers dataChannel in the same Activity but different Fragment, they will still be called back in the current Activity at the same time.
In a Module App, you can use dataChannel in Activity, Application and Service, when used in places other than Activity, each callback event will instant callback, at which point you can use ChannelPriority to manage.
If you want to use dataChannel in Fragment, use activity?.dataChannel(...).
If you want to manually set the response priority (condition) of each callback event in the same Activity, you can use
ChannelPriority
.For example, if you are using one Activity binding multiple Fragment cases, this will be able to solve this problem.
The following example
open class BaseFragment : Fragment() { + + /** Identify that the current Fragment is in the onResume lifecycle */ + var isResume = false + + override fun onResume() { + super. onResume() + isResume = true + } + + override fun onPause() { + super. onPause() + isResume = false + } + + override fun onStop() { + super. onStop() + isResume = false + } +} + +class FragmentA : BaseFragment() { + + // Omit part of initialization code + //... + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + // Use the custom isResume combined with the isVisible condition + // To judge that the current Fragment is in the displayed state + activity?.dataChannel(packageName = "com.example.demo1") + ?.wait(key = "test_key", ChannelPriority { isResume && isVisible }) { + // Your code here. + } + } +} + +class FragmentB : BaseFragment() { + + // Omit part of initialization code + //... + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + // Use the custom isResume combined with the isVisible condition + // To judge that the current Fragment is in the displayed state + activity?.dataChannel(packageName = "com.example.demo2") + ?.wait(key = "test_key", ChannelPriority { isResume && isVisible }) { + // Your code here. + } + } +} +
Security Instructions
In the module environment, you can only receive the communication data sent by the Host App of the specified package name and can only send to the Host App of the specified package name, except for System Framework.
Pay Attention
In order to further prevent broadcast abuse, the API in the communication data will automatically specify the package name of the Host App and Module App to prevent other apps from monitoring and using broadcast to make overrun behaviors.
Xposed Module Data Storage | Yuki Hook API + + + + + ++ + + diff --git a/en/config/api-example.html b/en/config/api-example.html new file mode 100644 index 00000000..2435c7ba --- /dev/null +++ b/en/config/api-example.html @@ -0,0 +1,270 @@ + + + + + + + + +Yuki Hook API
Xposed Module Data Storage
This is an efficient Module App data storage solution that automatically connects
SharedPreferences
andXSharedPreferences
.We need to store the data of the Module App for the Host App to call.
At this time, we will encounter the data exchange obstacle of the native
Sp
storage.The native
Xposed
provides us with aXSharedPreferences
for reading theSp
data of the Module App.Use in Activity
Loading
YukiHookPrefsBridge
inActivity
is described here.Usually we can initialize it in Host App like this.
The following example
XSharedPreferences(BuildConfig.APPLICATION_ID) +
Is there a convenient and quick solution?
At this point, you can use the extension capability of
YukiHookAPI
to quickly implement this function.When you store data in a Module App, you can use the following methods if you are currently in an
Activity
.The following example
prefs().edit { putString("test_name", "saved_value") } +
When you read data in a Host App, you can use the following methods.
The following example
val testName = prefs.getString("test_name", "default_value") +
You don't need to consider the module package name and a series of complicated permission configurations, everything is handled by
YukiHookPrefsBridge
.To achieve localization of storage, you can specify the name of each
prefs
file.This is used in the
Activity
of the Module App.The following example
// Recommended usage +prefs("specify_file_name").edit { putString("test_name", "saved_value") } +// Can also be used like this +prefs().name("specify_file_name").edit { putString("test_name", "saved_value") } +
Read like this in Host App.
The following example
// Recommended usage +val testName = prefs("specify_file_name").getString("test_name", "default_value") +// Can also be used like this +val testName = prefs.name("specify_file_name").getString("test_name", "default_value") +
If your project has a lot of fixed data that needs to be stored and read, it is recommended to use
PrefsData
to create templates.Through the above example, you can call the
edit
method to store data in batches in the following two ways.The following example
// <Scenario 1> +prefs().edit { + putString("test_name_1", "saved_value_1") + putString("test_name_2", "saved_value_2") + putString("test_name_3", "saved_value_3") +} +// <Scenario 2> +prefs(). edit() + .putString("test_name_1", "saved_value_1") + .putString("test_name_2", "saved_value_2") + .putString("test_name_3", "saved_value_3") + .apply() +
Tips
For more functions, please refer to YukiHookPrefsBridge, PrefsData.
Use in PreferenceFragment
Loading
YukiHookPrefsBridge
inPreferenceFragment
is described here.If your Module App uses
PreferenceFragmentCompat
, you can now start migrating its extendsModulePreferenceFragment
.Pay Attention
You must extends ModulePreferenceFragment to implement the module storage function of YukiHookPrefsBridge.
Tips
For more functions, please refer to ModulePreferenceFragment.
Use Native Storage
In the Module environment,
YukiHookPrefsBridge
will store data in the Module App's own private directory (or the shared directory provided by Hook Framework) by default.Using
YukiHookPrefsBridge
in the Host environment will read the data in the Module App's own private directory (or the shared directory provided by Hook Framework) by default.If you want to store data directly into a Module App or Host App's own private directory, you can use the
native
method.For example, the directory of the Module App is
.../com.demo.test.module/shared_prefs
, and the directory of the Host App is.../com.demo.test.host/shared_prefs
.The following is the usage in
Activity
.The following example
// Store private data +prefs().native().edit { putBoolean("isolation_data", true) } +// Read private data +val privateData = prefs().native().getBoolean("isolation_data") +// Store shared data +prefs().edit { putBoolean("public_data", true) } +// Read shared data +val publicData = prefs().getBoolean("public_data") +
The following is the usage in
PackageParam
.The following example
// Store private data +prefs.native().edit { putBoolean("isolation_data", true) } +// Read private data +val privateData = prefs.native().getBoolean("isolation_data") +// Read shared data +val publicData = prefs.getBoolean("public_data") +
After using the
native
method, no matter inActivity
orPackageParam
, the data will be stored and read in the private directory of the corresponding environment, and the data will be isolated from each other.Tips
For more functions, please refer to YukiHookPrefsBridge.
API Basic Configs | Yuki Hook API + + + + + ++ + + diff --git a/en/config/api-exception.html b/en/config/api-exception.html new file mode 100644 index 00000000..5bc24b86 --- /dev/null +++ b/en/config/api-exception.html @@ -0,0 +1,373 @@ + + + + + + + + +Yuki Hook API
API Basic Configs
The basic configuration method of
YukiHookAPI
is introduced here.Function Configs
Either Use as Xposed Module Configs or Use as Hook API Configs, you can specify
YukiHookAPI
for configuration.configs Method
fun configs(initiate: Configs.() -> Unit) +
The
configs
method implements a lambda method body on theConfigs
class, which you can easily call for configuration.Tips
For more functions, please refer to the YukiHookAPI.configs method.
Hooker Configs
The most important part of an Xposed Module or Hook API is the creation and use of Hooker.
YukiHookAPI
provides two ways to use it.Created by lambda
This solution is the simplest. If your module has few functions and a small amount of code, and does not need to be classified, it is recommended to create it in this way.
encase Method
fun encase(initiate: PackageParam.() -> Unit) +
The
encase
method is the beginning of all Hook life. In a Module App or a Hook process, theencase
method can only be used once to create a Hooker.
PackageParam
is an important instance object of the Host App, andPackageParam
is used to implement all Hook operations on the current Hook object.Tips
For more functions, please refer to PackageParam.
The
encase
method can be created in theonHook
method using two schemes.Sample Code 1
YukiHookAPI.encase { + loadApp(name = "com.example.demo") { + "$packageName.DemoClass".toClass() + .resolve() + .firstMethod { + // Your code here. + }.hook { + // Your code here. + } + } +} +
Sample Code 2
encase { + loadApp(name = "com.example.demo") { + "$packageName.DemoClass".toClass() + .resolve() + .firstMethod { + // Your code here. + }.hook { + // Your code here. + } + } +} +
Do your Hook operations in the
encase
method.Created by Custom Hooker
This scheme is more suitable for large-scale projects, such as the need to classify Hooker or classify the role of Hook.
encase Method
fun encase(vararg hooker: YukiBaseHooker) +
Also for the
encase
method, the variable array parameterhooker
of the method here provides an object for creating an entry, you can load all Hookers extendsYukiBaseHooker
at one time.YukiBaseHooker Usage
YukiBaseHooker
extendsPackageParam
, you need to extends your child Hooker fromYukiBaseHooker
.Tips
For more functions, please refer to YukiBaseHooker.
The following example
object CustomHooker : YukiBaseHooker() { + + override fun onHook() { + // Your code here. + } +} +
Child Hooker recommended to use singleton
object
to create, you can also useclass
but it is generally not recommended.Notice
You don't need to re-call encase in the onHook method extends YukiBaseHooker, this is wrong and will not take effect, you should start writing your Hook code directly .
The following example
object CustomHooker : YukiBaseHooker() { + + override fun onHook() { + loadApp(name = "com.example.demo1") { + "$packageName.DemoClass".toClass() + .resolve() + .firstMethod { + // Your code here. + }.hook { + // Your code here. + } + } + loadApp(name = "com.example.demo2") { + "$packageName.CustomClass".toClass() + .resolve() + .firstMethod { + // Your code here. + }.hook { + // Your code here. + } + } + } +} +
As a child hooker, you can also call the
loadApp
method externally, and then directly start the Hook internally.The following example
object HookEntry : IYukiHookXposedInit { + + override fun onHook() = encase { + loadApp(name = "com.example.demo", ChildCustomHooker) + } +} + +object ChildCustomHooker : YukiBaseHooker() { + + override fun onHook() { + "$packageName.DemoClass".toClass() + .resolve() + .firstMethod { + // Your code here. + }.hook { + // Your code here. + } + } +} +
You can use the
loadHooker
method to load another Hooker in multiple layers in the child Hooker, please do as you like.The following example
object FirstHooker : YukiBaseHooker() { + + override fun onHook() { + "$packageName.DemoClass".toClass() + .resolve() + .firstMethod { + // Your code here. + }.hook { + // Your code here. + } + loadHooker(SecondHooker) + loadHooker(ThirdHooker) + } +} +
Once all Hookers are set up, you can load your Hooker in the
onHook
method of your Hook entry class.The following example
object HookEntry : IYukiHookXposedInit { + + override fun onHook() = + YukiHookAPI.encase(FirstHooker, SecondHooker, ThirdHooker ...) +} +
Of course, we can also abbreviate it.
The following example
object HookEntry : IYukiHookXposedInit { + + override fun onHook() = encase(FirstHooker, SecondHooker, ThirdHooker ...) +} +
Special Case
As we mentioned above, it is generally not recommended to use
class
to create child Hookers, but there is a special case where it may still be necessary to keep your Hooker supporting multiple instantiations.There is a rare possibility that there are multiple package names in a process.
In this case, when
YukiHookAPI
finds that the child Hooker is a singleton, it will ignore it and print a warning message.This Hooker "HOOKER" is singleton or reused, but the current process has multiple package name "NAME", the original is "NAME" +Make sure your Hooker supports multiple instances for this situation +The process with package name "NAME" will be ignored +
In this case, we only need to modify
object
toclass
or determine the package name during loading and then load the child Hooker.For example, in the above cases, the following forms can be used to load.
The following example
encase { + // Assume this is the app package name and child Hooker you need to load + loadApp("com.example.demo", YourCustomHooker) +} +
Expansion Features
If your current Hook Framework supports and enables the Resources Hook feature, you can now create Resources Hooks directly in
encase
.You don't need to separate the
initZygote
,handleLoadPackage
,handleInitPackageResources
methods to perform different functions as before using the Xposed API.In
YukiHookAPI
, these functions are seamless.The following example
encase { + loadApp(name = "com.example.demo") { + "$packageName.DemoClass".toClass() + .resolve() + .firstMethod { + // Your code here. + }.hook { + // Your code here. + } + // Create a Resources Hook (fixed usage) + resources().hook { + // Your code here. + } + } +} +
You can also use the
loadZygote
method to load the first eventinitZygote
after a new process has been forked.The following example
encase { + loadZygote { + Activity::class.resolve().firstMethod { + // Your code here. + } + // Create a Resources Hook in Zygote + resources().hook { + // Your code here. + } + } + loadApp(name = "com.example.demo") { + "$packageName.DemoClass".toClass() + .resolve() + .firstMethod { + // Your code here. + }.hook { + // Your code here. + } + // Create a Resources Hook in the app + resources().hook { + // Your code here. + } + } +} +
Precautions
It is wrong to load Hooker directly or start Hook directly,
encase
event will go through three callbacks after being loaded by Hook Framework.
load
initZygote
→encase
load
handleLoadPackage
→encase
load
handleInitPackageResources
→encase
In this process, you need to use
loadApp
,loadSystem
,loadZygote
to distinguish the calling domain of each loading code, otherwise your code will be executed multiple times and cause errors.Notice
Whether you use encase to create the lambda method body or use the Hooker form directly, you should not directly load the Hooker or start the Hook directly in the first onHook event.
Below are two error examples.
Sample Code 1
encase { + // Wrong usage, can't start Hook directly + "com.example.demo.DemoClass".toClass() + .resolve() + .firstMethod { + // Your code here. + }.hook { + // Your code here. + } + // Wrong usage, can't start Hook directly + resources().hook { + // ... + } +} +
Sample Code 2
object HookEntry : IYukiHookXposedInit { + + override fun onHook() { + // <Scenario 1> + encase { + loadHooker(CustomHooker) + } + // <Scenario 2> + encase(CustomHooker) + } +} + +object CustomHooker : YukiBaseHooker() { + + override fun onHook() { + // Wrong method of use + // Because there is no judgment object in the outer layer, you cannot start Hook directly + "com.example.demo.DemoClass".toClass() + .resolve() + .firstMethod { + // Your code here. + }.hook { + // Your code here. + } + } +} +
Below is a correct example of the wrong example above.
Sample Code 1
encase { + // ✅ Correct usage, load in Zygote + loadZygote(CustomHooker) + // ✅ Correct usage, load in Zygote + loadZygote { + // ✅ Correct usage, Hook in Zygote + resources().hook { + // ... + } + } + // ✅ The correct way to use it, use the app scope to load + loadApp(/** name parameter optional */, hooker = CustomHooker) + // ✅ The correct way to use it, load the Hooker after judging the scope of the app + loadApp(/** name parameter optional */) { + loadHooker(CustomHooker) + // ✅ Correct usage, Hook in app scope + "com.example.demo.DemoClass".toClass() + .resolve() + .firstMethod { + // Your code here. + }.hook { + // Your code here. + } + // ✅ Correct usage, Hook in app scope + resources().hook { + // ... + } + } +} +
Sample Code 2
object HookEntry : IYukiHookXposedInit { + + override fun onHook() { + encase(CustomHooker) + } +} + +object CustomHooker : YukiBaseHooker() { + + override fun onHook() { + // ✅ The correct method of use, since there is no judgment object in the outer layer + // it is necessary to judge the scope of the app before performing Hook + loadApp(/** name parameter optional */) { + "com.example.demo.DemoClass".toClass() + .resolve() + .firstMethod { + // Your code here. + }.hook { + // Your code here. + } + } + } +} +
Precautions when using as Hook API
If you are using it as a Hook API, then you only need to differentiate the
encase
method at the entry point.Notice
The encase method provides two identical methods for use as a Hook API, but with only one more parameter baseContext than the previous two.
Method 1
fun encase(baseContext: Context?, initiate: PackageParam.() -> Unit) +
Method 2
fun encase(baseContext: Context?, vararg hooker: YukiBaseHooker) +
The
baseContext
here only needs to fill in theContext
you got atattachBaseContext
, and other usages are exactly the same as the above.Pay Attention
Never use the encase method in an Xposed way without omitting the baseContext parameter, this will lead to your Hook not work at all.
The Resources Hook feature is not supported as Hook API.
API Exception Handling | Yuki Hook API + + + + + ++ + + diff --git a/en/config/api-using.html b/en/config/api-using.html new file mode 100644 index 00000000..cb3f23bc --- /dev/null +++ b/en/config/api-using.html @@ -0,0 +1,83 @@ + + + + + + + + +Use as Hook API Configs | Yuki Hook API + + + + + ++ + + diff --git a/en/config/move-to-api-1-2-x.html b/en/config/move-to-api-1-2-x.html new file mode 100644 index 00000000..14f1439f --- /dev/null +++ b/en/config/move-to-api-1-2-x.html @@ -0,0 +1,100 @@ + + + + + + + + +Yuki Hook API
Use as Hook API Configs
As a Hook API, it is usually used for Hook operations for hot updates or functional needs of its own app and product testing.
Dependency Configs
You just need to integrate the
com.highcapable.yukihookapi:api
dependency.Then please integrate the
Hook Framework
dependencies used by your target.Entry Configs
Create your custom
Application
.Add
YukiHookAPI.encase
method toattachBaseContext
.The following example
class MyApplication : Application() { + + override fun attachBaseContext(base: Context?) { + // Load Hook Framework + // + // Your code here. + // + // Configure YukiHookAPI + YukiHookApi.configs { + // Your code here. + } + // Load YukiHookAPI + YukiHookAPI.encase(base) { + // Your code here. + } + super.attachBaseContext(base) + } +} +
In this way, you have completed the relevant configuration of the API.
You can click here to see the similarities, differences and caveats.
Notice
You can no longer wrap with loadApp and start writing your Hook code directly.
Hook Framework
Here are some related ways of how to connect the
Hook Framework
with theYukiHookAPI
, which is widely used.Pine
Required Xposed API dependencies
top.canyie.pine:xposed
The following example
override fun attachBaseContext(base: Context?) { + // Load Pine + PineConfig.debug = true + PineConfig.debuggable = BuildConfig.DEBUG + // Load YukiHookAPI + YukiHookAPI.encase(base) { + // Your code here. + } + super.attachBaseContext(base) +} +
SandHook
Required Xposed API dependencies
com.swift.sandhook:xposedcompat
orcom.swift.sandhook:xposedcompat_new
The following example
override fun attachBaseContext(base: Context?) { + // Load SandHook + SandHookConfig.DEBUG = BuildConfig.DEBUG + XposedCompat.cacheDir = base?.cacheDir + XposedCompat.context = base + XposedCompat.classLoader = javaClass.classLoader + XposedCompat.isFirstApplication = base?.processName == base?.packageName + // Load YukiHookAPI + YukiHookAPI.encase(base) { + // Your code here. + } + super.attachBaseContext(base) +} +
Whale
Required Xposed API dependencies
com.wind.xposed:xposed-on-whale
Please refer to xposed-hook-based-on-whale.
The following example
override fun attachBaseContext(base: Context?) { + // Loading Whale does not require any configuration + // Load YukiHookAPI + YukiHookAPI.encase(base) { + // Your code here. + } + super.attachBaseContext(base) +} +
Migrate to YukiHookAPI 1.2.x | Yuki Hook API + + + + + ++ + + diff --git a/en/config/move-to-api-1-3-x.html b/en/config/move-to-api-1-3-x.html new file mode 100644 index 00000000..d22d651f --- /dev/null +++ b/en/config/move-to-api-1-3-x.html @@ -0,0 +1,51 @@ + + + + + + + + +Yuki Hook API
Migrate to YukiHookAPI 1.2.x
YukiHookAPI
has undergone a lot of adjustments since version1.2.0
, you can read on to see what are the notes and new features.Notice
If you are using the YukiHookAPI previous version of
1.2.x
, it is recommended to refer to this document to migrate to the1.2.x
version first.If you are using the
1.2.x
version ofYukiHookAPI
, please read directly Migrate to YukiHookAPI 1.3.x instead of this document.Default Behavior Changes
Since version
1.2.0
, theisUsingResourcesHook
function in@InjectYukiHookWithXposed
is no longer enabled by default, please enable it manually if necessary.Notice
Resources Hook will be removed in version 2.0.0 and is now marked LegacyResourcesHook.
You can use @OptIn(LegacyResourcesHook::class) to eliminate the warning, continue to use version 1.x.x.
New API
YukiHookAPI
introduced the New Hook Code Style (New API) of2.0.0
in the1.2.0
version, it is now in the experimental stage.You can before the
2.0.0
version is officially released, start migrating and experience the New API.Notice
All legacy APIs have been marked LegacyHookApi, you can use @OptIn(LegacyHookApi::class) to eliminate the warning and continue to use the legacy API.
For example, we want to Hook the
test
method in thecom.example.Test
class.Legacy API
findClass("com.example.Test").hook { + injectMember { + method { + name = "test" + } + beforeHook { + // Your code here. + } + afterHook { + // Your code here. + } + } +} +
New API
"com.example.Test".toClass() + .method { + name = "test" + }.hook { + before { + // Your code here. + } + after { + // Your code here. + } + } +
The Hook object of the New API has been migrated from
Class
toMember
, which will be more intuitive.Differential Functions
The following are some of the different functions of connecting to the new version of the API.
New Multi-Hook Usage
Previously we needed to hook all methods that match conditions like this.
The following example
injectMembers { + method { + name { it.contains("some") } + }.all() + afterHook { + // Your code here. + } +} +
Now, you can use the following method instead.
The following example
method { + name { it.contains("some") } +}.hookAll { + after { + // Your code here. + } +} +
New
allMembers(...)
UsagePreviously we needed to hook all methods and constructors like this.
The following example
injectMembers { + allMembers(MembersType.METHOD) + afterHook { + // Your code here. + } +} +
injectMembers { + allMembers(MembersType.CONSTRUCTOR) + afterHook { + // Your code here. + } +} +
Now, you can use the following method instead.
The following example
method().hookAll { + after { + // Your code here. + } +} +
constructor().hookAll { + after { + // Your code here. + } +} +
When the find conditions are not filled in, all members in the current
Class
are obtained by default.If you want to hook
MembersType.ALL
, there is currently no direct method, but you can concatenate all members and then hook.The following example
(method().giveAll() + constructor().giveAll()).hookAll { + after { + // Your code here. + } +} +
But we do not recommend this approach, too many hook members at one time are uncontrollable and problems may occur.
Migrate to YukiHookAPI 1.3.x | Yuki Hook API + + + + + ++ + + diff --git a/en/config/r8-proguard.html b/en/config/r8-proguard.html new file mode 100644 index 00000000..d34ca8a8 --- /dev/null +++ b/en/config/r8-proguard.html @@ -0,0 +1,35 @@ + + + + + + + + +Yuki Hook API
Migrate to YukiHookAPI 1.3.x
YukiHookAPI
has deprecated its own reflection API since1.3.0
, you can read on to see what are the notes and new features.Notice
If you are using
1.2.x
and previous versions ofYukiHookAPI
, it is recommended to read Migrate to YukiHookAPI 1.2.x instead of this document.Self-reflection API Deprecated
YukiHookAPI
has deprecated its own reflection API since the1.3.0
version. Now we recommend that all developers move to a brand new development. KavaRef, we no longer recommend the reflection API ofYukiHookAPI
itself, which have been marked as deprecated.Please refer to the migration document here which will jump to the
KavaRef
document.
YukiHookAPI
has now implemented complete decoupling of the reflection API. The reflection API used by its internal API has also been migrated toKavaRef
and has been tested stably.In later versions of
2.0.0
, the self-reflection API will be completely removed, during which time you will have enough time to learn and migrate to this brand new set of reflection APIs.FreeReflection Deprecated
YukiHookAPI
has deprecated FreeReflection since the1.3.0
version and migrated to a maintained by the LSPosed team AndroidHiddenApiBypass.When the reflection system hides the API, you cannot reflect directly like before, but need to do some operations.
YukiHookAPI has built-in
AndroidHiddenApiBypassResolver
inKavaRef
's third-party Member parser, and now you can use it like this where you need the reflection system to hide the API.The following example
"android.app.ActivityThread".toClass() + .resolve() + // Add a custom Member parser + .processor(AndroidHiddenApiBypassResolver.get()) + .firstMethod { + name = "currentActivityThread" + emptyParameters() + }.invoke() +
Notice
AndroidHiddenApiBypassResolver
is a tentative feature and may be migrated to a separate module in the2.0.0
version, you can also refer to Third-party Member Resolvers implement one by yourself, which will jump to theKavaRef
document.Original Method Call
Xposed
provides theXposedBridge.invokeOriginalMethod
function, which can call original methods without a Hook.Due to deprecation of the self-reflection API, the method
method { ... }.get().original().call(...)
will no longer be available.So, YukiHookAPI has added an extension to
KavaRef
, and you can still implement this feature now.
YukiHookAPI
provides the following methods to connect to the original method calls ofKavaRef
.
invokeOriginal(...)
→invoke(...)
invokeOriginalQuietly(...)
→invokeQuietly(...)
The following example
// Suppose this is an instance of the Test class +val instance: Any +// Original call to the method using KavaRef +"com.example.Test".toClass() + .resolve() + .firstMethod { + name = "test" + emptyParameters() + }.of(instance).invokeOriginal() +
Repeat Hook Restricted Deprecated
YukiHookAPI
has deprecated the restriction of duplicate Hook since the1.3.0
version. Now,YukiHookAPI
no longer limits duplicate Hooks to the same method, you can hook multiple times on the same method.
YukiHookAPI
also deprecated theonAlreadyHooked
method ofhook { ... }
. Now this method will be useless and will not be called back. If necessary, please manually handle the relevant logic of duplicate Hooks.Register Module App's Activity Behavior Change
YukiHookAPI
starting with1.3.0
, the way in which the moduleActivity
behavior has changed.Please read Register Module App's Activity for more information.
YLog Behavior Change
YukiHookAPI
allows themsg
parameter ofYLog
to be passed into any object starting from1.3.0
, and they will be automatically converted using thetoString()
method.R8 & Proguard Obfuscate | Yuki Hook API + + + + + ++ + + diff --git a/en/config/xposed-using.html b/en/config/xposed-using.html new file mode 100644 index 00000000..f22956c1 --- /dev/null +++ b/en/config/xposed-using.html @@ -0,0 +1,121 @@ + + + + + + + + +Yuki Hook API
R8 & Proguard Obfuscate
In most scenarios, the Xposed Module can be compressed by native obfuscation.
Here is the configuration method of obfuscation.
R8
If you are using
R8
then you don't need any special configuration forYukiHookAPI
.Proguard
If you are still usingProguard
, you need to do some rule configuration.Pay Attention
Proguard rules have been deprecated, please don't use them anymore.
Since Android Gradle Plugin 4.2, the obfuscator with the latest version of the Android Jetpack default is R8, and you no longer need to consider obfuscation.
To enable
R8
in any version, please add the following rules to thegradle.properties
file, no configuration is required for Android Gradle Plugin 7.0 and above.android.enableR8=true +
Use as Xposed Module Configs | Yuki Hook API + + + + + ++ + + diff --git a/en/guide/example.html b/en/guide/example.html new file mode 100644 index 00000000..6591d958 --- /dev/null +++ b/en/guide/example.html @@ -0,0 +1,333 @@ + + + + + + + + +Yuki Hook API
Use as Xposed Module Configs
Here are the related configuration methods used by
YukiHookAPI
as an Xposed Module.Dependency Configs
As an Xposed Module,
YukiHookAPI
provides an automatic builder.You need to integrate the latest version of the
com.highcapable.yukihookapi:ksp-xposed
dependency in your build script.Custom Automatic Builder
You can configure how
YukiHookAPI
will generate thexposed_init
entry point.InjectYukiHookWithXposed Annotation
annotation class InjectYukiHookWithXposed( + val sourcePath: String, + val modulePackageName: String, + val entryClassName: String, + val isUsingXposedModuleStatus: Boolean, + val isUsingResourcesHook: Boolean +) +
The
@InjectYukiHookWithXposed
annotation is an important annotation to mark the entry point of a Module App's Hook.Pay Attention
The Class of the @InjectYukiHookWithXposed annotation must implements IYukiHookXposedInit interface.
All Class tags in your current project can only exist once, if there are multiple declaration automatic builder will throw an exception at compile time, you can customize its related parameters.
sourcePath Parameter
The
sourcePath
parameter determines the important identifier for the automatic builder to automatically find and match your current project path.The content of this parameter is a relative path match, and the default parameter is
src/main
.Pay Attention
If your project is not in ../src/main.. or you set the project path manually using sourceSets, you need to set the sourcePath parameter manually, otherwise the automatic builder will not recognize your project path and will throw an exception at compile time.
The following example
@InjectYukiHookWithXposed(sourcePath = "src/custom") +
The file path separator used by
sourcePath
will be automatically recognized according toWindows
andUnix
, either/
or\
can be used.modulePackageName Parameter
modulePackageName
is theapplicationId
of your current project, which is your module package name (the final generated application package name).If left blank or not filled, the automatic builder will analyze and generate the current project file.
Notice
If you want to use the module package name to be automatically generated, you need to ensure that your project namespace has any of the following definitions in AndroidManifest.xml, build.gradle or build.gradle.kts.
Pay Attention
In Android Gradle Plugin 8+ versions, you need to manually enable buildConfig in the project's build.gradle or build.gradle.kts.
Groovy DSL
android { + buildFeatures { + buildConfig true + } +} +
Kotlin DSL
android { + buildFeatures { + buildConfig = true + } +} +
Example namespace
com.example.demo
, any one of the following definitions.The following definitions are for reference only, usually as long as your project can generate the
BuildConfig.java
file normally, no additional operations are required.
AndroidManifest.xml
example<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.demo"> +
build.gradle
exampleandroid { + namespace 'com.example.demo' +} +
build.gradle.kts
exampleandroid { + namespace = "com.example.demo" +} +
If your module package name is automatically generated by unconventional means, or you think it is necessary to manually define the module package name, then you can directly set the
modulePackageName
parameter.The following example
@InjectYukiHookWithXposed(modulePackageName = "com.example.demo") +
Pay Attention
Please do not fill in BuildConfig.APPLICATION_ID in modulePackageName, this will get an empty string during compilation, depending on the behavior of the Android Gradle Plugin.
As long as you customize the
modulePackageName
parameter, you will get a warning at compile time.The following example
You set the customize module package name to "com.example.demo", please check for yourself if it is correct +
Notice
In addition to the format of the manually defined module package name, the automatic builder will no longer check whether the module package name is correct, and you need to confirm its validity by yourself.
entryClassName Parameter
entryClassName
determines how the automatic builder generates the entry class name inxposed_init
.By default, it will use your entry class package name to insert the
_YukiHookXposedInit
suffix for generation.Suppose this is your entry class.
The following example
@InjectYukiHookWithXposed +object HookEntry : IYukiHookXposedInit +
The Xposed entry class is handled as follows.
The following example
class HookEntry_YukiHookXposedInit : IXposedHookZygoteInit, IXposedHookLoadPackage, ... +
The compiled class name structure is as follows.
The following example
...hook.HookEntry ← Your entry class +...hook.HookEntry_Impl ← Auto-generated Impl class +...hook.HookEntry_YukiHookXposedInit ← Automatically generated Xposed entry class +
We now define the entry class name as
HookXposedEntry
.The following example
@InjectYukiHookWithXposed(entryClassName = "HookXposedEntry") +object HookEntry : IYukiHookXposedInit +
The Xposed entry class is handled as follows.
The following example
class HookXposedEntry : IXposedHookZygoteInit, IXposedHookLoadPackage, ... +
The compiled class name structure is as follows.
The following example
...hook.HookEntry ← Your entry class +...hook.HookEntry_Impl ← Auto-generated Impl class +...hook.HookXposedEntry ← Automatically generated Xposed entry class +
Tips
The entry class can be defined using class or object, but it is recommended to use object definition to ensure that each injected process is a single instance.
Pay Attention
The entryClassName you define must not be the same as the class name in xposed_init, otherwise the automatic builder throws an exception at compile time.
isUsingXposedModuleStatus Parameter
isUsingXposedModuleStatus
determines whether the automatic builder generates relevant code for status functions such as Xposed Module activation, this feature is enabled by default.After generation, you will be able to use the related functions of
YukiHookAPI.Status
in the Module App's process.If you do not want to generate related code, you can manually turn off this feature, which will only take effect for the Module App's process.
isUsingResourcesHook Parameter
isUsingResourcesHook
determines whether the automatic builder generates relevant code for the Resources Hook, this feature is not enabled by default.By default the generated entry class will look like this.
The following example
class _YukiHookXposedInit : IXposedHookZygoteInit, IXposedHookLoadPackage { + + override fun initZygote(sparam: IXposedHookZygoteInit.StartupParam?) { + // ... + } + + override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) { + // ... + } +} +
If your current project need to use Resources Hook, you can set
isUsingResourcesHook = true
to enable automatic generation.Notice
This feature will no longer be enabled by default after version 1.2.0, please enable it manually if you want to use it.
The following example
@InjectYukiHookWithXposed(isUsingResourcesHook = true) +
The resulting entry class after enabled will look like the following.
The following example
class _YukiHookXposedInit : IXposedHookZygoteInit, IXposedHookLoadPackage, IXposedHookInitPackageResources { + + override fun initZygote(sparam: IXposedHookZygoteInit.StartupParam?) { + // ... + } + + override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) { + // ... + } + + override fun handleInitPackageResources(resparam: XC_InitPackageResources.InitPackageResourcesParam?) { + // ... + } +} +
Tips
Since the Xposed entry class is dynamically generated by YukiHookAPI, it will generate the following two files at the same time.
assets/xposed_init
resources/META-INF/yukihookapi_init
If you are using Git code control system, you can add these two files to .gitignore file.
IYukiHookXposedInit Interface
The
IYukiHookXposedInit
interface that your Hook entry class must implements it, which is the entry point for your Module App to start hooking.Tips
For more functions, please refer to IYukiHookXposedInit.
When your Module App is loaded by Xposed, the
onHook
method will be called back, you need to start usingYukiHookAPI
in this method.The basic calling process is
_YukiHookXposedInit
→IYukiHookXposedInit.onXposedEvent
→IYukiHookXposedInit.onInit
→IYukiHookXposedInit.onHook
For details, please refer to API Basic Configs.
Native Xposed API Events
If your current Xposed Module uses third-party resources, but may not be able to transfer them in a short time, you can use
onXposedEvent
to monitor all loading events of the native Xposed API.The following example
@InjectYukiHookWithXposed +object HookEntry : IYukiHookXposedInit { + + override fun onHook() { + // Your code here. + } + + override fun onXposedEvent() { + // Listen to the loading events of the native Xposed API + YukiXposedEvent.events { + onInitZygote { + // The it object is [StartupParam] + } + onHandleLoadPackage { + // The it object is [LoadPackageParam] + } + onHandleInitPackageResources { + // The it object is [InitPackageResourcesParam] + } + } + } +} +
onXposedEvent
andonHook
methods exist completely independently and do not affect each other. You can continue to useYukiHookAPI
in theonHook
method.Tips
For more functions, please refer to the IYukiHookXposedInit.onXposedEvent method.
Usage Example | Yuki Hook API + + + + + ++ + + diff --git a/en/guide/home.html b/en/guide/home.html new file mode 100644 index 00000000..b7158d17 --- /dev/null +++ b/en/guide/home.html @@ -0,0 +1,104 @@ + + + + + + + + +Yuki Hook API
Usage Example
Here is an introduction to the basic working method of
YukiHookAPI
and a list of simple Hook examples and common functions.Structure Diagram
The structure below describes the basic working and principle of
YukiHookAPI
.Host Environment +└─ YukiMemberHookCreator + └─ Class + └─ MemberHookCreator + └─ Member + ├─ Before + └─ After + MemberHookCreator + └─ Member + ├─ Before + └─ After + ... + YukiResourcesHookCreator + └─ Resources + └─ ResourcesHookCreator + └─ Drawable + └─ Replace + ResourcesHookCreator + └─ Layout + └─ Inject + ... +
The above structure can be written in the following form in code.
// KavaRef +TargetClass.resolve().firstMethod { + // Your code here. +}.hook { + before { + // Your code here. + } + after { + // Your code here. + } +} +
Click to view the previous writing method
// Old version (1.2.x-1.3.0 (Not included)) +TargetClass.method { + // Your code here. +}.hook { + before { + // Your code here. + } + after { + // Your code here. + } +} +// Old version +TargetClass.hook { + injectMember { + method { + // Your code here. + } + beforeHook { + // Your code here. + } + afterHook { + // Your code here. + } + } +} +
// Resources Hook (2.0.0 will be discontinued) +resources().hook { + injectResource { + conditions { + // Your code here. + } + replaceTo(...) + } +} +
Demo
You can find the demo provided by the API below to learn how to use
YukiHookAPI
.
Host App Demo click here to view
Module App Demo click here to view
Install the Host App and Module App Demo at the same time, and test the hooked function in the Host App by activating the Module App.
A Simple Hook Example
Here are examples of Hook App, Hook System Framework and Hook Resources for reference.
Tips
Starting with version
1.3.0
, YukiHookAPI has moved its own reflection API partially to KavaRef, the reflection APIs in the demonstration section below use theKavaRef
writing method. We no longer recommend using theYukiHookAPI
's own reflection API.Hook App
Suppose, we want to hook the
onCreate
method incom.android.browser
and show a dialog.Add code in the body of the
encase
method.The following example
loadApp(name = "com.android.browser") { + Activity::class.resolve().firstMethod { + name = "onCreate" + parameters(Bundle::class) + }.hook { + after { + AlertDialog.Builder(instance()) + .setTitle("Hooked") + .setMessage("I am hook!") + .setPositiveButton("OK", null) + .show() + } + } +} +
At this point, the
onCreate
method will be successfully hooked and this dialog will show when everyActivity
incom.android.browser
starts.So, what should I do if I want to continue the Hook
onStart
method?We can use Kotlin's
apply
method onActivity::class.resolve()
to create a call space.The following example
loadApp(name = "com.android.browser") { + Activity::class.resolve().apply { + firstMethod { + name = "onCreate" + parameters(Bundle::class) + }.hook { + after { + AlertDialog.Builder(instance()) + .setTitle("Hooked") + .setMessage("I am hook!") + .setPositiveButton("OK", null) + .show() + } + } + firstMethod { + name = "onStart" + emptyParameters() + }.hook { + after { + // Your code here. + } + } + } +} +
For the
Class
that does not exist in the current project, you can use thestub
method or theString.toClass(...)
method to get the class that needs to be hooked.For example, I want to get
com.example.demo.TestClass
.The following example
"com.example.demo.TestClass".toClass() + .resolve() + .firstMethod { + // Your code here. + }.hook { + // Your code here. + } +
If
com.example.demo
is the app you want to hook, then the writing method can be simpler.The following example
"$packageName.TestClass".toClass() + .resolve() + .firstMethod { + // Your code here. + }.hook { + // Your code here. + } +
If this
Class
is not immediately available, you can uselazyClass(...)
to define it.The following example
Define
TestClass
.val TestClass by lazyClass("com.example.demo.TestClass") +
Use it when appropriate.
TestClass.resolve().firstMethod { + // Your code here. +}.hook { + // Your code here. +} +
Tips
For more functions, please refer to MemberHookCreator.
Hook Zygote
The first event
initZygote
after the new process is forked when the app starts.Suppose we want to globally Hook the
onCreate
event of an appActivity
Add code in the body of the
encase
method.The following example
loadZygote { + Activity::class.resolve().firstMethod { + name = "onCreate" + parameters(Bundle::class) + }.hook { + after { + // Your code here. + } + } +} +
Notice
The functionality performed in loadZygote is very limited, and the loadZygote method is rarely needed.
Hook System Framework
In
YukiHookAPI
, the implementation of the Hook System Framework is very simple.Suppose, you want to get
ApplicationInfo
andPackageInfo
and do something with them.Add code in the body of the
encase
method.The following example
loadSystem { + ApplicationInfo::class.resolve().firstMethod { + // Your code here. + }.hook { + // Your code here. + } + PackageInfo::class.resolve().firstMethod { + // Your code here. + }.hook { + // Your code here. + } +} +
Pay Attention
loadZygote is directly different from loadSystem, loadZygote will be loaded in initZygote, and the System Framework is regarded as loadApp(name = "android") and exists, To Hook the System Framework, you can use loadSystem directly.
Hook Resources
Notice
This feature will be discontinued and removed in version 2.0.0.
Suppose, we want to replace the content of
app_name
of typestring
in Hookcom.android.browser
with123
.Add code in the body of the
encase
method.The following example
loadApp(name = "com.android.browser") { + resources().hook { + injectResource { + conditions { + name = "app_name" + string() + } + replaceTo("123") + } + } +} +
If the current app has a title bar text set with
app_name
, it will become our123
.You can also replace the Hook App's Resources with the current Xposed Module's Resources.
Suppose, we want to continue to hook
ic_launcher
of typemipmap
incom.android.browser
.The following example
loadApp(name = "com.android.browser") { + resources().hook { + injectResource { + conditions { + name = "ic_launcher" + mipmap() + } + replaceToModuleResource(R.mipmap.ic_launcher) + } + } +} +
At this point, the icon of the target app will be replaced with the icon we set.
If you want to replace the Resources of the System Framework, you can do the same, just replace
loadApp
withloadZygote
.The following example
loadZygote { + resources().hook { + // Your code here. + } +} +
Tips
For more functions, please refer to ResourcesHookCreator.
Remove Hook
The native Xposed provides us with a
XC_MethodHook.Unhook
function, which can remove the current Hook from the Hook queue, andYukiHookAPI
can also implement this function.The first way, save the
Result
instance of the current injected object, and callremove
at the appropriate time and place to remove the injected object.The following example
// Set a variable to save the current instance +val hookResult = + resolve().firstMethod { + name = "test" + returnType = Void.TYPE + }.hook { + after { + // ... + } + } +// Call the following method when appropriate +hookResult.remove() +
The second method, call
removeSelf
in the Hook callback method to remove itself.The following example
resolve().firstMethod { + name = "test" + returnType = Void.TYPE +}.hook { + after { + // Just call the following method directly + removeSelf() + } +} +
Tips
For more functions, please refer to MemberHookCreator.
Exception Handling
YukiHookAPI
has redesigned the monitoring of exceptions, any exception will not be thrown during the hook process, to avoid interrupting the next hook process and causing the hook process to "die".Listen for Exceptions
You can handle exceptions that occur during the Hook method.
The following example
hook { + // Your code here. +}.result { + // Handle the exception at the start of the hook + onHookingFailure {} + // Handle exceptions in the hook process + onConductFailure { param, throwable -> } + // Handle all exceptions + onAllFailure {} + // ... +} +
This method also works in the Resources Hook.
The following example
injectResource { + // Your code here. +}.result { + // Handle arbitrary exceptions when hooking + onHookingFailure {} + // ... +} +
(Applicable to older versions) You can also handle exceptions that occur when the Hook's
Class
does not exist.The following example
TargetClass.hook { + injectMember { + // Your code here. + } +}.onHookClassNotFoundFailure { + // Your code here. +} +
(Applicable to older versions) You can also handle exceptions when looking up methods.
The following example
method { + // Your code here. +}.onNoSuchMethod { + // Your code here. +} +
Tips
For more functions, please refer to MemberHookCreator.Result, ResourcesHookCreator.Result.
Common exceptions that may occur are described here. For more information, please refer to API Exception Handling.
Notice
The exception of
KavaRef
will be managed separately by itself. For detailed configuration plans, you can refer to here, which will jump to theKavaRef
document.Throw an Exception
In some cases, you can manually throw exceptions to alert some functionality that there is a problem.
As mentioned above, the exception thrown in the
hook
method body will be taken over by theYukiHookAPI
to avoid interrupting the next Hook process and causing the Hook process to "die".Here's how these exceptions work when
YukiHookAPI
takes over.The following example
// <Scenario 1> +injectMember { + method { + throw RuntimeException("Exception Test") + } + afterHook { + // ... + } +}.result { + // Can catch RuntimeException + onHookingFailure {} +} +// <Scenario 2> +injectMember { + method { + // ... + } + afterHook { + throw RuntimeException("Exception Test") + } +}.result { + // Can catch RuntimeException + onConductFailure { param, throwable -> } +} +
The above scenarios will only be processed in the (Xposed) Host App environment and will not have any impact on the host itself.
If we want to throw these exceptions directly to the Host App, the native Xposed provides us with the
param.throwable
method, andYukiHookAPI
can also implement this function.If you want to throw an exception directly to the Host App in the Hook callback method body, you can implement the following methods.
The following example
method { + // ... +}.hook { + after { + RuntimeException("Exception Test").throwToApp() + } +} +
You can also throw exceptions directly in the Hook callback method body, and then mark the exception to be thrown to the Host App.
The following example
method { + // ... +}.hook { + after { + throw RuntimeException("Exception Test") + }.onFailureThrowToApp() +} +
The above two methods can receive an exception at the Host App and cause the Host App process to crash.
Notice
In order to ensure that the Hook calling domain and the calling domain within the Host App are isolated from each other, exceptions can only be thrown to the Host App in the before and after callback method bodies.
Tips
For more functions, please refer to Throwable.throwToApp, YukiMemberHookCreator.MemberMookCreator.HookCallback.
Expansion Usage
You can use the following methods to easily implement various judgments and functions in the Hook process.
Multiple Hosts
If your Module App needs to handle Hook events of multiple apps at the same time, you can use the
loadApp
method body to distinguish the app you want to hook.The following example
loadApp(name = "com.android.browser") { + // Your code here. +} +loadApp(name = "com.android.phone") { + // Your code here. +} +
Tips
For more functions, please refer to PackageParam.loadApp.
Multiple Processes
If your Hook's Host App has multiple processes, you can use the
withProcess
method body to hook them separately.The following example
withProcess(mainProcessName) { + // Your code here. +} +withProcess(name = "$packageName:tool") { + // Your code here. +} +
Tips
For more functions, please refer to PackageParam.withProcess.
Writing Optimization
To make the code more concise, you can omit the name of
YukiHookAPI
and write youronHook
entry as lambda.The following example
override fun onHook() = encase { + // Your code here. +} +
You can also abbreviate the
hook { ... }
method body when you only need a Hook callback event.The following example
Activity::class.resolve().firstMethod { + // Your code here. +}.hook().after { + // Your code here. +} +
Xposed Module Status
Usually, the developer of the Xposed Module will choose to read the activation information of the current Xposed Module to better show the user the effective status of the current function.
In addition to the basic Hook functions,
YukiHookAPI
also designed a set of Xposed Module status judgment functions for developers, such as activation status and Hook Framework information.Determine Self-activation Status
Usually, we will choose to write a method to make it return
false
, and then hook this method to make it returntrue
to prove that the Hook has taken effect.In
YukiHookAPI
, you don’t need to do this at all,YukiHookAPI
has already encapsulated this operation for you, and you can use it directly.Now, you can directly use
YukiHookAPI.Status.isXposedModuleActive
to determine whether it is activated in the Module App.The following example
if(YukiHookAPI.Status.isXposedModuleActive) { + // Your code here. +} +
Due to some special reasons, the Xposed Modules in TaiChi and Wuji cannot use the standard method to detect the activation state.
At this point you can use
YukiHookAPI.Status.isTaiChiModuleActive
to determine whether it is activated.The following example
if(YukiHookAPI.Status.isTaiChiModuleActive) { + // Your code here. +} +
If you want to use both judgment schemes,
YukiHookAPI
also encapsulates a convenient way for you.At this point, you can use
YukiHookAPI.Status.isModuleActive
to determine whether you are activated in Xposed or TaiChi and Wuji.The following example
if(YukiHookAPI.Status.isModuleActive) { + // Your code here. +} +
Tips
For more functions, please refer to YukiHookAPI.Status.
Notice
If your Module App's API version is higher than 29 and is running on a system whose target API is 29 or higher, you need to add the following permission statement in AndroidManifest.xml to judge the activation status of the module in TaiChi and Wuji.
The following example
<queries> + <intent> + <action android:name="android.intent.action.MAIN" /> + </intent> +</queries> +
There is another solution, you can directly declare the android.permission.QUERY_ALL_PACKAGES permission, but it is not recommended and will be warned by code inspection.
The following example
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" /> +
If the activation status of TaiChi and Wuji is included in the Module App activation judgment, the Application of the Module App must be extends from ModuleApplication or directly use ModuleApplication.
Get Hook Framework Information
In addition to judging your own activation status, you can also get information about the current Hook Framework through the
Executor
inYukiHookAPI.Status
.For example, we can use
YukiHookAPI.Status.Executor.name
to get the name of the current Hook Framework.The following example
val frameworkName = YukiHookAPI.Status.Executor.name +
We can also use
YukiHookAPI.Status.Executor.apiLevel
to get the API Level of the current Hook Framework.The following example
val frameworkApiLevel = YukiHookAPI.Status.Executor.apiLevel +
Tips
For more functions, please refer to YukiHookAPI.Status.Executor.
Notice
YukiHookAPI after 1.0.91 version modifies the logical judgment method of obtaining the status of the Xposed Module, and now you can use this API in the Module App and Host App at the same time;
Need to make sure InjectYukiHookWithXposed.isUsingXposedModuleStatus is enabled;
YukiHookAPI only connects to the known acquisition methods.
Except for the Hook Framework that provides standard APIs, in other cases, the Xposed Module may not be able to determine whether it is activated or obtain information about the Hook Framework.
Introduction | Yuki Hook API + + + + + ++ + + diff --git a/en/guide/knowledge.html b/en/guide/knowledge.html new file mode 100644 index 00000000..a46c426e --- /dev/null +++ b/en/guide/knowledge.html @@ -0,0 +1,46 @@ + + + + + + + + +Yuki Hook API
Introduction
YukiHookAPI
is an integrated Hook API Framework, which does not provide any Hook functions, and needs the support of Xposed related basic APIs.Background
This is an efficient Hook API rebuilt based on the Xposed API using Kotlin, and creates rich function extensions for the development of Xposed Modules.
The name is taken from "ももくり" heroine Yuki Kurihara.
Formerly the Innocent Xposed API used in Development Learning Project, now renamed and open sourced.
Usage
YukiHookAPI
is built entirely with Kotlin lambda syntax.Abandoning the original less friendly
XposedHelpers
, you can use it to easily create Xposed Modules and easily implement custom Hook API.Language Requirement
Please use Kotlin, the framework part of the code composition is also compatible with Java but the implementation of the basic Hook scene may not work at all.
All demo code in this document will be described using Kotlin, if you don't know how to use Kotlin then you may not be able to use
YukiHookAPI
.Source of Inspiration
Previously, when we built an Xposed Module, we first needed to create an
xposed_init
file underassets
.Then, manually fill in your own entry class name into the file and use
XposedHelpers
to implement our Hook logic.Since Kotlin is the main Android development language, this API is really not very elegant to use.
Is there any easy to use, light, elegant solution?
With this idea,
YukiHookAPI
was born.Now, we only need to write a small amount of code, and all the time and expense are handed over to automation.
With Kotlin's elegant lambda writing and
YukiHookAPI
, you can make your Hook logic more beautiful and clear.The following example
@InjectYukiHookWithXposed +object HookEntry : IYukiHookXposedInit { + + override fun onHook() = encase { + loadZygote { + Activity::class.resolve().firstMethod { + name = "onCreate" + parameters(Bundle::class) + }.hook { + before { + // Your code here. + } + after { + // Your code here. + } + } + } + loadApp(name = "com.android.browser") { + Activity::class.resolve().firstMethod { + name = "onCreate" + parameters(Bundle::class) + }.hook { + before { + // Your code here. + } + after { + // Your code here. + } + } + } + } +} +
class HookEntry : IXposedHookZygoteInit, IXposedHookLoadPackage { + + private lateinit var moduleResources: XModuleResources + + override fun initZygote(sparam: IXposedHookZygoteInit.StartupParam) { + moduleResources = XModuleResources.createInstance(sparam.modulePath, null) + XposedHelpers.findAndHookMethod( + Activity::class.java.name, + null, "onCreate", + Bundle::class.java, + object : XC_MethodHook() { + override fun beforeHookedMethod(param: MethodHookParam?) { + // Your code here. + } + + override fun afterHookedMethod(param: MethodHookParam?) { + // Your code here. + } + }) + } + + override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) { + if (lpparam.packageName == "com.android.browser") + XposedHelpers.findAndHookMethod( + Activity::class.java.name, + lpparam.classLoader, "onCreate", + Bundle::class.java, + object : XC_MethodHook() { + override fun beforeHookedMethod(param: MethodHookParam?) { + // Your code here. + } + + override fun afterHookedMethod(param: MethodHookParam?) { + // Your code here. + } + }) + } +} +
Yes, you read that right, just needing these codes can completely replace the traditional Xposed API to achieve the same function.
Now, with the help of the efficient and powerful
YukiHookAPI
, you can implement a very simple Xposed Module.Tips
Starting with version
1.3.0
,YukiHookAPI
has migrated its own reflection API part to KavaRef (including the reflection API part demonstrated above).Now, you can make the
YukiHookAPI
more easy to use with the powerful reflection ability ofKavaRef
.Basic Knowledge | Yuki Hook API + + + + + ++ + + diff --git a/en/guide/move-to-new-api.html b/en/guide/move-to-new-api.html new file mode 100644 index 00000000..f43eb009 --- /dev/null +++ b/en/guide/move-to-new-api.html @@ -0,0 +1,241 @@ + + + + + + + + +Yuki Hook API
Basic Knowledge
Here is a collection of Xposed-related introductions and the key points of knowledge that need to be grasped before start.
Anyone who already knows can skip it.
The basic knowledge content not necessarily completely accurate, please read it according to your own opinion.
If you find any errors in this page, please correct it and help us improve.
Related Introduction
Here's an introduction to Xposed and how Hooks work.
What is Xposed
Xposed Framework is a set of open source framework services that run in Android high-privilege mode. It can affect program operation (modify the system) without modifying the APK file. Based on it, many Powerful modules that operate simultaneously without conflicting functions.
The above content is copied from Baidu Encyclopedia.
What can Xposed do
The structure below describes the basic workings and principles of Xposed.
Xposed Framework +└── App's Environment + └── Hooker (Hooked) + ... + App's Environment + └── Hooker (Hooked) + ... + ... +
We can achieve the ultimate goal of controlling its behavior by injecting the Host (App) when the Host (App) is running.
This mode of operation of Xposed is called parasitism. The Xposed Module follows the lifecycle of the host and completes its own life course within the lifecycle of the Host.
We can call the Host's methods, fields, and constructors through reflection, and use the Hook operation provided by
XposedBridge
to dynamically insert our own code before and after the method to be executed by the Host (App), or completely replace the target, or even intercept.Development Process
Today's Xposed Manager has been completely replaced by its derivative works, and the era of SuperSU has ended, and now, with Magisk, everything behind is possible again.
Its development history can be roughly divided into Xposed(Dalvik) → Xposed(ART) → Xposed(Magisk) → EdXposed(Riru)/LSPosed(Riru/ Zygisk)
Derivatives
The structure below describes how and how the Xposed-like Hook Framework works.
App's Environment +└── Hook Framework + └── Hooker (Hooked) + ... +
Through the operation principle of Xposed, many frameworks of the same type have been derived. As mobile devices in today's era are more and more difficult to obtain Root permissions or even flash, and when they are not just needed, some Root-free frameworks are also produced, such as LSPatch、TaiChi.
These Hook Frameworks at the ART level can also complete the Hook process with the same principle as Xposed without using the Xposed API. The operating principle of Root-free is to modify the APK and inject the Hook process into the Host, and control it through external modules.
Another product is to use the existing functions of the Android operating environment to virtualize an environment that is completely the same as the current device system, and run App in it. This is the virtual App technology VirtualApp, which was later derived as VirtualXposed .
The Root-free frameworks mentioned above are LSPatch、TaiChi、VirtualApp、SandVXposed.
What YukiHookAPI does
Since Xposed appeared until now, apart from
XposedHelpers
, which is well known to developers, there is still no set of syntactic sugar for Kotlin and API with complete usage encapsulation.The birth of this API framework is to hope that in the current era of Xposed, more capable Xposed Module developers can avoid detours and complete the entire development process more easily and simply.
In the future,
YukiHookAPI
will adapt to more third-party Hook Frameworks based on the goal of using the Xposed API, so as to improve the entire ecosystem and help more developers make Xposed Module development simpler and easier to understand.Let's Started
Before starting, you need to have the following basics to better use
YukiHookAPI
.
Grasp and understand Android development and simple system operation principles
To grasp and understand the internal structure of Android APK and simple decompilation knowledge, you can refer to Jadx and ApkTool
Grasp and proficient in using Java reflection, understand simple Smali syntax, understand Dex file structure, and use reverse analysis to locate method locations
Grasp the basic native Xposed API usage, understand the operation principle of Xposed, see here (Friend Link)
Grasp Kotlin language and learn to use Kotlin lambda
Grasp and understand Kotlin and Java mixing, calling each other, and Java bytecode generated by Kotlin
Migrate from Other Hook APIs | Yuki Hook API + + + + + ++ + + diff --git a/en/guide/quick-start.html b/en/guide/quick-start.html new file mode 100644 index 00000000..992ebc38 --- /dev/null +++ b/en/guide/quick-start.html @@ -0,0 +1,203 @@ + + + + + + + + +Yuki Hook API
Migrate from Other Hook APIs
This document can help you quickly migrate from the Hook APIs you are familiar with to
YukiHookAPI
to become familiar with the related writing methods ofYukiHookAPI
.Rovo89 Xposed API
If you are familiar with Rovo89 Xposed API, you can refer to the same point below to quickly migrate your API to
YukiHookAPI
.Migrate Hook Entry Point
Migrated from
XC_LoadPackage.LoadPackageParam
toPackageParam
.
YukiHookAPI
implements the lambda method bodythis
usage forPackageParam
, and thePackageParam
object can be obtained globally in theencase
method body.The API function differences are compared as follows
override fun onHook() = encase { + // Get the package name of the current Hook + packageName + // Get the ApplicationInfo of the current Hook + appInfo + // Get the system context object + systemContext + // Get the host Application lifecycle + appContext + // Hook specified app + loadApp(name = "com.demo.test") { + // Member Hook + "com.demo.test.TestClass".toClass() + .resolve() + .firstMethod { + name = "test" + parameters(Boolean::class) + }.hook { + after { + // ... + } + } + // Resources Hook (fixed usage) + resources().hook { + injectResource { + conditions { + name = "ic_launcher" + mipmap() + } + replaceToModuleResource(R.mipmap.ic_launcher) + } + } + } +} +
private lateinit var moduleResources: XModuleResources + +override fun initZygote(sparam: IXposedHookZygoteInit.StartupParam) { + moduleResources = XModuleResources.createInstance(sparam.modulePath, null) +} + +override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) { + // Get the package name of the current Hook + lpparam.packageName + // Get the ApplicationInfo of the current Hook + lpparam.applicationInfo + // Get the system context object + // There is no ready-made calling method in the Rovo89 Xposed API, you need to reflect ActivityThread to achieve it + // Get the host Application lifecycle + AndroidAppHelper.currentApplication() + // Class Hook + if(lpparam.packageName == "com.demo.test") + XposedHelpers.findAndHookMethod( + "com.demo.test.TestClass", lpparam.classLoader, + "test", Boolean::class.java, + object : XC_MethodHook() { + override fun afterHookedMethod(param: MethodHookParam) { + // ... + } + } + ) +} + +override fun handleInitPackageResources(resparam: XC_InitPackageResources.InitPackageResourcesParam) { + // Get the package name of the current Hook + resparam.packageName + // Resources Hook + resparam.res.setReplacement( + "com.demo.test", "mipmap", "ic_launcher", + moduleResources.fwd(R.mipmap.ic_launcher) + ) +} +
Migrate Hook Method Body
Migrated from
XC_MethodHook.MethodHookParam
toHookParam
.Before/After Hook
YukiHookAPI
also implements the lambda method bodythis
usage forHookParam
, and theHookParam
object can be obtained globally in the method bodies such asbefore
andafter
.The API function differences are compared as follows
after { + // Get the current Hook instance + instance + // Get the Class instance of the current Hook + instanceClass + // Get and cast the current Hook instance to the specified type T + instance<T>() + // Get the method parameter array + args + // Get the first T of the method parameter + args().first().cast<T>() + // Get the last bit of the method parameter T + args().last().cast<T>() + // Get any subscript T of the method parameter, here is an example of 2 + args(index = 2).cast<T>() + // Set any subscript of the method parameter, here is an example of 2 + args(index = 2).set(...) + // Get the return value + result + // Get the return value and cast to T + result<T>() + // Modify the content of the return value + result = ... + // Remove the content of the return value + resultNull() + // Get the data storage instance within the scope of the current callback method body + dataExtra + // Throw an exception to the Hook app + Throwable("Fatal").throwToApp() + // Execute the original method without hook and call with the original method parameters, generics can be omitted + callOriginal<Any?>() + // Execute the original method without Hook and customize the method parameter call, the generic type can be omitted + invokeOriginal<Any?>(...) +} +
override fun afterHookedMethod(param: MethodHookParam) { + // Get the current Hook instance + param.thisObject + // Get the Class instance of the current Hook + param.thisObject.javaClass + // Get and cast the current Hook instance to the specified type T + param.thisObject as T + // Get the method parameter array + param.args + // Get the first T of the method parameter + param.args[0] as T + // Get the last bit of the method parameter T + param.args[param.args.lastIndex] as T + // Get any subscript T of the method parameter, here is an example of 2 + param.args[2] as T + // Set any subscript of the method parameter, here is an example of 2 + param.args[2] = ... + // Get the return value + param.result + // Get the return value and cast to T + param.result as T + // Modify the content of the return value + param.result = ... + // Remove the content of the return value + param.result = null + // Get the data storage instance within the scope of the current callback method body + param.extra + // Throw an exception to the Hook app + param.throwable = Throwable("Fatal") + // Execute the original method without hooking + XposedBridge.invokeOriginalMethod(param.method, param.thisObject, ...) +} +
Replace Hook
The
replaceHook
method is special, and theYukiHookAPI
makes a variety of forms for it to choose from.The API function differences are compared as follows
/// A method with no return value void + +replaceUnit { + // Implement the replaced logic directly here +} + +/// A method with a return value + +replaceAny { + // Implement the replaced logic here + // ... + // Need to return the return value corresponding to the method, no need to write return, just put the parameter in the last digit + // Assuming the return value of this method is an Int, we just need to ensure that the last bit is the return value we need + 0 +} + +/// For some methods, we just need to replace their return value, then there are the following implementations +/// It should be noted that the parameters passed in by the method of directly replacing the return value are fixed. If you want to dynamically replace the return value, please use the above replaceAny method body + +// Replace with the return value you need +replaceTo(...) +// Replace with return value of type Boolean +replaceToTrue() +// Intercept return value +intercept() +
/// A method with no return value void + +override fun replaceHookedMethod(param: MethodHookParam): Any? { + // Implement the replaced logic directly here + return null +} + +/// A method with a return value + +override fun replaceHookedMethod(param: MethodHookParam): Int { + // Implement the replaced logic here + // ... + // Assume the return value of this method is an Int + return 0 +} + +/// For some methods, we just need to replace their return value, then there are the following implementations + +// Replace with the return value you need +override fun replaceHookedMethod(param: MethodHookParam) = ... +// Replace with return value of type Boolean +override fun replaceHookedMethod(param: MethodHookParam) = true +// Intercept return value +override fun replaceHookedMethod(param: MethodHookParam) = null +
Notes on Migrating XposedHelpers
The reflection functionality provided in
YukiHookAPI
differs from the reflection functionality ofXposedHelpers
.Here is a guide to avoid common pitfalls.
Methods like
XposedHelpers.callMethod
andXposedHelpers.callStaticMethod
automatically search and invoke all public methods (including those in superclasses), which is a feature of native Java reflection. In contrast, the reflection solution provided byYukiHookAPI
first searches and then calls, and by default, the search process does not automatically look for methods in superclasses.Notice
The reflection API of
YukiHookAPI
itself has been deprecated in1.3.0
version. The following content is only used as migration guidelines before1.3.0
version, we will retain it but will not update the content again.You can migrate to KavaRef, and this feature is also applicable to
KavaRef
.For example, class
A
inherits fromB
, andB
has a public methodtest
, whileA
does not.public class B { + public void test(String a) { + // ... + } +} + +public class A extends B { + // ... +} +
Usage with
XposedHelpers
.val instance: A = ... +XposedHelpers.callMethod(instance, "test", "some string") +
Usage with
YukiHookAPI
.val instance: A = ... +instance.current().method { + name = "test" + // Note that you need to add this search condition to ensure it searches for methods in superclasses. + superClass() +}.call("some string") +// Or directly call the superClass() method. +instance.current().superClass()?.method { + name = "test" +}?.call("some string") +
Migrate More Functions Related to Hook API
YukiHookAPI
is a brand new Hook API, which is fundamentally different from other Hook APIs, you can refer to API Document and Special Features to determine some functional Migration and use.Quick Start | Yuki Hook API + + + + + ++ + + diff --git a/en/guide/supportive.html b/en/guide/supportive.html new file mode 100644 index 00000000..7ba27154 --- /dev/null +++ b/en/guide/supportive.html @@ -0,0 +1,34 @@ + + + + + + + + +Yuki Hook API
Quick Start
Integrate
YukiHookAPI
into your project.Project Requirements
The project needs to be created using
Android Studio
orIntelliJ IDEA
and be of type Android project and have integrated Kotlin environment dependencies.
Android Studio (It is recommended to get the latest version from here)
IntelliJ IDEA (It is recommended to get the latest version from here)
Kotlin 1.9.0+, Gradle 8+, Java 11, 17+, Android Gradle Plugin 8+
Automatically Build Project
YukiHookAPI
provides an automated build tool that can help you quickly build an Android standard project template with Xposed Module dependencies, and use the built template to start the next step directly.You can click here to check it out.
Manually Configure Project
If you don't want to use automated build tools, you can still manually configure project dependencies as follows.
Create Project
Use
Android Studio
orIntelliJ IDEA
to create a new Android project and select Kotlin in theLanguage
column to automatically add basic dependencies.Integration Dependencies
We recommend using Kotlin DSL as the Gradle build script language and SweetDependency to manage dependencies.
SweetDependency (Recommended)
Add the repositories and dependencies in your project's
SweetDependency
configuration file.The following example
repositories: + # Must be added when used as an Xposed Module, otherwise optional + rovo89-xposed-api: + url: https://api.xposed.info/ + +plugins: + # Must be added when used as an Xposed Module, otherwise optional + com.google.devtools.ksp: + version: + + ... + +libraries: + # Must be added when used as an Xposed Module, otherwise optional + de.robv.android.xposed: + api: + version: 82 + repositories: + rovo89-xposed-api + com.highcapable.yukihookapi: + api: + version: + + # Must be added when used as an Xposed Module, otherwise optional + ksp-xposed: + version-ref: <this>::api + # YukiHookAPI version 1.3.0 uses KavaRef as core reflection API + # YukiHookAPI no longer binds its own reflection API, you can start trying to use KavaRef + com.highcapable.kavaref: + kavaref-core: + version: + + kavaref-extension: + version: + + ... +
After adding it, run Gradle Sync and all dependencies will be autowired.
Next, deploy plugins in your project's
build.gradle.kts
.The following example
plugins { + // Must be added when used as an Xposed Module, otherwise optional + autowire(libs.plugins.com.google.devtools.ksp) + // ... +} +
Then, deploy dependencies in your project's
build.gradle.kts
.The following example
dependencies { + // Basic dependencies + implementation(com.highcapable.yukihookapi.api) + // It is recommended to use KavaRef as the core reflection API + implementation(com.highcapable.kavaref.kavaref.core) + implementation(com.highcapable.kavaref.kavaref.extension) + // Must be added when used as an Xposed Module, otherwise optional + compileOnly(de.robv.android.xposed.api) + // Must be added when used as an Xposed Module, otherwise optional + ksp(com.highcapable.yukihookapi.ksp.xposed) +} +
Version Catalog
Add repositories in your project's
build.gradle.kts
.Kotlin DSL
repositories { + google() + mavenCentral() + // Must be added when used as an Xposed Module, otherwise optional + maven("https://api.xposed.info/") +} +
Add dependency in your project's
gradle/libs.versions.toml
.The following example
[versions] +yukihookapi = "<yuki-version>" +ksp = "<ksp-version>" +kavaref-core = "<kavaref-version>" +kavaref-extension = "<kavaref-version>" + +[plugins] +# Must be added when used as an Xposed Module, otherwise optional +ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } + +[libraries] +yukihookapi-api = { module = "com.highcapable.yukihookapi:api", version.ref = "yukihookapi" } +# Must be added when used as an Xposed Module, otherwise optional +yukihookapi-ksp-xposed = { module = "com.highcapable.yukihookapi:ksp-xposed", version.ref = "yukihookapi" } +# YukiHookAPI version 1.3.0 uses KavaRef as core reflection API +# YukiHookAPI no longer binds its own reflection API, you can start trying to use KavaRef +kavaref-core = { module = "com.highcapable.kavaref:kavaref-core", version.ref = "kavaref-core" } +kavaref-extension = { module = "com.highcapable.kavaref:kavaref-extension", version.ref = "kavaref-extension" } +# Must be added when used as an Xposed Module, otherwise optional +xposed-api = { module = "de.robv.android.xposed:api", version = "82" } +
Next, deploy plugins in your project's
build.gradle.kts
.Kotlin DSL
plugins { + // Must be added when used as an Xposed Module, otherwise optional + alias(libs.plugins.ksp) +} +
Then, deploy dependencies in your project's
build.gradle.kts
.Kotlin DSL
dependencies { + // Basic dependency + implementation(libs.yukihookapi.api) + // It is recommended to use KavaRef as the core reflection API + implementation(libs.kavaref.core) + implementation(libs.kavaref.extension) + // Must be added when used as an Xposed Module, otherwise optional + compileOnly(libs.xposed.api) + // Must be added when used as an Xposed Module, otherwise optional + ksp(libs.yukihookapi.ksp.xposed) +} +
Traditional Method
Add repositories in your project's
build.gradle.kts
.Kotlin DSL
repositories { + google() + mavenCentral() + // Must be added when used as an Xposed Module, otherwise optional + maven("https://api.xposed.info/") +} +
Add plugins in your project's
build.gradle.kts
.Kotlin DSL
plugins { + // Must be added when used as an Xposed Module, otherwise optional + id("com.google.devtools.ksp") version "<ksp-version>" +} +
Add dependencies in your project's
build.gradle.kts
.Kotlin DSL
dependencies { + // Basic dependency + implementation("com.highcapable.yukihookapi:api:<yuki-version>") + // It is recommended to use KavaRef as the core reflection API + implementation("com.highcapable.kavaref:kavaref-core:<kavaref-version>") + implementation("com.highcapable.kavaref:kavaref-extension:<kavaref-version>") + // Must be added when used as an Xposed Module, otherwise optional + compileOnly("de.robv.android.xposed:api:82") + // Must be added when used as an Xposed Module, otherwise optional + ksp("com.highcapable.yukihookapi:ksp-xposed:<yuki-version>") +} +
Please modify <ksp-version> to the latest version found here (please note to select your current corresponding Kotlin version).
Please change <yuki-version> to the latest version here.
Please change <kavaref-version> to the latest version here.
Pay Attention
The api and ksp-xposed dependency versions of YukiHookAPI must correspond one-to-one, otherwise a version mismatch error will occur.
Configure Java Version
Modify the Java version of Kotlin in your project
build.gradle.kts
orbuild.gradle
to 17 or above.Kotlin DSL
android { + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = "17" + } +} +
Groovy DSL
android { + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = '17' + } +} +
Notice
Since API 1.0.80, the Java version used by Kotlin defaults to 11, and versions 1.8 and below are no longer supported.
Since API 1.2.0, the Java version used by Kotlin defaults to 17, and versions 11 and below are no longer supported.
Use as Xposed Module
Add the base code to your
AndroidManifest.xml
.The following example
<!-- Set as Xposed Module --> +<meta-data + android:name="xposedmodule" + android:value="true" /> + +<!-- Set your Xposed Module description --> +<meta-data + android:name="xposeddescription" + android:value="Fill in your Xposed Module description" /> + +<!-- The minimum Xposed version number --> +<!-- If you are using EdXposed/LSPosed, the minimum recommended is 93 --> +<meta-data + android:name="xposedminversion" + android:value="93" /> + +<!-- Optional: Configure support for New XSharedPreferences without adjusting xposedminversion to 93 --> +<meta-data + android:name="xposedsharedprefs" + android:value="true"/> +
Create a Hook entry class in your project, implements
IYukiHookXposedInit
and add the annotation@InjectYukiHookWithXposed
.The following example
@InjectYukiHookWithXposed +object HookEntry : IYukiHookXposedInit { + + override fun onHook() = YukiHookAPI.encase { + // Your code here. + } +} +
Suggestion
Please configure YukiHookAPI in the onInit method and set the isDebug mode to the following form.
The following example
override fun onInit() = configs { + isDebug = BuildConfig.DEBUG +} +
You can also extends Application of your Module App from ModuleApplication to achieve a complete user experience.
For more functions, please refer to ModuleApplication.
Then, you can start writing Hook code.
For configuration details related to use as an Xposed Module, you can click here to continue reading.
If you are currently using Hook APIs such as Rovo89 Xposed API, you can refer to Migrate from Other Hook APIs.
Use as Hook API
Integration
Create your custom
Application
.Pay Attention
Regardless of the Hook Framework you use, you need to add its docking Xposed dependency support.
If the target Hook Framework does not integrate Rovo89 Xposed API, you need to implement and connect XposedBridge by yourself.
Add
YukiHookAPI.encase
method toattachBaseContext
.The following example
override fun attachBaseContext(base: Context?) { + // Load Hook Framework + // + // Your code here. + // + // Load YukiHookAPI + YukiHookAPI.encase(base) { + // Your code here. + } + super.attachBaseContext(base) +} +
Then, you can start writing Hook code in much the same way you would use it as an Xposed Module.
For configuration details related to use as a Hook API, you can click here to continue reading.
Notice
YukiHookPrefsBridge, YukiHookDataChannel and Resources Hook functionality will not work when using a custom Hook Framework instead of the full Xposed Module.
Supportive | Yuki Hook API + + + + + ++ + + diff --git a/en/index.html b/en/index.html new file mode 100644 index 00000000..27a74746 --- /dev/null +++ b/en/index.html @@ -0,0 +1,47 @@ + + + + + + + + +Yuki Hook API
Supportive
The following are the related functions, Xposed Frameworks, Hook Frameworks and Hook APIs supported by
YukiHookAPI
.Basic Functions
Name ST Description Xposed Module Auto Builder ✅ Will use New Xposed Module Config Plan on YukiHookAPI
2.0.0
ART Dynamic Method Hook ✅ Stable use in multiple scenarios Xposed Resources Hook ❗ Supported, but will be removed on YukiHookAPI
2.0.0
Extended Functions
Name ST Description Reflection Extensions❗ Completely deprecated, recommended to migrate to KavaRef, planned YukiHookAPI
2.0.0
version removedXposed Module Data Storage ✅ Normal use Xposed Module and Host Channel ✅ Normal use Host Lifecycle Extension ✅ Normal use Inject Module Apps Resources ✅ Normal use Register Module Apps Activity ✅ Normal use Xposed Frameworks
Name ST Description LSPosed ✅ Stable use in multiple scenarios LSPatch ⭕ Support, API support will be gradually added after the project is completed EdXposed ❎ Maintenance has stopped and is no longer recommended Dreamland ⭕ Theoretical support (not tested by developer) TaiChi ⭕ Hook functions normally (some functions have restrictions) Xposed ❎ Maintenance has stopped and is no longer recommended Hook Frameworks
Name ST Description LSPlant ⭕ Please visit AliuHook Pine ⭕ Theoretical support (not tested by developer) SandHook ❎ The latests Android are not supported, you need to integrated the Rovo89 Xposed API yourself Whale ❎ The latests Android are not supported, you need to integrated the Rovo89 Xposed API yourself YAHFA ❎ The latests Android are not supported, you need to integrated the Rovo89 Xposed API yourself FastHook ❎ Maintenance has stopped and is no longer recommended Epic ❎ Maintenance has stopped and is no longer recommended Hook APIs
Name ST Description Rovo89 Xposed API ✅ Stable use in multiple scenarios Modern Xposed API ❎ Will be supported on YukiHookAPI
2.0.0
Home | Yuki Hook API + + + + + ++ + + diff --git a/en/tools/yukihookapi-projectbuilder.html b/en/tools/yukihookapi-projectbuilder.html new file mode 100644 index 00000000..f34ab74c --- /dev/null +++ b/en/tools/yukihookapi-projectbuilder.html @@ -0,0 +1,34 @@ + + + + + + + + +YukiHookAPI Project Builder | Yuki Hook API + + + + + ++ + + diff --git a/images/logo.png b/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..7576340dc8d4839aefac808e9e68a48598e08414 GIT binary patch literal 24264 zcmc$`c{G(@^gn*DAya0VYuki Hook API
YukiHookAPI Project Builder
This is an automatic building tool for Xposed Modules using
YukiHookAPI
as the core.Implementing automated search relies on quickly building an Android project template that includes a Xposed Module environment.
Get Project
This project is open source and free, and will be maintained continuously according to your usage.
The original version may have imperfections or bugs. We welcome to your feedback.
Notice
The project builder will be maintained before the release of the first
2.0.0
version ofYukiHookAPI
. This project will be officially deprecated after the new version is released.Project Address YukiHookAPI-ProjectBuilder。
If you want to download directly, you can click here to go to the Release address.
Usage
Here contains the basic usage and function explanation.
Basic Usage
The software use process requires your device connected to the Internet.
After starting the software, simply configure the project you want to create, click the button in the lower right corner or select Project > Run Build from the menu bar to start the task.
After waiting for the automatic dependency search to complete, you can configure the project dependencies. It is recommended to use the latest dependencies to ensure the stability of the project, and the build tools only support the latest dependencies.
Select the folder where you need to create the project. After starting, the project will be created in the location you selected, and wait for the whole process to complete and the project will be created.
Config Template
Config template is an extension function, you can select menu bar Project > Config Template > New Template.
And then, you can create a template with the current config, and you can re-create it from Saved Template next time Load the template to restore the current config.
Multilingual Support
The software language follows the current system, and you can manually select the software interface language in the Language column of the menu bar.
(K=GkpPnP(CrQ|6h>QZj{HQ|8Q5 z2+8dJ&U1TzKHs%|YkmLzww8FFbDn+n+55F$XP )>JMlu8?!A98diA zqXto)gp?VdZ|(1=ySBV5(1nrxoL=^rIoCJnjNOV9S6Wba z #R<)u5}l3F9!$eC9P7xVcBm-GgA3?n)&lW7YbteV>!>XU&OA* z?T2u4=r2&E9o0Eq)VYMrPL=s3yZiI@;3&K*xsnQ|5xh@*=V&`7q2Rb$XO}>_R^Qw~ z^ORR8N%uh-Jq(k$ZLc=YmFKt =mv)Au22&sU11E!t}!qK}9 z!$Zc>lu74{6FdtS^{V @6)?RO@)Tg+l=x*8n$?bx_@Nhyhma! zf)+}mM<2S>YhbU$+8Egq!VrW<+_=O>Uv;#T+SxtDUV|x)8Q)PPGm?pz$Z AOys<~){Y579nWHl3Bzzr{Y0RYB?m>?GlJ(|4nkTyGEHTL z+0eCW^*TD!Qj9Q|l&;xyi(s8lY)$8A?Z 9)pIk1lkH$Oy--^o%#nzY7coE6*2jP_dI_P(?e^gb~i^SkCOwGi#t-#C6 z7j=bj^q%{Yk%lDlK3XVe^Rvv-euK=jE8e(vFQJfme?k~6*!$X6dUT4MPUc^W$ql)i z57J2Q&nwZ*?@;?cjNHlT?^>mZmA%9mMF_*}7OJ1+#U96y? 4&PN({1*25LqE`M#b z*@!oo(#Qe4>r^EM*W55KV^TcW%1E58a2T?=sxOLD^v2y&9W`2p!(eG`P6?hf2DfmM zo10GOjq`3FYon0iGmW!^_G_|Txb)QZnm#ZSq<-lF?wa&zP{XcFsbR?NV=WXC6S%Ug zcp=gM_Krn@TcP_!7z`uY7%1;DV_+1xEW2yjj--lJgm;PHR)WV0R$Air*`yNKLB#eS zbHq01R2)<6zafb->9~EJ7s0Z?+3XqdekDLP5Mft?7p006-onXG2ln`HHpmox&Zq{x z<~WUT_r)hqV{vBENtKXZB0|%W+>Y^{flIRcKXpf*erIKfKF=(C5oeBWxt~T12!Z8n zd1n*uIr^fd4E=mH6O+x{4xV$n7^*U^jna8F2W)_%RTUst2|ZBWJpRaf7Pa_CbX^co z%l(X3*_6cG#3#9XEkdhNS3Kj~0S+-D+IO(e3Ft&{ot$O`O1p1ej;iqY^?v(k)U5<~ zcGON+L_XivMiDG<9v%5zu%}kpbco%7d;-(S6)xS%Psh~)W3!i2y(s5Jz_+91q7Ak( zOS>9K7H-TSsewKP-W)N5oDQ4MIX_0pY1Kx)U?%3K3D`Z-%+Gh~uInkP1fm{FjX-uMyAc0|pwdX*n9Z-Pyn^ zTR6SG-g3x%-)S4=ayw5QrpkZHN$;Zuk!YUx80Oz>TMhChhk >4fv39%&$A!QhxjsGIcbwpAV6-do`c0q^NAGb;>X~H1WQ+Sd?=mZnJY6l+_!p m2#sr48#1xJMj0^javoCBP0r1xzhh>aH2t0%x>Jd!1I3Cmc^f z@xpPXhZjM%!!{ZykDckPYacNJ1Bt+=_f?LPHcPfnz9H50wNZ3GIdLvVO;b2?tbgph z^?4X9nt!@y{cVcp+|0))++wtQO401n$M%z4-;$W9GfrvGI>=)%jTie)o#HJE0sFq! zjFr3S$W_7)LS*0RK3#3mACzmQG5~#8X8rHR99y_`yuf{u_Fk7VLc#6exXz F;u-WA-aONtYOK^WN%@^ambtEd05=sK?*qY;UU zz}Di)*F7A% -H^`wRRW^FO#@z&?K zz y*7&~y9TyEYka*w`opL~S-AY%Wl z*>rRCy&sT(G8RfYuAcGQ+A<+grB^~-MaUXDkL+LZAA=ABd;TXWWny2PO8BN6d8hYz zr}E?d*pkXV0s#7qTX~& n`B^5lsO6(L3Yf>Ayv}&YNjP z*=clemra&W(S(;1NKF=5)>j!wJTRx5&%}g(27oa4#(hYAYmL{KZ+?;;Tmqe%MzrO> zFcfJw1|qOapJ!sLrtwN$pOxA4 eK=Y6&Xl~x3Ufh!e)B&L$bKl$hG-2lB zS>ed-@f $h<0rJD#4s&G0w5;v? 29iiIw7{2{h((le) z9ImUb0uOS_wnom_$-F5u>a#Ya8r^jxRB%s6mP^S5-b*6H{-Gy4lN>W+_8i&6*9}l7 zpZCoLmIH1d0?knMho3|LtQI9iYXGCn? b%=kT-3X4YmOiA60M%m0QC zaTc@JGyGl5 D2f9)(&BV^e1@F0S(yN53w%JLL)#QNMdj2`_s|s#vf1_lLlf zo;N>C`Sysv_)3f0K8c@9_-C~{Qf4{Rn=L!Cr((%E7N{!kQ%UYqv2`eqL{&^K2XFc7 z3Jn8Wk2|+4oOL3>0t@?oaWiVp_vatA4VuWAsx!3rewk^#Is<4C;WNLhcog5T`zf#@ z^7@5*K}5j3zk$jbi?ll)V6gM-NxLnxn hN5*3m|ta0R;Mvqt1CPO{?-jKcUN z?ALyrXxYtmkKQF~#vFt+Pv`h;cuRY}!7GI@oNmeVnMHzJ=3H@Bs``Ngio6>40#XT< z8seH%sCAs_9==Ofk2(L&?d-}rSi)f_jc6-T6krZG10M#j ^26eFH3{q^eoFD~(6M z3y0}nnbIiq`5-fsBS*Ib}!*`B_pwwdd33nF_AnRC5#vw_p- zVD+0vXMox4mr$ZBA%++HmTd#6bs8*nu#e{`#DiMVAQWAHe8*;yyveeG~-VnRU-VySWCe_#$^&?d}4*2~E zGtd{I*yzN&!-;k=nSP**YCKbT9|aAa;hx%)&vII-DywJ(g55aqZK`bI&^$B~70h4< z$na{f?EUVFzb#3diJ&%=xw2k=shek@ zwKI}h?39+q0>=+!9 w Ut6^P7YUZe)&WG%Jp#*ltH+~+Ie93Gyy4W)+u#2iKOvB zK_4wKEzoT?zj-jyqkA|w$P9nod~;6@>W@fE)veqn(LEc~JybZ`CfQlL)o6fi%a;`e zjbOz>e( W&I+OUx8ABy}ZsX15Py$*uV)!mM(as=2%XYhZ5ock{537pM7!2MXDc*WFU z0f9a`wfXv(-1U5DiEO#sSN!Hz95g`Z<=PQ|orwo$Ulx>5jmLA@0eA#Fe)~W<*%_b6 zCk>{>Y2pq3S#})|pUA+>&28G~EakH|*;jN`@hw@YiFUS!k~~KfJfg%sVn@)3mhALf z b;1aexH#J3n=(sHOpBQIz`qW_eGg_K0*{N6*)T6?YKrHX72yu@t{!*j$u;GQw zGAC}^z~Dpr%#}LVGl*Sa(TzzCB~LvAoJPk2I_i{BYe6&k{1KMSyu9GLeDlKTP2I9& zybhMvPaKzzhFzIxu91_1M=`3-oN}Y3>D3@R+BfA|UaFFXkc2sJvLQL;+B+7o{fi4B zYxM_$Uh6_ymU^l+IpcC5xPm2zR(igE>iKae>Itu1=YDsci%TYS|3U0%#?oG|Cnv5a zb1=~Egf=>~B?wO&mTIZ>ZVyI2uA{zQLzqkQutFN3Y82-^Lo18mPZ{tS)?F6g^hV4x z(R7gF6||F5&y&i6)U!a?sm?va4>1-y`$Y7s6c-}G^ `IdvxU#;RP|6uEGfD>4qQK6?{BH01Tj?WITe)JERzoOW%Zw|j zm-jrPScq9nBpQVs91u{~F%RPoDaWeM5x%AnLSY)cKO#kIFjAUu2oB$odG6u5P%fit zP;(1!z+cF9hN9m6(wNEc8WIR3(Pn+U+c@WbY#dHn2jv$>yaLHFE{&BFr*s%%jlQ}L zffL4^A&rJVeUE|uesoK+g6hE#gJ2&F8YTMGQ}S1C&u-(*WVEa)fCv~obp?q-!yTyi z^`1Iu=thn%7vdhC>tNixo9v&7x&KL1(YjHOk^1L#qPhX%FaJQr-5JG?NT qR z!jLGj6t=EqJ_OV?)?gH?VlP4rkq2t0(SlVqk^qvLK{+|8LPre67fR+^#Dd{V$cY&o zbF?)76kL#QiRUu}_h91>?YOtPNBE$>-C$eYF{ybN=x>$u-9;7ie-7^2 };FHGAv7d#_y|=2}9=d_=8;0>5BYy4?8>IG`s{B$l*z_L1P% z{?`ObXwdx$t^Y@t3&nZ!Ajdc-OdxitTMypfN?ODLe`F#k%2(O>U2C-ND}JdISMo z3hy 6X_}kLBL#_yb6ELO0#{2k?n?y(%4XHqdXKNgN;g|Qw92I zu47B$ngZmF&YR>auhtZ>e=SV%qy~v=)#~26lV?wjQ>)iKcMmN;qE_`auR_CNDCG>y z%YtQMyWbzc?VX&DFJZdF;+n=D31Cu9r Jx?go7f;X z!~LhKeP{kRkC49^Df;2CM_lA8ospZ-R83sRGF93J45|)tDZeR{ul5>U5i%6m-T%E( zXcRYn?A>+^B)#EEaI&cexwsU{bp~spX1z7@$7uxlbJ<~FyEmuNke q2 z*wHNJRD-(JoW|Cv>CUqVVFK89I4{EPdy)DUt_|7#X2d`KGuhJsfl}(NFT3-;IWL@y z@&L@ap6(|z9$O?uZp9qFpBgamuBkdnd1)b~Q!Juj?Em81OkviwnfU3$4sZ`tQrXB= zQX1)h8WB4@nRAv;og%Ic_FVbdY>-1wQmhLQ52{jjE^`@GTjF4*7wWUcB~9{Buj-f7 zdP=I$qWVqzO*nydupe@}L9R01h*Qtku0)HDkW=w|ks9$gb?F0so_H7kNns7^184 z0T^nNHM2Nf>r$)!a*?$-XLqM2U{9+5ZuJg~wrb}u2mRBGlU#*$@8&hii(scSav2Cz zMc4DTDv-<^zL~oUVoFdOh3%A_7d!v0CC6{veV`-Ge@Z3fN|L%5Q|HO4)DiL|eW-zJ zmI(y^)#n7U`pPw`%7hJ>DNUxvUghrOhM_K4V$K>chssM$Oh2VTbh_~ZV>InndfnjW zW(s)unM}s$RS4Bzpu?UqFfHu!M_rA|O!NF@MPQ4BWtE=N8Z?|Dhy`1~R-_w#j|2Gg zA@C =KwSG0ShdDNwYMIMD-m*H?hV#^cE|MBEf!>s_~Ym3 zu>;b;sOoaOyZh5C>tEn@xOHF}(A9_`TJXody`P$oN}>f dgmb _>m>%C%$@{ko8J_jKIQwbhd zt+p6HE&8?G5?*g}ErHQI{x?O)YhI=;zlWz6+59Ov!up{U`O|yMgWi(m?96#Eka5rK z%QsbX^}ne&{I-_KH=WTy=X0JxM)Pd5y@A*I6BEsV(Tep}V)f0O(yWTIWOBGBil6~^ z!GHsqo;lXHATj>*A@nv~DXml-f9|eMb>LMZ13iX87&g|TMc->B>d!m^lAPDRf5QCo zR%KnQ1`GkaiXn)-N2r|Lbgjov`}c~&;V?TonV2cyjthEeD=*H#QEPl#4_nF#*qW4> zyT{{kj6I+rr90Ag8^t4hA{?&zD!Ze`dCU&SaXMM{kb5;~K) fdyB zOYZ?@V`sA|oGJsUBbtw>)Q-*X9=HRe>jPU%O&erC`wUIO^Q}99M*Cb(n~dA 0V*w=yH@twuIr&`S)_=<*GN?YnOevrlIWZ>k&j&A!an0!B6G+1>xP;xMY8 zKmP7F1qlqMnt^c(ReLwI+X&c3f2wo#rCr(4QW+Ho`&yiboGpHaw8YtQFaMg&%NrTH zzi=l{RrfBb`a=k2F#gw}OA_xLzV{fnSR1qPzb}CpsZ^22kV)aE;!lf|k?cQwpmP^K z_>@tG5LNSqk-pp7=z2uiR07T0O8Jz)XYQf2)9PEqHCaISWWXFeKKoC*Bp)_MA1qX_ zSW)qukBk#O`S5LqEvwYORE1EPE?^2|3wB_VLxC#exZuOnh2-_NsH-RMMft+OG9y?P zXp!1zuYirriwzitQUG2=ntcajzBV9_=by xA?ST8)qZUW4LSSH{_yxQ=Qm}U`R z2os)lZu2l^`XMa{h&aU^G5`Y3K=XyQ`XIOe*tvv4&gxWq^?aCcLjBTMV6&!q$G$4b zOwHK`5P~nYP$F}!Z@2kYGn1?JQd&lkiZzPTcD=nILcHV}#en-d`N>JY`dlk}D@Vnn zF|y;(X8fDem<&u _UCFG5P!5jB3A`c3nbtoH>qZ1*~Fb6U<# zWn-7RZ*sLfrJttDYMz5ZUuR-0{d~=1q4ifuu;F@9HMw2w-_O8+2WQu=%s@E hGk8&LG=gHI=F;bl_t|;yq|T7p3NF zA!d=~x3;$A+{PE?f?a#NAs50^x|UJp>wsq-qF{pOyA!8HdYrMR9P7WUm-L@X%`yl! z81wf 2t2+zDx}W*Nyx4 *DKcjva>k5b>dmJ!)~|z z5IEzPkG{Pg9vc`S=vG8)^XH~N{Q2KMh0vGONvA51kVL8-gX%XVhQ9MAW%hWpK{m)~ z%v_7(zCe9c0aLDXZ%F#Sx#1K6OsOh-(;}dnf#r0s8b?W`dw#fk{a3p0R*z1W&Hf22 z`Z5De)z`l~**$XBX_sq$U$)y4(7{~-0^C1^T)1{Z)jGSM)9l}M>#U+MTVA@ZLoO*x zh8J<$1>5bgk$%?t7Nqyd8K@ X{+NE8Va8NZIjEP+UNQV-mAG@)7xA4?O6v}7#C~fVv*V^DtA()W<3^&JA zzGd!}D-XvKbne?QU#mnS_8OB uvE>_N>qK0M z0U~dK?WtD2e|q7hN*IC{$w0cWN&H64*${aEc2I`#Nl^CjzS>48ZmGBiP3xeSlh%*V z8u@O+Z@YNNa*3~v@L5q@iv^1ndH{JT&9&m#J72pTa<$HLg69iEA#-Ns^0e5y$8Im( zR(^gLwVQFkPcM|H!k_B8!%QJIwkJoY)}797WX@|GJCHV_n%lRSeQ%U6S+Nvw`&~xH zGpn18JTL?$GyHaipYC{bJD{UsNi~-dzT78c7j&NHx`+N4;J}sxJ_9lF5Omw|@l ?*WKdRq|2I zX`zv2$A?}rlYU*u*C4rgdZ~cYkmpVEJxR4bzE{#$8`5J^MkWNrNGRrKT?t`!t)!&m zc}8&_j@4+|upNBLt?{iWXO ?~H1#Fe%~dX)c)d;9?e|X^Y%4AP;YILp%h?M+dEj9ip~R(g*PB+|gqiwo zlq;Ey?-fBfkA@4%heV`lcC53$PX(UX+tb++Ca%S}uae|gB|Yz~UM9|$eUN6wfR^v@ z^3sH%SVag3*s5>a_4jb?$0Qoqp`}bF)8pBu`F|W)&tIXunDn ;hNd-n>Szd%*C+v)!Shy@B~=V48ssa(pK;8P+M3;loYaj}EV^N0 z?DiVCwmf}y)eiWe_%{4man=NgYydfRS;Pe!!@Owy8AKhd`G&vl_;x&gDx&bo#f*8! znahW;tJ=!mc8hy8EH*-vwgx4qPAUoWc
xP=>Ct>M!izQyjR6_T}$3fMRD~6(r#tT-uXs&YP|l6 z;JL_+0-gRapx9JcPF>;najGy+abrnSzqbU)(qA~?LByg6zb!@8$Vd6t7>KIB9qTZ& zD|Cv{J8ubZWGL+dA)`V{Oa$M?Mxves^i)oGO3ijDkSI8Ny&Vet4k4_w424D#2JdYo zMgEFjA}*sJ+HuHM*i!5DspzkqQ_zWzJ49RdD*3HgvU)k;w&n4@;uj%!{`;5D)n=BO zk;u XkW)OgzWz^ws-|Ui+Y`iXqZQ(WKkARN=s8xI7zR-`$@%gi0T+a%_&@YamfD zPuW(fzs;BLfmQU2ZkE3J+i%wW#^YyGHGMYw`dyNE>YzfwZzrd?+wHqTj4+}qwp4re z)POBb(xtxHA3MN-w|qzj24Si^orGqOKFt5QQ+$nrLO8yD=|_w3OuWa<;qlQCiBzwM zL8E|MaM;yQg6CyHF0PYJDk+r};!%q(*wB}`?srE%)#hYc _LpH~4M${ 3^~okF$0z}*;MC>2E$%c?q0_MVdKGp$6rFI zpsWPU)XYOR3xWP+?mW9d#bfHP;9_*u8n>=fJp*B51>_>x>N(dy{`~x&B>LBWZ;Mt+ zIbuwZUYjlYZxcSXar );kt;R5^vQw36tfXv?#$CVu} zIbzg2g1xbf=8xYMU;OS?tv^>J{Vx^?h>2E5b{mI^O!A@`-+4&QhOW0sxjBQx;NJv) z#>19EV1rt0@qe4IHx9;U@`h?6 +gxabSKY{*O{a+ z6$)}v>{ct=w*2oojS2Q${SE_Oc_Xek@lE!I^iMSJm|!Ylu%%b9!G*WmEKJN`E4Vg+ z-%$PpZ>2p@*b>fnYH<%0(dq NLqNVER0k~3+WV25!8POUJo@^eIEqHY? E8=>soNR5I7rZHPS*w3q=%EEnit@ zkT@5q7BYj+pPbPepXC3t`zRZGy&e+pK&tw>V`~}`#mbTw>4jw_VbSE_7{pr-Ift~2 zrpU)}=cw?^BXvy)6@8b7N~K8#uv1YScd1d552!T`*a-d~Mt}Zm{IqfCv0 m;(gFPX%e(G`;j&r^{1_2XI2PQsoHkxA`tW4q|*FPHu*4=wx>NPeBYu=xb ziq}DWM{a;R60~0ylvn=CF?9*rNz}C>Ro4%4s|r7R9I?Le_Y%DbseCRRlOYCj$Q_n? zY3V;DH{2#6K(}U#5 zus|6Z$8DAgL=)?ys=l*9AL3hktQca z>h@EtB5$9xvg!DD;uWp}>+qWbo@_!;vrJANzILMj+U2;@r3<2Yla(gm!9F$j5Q zDqxdkdx`8@*HjCgs?aVTry=w0%TknK-$gG@)8k3Qt%hqNCx}ViY_}*bwaeFT6wqqh z9bD^woK8&fgJb3HS ZUT!H82AxT6QSyB5esdQx&Ais zix)t&2{VoqM_{ `AX6dUYO)^=E>Lj4 zCy-U5jWa8h;8v|%c3;I7Cb99H6S)YTr;y4Q``BcD&{w(;Y46`Aw!sXCw*d>oU^bB# z*G5Y`sq?SvIjzp?o1A#Tj6( )`ZDO z#!TRPu|*c*F20yBJ3~}5F9M)kBi}UIwd>~J?=WH_Qd-?I%%CWtfFB6x1NNY>{=4=G zwhZDwW{xUArbu%YG6*K$#XvNs;~^0dDLogWm3buW?IGjlm+kVlRWHr#d)`X7Rll{d zvVOSw`vWXD3^KZ9!Q?%ag{N;R1J^9&VY8M*0Kv(~YI=Qw;ByZA3}AFA4BvhH-L;gM zZ>%(`1?R6*Qb6xRgO1&cT#FQ4ld)wq9Hi7hKd~~>TYe*Ni4hu&JlLYid*5Fh=PX9` z=r^LgfRSLZCAx{wBmx2=V3e2K`SX|odA}r%`QMG#atm*8y-6zzK4-t<7l6qCM_kOk zJ~q@i6?FLO^6OaUY}0|i4oOZIHB1^WI9=!L=+?SbUK{||xX6WoVg7_21Q?H}jfYA; zgKTFAY=`-ig~>LL l9ZzolE3E2Y$CPSviwOwRh?S>e9;2 z8IceWy>McI+ln;C{Jd&o<)`Zr_MH!Lo8P_X4>ZN9J30<1?)>XogWooFtfHtb=fHfh z9g@G&WjgNLfNmx{C<+F3Z^b&5UZwS(1ucRG2Y50o2tK68ETu)I-F|s@QbaoQvfi&H z2T88(#pmaa3WWkqp&5Q+rGc#u-e8B9n>%2{F4$H`qk`k<#>v8py`DM$mXyH!*$!?P zV_=4pq3sgg397VoWbRW^Rt4x0w+=x*c@g(r_mkv k*7OV(D6fDA|@*9U=W0@TGvq| zx^6$WeQEvGZ=L8-=1#bkRa7sM1_2gMsP){PSdjb4$|*54 %z|vC+(Ei z2H->k*(C3NV{+Ba(Z7eHRwGvHL@Fp961wXES |s4mnlcjYn_nDof`Bh%MDKwZA1mxT={2c?nDt3FqF2|HUix#1zGCch!OV zoBOVGXMu}>3;hj#jn4$%v{A6^s6EnG41xO`HT6k`JScg!#Rs{Ts{iSs!Z{Po`c;zF z%r(c IS**@$20 )CT8j2ieb3l=f;eS3JQ|%KyH2#tSmtV=9x`2y#!82Zjhz-K#CLa1 zy+2Pma>G@hue^iWENeio7^}6Xm&t5)oweZJTEXbsW&c!Os~cpxfcSxw`4KWJR|9R- zxZNjY-`NVy_T@hhWJisJ5YxWH4!ycLbKud_nFJ7MuZ!LxaUIRZw?J@y1rICj$~Mz9 zuVIEhbc7HXgE_sS$T?G}kw)IWAAG}>*dmMLvPCCf=p>O-A`ef5?X!bi&U?IQwsK~1 z@q#pqi_NR|3dQw!nQ^zmhcW>)X206I@cZ8vR7wxLM4Zi$Xm&ph=BS^p{k`?IeGjK6 zZ&|Tde=6Oul=YNi6XVh&g<_pNj3pL=K%vXcaDwZuw;RO FDkBR%%-LQV ctsa<^RMnTHwo#m*2i`tXgnc zXAsd^Q(KbAxe!7dDS5@d(N5cl^GAt3Rx*te4?2Nt+K`gE?V83@lH#}r{qNPK-J2Dz zR9`4f(qk!j=bl%rlqG#OQmOlfE@Ar?eZg?BJ5e@Rm!$}KGV_#juF2Bg;_Q4Pp)MR( z!(k<)DUe{R?rIQP8qpWOpx>xWy(f?qrB@h{LU)fPoi3rZZNI2Mp9TJD0YbD1?!H|g zP_TSX!|s#f GE?ZQKy&(+aFFAh&@}20#Y| z?Qaq-t~dtj6i^!TsD_wo8+)fQY^Uj|?~Si=F #8<#{2p}m_ ITZd`TjU0ySLW3dhtJagE0JNk2Fr{y=tJFTAN-uc9;TLz9_fh`y_^Yr~y zSf$uEM~cOmR0K*Aeaz|JE#DVo`bt8n6ocHhb~%dwpnJtyug+490gL%eDhi&1jXm|# z{74L#n@Lw5ol+@pyz@*%xybm@qq5v*^uwYJcZMDA-U|sNs>t|CN(#*gA#?OsU0pbe zDKMnK_i5ww{r)ge$4$#UeV 2wrdf099cM%69-f0#ru2&t$ z6%5t(BkxuKRMy`(YgFOblf9Pcl3Gb3mKAnqw#wzH3&Uq^VM`3;AU>AC(GM!%)XV!> z)N_^Xx%Gzzs$xvwc=?hsEKs7R8NVt(1_Wn16k(ha~O4B`{bXqoa9wp3pz z7t!DC4L`)5P|UjvN4swKayJm&j&(U)318J}A5^;Tav1M7Pm~NkGe$!f++(u5U>sew znj%nKk7kv+%;Be8kou4$=leHPULixC1l!tuZ<465oC0-TU)sNoDSL(Hq}q# ?H+7|+rg!eBd!dV>GauU8#18Ts+sRe89Ko=*olcy9vlIhDb;tn zFMt}Z+34hfv0uKM-#fQPW!CHL7gkdwb&%v=CssH8uUw$m54&=fPdVIawb@7>qypT2 z*!G5)5aqC4ds*b%@oyWoEPf6@6XPTJI`<&cVs@RtT%iQ-9%p3UMN0OVl)VwTcVXGs zqS-><1y l`!m zQP01bTBc>YlbdZ1Rm2VU1V^e?U&=RU@fBa!sl0UfwX;9V&u@|Zvm6!9Q}0!vdCHXw zw&NQ4DIe?uO$Bw|8-80i)vdBDy&jKxP2#N2K!e~ef~$T78#Ib15z4d`A8ztABcC~e zLpMsNTi>J^)LHyzt~~f-wK*VjXOTjBW5(6=)PFcp&NfFL4j%_TNEQBO#GV}Kqlo p`u|QmDM`x7+v={1g`3$&ha5oGJy2mf~U=} zMLB6=I?;-N!LlZbbv2CR!{U2n#Mz!nWHUO)unE%){IC)|`rUZ)M{`LyY4`OvJx7pF z+(_wOlzKt 8|xnR_FhpirPE{JUs(9bKNQt>sv+3!TYzn*9K&5k!`=3$h}6O9;N zD$Nj9Gm#xf e X1`t%S5ZTQu1 NdH@m=q(SASjey(6Pa}rf|2E$K09icIK2C`9{@XD#EJ>-64F?x}>^NDEZ@zJU zq2b&JsS2yb!`4UVF>V)UqJ7Mx69Zq-Sry}=t8mpHnbE`+avYiQmbX8EZFP-h5fcoY zz3e`};WdO*wcRmCo&@-zd-QrpkV@}upPk=6BOHGQUR1<7lX<_U!#?S)uiDSiOLwMX z<6&Ckc^0&S@&)e%{^XvC_c4!$N<&x{P;@ZsS0hv|ibFi?&S^{?+9^~6*nR#w5@hxS z&yuK`g(%q*5>15_)0!6TtkCT7e_JjlH7Cxl=jq0Gd#9~9oF0lKkP{O@aD#>C;WDZU zEsQ;K^iuDqU6lc^O@Oi_IQNZ1w1+O5-h41%Rc)-$o2xlRwv8Hx-mmP-l|XEavu^dh zT(y(P2Gy1{O z6l_Cl=kD6XzenmB7#LiN={QG|g@Lu+NtHtEaV9R6CV+|~J7MSYJ&sqSgJqS>#zltR zJ#}6r%lg(lf(UO0nxE%`DU9BDuuIHDQ?&@}ZNxB|b$<%7)h$(PYM3i5Hhej)s+Q9j zOvg)+KyLdCrV6BIy>WWpPN~PQM>01!Xe$`KRGiq&K&z^gV}YzuUz@lVca6K*52;q3 zss#u8c@@B&uw46}&VC8YUlkvKJ=h&kN&MRWV)y2Er5qR87;S4%ljwr9cB9-=^YzWK zss-n-H(WCpuFJmbJN7cu*h1%zJEfiD_@IYg3QxBgEHroEwfK1+f#3rfM3r^JkIM|Y z2DdJ41PV>_75b_+y6WdoAn!Q -#rCD}OG#92MW(_!!kqcqPBkax zg@SiT=s+@t@yJhoRr-0WgNrL?OvhXQ#M&-*YV0!LXe O+JOn?eW6EXp1P zB;_BT@(b4>U%dw^^741&>=r-lyO7N*=eL;sfrcrLmvgIe`0 of6?stVd)_znJuGl|ELaV}IbPxrFDVz|zxLr+ByAJ&3n^(dkq7j$alXFb za{L#4!vucNg$`dY0uO*s{^%5U^OAnI2l*u|+8*$5HsC~{maz^O0_3@HRZB{!a#zjk z(#_;jFq$G1_=_CWq7ngiVVEI-1Q&bYG9b=43VH<^v8R^f*GR7)R?6>y`kzkf_LqE$ zN8 MM6v(;}#UjgB_VH7_Yrtb{-7=*>x<|cgL<) S5W?SZ7^y<=bl_ZU=nA`j*Hp$31w#1Wv&xPU{Zxr z+rT}FV5ee6ffr|BFfGzy`_vv6zQ{Q<^U6An za>Jb_bhjc8E9Ds*0~uru26=bxt{hDKHg}N?*S)MdH>07sih=&7L+{D$=gyGtGiVC9 zo*o}ehW9c)BADB>mq-!}vlpIr8hDhe!?SofL~cFdMhZjpWw5)3VdR-vRO37H=JX4j zk}gG(9RJqxY>~=LerGNy$h1*WULz|JMkNa8gGy{L-j|J=1To{v+fOE$OEB5_rKW-@ z8`uG(I%YJ}rnM+rqsz-pke9$vm%_up)Sb2*kG)Bhcv7^m^Q*n%d!JB*eQsF5w0&{Y z)q)kyUX!~9I($c473}|1o|DpHH&NysX&7Et`lBykmT71z$ZnLzaL+BmMqTw`S< K67Oq`OT_YQUA!fbpC7(#|0EAy#?@lx zl1_gaR3;T#E0qk1dzO^je9+doH21ddZLbxl0);S_ARWE{Z9gDd6&Crf>Eq1%%DCbm z&e{(&P@ylN_;wKsJn!h5Gyh1Mk37vz3q_8<>*I2NY%oaYsp`NZ9pPw>eUHot>lzVi z8A#a2FMj2ZY8VAW)TDzMZ;OMk5V#CYM(gsXY~Zu$_E^!{I^R!!-qX8L{9z-ZWFQ21 zz!2Dd6P~mfFs^wF`}|cyEmp-!(c%*HUOzJdQ)H&uM -*PlfB z*DW4oTrdo~(5+yP*@r$%iHc8k7=i~}7OhsfU${J5ghuS_taGhI`r3F5tZJvFF|>O; zIiL8jr#*;FNxrW2=wFX-Zt8iO{VyZoMf{ dmKXTbMLT>nBc_ P+{KLriW|^jLm;3GXtZNb`DxbZ_H(yG$6uO3nY!K^aAdI|kQ=re)yHsXs zpGZLP=bzI22_M`9%3{Baw_DwQV|dhWloW=(r)<@` Ieu#2G@d@TufFLP zuW{a`Zsm@zswvm*@^v`e2NVin2x|ZWeTUz28Ron+s#XPhbB7h8f{X9zy{Co;?CXq$ z4A`mn-%- >wUNNMTd{5Yf=M4F<%RL)3m~%Y$;bzwKfChLQ*Hp4?1dc0OiHKG%(nIv@HLNCk zjQU9Nzt;)&f_r{)r`;)c4N~ggzoOuNhQ@Q?Y=mAG` `GoW4I^QMutik))OxJ9v@i z^+Q9Hq!e_{7BA2K29Ryx;u|^NL^9IvqIfA0YT`N$$YVQVV7NZK{&wMdmwUmMBI5@k zu#_5CsXrn@iGTlBk_TMz4zM{aCuY o@P$mnDS4t;-83*K)k%5n_#RtF1 z*NJd>qkn^Sl9<5lIetb7jkyR76sAuEFG#2O3$pZP s z3_b!;6D%ioS-Y{aQt&gu|6FfrH$J{YGSYSt@(RBy9p81nsIZ Bx?wv5@MvRFWZ!5% `Y@Dio_&C z$r`;3#x}A{V=Ob@?~d>L{=C2QyJtVYd+xpGoXNX#PO085EnTBUDp>+u6xXOD(rGe* z=XN<=*XtI6WVC5ETe8Ox6e+eL;*eQ$P`b#(;-M~{mK&g_FQ8}N6`-OYi6K0x6oC|f z$xZbBZm|k+&MlTeq%>!tTYA@S9U3UzVe0YJ2I~pAq-D{SMC@;d4MXOaNK+w0zaINM z`clQB$aoqCYDdVH#BpQU$KOSrJZvBolWiBl|Cb^;N={b*4~TQDMYA83QAPizs^x)H zm&?kNm4bM+tCcJ6eLo=(lop(mz|j8%>e$DK-CfvmT}G_pnL`R=ew(EMBUxPWlegM) zEk9NqQWT&@I*dl;FUm~vnxm=@#9&wPQ!k+`Zx#JNH2iYS9oY`PRRS~HDr7x#u?%5~ z1G{=Vh8?y)aa|BXq{j5?w-t0M9zL43HPvfgOdGY0ho(@-8lOtU+E1aMg8l8Iwj=3( zeNxioPn>-V1Qj8Ui`)l!Bl1v2A%%MTynwgQ%@V3f`w}W;L|oeTD9DBg{Pu-w(sysT z*dM*F(;fo#k%$c3{+rKRb+x`d3!gS0MlW@YJU0fG4nBSYspxPb-tYh*7`x{J#$F8p za;2K#4NMg{5BFFq?Mc=Yc#hK{TE#Q-2M-n1T1*!{9_N$a$SfEktEb~7fHGy@Wrau? zuFU&)P>pmoY^*H~Y9wB;@O&`Qjy~PB>yMO;TO}9#iBlYcxo)&=-<+{G5LL|kKRK-v zwN~d2c0YOeGbuJ! ;UJC800k< z6|&C%dz-lzbDP^PT=ngJJd-DT8R!V6@U^|{b|vBANev(e=%^*<`+ZQ7ZNSgo2O1VM z_~z%^46_~7k8Wa@NCpz&Mc}_Stfij&{c+`M!s|*&fE|WOchW!vLo9&KSZ&r`Ehzhk zCFdbaO4GGkm*W|h8{56C$0_!;M5^l=$yBt>H?_x{XBXoDJP?Lbi+LX&waVAtv 8(6>0)7xbDIitTYA>T!_r z(5}P!w FF z$yb^Q{`xo_B{_(FX5vQ8`S}C1trBmEgn-}9Xs@7Yrv=T+#=3?cLI3t>amt;p+(TM) z1V4aul0WD)FLy*K`7@Lh!eI4e%Z%5IL&>q5KXQGL0bRd?69z``3`PgkCMp`V`GVt{ zyFK&?mfzyfCLQ!skWIf1DTDcLR@sv+>`5xOU}a4~D|U7)%l+<`7o1D4VEp}OgBTIV zM(n^kkcyojuravQkMG aP5A^@CNtcZDdv>wdxLUIzqNgPDf)y;Ik3 zHmH~o_8d5PvqIoCEr+jZQHk|Hg*MxCTr!jkCLAh`{&?E}e= txm4WVb&~+%?)zrH+2Q4YYMVc%p;WnzuBoZDiM!HrRG(>|( z2XKi>1Ck!snp{5Xy*nL?uP7Q2_*~o}gR?=R*iTaijEMT80Z7!n;popVyK$?_Z*s*G z0)|G?xN!Eez(3x8 )5}0 zUK4E#AN@j%3O4M4AjeLs4J+s4=3MU~i-+q?msjTSpcxQG5Sr@gB8F*GiQvur=M;ar zbkwMNY#O>_uSei6|ETd|w$Y6(c~IQ3W@KTQvjdd#z&yU4QrzHa9ZIthstk}HPu={f zl?xtKFc13Lf}Z{oc8_h>4dKHU#S64~!O^hOEH00I;s~Oy319At^I`uEq2JLGMh+++ z&+eb7$|jf-xntIOkd+Xn5784oz&oS9AAN}c3z)O7S#?W^4OLOtI(gYd4JhX96n=}U z>uDq$6NPjnj) `Yl)0JaM#1O~ z*6UoSYBqdh$thX`p%*cCxfA_4i371u*XAcLWa LRGM95sYF!|GOD*_D>QvPG(RCUuW>R4F}FqG3sjP VKrO(nqt Ay%%v`JHX!mYE%T=X8hOrJ_z|8hC|QVF zS+rWWN#;QDY}vCoFet%^zcY;xEo|z1!M350jT<2r?5?o1DPISB9!*QcW)aM*mWnsL zpNg@00EGE%2<}4SVP4^6oPfU{IK6q5(hNTdIkDY-UP9SZZg=wTdwXOzrel8mbGYdU z7NV4Y^6=N2AinQElFfY7&v#t5jr|CTqmUibbzYr^V=A;tm|qP}9feCl^}5ipZ*3VU zo@2Z}S=e)8!$xD7+@*+BhlV!Txs*9pkq6hB9SWYC@303k^iFLtbv1})0FC{*bueUj086=|rnJ<^Ghn@S|#H)8u1 z|EY-}VnKA$w*D#z0XM-+y0`uUNyQTVczP9G$mx4LC+cz^T0$^XXRon)?b3Q!fr*yS zH#Nk{za;mR%^^A{+Jq4bzT=HAuF?v;O0gai3D?kJ#;l;}n{EJ _qot*{V zx%wqnfj50%_ %o5JX{_>&^w*Q|fXpPz!uE$~L6(C{{oinY6@ z`>Rj)_uRMXODsSENk`PF+CydAifi?3@UP+J&^7c=orLaf#M_l!6{Ll*o%iPU94LoN zDnCD9atWAR=gxnD7USD$73 3CVjD-_??Lul6ASdt{m8^Wbu8^e+O2={Q!0;#@6s zhA>fI_c!lOP#yVMIq_ig0x{0>IW&GIx!{C-P1s(*aUn$2|NF05b+o4cy<3STr9rwJ zz<*oteAV}+M1ty&%T|eQB#sHX)M1#I!SdlX#sFv{Oe#2v=-cdcp(+U`MJ4O-wM+WZ z%KGgQQj=<{FGjuft2XpH>jZfr4BLbDo{&EsXOj|JkO$PC<(mC*tBNr$CKyikK5fn| zV0g2nzzh3A7UGE3dh3*CQ2K`Zwu-TDwsbyQmyxw2vkRVsEmjqKmPdltZ(m+Hl(m&Z zhmJ==E(NV=JLWOM*$QByE^E39rKs}XuuA&-42exA1-8hK Y|3xI+Ail@OFrU!D?R_JG!9hu
qwssxYi4Oh(|FrT#hWMG>mHw#H5xwQiA|?$ ZkquUx!X@Lou!#^O?+kwY=TR-m+% tKcydYcE9Tx~EDa84tJ92%3%?IZ~ z{xd>ps| z`{Exun?kpUld`Ia@ObW!^lE5*AH@hR zi1hUj?7IQ_oGV>sL79ZoRQOPnLvgg@OJBj=?^FDoEYTjdot^ZHar;D7ci?Xhpws8& zbvNR-sVniF`$hs9KX$&FJ15kc5VQ48D&ptzcq;c$=UNEJL{K8QPPN*Z`EuwruHch` z5IpU~RD3w~VqcMWxVM0YOGd|JeXlRO!DN?)oL+&?2jEDDt=y1Y^=;4V3G9ED;(XDl zszXH84A9S>{u$SJMxgu97IqCbh&;^mDtNA-D5~m%pUzdfbv`e-Mq2 BgAf zi1g;M&@}LkZ8Z@-9F~KHXAIE<$XkTV7OiHEf}lZ$rs;afnCH0!EFXy&i*vT* `zPLT^E)kz$3;>urun&1~rHXA$S>`VYXN?%!@Zs*8qbn5UfZQ zW&FC@ huZn$&-Jf1 zg>QXMq+4`>@-)QM bn&C`YtTIn!1TQP7Ie zNY)m52pEUD*#EM-yf8{qS`D$|eNyvEaIGHR{6?heqx*tcw62?tSpMbS5NgnKa;{X) z&c82Wc4oqxXD03EaLAayv72NNEG|zPuz8ml@S5I4b(5mj IEjPVNMr#tr1_0s7aQ4*FDV<0 zDgtjIlFDLRpo4Cc9_d#4YFU~>b*KUlMPOId-T{vHjQS+W)@8xV7ErA~Aza#$Sk31H z4H)Z43mq9q0!dPbcl`y@mw>wH*&gHg)^GU)57V??KoX0z-1P-CKboObfSjUf;M1Y- zy)y29IcQ{3on_sn<-F9($WS$~QJp1aF`mplZrXeN04YX2R8>+*T NqrZ#5@(H7P$@7^Xl8RIC{o&R*63V;Z{w;jZn%m3aN53GE7L1?eWz1C3vw$ix zMvJ`buU2_kZe|8#uemYJQPSdK!4vM(+kbuheX-VesFv7t_GMmbs43GGWWsVjs{A-C z#~h!em(ws%ckmx+W$|{v`}pg{N1 IP#&a((sZZ15`q2G@f5T6X zWXIXW27~T26uN#zae1wX!8;Kg`RIeY%8+f`M^PB&`fEI5Wf#&AQ5{6P!Wn^#<5kdz zLhL=mqu|i)PiAe&5{bMNMtRD}ks(`QSc@-+6&V^k-&zJ`3IA+8AvALPTPPFTVyqx5 zDT>Qt-RZIFPbf=AI@7j%v&z!_SS9Wn)n`J%Ad%pSG2+l|%AwSm%Ad}W)>BC(FFG7c z;HOjLAMY*&>VNa&xq*9uQ`8G=Hg;x`c 3ZvzG=|aPV$ECUswm}SJm0!s znL%Q(W22)*$Zm7J5#DTw`>7+<`zUzTm0OgL@8?SyJ};2&hWbai8ttSBt!(3qn=w-} XpOeE> gwMkM60AXQ+IuZGNk@%JRA>btvF (s50cQl zi=HVM?QTcC1DA=&NTMkcf&!HreV3o8nGdu*z5A}C(DK6Sg^{UuR|#Hz$yC8lj*7y; zL1Bc45e4KpQxUNmSxP6E6K|btCC$9c y{%ThLD(k}M z$2cC2#%j;LCSLMMft9IWnp#|06T~@O88Ev0Rp82_M*+<%9$%{oeNts2U>82|UvOc} zvZMKWALkEd7MAdf^~5+EkO&X_uL+l)f5ybgoe6W=yK^?roRDg%-^BS!uB4l<^pWmN z7`f#QGw`kC_hZD#xaerfjwAG3o0TCz{_2~{cSzdDrvq?0aAqpBZ!B3xD5nO?_HRiN zN#;Ev@}YU|Cfyvqg=2}s{yOhba%zkH&Rnl8jtq|7JMH_iH&VHucZEm4%39)G9i(YH z)-cjZe*K`hrTgQckI)c_mE!Aa-E+;iOmZ-J!dQY#W1K0RDEl}8PaYgYpB25=QTJer zxGb!9@X!mn6>VlXi5D0&vp)s&EGt7?SC)(f8%wLp>vYXM-wIe)PfQfhO9T(@`Sa1- z70+5SPm71NZ R&AS_zkli%B1LE$S1cUiB~wkqXaT>le!JkQ2~6`EcSP?s@I< zair #FqBxx(cm|8FY$47#_5ftz5i77lkgSnu%3;b}iCivk<_~dFA zXX*9FICr9RY4higt~`EGEtM5^eI_d6?DVqGgpkm4W3|fX2RnNnm;b=|0O_Z*9D+V? z{Zd?9OeU-^5_)0s+Qr28DQwOZZ_NKl @C7_A zuAG-S6~6R_FGendW|zl}K`>NT44SdJq`XUW%z~2iHnJgnhAaP*{1q`(WO( u3Kbi%+YcSRV^de{p50x0!gP%L|LI3Uz)vtpEL)E!W++kFweE1D}aGYmB$Q z4~#pcnx&h4Sr+Ig$u^NCi~G`{-I?BzX TE?(ZKB`ju~$NLI!fm9=HJE%+8CS$!&Mcgk9qMBd_;u4AivS(oJ`zCO0zxh}Fk zzc0NWI(kk~a_7U%2k-FTDZi7uM&z$?t*Gg$|IRHmF^agK*o1Gxseb*3?LEGEUS>yg zn-zyjXVL|MQP-Ru7>gxAn)F+QUF@q^^ oNSpo*ywh z2f-V$7 pM{;JXUyPF43HgmVCrzG93y0i-pyHxHP?%rI a=*WL)$Hmz$*y{dx{cyy$dved)K$b)D5;0=kEf!28OMDm042R;MuAB?@^y$^b~BpBFfOWC(Q zqBK=r59H_a_lEQy_3~%%8=e@_HWP ?^aLAhwiN}f@GcUHk&b74# z(=X5)Dm!J?%LGg4gt>8a3d$x7g>^}jMK=hZs=hM%IrC|#<3gM=dpAVWq^<0hQCVq! zS(Q=aBSJ2_(bh`EvkZn;Iwb4Q+`ccB85XuY`AJNOAYvq~WAzV@3@@Wvg!3rYE1pnt zvp73i=ZI2kvbZwgMY2R!B3>E=L2mE7+ 4c3PyU8^!3zKE+#w77p{O-qV7` uEn*^&MIT{W76cG2f&%KQv_3hLp3qJ>KBy-x+d+zb$DjX}#{%y7?K)cHN~4-3lTn zt&QTb_kv@B-X1ACr-Se sd2G9KvV7QY z;uUzdY-H#%`-OwT ra!~RtF_mtJ{D~Sab+t9J|pmSDC_q9Y=-5r sR=m 7-9UX=*uW@lwal%|(zm^r@aNlHuUge>3 z+#$p9>FF%=*${5^u5#p{#39GYoxeoIhttdTrrY={*X^m`ixJh&&F@I)O(y5Kt1+_l z%Idy}$61XOntQl7)5wJCIMSTZ+rU{~UG--@ILD#G_b};wV3h-6jO#WMn)Wz24{5Of zE=Vd-Z{pxwxof7P;h-Ta!)FM!V$nB(8bDZFtZYDQ92@~*7aM&;3y1@`0mQ`2T96W5 z*GNfjW+X_d&LztxYa;?NHIs0&gDAVnsTjIh81foX3JZ}7xbT4vtRN2h ;L9LnFg~+SxeTS^gT_$dDCc39*7$JJ^G^ zPycCaV+wVE+M7cEKf3 }qWIMC>5?4p2K4DAe+ANh$n2WpZ|Q7EbafvigQ**4RbR|Mmz( zRNnz2ND1V|&dkQk%+9XD&d$fi!S|G#k&TCsjqT5-vQQ&4W7q$&DK{TG=f9c)tufMf z(EndHHZtThhT2)_gC(0;>6<`UZLCcw$^Y3%J`t!T)D8>`X2ISIZ*2&X6cwZdo5EsdX2fUw)R4n~myL_rfSZ?{nUjZ$jhV;DfS1{T z<0-c>m!W|%FXx|&1kZ~?4IQzf|ND8P|HJ3y?aaX0)3^M;?gx7!u{y&iVP+4c>H61^ zQHI$5^_Qg?`7br$(>KJbzaXU{R_+iZ%D--#{a^3EpWQl}LO`egKicqTGkd79gR{OJ zX9BkR|Y)3^VWu&LST%YuQe(kog+3*G`3D&R@IGFJYMR2x_h}>4W JPtXn&haOV*>9@nWVVCIFx1;;Qyji=afM$ZC#a+$@`xUramvMDhY9N zGFi?33?>ps*`Mb^8{^>V^;R9*4?{?}&*oSg4=ru|Z>@{hpu~VgC|z&;=V_jWqn`?3 z0rIBEXIr0OXP8lS! $ z_LOr6 3Ou_$9nKP@8585@V@9d-yR+Ly2{#-HG1(sjeUgK zLt8SE_>~*c<25_aCk6PGz0jWCX2=H5x(n3Z7yi@I+kquk+G?!a+VcRF0o&^=W9+H2 zMjh)m`F$CVcz*3a4HKX2Z=k9Qt&o-QteG3T7JhipflNv5d;eNi05uB>%SOC@Q+IUW z{Uvp6uhG=>^mMOpcsKvkkxvGKEy@LGY;jm%olSSg_<^jc=@Rd^Te!csX)9&I$Hy-c zKAMY)?BwX?YZTYe&`>OSfALqNuK`q4R3aQEUfFuyr>dl(bR*N)`#f(6{nFg_R;*SB zvXs@EN}1;8jJhkCEEKHBo -p@Zpn=(=xJ(kRl=&DRtAH7OBFv+VY1p6J8P}5l0=`+1ZtQ zduNxHmO38xP|V{$kSKki%c>n79v*0UCvU{>OJHE&4Ji-oyc*``=fR4^L`5(2Kfrmx z?zo~dKQ}khPxa~(4@JZMp+e0J*PVsY{v>|q-mh;>2FA`B&yFpu#;bdi8>ZgfjEag< zvA~>DwRUt2BsoveR3VuqYj^vk9ZvU#ukkWqmrhsBtEkvZ@Im10M}H9-zS#8|Wj_(G z+OBz+WcRRBT?Wo3<}cog|CqMIlpdHVeEdAqmS^)Yy&Rns&)in!YYf}vWe>dUVqXVm zFkNw1U+LM0Mpt<@q-QWU`}xx|35nWqMd6AtFevDsnUlz!$}U?7DZGDXLZ3c3nolsi zm;1w+jZu2p-HB1q5N42`q1x!>DJI_Xgp*0sj|TtYLxx6jy=!H+%v-uh%= |esQ?lUjA7^ zt{;%aN*#Iu*`K|fKY01LJ-VRWVOhzYkA`MGm%4{eJ~_R~|F+rL37SR{ST99w?L@eM zkdSU$Tbuc0!~5?|tAnlr^P1(RUy=l3Gmmx}>E2=u2KmTCtca#5n6)aGnCWxA4>HnQ zbP@0!4lV{VGpIO}EwIaoL>RS&QAo!y5vHZxz{69NFv@&fjbhL^3u5=u%lrH-mf`p$ z$bvD-=ayA+)|w;7AP>8=ZGd8geruS~sD%dmOYIwYd9V=)`s{G6n$erlHI_B$e7eO~ zC1VH7Jj~3@q);`=y-%M?nIqL$V(CL6tzqI36md$Xrh>k{gUTu@ &a51O*ai27+YS2UGcaQGor&}RK;fFIp?d|QQi>KQN*vfc~{nsBGT2Oe_V8QT6 zKX9)D!Q2xrDh7h#%o>|;JG)!F3rV&=3C;VnWowX~$%0xt3!aOg2?z+B2ktL (-yuXcuSTCyTU%kVwfm<4O^~&CJd=2Zw9lVQ1m`WA?dH@>d|Y zgEM7nQ=@%)b~ZJ+-H~8Td=}6$+Xf3xB0XHATK8OZ @N%T*vk zt8|>f%c?C*dM{(OKrHg&`uUzJXsv6qwLbDiCxP2at!$xlutc#?ra!91u&tziv1@j# zb#}isLYx#qRfUBUgC+Wf@mv=9om$T >=(NRh0nGuzs|WzBCDXoBVT6A z^_%=M?r5SkDlOv{Ix$^m$U0}e5|NkqqOV?=|M-|dymO0GAU9O#xO$)#XqGK?H;vg` zD^jJ=>$Dd4F62qvBUXA=Rz2a9&8FV#SLXp>INnFPx*g5OlBiCJE8E$XS~s|U7^{N9 zIJ${*r<+2PR(3vpf`@pE$1rO>Tnhu+ibH&bG&IL%qiS-WEtXj;#wgx67_-jDvv_m; z+$H{Xr6rB8pH!)l3lm|CZRYX#c59ecgm{d8YYBBm^)B*{>#7AYR^{G5-P@0k8@cdu zqC^smm#6ac%#p=upV(rV5MkU8puY9oY2KL+Q4C!eEz(edn9MMR3Nxg}Xk%jmXdZ1F zwIVGo-M??eKkzKC===ATw)K4%!x8~I#P&~eNk4$jm=Nw>%!r5 tr `s{cGqegGiWCD&>8WV@;w#J08bcDWZ z )PuEc6^otmdt~r~33sP-L1AG%tV>UTl2S;vx3%^D3{F_vGc+`e`usT;*jkIh zeATfphW_9{WM8;+l_$h;sRx+R{W5m;zUWAM2`oS_P-7khj^RcfURP)5V5Jo@Dn34c zU_eDoOsoJ Q$E*x28~OVBMvpmx7GvdRkpS!z z^z 0My?Mh!@&;TKO}Sj8zgWGzQFLl|bv$t51)nN5nM`th~G$)L^ E>ym6oIFj;ljvlMSBW=$emLe;KQ^Du|R9s`+kpo0umRz%~oa{`y#> zurhX{t3wm+>FKsD7TcQbU0p+g_>57>$!W)XR0Fk+t5VHcs-vT$$Mdmz13B_3K8Qw) zwQlr5Tx@JkiuakO`+g>H4(|g)LX@<%@9(XRiYO{7;#)U5t-rRKY|!E5^^Xec(WXms zP|Dg6o;(PU2fHMdw8&*K^hCHZb=;95gQdaSgVba5MTNz1SF)TmGK)aZLs6@e_(;1u zfm?o9mtO`r`-t|lhS5r^gi}}aWMj(A>?}!3{z?Ua24T-EM@;3f9eZu*Rn;Ce&cSa# zgH9B7bjSet<$-ldNl7Vzc!6XUVr*=V*(U+g%rNwlldFtjJ(rCbsJ5l5FdxkSZiq#a zJVMPsemu$4g|o$FYvxmCF_aQ`6uc7iWq&-tx{(jBjzDh1cb&Mb+qP*v@bvg}nzJUv z8G4IK6q*<2S9;#LR>V9PE?+0&G7n?+ IuO $Xh8XY;19;c!L*svvxR zQkL{wugW?p+0{55UML>=Ajxe72Y$R#u =~06I?7bJsJ9)W?Aa~o zT%epImldNKlLfHT3d(tsx$N~`dH>ZVdGF&$D#EjI`|jw+k(v=gC!185y-dk&{+}Y< zt*t#j0?vED5tFhqdE|$+c&A6*-o;8vg|%C;i@=pTP}h@sd%QF5I*|brv(Iz9cAK (XtiR}W#ejXcpo#qA+}zTa7FwSDotYrkT!4r7cY(zyH)xh} zcN?#^m68l7njX(oMU`I%Ne*`Qmi#x6RBMJGQqliKsFrp%-SfC(`G?Lu7NZXknL zYBkQ!4jM_?oZB!y9%%SMuKnWI?ljB+dKf$LY}tg1Eb vp@w=Xc#7CA|(~{!4janb1F$A& Yh)O0P7#<0K4(qBIE78xG#bj9w zvp8KM^yaELS5{W$vYioKAFJS>+6H1U@A%yKgqHSIL{;qNb2M>EdAW{LVNUXx9o5SUYjc&|AZpSyMk~L+if6}!0IECP z ivdc_>Pa9)f!XM{nm@CJ_jc2M^S6jrX&JHHMh2LyzZ_}1GobDr) zb_(oe`JC34BsjCPvw80sSq#T`8EcjOJW8Acg#_2H_X3qr`B}$c)sy;Sr6=vZ;lw~5 zdIg*woBGhRQ%oLovH^dCRZvi;Tlic%Z?0yJq;~3Pk&d2 ~I!B+f4&~ zw+_yZDZnFHF@n22O~3A41k{3?D!TF9D-XhT#8jm5MG1f#`e=dJ`rw<%?i;Qk#Ev0U zcRV>>h4I-;J o$ zA)9nu9K)okl;vWsrQ><7@(SR5Db)`q#>O!