1. 程式人生 > >Android動態載入(一)--載入已經安裝的APK

Android動態載入(一)--載入已經安裝的APK



最近在研究Android動態載入APK技術,偶有小得,共享一下,歡迎交流。

首先是Android 動態載入已安裝的APK

截圖:

被呼叫工程TestB:

其工程已添加了字串、顏色和圖片資源,這裡不寫了,讀者可自行新增。

[java] view plaincopyprint?
  1. publicclass TestBActivity extends Activity{  
  2.     /** Called when the activity is first created. */
  3.     @Override
  4.     publicvoid onCreate(Bundle savedInstanceState) {  
  5.         super.onCreate(savedInstanceState);  
  6.         setContentView(R.layout.main);  
  7.         Button button=(Button)findViewById(R.id.button1);  
  8.         button.setOnClickListener(new OnClickListener() {  
  9.             @Override
  10.             publicvoid onClick(View v) {  
  11.                 // TODO Auto-generated method stub
  12.                 Toast.makeText(TestBActivity.this"this is testB", Toast.LENGTH_SHORT).show();  
  13.             }  
  14.         });  
  15.     }  
  16. }  
public class TestBActivity extends Activity{
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		Button button=(Button)findViewById(R.id.button1);
		button.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				Toast.makeText(TestBActivity.this, "this is testB", Toast.LENGTH_SHORT).show();
			}
		});
	}
}

接著把TestB打包為TestB.apk,放到sdcard的根目錄。

呼叫工程TestA:

首先應該是安裝apk檔案:

[java] view plaincopyprint?
  1. protectedvoid InstallAPK(String apkname) {  
  2.         // TODO Auto-generated method stub
  3.         //程式碼安裝
  4.         String fileName = Environment.getExternalStorageDirectory() + "/"+apkname;   
  5.         Intent intent = new Intent(Intent.ACTION_VIEW);   
  6.         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
  7. //       intent.setDataAndType(Uri.parse("file://"+fileName), "application/vnd.android.package-archive"); 
  8.          intent.setDataAndType(Uri.fromFile(new File(fileName)), "application/vnd.android.package-archive");   
  9.         TestAActivity.this.startActivityForResult(intent, 1);  
protected void InstallAPK(String apkname) {
		// TODO Auto-generated method stub

		//程式碼安裝
		String fileName = Environment.getExternalStorageDirectory() + "/"+apkname; 
		Intent intent = new Intent(Intent.ACTION_VIEW); 
		intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//		 intent.setDataAndType(Uri.parse("file://"+fileName), "application/vnd.android.package-archive"); 
		 intent.setDataAndType(Uri.fromFile(new File(fileName)), "application/vnd.android.package-archive"); 
		TestAActivity.this.startActivityForResult(intent, 1);

但是安裝之前是不是要先檢測一下TestB.apk是否已安裝呢:

[java] view plaincopyprint?
  1. protectedboolean checkInstall(String pak) {  
  2.     // TODO Auto-generated method stub
  3.     boolean install=false;  
  4.     PackageManager pm=getPackageManager();  
  5.     try {  
  6.         PackageInfo info=pm.getPackageInfo(pak,1);  
  7.         if (info!=null&&info.activities.length>0) {  
  8.             install=true;  
  9.         }  
  10.     } catch (NameNotFoundException e) {  
  11.         // TODO Auto-generated catch block
  12.         e.printStackTrace();  
  13.     }  
  14.     return install;  
  15. }  
	protected boolean checkInstall(String pak) {
		// TODO Auto-generated method stub
		boolean install=false;
		PackageManager pm=getPackageManager();
		try {
			PackageInfo info=pm.getPackageInfo(pak,1);
			if (info!=null&&info.activities.length>0) {
				install=true;
			}
		} catch (NameNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return install;
	}

如果未安裝,便呼叫InstallAPK(String apkname)安裝,如果已安裝便可程式碼獲取其資源:

[java] view plaincopyprint?
  1. privatevoid getRes(String pak){  
  2.     if (checkInstall(pak)) {  
  3.     try {  
  4.             Context ctxTestB = getTestContext(pak);  
  5.             Resources res = ctxTestB.getResources();  
  6.             // 獲取字串string
  7.             String hello = res.getString(getId("string""hello", pak));  
  8.             ((TextView) findViewById(R.id.testb_string)).setText(hello);  
  9.             // 獲取圖片Drawable
  10.             Drawable drawable = res.getDrawable(getId("drawable""testb",pak));  
  11.             ((ImageView) findViewById(R.id.testb_drawable)).setImageDrawable(drawable);  
  12.             // 獲取顏色值
  13.             int color = res.getColor(getId("color""white",pak));  
  14.             ((TextView) findViewById(R.id.testb_color)).setBackgroundColor(color);  
  15.             // 獲取佈局檔案
  16.             View view = getView(ctxTestB, getId("layout""main",pak));  
  17.             LinearLayout layout = (LinearLayout) findViewById(R.id.testb_layout);  
  18.             layout.addView(view);  
  19.     } catch (NameNotFoundException e) {  
  20.     e.printStackTrace();  
  21. }}  
  22. }  
  23.  //獲取資源對應的編號
  24. privateint getId(String name, String type,String pak) {  
  25.     return testb.getIdentifier(name, type, pak);  
  26. }  
  27.  // 獲取檢視
  28. public View getView(Context ctx, int id) {  
  29.     return ((LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(id,null);  
  30. }  
  31.  //獲取TestB的Context
  32. private Context getTestContext(String pak) throws NameNotFoundException {  
  33.     return createPackageContext(pak,Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CODE);  
  34. }  
	private void getRes(String pak){
		if (checkInstall(pak)) {
		try {

				Context ctxTestB = getTestContext(pak);
				Resources res = ctxTestB.getResources();
				// 獲取字串string
				String hello = res.getString(getId("string", "hello", pak));
				((TextView) findViewById(R.id.testb_string)).setText(hello);
				
				// 獲取圖片Drawable
				Drawable drawable = res.getDrawable(getId("drawable", "testb",pak));
				((ImageView) findViewById(R.id.testb_drawable)).setImageDrawable(drawable);
				
				// 獲取顏色值
				int color = res.getColor(getId("color", "white",pak));
				((TextView) findViewById(R.id.testb_color)).setBackgroundColor(color);
				
				// 獲取佈局檔案
				View view = getView(ctxTestB, getId("layout", "main",pak));
				LinearLayout layout = (LinearLayout) findViewById(R.id.testb_layout);
				layout.addView(view);

		} catch (NameNotFoundException e) {
		e.printStackTrace();
	}}
	}
	 //獲取資源對應的編號
	private int getId(String name, String type,String pak) {
		return testb.getIdentifier(name, type, pak);
	}


	 // 獲取檢視
	public View getView(Context ctx, int id) {
		return ((LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(id,null);
	}


	 //獲取TestB的Context
	private Context getTestContext(String pak) throws NameNotFoundException {
		return createPackageContext(pak,Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CODE);
	}

接下來再來看看怎麼使用Intent元件啟動被呼叫工程: [java] view plaincopyprint?
  1. protectedvoid startAPK(String pak) {  
  2.     // TODO Auto-generated method stub
  3.     //程式碼啟動
  4.     try {  
  5.                       //pak=PACKAGE_TEST_B+".TestBActivity"
  6.         Context ctxTestB = getTestContext(PACKAGE_TEST_B);  
  7.         Class cls = ctxTestB.getClassLoader().loadClass(pak);  
  8.         TestAActivity.this.startActivity(new Intent(ctxTestB, cls));  
  9.     } catch (ClassNotFoundException e) {  
  10.         e.printStackTrace();  
  11.     } catch (NameNotFoundException e) {  
  12.         // TODO Auto-generated catch block
  13.         e.printStackTrace();  
  14.     }  
  15. }  
	protected void startAPK(String pak) {
		// TODO Auto-generated method stub

		//程式碼啟動
		try {
                       //pak=PACKAGE_TEST_B+".TestBActivity"
			Context	ctxTestB = getTestContext(PACKAGE_TEST_B);
			Class cls = ctxTestB.getClassLoader().loadClass(pak);
			TestAActivity.this.startActivity(new Intent(ctxTestB, cls));
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (NameNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

以下為擴充套件內容:

比如加上網路下載apk檔案功能,然後再安裝,這裡使用的是URL通訊協議,用HttpURLConnection類,面向的是應用層:

[java] view plaincopyprint?
  1. protected File downLoadFile(String httpUrl) {  
  2.                     // TODO Auto-generated method stub
  3.         String filename="down_TestB.apk";  
  4.         File file=new File(Environment.getExternalStorageDirectory() + "/"+filename);  
  5.                     try {  
  6.                             URL url = new URL(httpUrl);  
  7.                             try {  
  8.                                     HttpURLConnection conn = (HttpURLConnection) url  
  9.                                                     .openConnection();  
  10.                                     InputStream is = conn.getInputStream();  
  11.                                     FileOutputStream fos = new FileOutputStream(file);  
  12.                                     byte[] buf = newbyte[256];  
  13.                                     conn.connect();  
  14.                                     int count = 0;  
  15.                                     if (conn.getResponseCode()==200) {  
  16.                                            while ((count=is.read(buf))>0) {  
  17.                                                fos.write(buf, 0, count);  
  18.                                         }  
  19.                                     }  
  20.                                     conn.disconnect();  
  21.                                     fos.close();  
  22.                                     is.close();  
  23.                             } catch (IOException e) {  
  24.                                     // TODO Auto-generated catch block
  25.                                     e.printStackTrace();  
  26.                             }  
  27.                     } catch (MalformedURLException e) {  
  28.                             // TODO Auto-generated catch block
  29.                             e.printStackTrace();  
  30.                     }  
  31.                     return file;  
  32.             }  
protected File downLoadFile(String httpUrl) {
	                // TODO Auto-generated method stub
		String filename="down_TestB.apk";
		File file=new File(Environment.getExternalStorageDirectory() + "/"+filename);

	                try {
	                        URL url = new URL(httpUrl);
	                        try {
	                                HttpURLConnection conn = (HttpURLConnection) url
	                                                .openConnection();
	                                InputStream is = conn.getInputStream();
	                                FileOutputStream fos = new FileOutputStream(file);
	                                byte[] buf = new byte[256];
	                                conn.connect();
	                                int count = 0;
	                                if (conn.getResponseCode()==200) {
	                                       while ((count=is.read(buf))>0) {
											
	                                    	   fos.write(buf, 0, count);
										}
	                                }

	                                conn.disconnect();
	                                fos.close();
	                                is.close();
	                        } catch (IOException e) {
	                                // TODO Auto-generated catch block

	                                e.printStackTrace();
	                        }
	                } catch (MalformedURLException e) {
	                        // TODO Auto-generated catch block

	                        e.printStackTrace();
	                }

	                return file;
	        }

此工程還可擴充套件,比如獲取未安裝apk或者已安裝apk的版本、圖示等資源,和已安裝的apk進行版本比較,以確定是否要升級新版本。關於此可以看下我的另一篇博文《Android獲取未安裝和已安裝apk的版本、圖示等資源》。