最近为了解一个盒子上app在我们平台上无法工作的问题,去浅尝了反编译apk并在smali中注入代码,推荐一个叫Android Killer的IDE工具,几乎集成了所有反编译和打包的功能。
同时也了解该app使用的插件加载,之所以会使用到插件来完成该功能,因为该app涉及到底层的audio实现,audio在framework会在各家平台有不同定制,利用插件就能保证对主程序来说平台都一样,而插件就根据各个平台的不同去做不同实现。
下面简要介绍一下该app的插件实现方法:
1、插件也是以apk的形式存在的
先来看看插件的Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest android:versionCode="1" android:versionName="1.0" package="com.kelvinwu.earlycmccplugin" platformBuildVersionCode="19" platformBuildVersionName="4.4.2-1456859"
xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<meta-data android:name="IPlugin" android:value="com.kelvinwu.cmccplugin.EarlyAppEvent" />
<meta-data android:name="IMicrophone" android:value="com.kelvinwu.cmccplugin.MicrophoneController" />
<meta-data android:name="IKaraoke" android:value="com.kelvinwu.cmccplugin.EarlyISingEvent" />
<meta-data android:name="IAudioTrack" android:value="com.kelvinwu.cmccplugin.AudioTracker" />
<meta-data android:name="IAudioTrackProfile" android:value="com.kelvinwu.cmccplugin.AudioTrackProfile" />
<meta-data android:name="HardWareLevel" android:value="2" />
<meta-data android:name="Manufacturer" android:value="kelvinwu" />
<service android:name="com.kelvinwu.cmccplugin.PluginService">
<intent-filter>
<action android:name="com.cmcc.karaoke.plugin" />
</intent-filter>
</service>
</application>
</manifest>
可以看到application下有两类tag:meta-data和service
meta-data:标签中name是接口的名字,value是实现该接口的具体实现类的名字,主程序中可以根据需要实现的接口去拿实现类的对象。
service:定义了一个有很特殊的名字的action,这个的作用是针对已经安装好的插件,主app能够通过pm去查询这样的一个service,用于辨别哪些package是插件。
这里的插件有两种存在方式:1、被安装(通过特殊的service去查询即可) 2、未安装(apk包中asset自带)
app会优先去查找系统中已经安装过的,如果找不到会用apk包中带的插件包。
2、如何使用插件中的类
app中提供了一个插件工具类,主要功能就是根据我们需要的接口类,根据插件创建出具体的实现类。
InterfaceClass I = function(InterfaceClass.class);
对外就这样封装使用很简单方便,下面看看代码实现,因为是反编译的就不是很好看,基本原理很简单。
final class d
implements b
{
private static final String b = MainApplication.b().getApplicationInfo().dataDir;
private static final String c = b + "/plugin/asset.apk";
private static final String d = b + "/plugin/asset.cfg";
private static final String e = b + "/plugin/libs";
private static final String f = b + "/plugin/opt";
HashMap<String, ClassLoader> a = new HashMap();
private ApplicationInfo g = null;
/*
返回一个可用的插件的application
*/
private ApplicationInfo a()
{
Object localObject2;
StringBuilder localStringBuilder;
if (this.g == null)
{
//优先查找已经安装的package
localObject1 = new ArrayList();
localObject2 = com.iflytek.app.b.b().getPackageManager().queryIntentServices(new Intent("com.cmcc.karaoke.plugin"), 128).iterator();
while (((Iterator)localObject2).hasNext()) {
((ArrayList)localObject1).add(((ResolveInfo)((Iterator)localObject2).next()).serviceInfo.applicationInfo);
}
//从已经安装的package中找到第一个能满足需求的package的applicationinfo
this.g = a((List)localObject1);
localObject2 = com.iflytek.log.b.a(this);
localStringBuilder = new StringBuilder("verify installed packages pass = ");
if (this.g == null)
{
localObject1 = "null";
((com.iflytek.log.b)localObject2).c((String)localObject1);
}
}
else if (this.g == null)
{
//其次查找asset中自带的插件
this.g = b();
localObject2 = com.iflytek.log.b.a(this);
localStringBuilder = new StringBuilder("verify assets packages pass = ");
if (this.g != null) {
break label233;
}
}
label233:
for (Object localObject1 = "null";; localObject1 = this.g.packageName)
{
((com.iflytek.log.b)localObject2).c((String)localObject1);
if (this.g == null)
{
this.g = d("empty.apk");
com.iflytek.log.b.a(this).c("use empty package = " + this.g.packageName);
}
return this.g;
localObject1 = this.g.packageName;
break;
}
}
/*
参数1:apk绝对路径
参数2:native lib库路径
*/
private static ApplicationInfo a(String paramString1, String paramString2)
{
PackageInfo localPackageInfo = MainApplication.b().getPackageManager().getPackageArchiveInfo(paramString1, 128);
if (localPackageInfo != null)
{
localPackageInfo.applicationInfo.sourceDir = paramString1;
localPackageInfo.applicationInfo.nativeLibraryDir = paramString2;
return localPackageInfo.applicationInfo;
}
return null;
}
/*
选出符合要求的application
*/
private ApplicationInfo a(List<ApplicationInfo> paramList)
{
paramList = paramList.iterator();
while (paramList.hasNext())
{
ApplicationInfo localApplicationInfo = (ApplicationInfo)paramList.next();
if (a(localApplicationInfo)) {
return localApplicationInfo;
}
}
return null;
}
private Object a(ApplicationInfo paramApplicationInfo, String paramString)
{
try
{
String str1 = paramApplicationInfo.packageName;
String str2 = paramApplicationInfo.sourceDir;
String str3 = paramApplicationInfo.nativeLibraryDir;
ClassLoader localClassLoader = (ClassLoader)this.a.get(str1);
paramApplicationInfo = localClassLoader;
if (localClassLoader == null)
{
paramApplicationInfo = new File(f);
if (!paramApplicationInfo.exists()) {
paramApplicationInfo.mkdirs();
}
paramApplicationInfo = new DexClassLoader(str2, f, str3, MainApplication.b().getClassLoader());
this.a.put(str1, paramApplicationInfo);
}
paramApplicationInfo = Class.forName(paramString, true, paramApplicationInfo).newInstance();
return paramApplicationInfo;
}
catch (Exception paramApplicationInfo)
{
paramApplicationInfo.printStackTrace();
}
return null;
}
private <T> T a(ApplicationInfo paramApplicationInfo, String paramString, Class<T> paramClass)
{
paramApplicationInfo = a(paramApplicationInfo, paramString);
if ((paramApplicationInfo != null) && (paramClass.isInstance(paramApplicationInfo))) {
return paramApplicationInfo;
}
throw new InstantiationError("pluginClassName:" + paramString + "Instance fail");
}
/*
判断系统是否满足底层需求,判断的方法存在于插件当中
*/
private boolean a(ApplicationInfo paramApplicationInfo)
{
String str = paramApplicationInfo.metaData.getString("IPlugin");
if (str == null) {
return false;
}
paramApplicationInfo = (IPlugin)a(paramApplicationInfo, str, IPlugin.class);
if (paramApplicationInfo == null) {
return false;
}
return paramApplicationInfo.isSupport(MainApplication.b());
}
/*
参数1:插件包
参数2:配置里写入的package名
*/
private static boolean a(File paramFile, String paramString)
{
try
{
boolean bool = Arrays.equals(com.iflytek.utils.hash.b.a(MainApplication.b().getAssets().open(paramString)), com.iflytek.utils.hash.b.a(paramFile));
return bool;
}
catch (Exception paramFile) {}
return false;
}
private ApplicationInfo b()
{
int i = 0;
Object localObject1 = new File(c);
Object localObject2 = new File(d);
if ((((File)localObject1).exists()) && (((File)localObject2).exists()))
{
localObject2 = e.b((File)localObject2);
if (TextUtils.isEmpty((CharSequence)localObject2)) {}
}
for (boolean bool = a((File)localObject1, "plugin/" + (String)localObject2); bool; bool = false)
{
localObject1 = a(c, e);
if ((localObject1 == null) || (!a((ApplicationInfo)localObject1))) {
break;
}
return localObject1;
}
for (;;)
{
try
{
localObject1 = new File(d);
e.a((File)localObject1);
localObject2 = MainApplication.b().getAssets().list("plugin");
int j = localObject2.length;
if (i < j)
{
String str = localObject2[i];
if ((!str.endsWith(".apk")) || (str.equals("empty.apk"))) {
break label217;
}
ApplicationInfo localApplicationInfo = d(str);
if ((localApplicationInfo == null) || (!a(localApplicationInfo))) {
break label217;
}
e.a((File)localObject1, Arrays.asList(new String[] { str }));
return localApplicationInfo;
}
}
catch (IOException localIOException)
{
localIOException.printStackTrace();
}
return null;
label217:
i += 1;
}
}
private static ApplicationInfo d(String paramString)
{
String str1 = c;
String str2 = e;
File localFile = new File(f);
e.a(new File(str2));
e.a(localFile);
localFile.mkdirs();
com.iflytek.aichang.util.b.a(MainApplication.b(), "plugin/" + paramString, str1);
a.a(str1, str2);
return a(str1, str2);
}
/*
这个是核心的接口,构造需求的接口类
*/
public final <T> T a(Class<T> paramClass)
{
ApplicationInfo localApplicationInfo = a();
return a(localApplicationInfo, localApplicationInfo.metaData.getString(paramClass.getSimpleName()), paramClass);
}
/*
对外获取manifest中对应的meta-deta
*/
public final String a(String paramString)
{
return a().metaData.getString(paramString);
}
public final int b(String paramString)
{
return a().metaData.getInt(paramString);
}
public final boolean c(String paramString)
{
return a().metaData.getBoolean(paramString);
}
}
中间都是一些跟package和application相关的API,这里就不多说了
插件的两个基本核心就是,插件apk的设计和插件的工具类的实现。