浅析QQGame
通过分析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实现。
相关推荐
adb shell cd system/app rm *.apk21. 获取管理员权限: adb root22. 启动Activity: adb shell am start -n 包名/包名+类名。