为了让其他人可以调用我们应用的方法。我们可以通过通过JNI实现跨进程通讯。也可以用java的反射调用其他APP中的方法。但是你需要知道其他APP得包名,类名,或获取他的JNI文件。
通过制作SDK(即是一个jar包),在其他项目中,只要导入这个jar包,就可以很快捷的使用sdk中的方法调用目标应用的方法。假如提供给别人,别人也不用知道你应用的结构,原理。只需导入sdk,调用sdk中的方法即可。
第一步,编写一个Library。SDK类中初始化sdk,通过反射,找到被调用应用的sdk实现方法
package com.greetty.printer;
import android.app.Application;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.util.Log;
import java.lang.reflect.Method;
import dalvik.system.DexClassLoader;
/**
* Created by Greetty on 2017/8/1.
*/
public abstract class SDK {
private static final String TAG = "SDK";
private static final String GREETTY_INST_PKG = "com.greetty.printer";
private static final String SDK_IMPL_CLASS = "com.greetty.printer.SdkImpl";
private static SDK mSDK = null;
private static Object mInstLock = new Object();
private static void init() {
if (mSDK != null){
return;
}
try {
/*
* get current app context
*/
final Class> activityThreadClass;
activityThreadClass = Class.forName("android.app.ActivityThread");
final Method method = activityThreadClass.getMethod("currentApplication");
final Context context = ((Application) method.invoke(null, (Object[]) null)).getApplicationContext();
final String dataDir = context.getApplicationInfo().dataDir;
/*
* get com.greetty.device package info
*/
Context dev = context.createPackageContext(GREETTY_INST_PKG,
Context.CONTEXT_INCLUDE_CODE
| Context.CONTEXT_IGNORE_SECURITY);
ApplicationInfo appInfo = dev.getApplicationInfo();
DexClassLoader loader = new DexClassLoader(appInfo.sourceDir, dataDir,
null, SDK.class.getClassLoader());
Log.e(TAG, "packageName: " + appInfo.packageName);
mSDK = (SDK) loader.loadClass(SDK_IMPL_CLASS).newInstance();
} catch (Exception e) {
Log.e(TAG, "error: "+e.getMessage());
e.printStackTrace();
}
}
/**
* 获取sdk对象
* @return
* @throws Throwable
*/
public static synchronized SDK getSDK() throws Throwable{
synchronized(mInstLock) {
if (mSDK == null)
init();
return mSDK;
}
}
public abstract Object newInstance(String interfaceName) throws Throwable;
public abstract void test();
}
定义SDK目标方法,也是通过反射找到该方法
package com.greetty.printer;
/**
* Created by Greetty on 2017/8/1.
*/
public abstract class Printer {
/**
* 创建Printer实例
* @throws Exception
*/
public static Printer newInstance() throws Throwable {
return (Printer) SDK.getSDK().newInstance(Printer.class.getName());
}
public abstract void logData(String data);
public abstract String getName(String nameOne);
}
sdk导入到别的项目的方法就已经完成了,把它打包成jar包尽可。现在开始编写被调用的应用。应用需要引用上一步中生成的jar包,但不能把jar包编译到APP中,因为在调用的APP使用了该jar包,被调用的APP也含有这个文件会出错。实现SDK类里面的方法,当调用SDK中的方法时,会进行该应用中对应的方法。
package com.greetty.printer;
import android.util.Log;
/**
* Created by Greetty on 2017/8/1.
*/
public class SdkImpl extends SDK {
private static final String TAG = "SdkImpl";
@Override
public Object newInstance(String s) throws Throwable {
if (s.equals("com.greetty.printer.Printer")){
return MyPrinter.class.newInstance();
}else{
throw new ClassNotFoundException("can't find implement class : " + s);
}
}
@Override
public void test() {
Log.e(TAG, "sdkimpln test : ");
}
}
SDK的Printer类中的实现方法。应用中可以做很多拓展,不是局限于继续实现SDK中的方法。
package com.greetty.printer;
import android.util.Log;
/**
* Created by Greetty on 2017/8/1.
*/
public class MyPrinter extends Printer {
private static final String TAG = "MyPrinter";
@Override
public void logData(String s) {
Log.e(TAG, "MyPrinter: "+s);
}
@Override
public String getName(String s) {
return s + "哈哈哈哈";
}
}
现在开始编写应用,导入SDK,调用SDK中的方法去执行被调用APP的方法,实现自己想要的功能。
public void Test(View view) {
try {
Printer printer = Printer.newInstance();
printer.logData("哈哈哈哈,我成功在输入信息");
String txt= printer.getName("Greetty");
Log.e(TAG, txt);
} catch (Throwable throwable) {
Log.e(TAG, "error: "+throwable.getMessage());
throwable.printStackTrace();
}
}