㈠ android Studio自定義加固插件
Gradle自定義插件
我們新建一個名為JiaguPlugin的Mole
調整build.gradle為如下所示(這里我使用Kotlin開發)
創建一個JiaguPlugin類
然後創建resources目錄並創建插件的配置文件
配置文件的內容如下:
1)創建一個擴展
這里我們創建的擴展名為jiagu,這個就好像app下build.gradle中的android擴展一樣
我們擴展中的參數是JiaguParams中的參數
2)添加監聽
添加一個讀取完配置信息後的回調
然後我們先將我們的插件上傳到Maven倉庫,也就是執行插件build.gradle的這個Task,這里我上傳到了項目下的Plugins文件夾下
然後我們在項目的build.gradle文件里引入
加固的任務類JiaguTask如下,這里的命令是參照文章開頭360加固的help文件:
4)配置加固信息
我們在build.gradle文件中配置好我們的加固信息
5)進行加固
首先我們先make一下項目,生成apk文件
https://gitee.com/itfitness/jiagu-plugin
㈡ android插件化(四)Hook載入插件APK(ClassLoader方式)
前面插件化一和二說了下插樁式載入未安裝的APK,主要是重寫了getResource和getClassloader兩個方法來實現的。以及每個組件要實現一個介面,通過介面注入上下文來達到它的生命周期。
那麼插樁式和hook式的實現方式有什麼不同呢?
插樁式是怎麼載入到插件中的class文件呢,是通過將將APK轉化成插件的Classloader,然後想要載入插件的class文件,我們的去拿這個插件的classloader去loadClass。所以是有一個中間者的。
hook式呢是將插件apk融入到了我們的宿主apk,那直接在裡面就可以直接loadClass了,在不用這個插件的ClassLoader了,這樣的話對於插件和宿主就沒什麼區別了,不像插樁式有一個中間者。
那麼要實現hook式 就要知道android中一個class文件式怎樣被載入到內存中去的。其實就是通過PathClassLoader來載入的。
那麼我們先看下ClassLoader
任何一個java程序都是由一個或者多個class組成的,在程序運行時,需要將class文件載入到JVM中才可以使用,負責載入這些class文件的就是java的類載入機制。CLassLoader的作用就是載入class文件提供給程序運行時使用,每個Class對象內部都有一個ClassLoader來標示自己是有那個classLoade載入的。
Android app的所有的java文件都是通過PathClassLoader來載入的,那麼它的父類是BaseDexClassLoader,還有一個兄弟類是DexClassLoader,那麼他們有什麼區別呢。
從上面可以看出這兩個類的構造函數不同。(在26的源碼中DexClassLoader中的optimizedDirectory也廢棄了)
PathClassLoader:用於Android應用程序類載入器。可以載入指定的dex,以及jar、zip、apk中的classes.dex
DexClassLoader:載入指定的dex以及jar、zip、apk中的classes.dex。
可以看到創建ClassLoader的時候需要接收一個CLassLoader parent的參數,這個parent的目的就在於實現類載入的委託。
某個類載入器在接到載入類的請求時,首先將載入任務委託給父類載入器,一次遞歸,如果父載入器可以完成載入任務,那麼就返回,只有當父載入器無法完成載入任務時,才自己去載入。
因此我們自己創建的ClassLoader:newPathClassLoader("/sdcard/xx.dex",getClassLoader()),並不僅僅只能載入我們的xx.dex中的class。
需要注意的是,findBootstrapClassOrNull 這個方法,當parent為null的時候,去這個BootCLassLoader進行載入,
但是在Android當中的實現:
所以new PathClassLoader("/sdcard/xx.dex",null),是不能載入Activity.class的。
上面分析了載入了一個class,是利用了雙親委託機制,那麼要是都找不到那就開始調用自己的findCLass方法
在ClassLoader類中findClass:
任何ClassLoader的子類,都可以重寫loadClass和findClass。如果你不想使用雙親委託,就重寫loadClas修改實現,重寫findClass則表示在雙親委託機制下,父ClassLoader都找不到class的情況下,定義自己去查找一個class。
而我們的PathClassLoader會自己負責載入Activity這樣的類,利用雙親委託父類去載入activity,而我們的PathClassLoader沒有重寫findClass,是在它的父類裡面。因此我們可以看看父類的findClass是如何實現的。
可以看到載入PathClassLoader載入class,轉化為從DexPathList中載入class了,那麼我們看看DexPathList中的findClass
那麼從上面分析得到
到這里我們想要載入一個插件的apk ,其實最終載入的是一個dex文件(先說class文件,載入資源後面說),有沒有辦法吧這個dex文件給轉化成一個 Element 對象,給放到 Elemeng數組 當中,這樣直接就可以載入我們插件中的類了。
1、首先我們肯定是要得到插件APK的的中DexPathList對象中的dexElement數組
2、插件的dexElements數組我們拿到了,那麼是不是要開始拿我們系統裡面的 ,我們反射獲取,和上面的一樣。
3、上面我們獲取到了系統和我們插件的dexElement數組,然後我們將這個數組合並到一個新的數組裡面去,並且給注入到系統裡面
至此,載入插件的一個流程基本就完成了。但是上面只是處理了class文件,沒有處理資源。資源的話我們也是採用hook的方式去實現
在宿主的Application中hook這個方法,然後去重寫getAsserts和getResources兩個方法:
然後在插件的BaseActivity中繼續重寫getAssets和getResources兩個方法
這樣就可以完成hook式載入一個未安裝的APK了。至此基本就完成了插樁式和Hook式插件化的基本實現。(後面幾篇是優化)。
㈢ Android的apkplug插件開發具體怎麼編譯生成插件 apk 文件
步驟1:注冊ApkPlug官網賬號:
打開Apkplug官網後,點擊右上角的「注冊」,在跳轉頁面填入相關信息,注冊界面如下:
確認後注冊成功,使用你的賬號登錄網站。你就可以用Apkplug開發應用了
END
步驟2:開發插件
Apkplug中的插件也是一個完整的apk,它與普通應用的區別有以下3點:
1, 插件assets目錄下有一個plugin.xml文檔,通過它可判斷一個工程是主應用還是插件。
2, 插件有一個入口類BundleActivator
3, 插件會外部引用一個osgi.jar文件
開發插件的步驟有如下4步:
1,引入osgi.jar庫文件
Apkplug中插件需要導入的庫文件只有一個osgi.jar。
導入osgi.jar庫文件需要注意一下
osgi.jar文件只能引用不能編譯到apk文件中,否則會出現類沖突的情況
異常代碼:had used a different Lorg/osgi/framework/BundleActivator; ring pre-verification。
osgi.jar包導入方法:
這文件在Apkplug SDK中可以找到。
2,編寫插件入口類BundleActivator
插件啟動時首先調用BundleActivator,其功能類似android中的application類。
public class SimpleBundle implements BundleActivator
{
private BundleContext mcontext = null;
public void start(BundleContext context) throws Exception
{
System.err.println("你好我是插件,我將為你展示啟動acitivty我已經啟動了 我的BundleId為:"+context.getBundle().getBundleId());
}
public void stop(BundleContext context)
{
System.err.println("你好我是插件,我被停止了 我的BundleId為:"+context.getBundle().getBundleId());
}
}
3,編寫plugin.xml配置文件
plugin.xml
是一個配置表,它跟AndroidManifest.xml作用類似。 plugin.xml文檔放置在assets中即可 重要屬性說明:
Bundle-Name 插件名稱 Bundle-SymbolicName 插件包名
-與應用packagename可一一對應 Bundle-Version 插件版本 -1.0.0
Bundle-Activator 插件入口 -與Appliction 類似
Bundle-Activity 插件界面 -多個Activity可用 , 分割
Bundle-Service 插件Service -多個Service可用 , 分割
(v2.0.0新增) Bundle-Receiver 插件廣播 -多個廣播類可用 , 分割
(v2.0.0新增)
4, 編譯生成插件apk文件
插件工程中添加的文件目錄結構如下:
最後編譯運行插件工程,生成的apk文件即為插件文件
END
步驟3:開發主應用
Apkplug 主應用開發分兩步集成:
1. 獲取主應用授權AppAuth。
登錄賬號進入Apkplug後台後,切換到「應用授權頁面」,按要求填寫好應用信息,然後確定,你就擁有了一個等待開發的應用授權AppAuth。應用授權界面如下:
進入「授權列表」頁面,點擊「查看詳情」鏈接,進入「應用詳情界面」,就可以看到已申請的AppAuth,點擊其後面的「復制」,即可直接復制AppAuth,如下圖所示
2. 對接Apkplug SDK 導入相關庫文件。
①配置應用許可權
主應用需要幾個基礎的許可權配置,請將以下的幾個許可權加入到主應用的AndroidManifest.xml中。
<!-- 插件平台需要的許可權! -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE">
</uses-permission>
另外將一下加入到<application></application>節點中
<!-- 插件平台需要的配置! -->
<activity
android:name="org.apkplug.app.apkplugActivity"
android:theme="@style/android:Theme.Light"
android:configChanges="orientation|keyboardHidden"
/>
最後將我們從Apkplug管理後台申請到的AppAuth加入到配置文件中。
<meta-data android:name="apkplug-auth" android:value="xxxxxxxx" ></meta-data>
註:由於3.2.2節中我們直接復制了AppAuth,此處直接粘貼到AndroidManifest文檔中。
如下圖:
②導入SDK庫文件
主應用需要導入兩個文件,將其放入libs目錄中即可。
1, libndkfoo.so
2, Bundle2.0.0.jar
如下圖:
這兩個庫文件在Apkplug SDK中可以找到。
然後:
主應用啟動Apkplug最簡只需要一段代碼即可,建議在Application中啟動框架。
FrameworkInstance frame=FrameworkFactory.getInstance().start(List<BundleActivator>,Context);
將上一步驟開發好的插件apk,放置在主應用工程里的assets路徑下。
如下圖:
END
步驟4:啟動主應用
最後啟動主應用即可。簡單的插件化apk的方法就講完了,有興趣的關注我,下次講雲端託管插件實現應用內更新。
㈣ Android 插件化
原理:實現原理上都選擇盡量少的hook,通過在manifest上預埋一些組件實現四大組件的插件化。其中Small更形成了一個跨平台、組件化的框架。
VirtulApp:
能夠完全模擬app的運行環境,能夠實現免安裝應用和雙開技術。
Atlas:
阿里出品,號稱是一個容器化框架,結合了組件化和熱更新技術。
Android中有兩種類載入器,DexClassLoader和PathClassLoader,它們都繼承於BaseDexClassLoader。
兩者的區別:DexClassLoader多了一個optimizedDirectory的路徑參數,這個目錄必須是內部存儲路徑,用於緩存系統創建的Dex文件。
所以我們可以使用DexClassLoader去載入外部Apk中的類。
ClassLoader調用loadClass方法載入類採用了雙親委託機制來避免重復載入類。
首先,ClassLoader會查看自身已經載入的類中是否已經存在此類,如不存在,然後,則會使用父類來載入此類,如不能成功載入,則會使用自身重載於BaseDexClassLoader的findClass()方法來載入此類。
DexClass的DexPathList在DexClass的構造器中生成,findClass()方法則是從DexPathList下面找出對應的DexFile,循環DexElements,通過dexElement.dexFile取出對應的DexFile,再通過DexFile.loadClassBinaryName()載入對應的類。
作用:使用插件DexClassLoader載入出需要的類。
通過每一個插件的DexClassLoader載入出自身所需要的類,當每一個插件需要載入相同的類庫時,可採用該類庫的不同版本來使用。
通過把每一個插件的pathList(DexFile)合並到主app的DexClassLoader上,來使各個插件和主app直接能夠相互調用類和方法,並且各個插件中相同的功能可以抽取出來作為一個Common插件供其它插件使用。
插件調用主工程
在ClassLoader構造時指定主工程的DexClassLoader為父載入器即可直接調用主工程中的類和方法。
主工程調用插件
如果是多DexClassLoader的情況,則需要通過插件的DexClassLoader載入對應的類並反射調用其方法。此種情況,主工程一般會在一個統一的地方對訪問插件中的類和方法做一些訪問許可權的管理及配置。
如果是單DexClassLoader的情況,則可以直接調用插件中的類和方法。但是當多個插件引用的庫的版本不同時,會出現錯誤,因此,建議採用Gradle版本依賴管理統一處理主工程及各個插件的庫依賴。
Android通過Resource來載入資源,只要有插件apk,就可以使用assertManager.addAssertPath(apkPath)的方式來生成assertManager,再使用其new出對應的Resource對象即可。
注意:由於AssertManager並不是Public,所以需要通過反射的方式去調用它。並且由於一些Rom對Resource的處理,所以,需要兼容處理。
有2種處理方式:
產生的原因:由於主工程和各個插件引用的Resource id重復產生的沖突。
解決思路:Android中的資源在系統中是以8位16進制0XPPTTRRRR的方式存在,其中PP即是資源區分的區域(Android系統只用它來區分系統資源和應用資源),只要讓每一個插件的PP段取不同的值即可解決資源id沖突的問題。
具體解決方式:
1.修改aapt源碼,編譯期修改PP段。
2.修改Resource的arsc文件,其中的每一條都包含了資源id和映射路徑。
Activity的處理最為復雜,有兩種處理方式:
1.ProxyActivity的方式。
2.預埋StubActivity,hook系統啟動Activity的過程。
原理:VirtualAPK通過替換了系統的Instrumentation,hook了Activity的啟動和創建,省去了手動管理插件Activity生命周期的繁瑣,讓插件Activity像正常的Activity一樣被系統管理,並且插件Activity在開發時和常規一樣,即能獨立運行又能作為插件被主工程調用。
Android插件化方向主要有2個方向:
Android 插件化
㈤ apkplug是什麼
ApkPlug是一款好用的Android平台下的模塊化、插件化開發框架工具。
ApkPlug可以幫你減少apk應用代碼,縮小apk應用體積,同時支撐動態載入、應用內進行更新升級,支持第三方插件接入,為你開發APP減少人力和時間成本。
有以下特點:
完美支持Android原生四大組件。
插件化apk:多個APK在一個APK上運行。而且APK無需改造為插件。
插件異常隔離:再也不會發生因插件奔潰而導致主應用隨之奔潰的情況。
類ip地址傳送數據更方便快捷:新增主應用與插件,插件與插件之間類似ip地址傳輸的數據流管道通訊方式,使其之間的通信更簡單快捷。
開發一般有3個步驟:
1,注冊開發者賬號,獲取應用授權AppAuth。
2,插件應用中導入SDK和配置文檔,之後編譯打包。
3, 主應用中導入SDK和配置文檔。並放置打包好的插件應用APK。之後編譯打包啟動即可。
㈥ 安卓上安裝後是視頻的apk文件需要什麼插件
我還沒懂你的意思,你跟我講一下這個文件的後綴名是什麼。就是.RMVB這樣的,告訴我,如果我沒回復,請加我企鵝。
㈦ Android插件化突破應用市場無法上廣告的問題
先簡單的描述一下在廣告方面遇到的問題.
開發一款App有了一定的用戶量之後通常會想接入第三方廣告來實現變現,
然而在很多市場不讓這類帶廣告的App上架,除非接的是他們家的廣告.
在這里我只能呵呵了.這點困難就想難倒我們.
那接下來ShowTime.怎麼做呢?
沒錯,就是插件化.
以廣點通廣告為例
這里我使用的是360開源的 RePlugin ,具體介紹和使用方法請看官方文檔.
一. RePlugin插件接入指南
第 1 步:添加 RePlugin Plugin Gradle 依賴
在項目根目錄的 build.gradle(注意:不是 app/build.gradle) 中添加 replugin-plugin-gradle 依賴:
第 2 步:添加 RePlugin Plugin Library 依賴
在 app/build.gradle 中應用 replugin-plugin-gradle 插件,並添加 replugin-plugin-lib 依賴:
接下來您就可以像正常接入廣告那樣,開發插件。生成出來的是APK,既可以「安裝到設備」,又可以「作為插件」使用。
二. RePlugin主程序接入指南
第 1 步:添加 RePlugin Host Gradle 依賴
在項目根目錄的 build.gradle(注意:不是 app/build.gradle) 中添加 replugin-host-gradle 依賴:
第 2 步:添加 RePlugin Host Library 依賴
在 app/build.gradle 中應用 replugin-host-gradle 插件,並添加 replugin-host-lib 依賴:
第 3 步:配置 Application 類
三. 宿主App 調用 插件廣告
1.編譯插件廣告,將生成的xx.apk包重命名xx.jar
將 xx.jar放到宿主App的 assets/plugins 目錄下 , Replugin將會自動獲取該內置插件
2.處理廣點通開屏廣告
由於廣點通開屏廣告的展示點擊都由SDK封裝處理了.
我們這里採用的方式是,由宿主跳轉到插件的閃屏頁,在插件中完成請求,展示,點擊結束後回到宿主的主頁面.
(1)宿主跳轉到插件Activity
(2)插件開屏廣告請求處理,就按正常的廣告邏輯走
(3)插件回到宿主的主頁面
(4)宿主的清單文件中添加必要配置,否則廣告無反應
注意 : 盡量使宿主和插件的包名一致,已避免廣告無收益
3.處理廣點通原生廣告
廣點通原生廣告不同於開屏廣告,其展示曝光和點擊曝光都由自己處理.
我們只能通過反射的方案去請求廣告
(1)在插件中先對廣告請求做一層封裝
(2)宿主中反射LoadManager的requestNativeAD()方法
a.拿到插件的ClassLoader
b.取得需要反射的類
c.由於請求廣告的requestNativeAD()方法中有一個參數是介面.
(這里得使用動態代理)
取得被代理介面
d.接下來就是反射請求介面了
注意傳入的Context必須是插件的Context
e.在動態代理中取得回調
這里我使用了EventBus將回調的廣告傳到請求的界面中
點擊曝光的反射
四.最後,第一次寫文章,歡迎點評
宿主App : https://github.com/AndWong/RePluginHostForAD/tree/master/app
插件App : https://github.com/AndWong/RePluginHostForAD/tree/master/pluginApp
㈧ 怎麼將 Android 程序做成插件化的形式
有個框架叫apkplug
就是apk插件式的開發框架
其實原理都一樣,因為android不支持動態的增加jar
因此插件需要做成一個單獨的apk,框架APK去查找系統中的其它插件
然後結合一起調用即可
㈨ 新一代Android渠道打包工具:1000個渠道包只需要5秒
♥♥♥ 原文轉自 極分享 更多詳情及更新 查看原文 ♥♥♥
最新版本
v1.0.4 - 2016.01.19 - 完善獲取APK路徑的方法,增加MarketInfo
v1.0.3 - 2016.01.14 - 增加緩存,新增ResUtils,更有好的錯誤提示
v1.0.2 - 2015.12.04 - 兼容proctFlavors,完善異常處理
v1.0.1 - 2015.12.01 - 如果沒有讀取到渠道,默認返回空字元串
v1.0.0 - 2015.11.30 - 增加Java和Python打包腳本,增加文檔
v0.9.9 - 2015.11.26 - 測試版發布,支持全新的極速打包方式
源碼:https://github.com/mcxiaoke/packer-ng-plugin
項目介紹
packer-ng-plugin 是下一代Android渠道打包工具Gradle插件,支持極速打包,1000個渠道包只需要5秒鍾,速度是 gradle-packer-plugin 的1000倍以上,可方便的用於CI系統集成,支持自定義輸出目錄和最終APK文件名,依賴包:com.mcxiaoke.gradle:packer-ng:1.0.+ 簡短名:packer,可以在項目的 build.gradle 中指定使用,還提供了命令行獨立使用的Java和Python腳本。實現原理見本文末尾。
使用指南
Maven Central
.
.
.
.
.
實現原理
PackerNg原理
優點
使用APK注釋欄位保存渠道信息和MAGIC位元組,從文件末尾讀取渠道信息,速度快
實現為一個Gradle Plugin,支持定製輸出APK的文件名等信息,方便CI集成
提供Java版和Python的獨立命令行腳本,不依賴Gradle插件,支持獨立使用
由於打包速度極快,單個包只需要5毫秒左右,可用於網站後台動態生成渠道包
缺點
沒有使用Android的proctFlavors,無法利用flavors條件編譯的功能
文件格式
Android應用使用的APK文件就是一個帶簽名信息的ZIP文件,根據 ZIP文件格式規范,每個ZIP文件的最後都必須有一個叫Central Directory Record 的部分,這個CDR的最後部分叫"end of central directory record",這一部分包含一些元數據,它的末尾是ZIP文件的注釋。注釋包含Comment Length和File Comment兩個欄位,前者表示注釋內容的長度,後者是注釋的內容,正確修改這一部分不會對ZIP文件造成破壞,利用這個欄位,我們可以添加一些自定義的數據,PackerNg項目就是在這里添加和讀取渠道信息。
細節處理
原理很簡單,就是將渠道信息存放在APK文件的注釋欄位中,但是實現起來遇到不少坑,測試了好多次。
同類工具
gradle-packer-plugin - 舊版渠道打包工具,完全使用Gradle系統實現,能利用Android提供的proctFlavors系統的條件編譯功能,無任何兼容性問題,方便集成,但是由於每次都要重新打包,速度比較慢,不適合需要大量打包的情況。(性能:200個渠道包需要一到兩小時)
Meituan-MultiChannelTool - 使用美團方案的實現,在APK文件的META-INF目里增加渠道文件,打包速度也非常快,但讀取時需要遍歷APK文件的數據項,比較慢,而且以後可能遇到兼容性問題
MultiChannelPackageTool - 將渠道寫入APK文件的注釋,這個項目沒有提供Gradle插件,只有命令行工具,不方便CI集成,使用ZIP文件注釋的思路就是來自此項目
轉自 極分享 閱讀原文
㈩ 什麼是Android插件開發
插件化開發和組件化開發略有不用,插件化開發時將整個app拆分成很多模塊,這些模塊包括一個宿主和多個插件,每個模塊都是一個apk(組件化的每個模塊是個lib),最終打包的時候將宿主apk和插件apk分開或者聯合打包。
開源的插件化框架
Qihoo360/DroidPlugin
CtripMobile/DynamicAPK
mmin18/AndroidDynamicLoader
singwhatiwanna/dynamic-load-apk
houkx/android-pluginmgr
bunnyblue/ACDD
wequick/Small
……
目前開源的這幾個框架有宿主和插件分離的也有融合在一起的,每個框架的詳細介紹和demo在github里都可以查看到。插件化demo運行起來比較簡單,但是真正將它用到實際項目中還是要考慮很多小細節的,目前我也正處於研究階段。