通过分析QQGame的项目,发现其存在两种方式:
1. 不安装游戏apk,直接启动
我这里只说其原理,详情讲查看:探秘腾讯Android手机游戏平台之不安装游戏APK直接启动法
其原理是:
1. 把apk里的class文件通过DexClassLoader把apk里的class文件全部加载到java虚拟机里,如果要使用其中的某个class时,就要使用反射来调用。
2. 如果这个类是Activity的子类,那如何来启动,Activity的子类是由android系统来创建,处理方法是:把Activity的子类当做一个有着Activity相应接口的类,在项目里创建一个空的Activity类,其里面不做任何事情,只是用反射调用真正的Activity的方法,代码如下:
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
private Class mActivityClass;
private Object mActivityInstance;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Bundle paramBundle = new Bundle();
paramBundle.putBoolean("KEY_START_FROM_OTHER_ACTIVITY", true);
String dexpath = "/mnt/sdcard/TestB.apk";
String dexoutputpath = "/mnt/sdcard/";
LoadAPK(paramBundle, dexpath, dexoutputpath);
}
});
}
@Override
protected void onStart() {
super.onStart();
try {
Method method = mActivityClass.getDeclaredMethod(
"onStart");
method.setAccessible(true);
method.invoke(mActivityInstance);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void onResume() {
super.onResume();
try {
Method method = mActivityClass.getDeclaredMethod(
"onResume");
method.setAccessible(true);
method.invoke(mActivityInstance);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void onPause() {
super.onPause();
try {
Method method = mActivityClass.getDeclaredMethod(
"onPause");
method.setAccessible(true);
method.invoke(mActivityInstance);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void onStop() {
super.onStop();
try {
Method method = mActivityClass.getDeclaredMethod(
"onStop");
method.setAccessible(true);
method.invoke(mActivityInstance);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
try {
Method method = mActivityClass.getDeclaredMethod(
"onDestroy");
method.setAccessible(true);
method.invoke(mActivityInstance);
} catch (Exception e) {
e.printStackTrace();
}
}
public void LoadAPK(Bundle paramBundle, String dexpath, String dexoutputpath) {
ClassLoader localClassLoader = ClassLoader.getSystemClassLoader();
DexClassLoader localDexClassLoader = new DexClassLoader(dexpath,
dexoutputpath, null, localClassLoader);
try {
PackageInfo plocalObject = getPackageManager()
.getPackageArchiveInfo(dexpath, 1);
if ((plocalObject.activities != null)
&& (plocalObject.activities.length > 0)) {
String activityname = plocalObject.activities[0].name;
Log.d(TAG, "activityname = " + activityname);
Class localClass = localDexClassLoader.loadClass(activityname);
mActivityClass = localClass;
Constructor localConstructor = localClass
.getConstructor(new Class[] {});
Object instance = localConstructor.newInstance(new Object[] {});
Log.d(TAG, "instance = " + instance);
mActivityInstance = instance;
Method localMethodSetActivity = localClass.getDeclaredMethod(
"setActivity", new Class[] { Activity.class });
localMethodSetActivity.setAccessible(true);
localMethodSetActivity.invoke(instance, new Object[] { this });
Method methodonCreate = localClass.getDeclaredMethod(
"onCreate", new Class[] { Bundle.class });
methodonCreate.setAccessible(true);
methodonCreate.invoke(instance, new Object[] { paramBundle });
}
return;
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
从上面可以看到,由于我们不能像系统一样初始化Activity,所以只能用一个Activity做为了容器,来调用其Activity相应的生命周期方法。
在另外的Activity里,把显示的view设置到传过来的Activity里面,同时,所有要与系统交互的,都要通过传过来的activity对象,这个和我们最开始的那个框架差不多。
这样做的好处:
1. 可以做到apk,不安装的情况下,就可以启动这个apk
2. 对于qqgame,由于只有一个Activity,而且游戏的图片资源都是自己加载的,所以很适合用这种方式
不足之处:
1. 不能把res里的资源文件交给系统来管理,也就是资源(图片等等),都要自己去sdcard里去读取,去维护。
2. 如果有多个Activity时,就会很麻烦,由于只是把些类加载进来,但不能由系统来初始化,那些startActivity的方法基本上不能用(虽然可以模拟,但会有很多的问题)
3. 由于有这种限制,所以QQ的项目里,现在还只有QQGame用了这种模式
2. 安装游戏apk,再进行启动
这种模式比较简单:
1. 不要用启动的Activity
2. 把第一个启动的Activity加一个约定的Catergory:
<category android:name="android.intent.category.XXXX" />
还后,在门户的项目里,对当前手机进行探测,看有多少个含有这个类别的Activity,可以进行显示出来了。
结论:
对了我们这种应用app的程序,用这种方式,会大大加大开发的复杂度,不过其第二种方法不错,但要变化着使用。
使用交叉推荐:
1. 在每个不同的项目里,都加入对其他产品的推荐(同时,检测用户手机里已经安装过的apk)。
2. 有一些功能,还可以让用户跳到其他的apk实现。