㈠ 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运行起来比较简单,但是真正将它用到实际项目中还是要考虑很多小细节的,目前我也正处于研究阶段。