目前市面上的市集,不管是 apple 還是 android 平台, 一般只有一家商店。
如果要動態添加商店,允許多家商店共存。
搭建一個平台,多家市集可以加入。
類似於商場與專賣店的關係。
每個商店的業務由各自實現,但統一由商場來提供介面供使用者選擇。
下面就來簡單做個原型:
1 ClassLoadTestMain 商場
2 ClassLoadTestPlugin 商店
3 PluginInterface 商場提供給商店的介面
介面定義:
view plaincopy to clipboardprint?
- package com.pathfindeng.android.test;
-
- public interface IPlugin {
-
- public int add(int a, int b);
-
- }
package com.pathfindeng.android.test;</p><p>public interface IPlugin {</p><p>public int add(int a, int b);</p><p>}
商店實現介面:
view plaincopy to clipboardprint?
- package com.pathfindeng.android.test.plugin;
-
- import com.pathfindeng.android.test.IPlugin;
-
- public class Plugin implements IPlugin{
-
- public int add(int a, int b){
- return a + b;
- }
- }
package com.pathfindeng.android.test.plugin;</p><p>import com.pathfindeng.android.test.IPlugin;</p><p>public class Plugin implements IPlugin{</p><p>public int add(int a, int b){<br />return a + b;<br />}<br />}
商場調用商店的實現:
view plaincopy to clipboardprint?
- package com.pathfindeng.android.test.main;
-
- import com.pathfindeng.android.test.IPlugin;
- import com.pathfindeng.android.test.main.R;
-
- import dalvik.system.DexClassLoader;
- import dalvik.system.VMStack;
- import android.app.Activity;
- import android.os.Bundle;
- import android.widget.TextView;
- import android.widget.Toast;
-
- public class ClassLoadTestMainActivity extends Activity {
-
-
- TextView result;
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- result = (TextView)findViewById(R.id.result);
-
- }
-
- public void doInPlugin(){
-
- String dexPath, dexOutputDir, libPath ,className;
- ClassLoader parent;
-
- dexPath = "/data/app/com.pathfindeng.android.test.plugin-1.apk";
- dexOutputDir = "/data/data/com.pathfindeng.android.test.main";
-
- libPath = "/data/data/com.pathfindeng.android.test.main/lib";
-
- parent = ClassLoadTestMainActivity.this.getClassLoader();
-
- //parent = VMStack.getCallingClassLoader();
-
- DexClassLoader mDexClassLoader = new DexClassLoader(dexPath, dexOutputDir, libPath, parent);
-
- className = "com.pathfindeng.android.test.plugin.Plugin";
-
- try {
- Class mClass = mDexClassLoader.loadClass(className);
-
- IPlugin mIPlugin = (IPlugin)mClass.newInstance();
-
- int c;
- c = mIPlugin.add(100, 200);
-
- result.setText("from plugin : "+c);
-
- Toast.makeText(ClassLoadTestMainActivity.this, "from plugin : "+c, Toast.LENGTH_LONG);
-
-
- } catch (ClassNotFoundException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (InstantiationException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
-
-
- }
-
- /* (non-Javadoc)
- * @see android.app.Activity#onResume()
- */
- @Override
- protected void onResume() {
- // TODO Auto-generated method stub
- super.onResume();
-
- doInPlugin();
- }
-
- /* (non-Javadoc)
- * @see android.app.Activity#onDestroy()
- */
- @Override
- protected void onDestroy() {
- // TODO Auto-generated method stub
- super.onDestroy();
- }
-
- }
package com.pathfindeng.android.test.main;</p><p>import com.pathfindeng.android.test.IPlugin;<br />import com.pathfindeng.android.test.main.R;</p><p>import dalvik.system.DexClassLoader;<br />import dalvik.system.VMStack;<br />import android.app.Activity;<br />import android.os.Bundle;<br />import android.widget.TextView;<br />import android.widget.Toast;</p><p>public class ClassLoadTestMainActivity extends Activity {</p><p>TextView result;<br /> /** Called when the activity is first created. */<br /> @Override<br /> public void onCreate(Bundle savedInstanceState) {<br /> super.onCreate(savedInstanceState);<br /> setContentView(R.layout.main);<br /> result = (TextView)findViewById(R.id.result);</p><p> }</p><p> public void doInPlugin(){</p><p> String dexPath, dexOutputDir, libPath ,className;<br /> ClassLoader parent;</p><p> dexPath = "/data/app/com.pathfindeng.android.test.plugin-1.apk";<br /> dexOutputDir = "/data/data/com.pathfindeng.android.test.main";</p><p> libPath = "/data/data/com.pathfindeng.android.test.main/lib";</p><p> parent = ClassLoadTestMainActivity.this.getClassLoader();</p><p> //parent = VMStack.getCallingClassLoader();</p><p> DexClassLoader mDexClassLoader = new DexClassLoader(dexPath, dexOutputDir, libPath, parent);</p><p> className = "com.pathfindeng.android.test.plugin.Plugin";</p><p> try {<br />Class mClass = mDexClassLoader.loadClass(className);</p><p>IPlugin mIPlugin = (IPlugin)mClass.newInstance();</p><p>int c;<br />c = mIPlugin.add(100, 200);</p><p>result.setText("from plugin : "+c);</p><p>Toast.makeText(ClassLoadTestMainActivity.this, "from plugin : "+c, Toast.LENGTH_LONG);</p><p>} catch (ClassNotFoundException e) {<br />// TODO Auto-generated catch block<br />e.printStackTrace();<br />} catch (IllegalAccessException e) {<br />// TODO Auto-generated catch block<br />e.printStackTrace();<br />} catch (InstantiationException e) {<br />// TODO Auto-generated catch block<br />e.printStackTrace();<br />}</p><p> }</p><p>/* (non-Javadoc)<br /> * @see android.app.Activity#onResume()<br /> */<br />@Override<br />protected void onResume() {<br />// TODO Auto-generated method stub<br />super.onResume();</p><p>doInPlugin();<br />}</p><p>/* (non-Javadoc)<br /> * @see android.app.Activity#onDestroy()<br /> */<br />@Override<br />protected void onDestroy() {<br />// TODO Auto-generated method stub<br />super.onDestroy();<br />}</p><p>}
從上面的代碼看,調用外掛程式還是強制定義的,不夠人性
接下來做些改進。
外掛程式端 註冊 固定 Action Name
view plaincopy to clipboardprint?
- <activity android:name=".商店Activity" android:label="@string/app_name">
- <intent-filter>
- <action android:name="介面指定固定 Action Name" />
- </intent-filter>
- </activity>
<activity android:name=".商店Activity" android:label="@string/app_name"><br /> <intent-filter><br /> <action android:name="介面指定固定 Action Name" /><br /> </intent-filter><br /></activity>
伺服器端 商場
利用 PackageManager 查詢所有註冊了介面定義的 Action Name 的商店,並獲得資訊。
view plaincopy to clipboardprint?
- Intent intent = new Intent(Constants.ACTION_PLUGIN, null);
- PackageManager pm = mContext.getPackageManager();
- List<ResolveInfo> plugins = pm.queryIntentActivities(intent, 0);
Intent intent = new Intent(Constants.ACTION_PLUGIN, null);<br />PackageManager pm = mContext.getPackageManager();<br />List<ResolveInfo> plugins = pm.queryIntentActivities(intent, 0);
這樣之前提到的
view plaincopy to clipboardprint?
- DexClassLoader(dexPath, dexOutputDir, libPath, parent)
DexClassLoader(dexPath, dexOutputDir, libPath, parent)
參數就不需要 手動指定了。
待敘……