2013.8.23 apk的安装,卸载,静默安装

1,安装方法有:

1),Intent 方式:

	private void install(File f){
		Intent intent = new Intent();
		intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		intent.setAction(android.content.Intent.ACTION_VIEW);
		String type = getMIMEType(f);
		intent.setDataAndType(Uri.fromFile(f), type);
		context.startActivity(intent);
	}
	
	/**
	 * 获取文件类型
	 * @Title: getMIMEType
	 * @Description: 
	 * @param @param f
	 * @param @return
	 * @return String
	 * @throws
	 * @date 2013-8-23 下午5:13:06
	 */
	private static String getMIMEType(File f){
		String type = "";
		String fName = f.getName();
		String end = fName.substring(fName.lastIndexOf(".")+1, fName.length()).toLowerCase();
		if(end.equals("m4a")||end.equals("mp4")||end.equals("mid")||end.equals("xmf")||end.equals("ogg")||end.equals("wav")){
			type = "audio";
		}else if(end.equals("3gp")||end.equals("mp4")){
			type = "video";
		}else if(end.equals("jpg")||end.equals("gif")||end.equals("png")||end.equals("jpeg")||end.equals("bmp")){
			type = "image";
		}else if(end.equals("apk")){
			type = "application/vnd.android.package-archive";
		}else{
			type = "/*";
		}
		return type;
	}


这种方式需要考虑一个问题:如果设置中是否安装应用商店外的选项,用户选择了否,那系统安装程序会引导用户是否设置,如果设置完了,不会回到安装界面,如果取消也就取消了。所以,应该判断设置中该选项的值,如有必要引导用户设置,用户设置完成后,如果允许安装,则回到安装界面。

改进后:

	private void install1(File f) {
		int result = Settings.Secure.getInt(getContentResolver(),
				Settings.Secure.INSTALL_NON_MARKET_APPS, 0);
		if (0 == result) {
			Toast.makeText(context, "请设置安装...", 1).show();

			Intent it = new Intent();
			it.setAction(Settings.ACTION_APPLICATION_SETTINGS);
			startActivityForResult(it, 1);

			return;
		}

		Intent intent = new Intent();
		intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		intent.setAction(android.content.Intent.ACTION_VIEW);
		String type = getMIMEType(f);
		intent.setDataAndType(Uri.fromFile(f), type);
		context.startActivity(intent);
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);

		if (requestCode == 1) {
			int result = Settings.Secure.getInt(getContentResolver(),
					Settings.Secure.INSTALL_NON_MARKET_APPS, 0);
			if (result == 1) {
				install1(f);
			} else {
				Toast.makeText(context, "无法安装,bye-bye", 1).show();
			}
		}
	}


2),这种方式需要申请权限:android.permission.INSTALL_PACKAGES,

sdk 已经屏蔽PackageInstallObserver 类,系统应用(安装在/system/app下面)可以采用该方式,第三方应用无法申请安装卸载权限。

		Uri mPackageURI = Uri.fromFile(new File(Environment.getExternalStorageDirectory() + apkName));
		int installFlags = 0;
		PackageManager pm = getPackageManager();

		try{
		    PackageInfo pi = pm.getPackageInfo(packageName,PackageManager.GET_UNINSTALLED_PACKAGES);
		    if(pi != null)
		    {
		        installFlags |= PackageManager.REPLACE_EXISTING_PACKAGE;
		    }
		}catch (NameNotFoundException e){
			
		}

		PackageInstallObserver observer = new PackageInstallObserver();
		pm.installPackage(mPackageURI, observer, installFlags);

3),命令安装, install –r  更新安装,默认新安装;如果不附上 -r 参数,则会清楚原应用的数据,版本一致则无法安装。

adb install xxx.apk


4,静默安装

参考:http://www.eoeandroid.com/thread-238338-1-1.html?_dsign=b0edbb6a

参考:http://blog.csdn.net/sodino/article/details/6238818

http://lhc180.blog.51cto.com/316940/757331

最近需要实现Android应用的静默安装,在网上看了不少帖子,最后在root权限下实现对应用的静默安装和卸载,现在就整个实现的过程做一个总结。
一.第一种方案
第一种方案参考了源码中/packages/apps/PackageInstaller的实现方式,实现的主要代码如下:

?
代码片段,双击复制
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.IPackageInstallObserver;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageParser;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.util.DisplayMetrics;
import android.util.Log;
import android.os.FileUtils;
 
public class MyPackageInstaller {
private static final String PACKAGE_NAME = "test.installservice" ;
private final int INSTALL_COMPLETE = 1 ;
private Context context;
Uri mPackageURI;
private PackageParser.Package mPkgInfo;
 
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case INSTALL_COMPLETE:
// finish the activity posting result
//setResultAndFinish(msg.arg1);
break ;
default :
break ;
}
}
};
 
void setResultAndFinish( int retCode) {
// Intent data = new Intent();
// setResult(retCode);
// finish();
}
 
public MyPackageInstaller(Context c) {
this .context = c;
}
 
public void installPackage() {
int installFlags = 0 ;
PackageManager pm = context.getPackageManager();
try {
PackageInfo pi = pm.getPackageInfo(
mPkgInfo.applicationInfo.packageName,
PackageManager.GET_UNINSTALLED_PACKAGES);
if (pi != null ) {
// installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
installFlags |= 2 ;
}
} catch (NameNotFoundException e) {
}
 
String array[] = null ;
try {
Runtime.getRuntime().exec( "chmod 777 /data/data/" + PACKAGE_NAME);
Runtime.getRuntime().exec(
"chmod 777 /data/data/" + PACKAGE_NAME + "/files" );
array = this .mPackageURI.toString().split( "/" );
System.out.println( "array[last]->" + array[array.length - 1 ]);
Runtime.getRuntime().exec(
"chmod 777 /data/data/" + PACKAGE_NAME + "/files/"
+ array[array.length - 1 ]);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
 
PackageInstallObserver observer = new PackageInstallObserver();
pm.installPackage(mPackageURI, observer, installFlags, null );
// context.deleteFile(array[array.length-1]);
}
 
class PackageInstallObserver extends IPackageInstallObserver.Stub {
public void packageInstalled(String packageName, int returnCode) {
Message msg = mHandler.obtainMessage(INSTALL_COMPLETE);
msg.arg1 = returnCode;
mHandler.sendMessage(msg);
}
}
 
private File createTempPackageFile(String filePath) {
File tmpPackageFile;
int i = filePath.lastIndexOf( "/" );
String tmpFileName;
if (i != - 1 ) {
tmpFileName = filePath.substring(i + 1 );
} else {
tmpFileName = filePath;
}
FileOutputStream fos;
try {
// MODE_WORLD_READABLE=1
fos = context.openFileOutput(tmpFileName, 1 );
} catch (FileNotFoundException e1) {
Log.e( "Installer" , "Error opening file " + tmpFileName);
return null ;
}
try {
fos.close();
} catch (IOException e) {
Log.e( "Installer" , "Error opening file " + tmpFileName);
return null ;
}
tmpPackageFile = context.getFileStreamPath(tmpFileName);
File srcPackageFile = new File(filePath);
if (!FileUtils.copyFile(srcPackageFile, tmpPackageFile)) {
return null ;
}
return tmpPackageFile;
}
 
public void makeTempCopyAndInstall(Uri mPackageURI) {
mPkgInfo = getPackageInfo(mPackageURI);
System.out.println( "package=" + mPkgInfo.applicationInfo.packageName);
System.out.println( "copy file=" + mPackageURI.getPath());
File mTmpFile = createTempPackageFile(mPackageURI.getPath());
if (mTmpFile == null ) {
// display a dialog
Log.e( "Installer" ,
"Error copying file locally. Failed Installation" );
// showDialogInner(DLG_OUT_OF_SPACE);
return ;
}
this .mPackageURI = Uri.parse( "file://" + mTmpFile.getPath());
}
 
public PackageParser.Package getPackageInfo(Uri packageURI) {
final String archiveFilePath = packageURI.getPath();
PackageParser packageParser = new PackageParser(archiveFilePath);
File sourceFile = new File(archiveFilePath);
DisplayMetrics metrics = new DisplayMetrics();
metrics.setToDefaults();
return packageParser.parsePackage(sourceFile, archiveFilePath, metrics,
0 );
}
}


在程序中的调用方式:this为Context,path为安装包的绝对路径
?
代码片段,双击复制
01
02
03
MyPackageInstaller mpi = new MyPackageInstaller( this );
mpi.makeTempCopyAndInstall(Uri.parse(path));
mpi.installPackage();


这种方式需要在源码下面编译apk,并将apk放入/system/app目录下面。

二.通过shell命令实现
首先,在java中实现安装和卸载apk的命令
?
代码片段,双击复制
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class PackageInstaller {
 
public void unInstallApp(String packageName){
try {
Runtime.getRuntime().exec( "pm uninstall " +packageName);
} catch (IOException e) {
e.printStackTrace();
}
}
 
public void installApp(String appPath){
try {
Runtime.getRuntime().exec( "pm install " +appPath);
} catch (IOException e) {
e.printStackTrace();
}
}
 
public void reInstallApp(String appPath){
try {
Runtime.getRuntime().exec( "pm install -r " +appPath);
} catch (IOException e) {
e.printStackTrace();
}
}
 
}

?
代码片段,双击复制
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
public class StartMain {
 
private static final String INSTALL_ACTION_LABEL = "install" ;
private static final String REINSTALL_ACTION_LABEL = "reinstall" ;
private static final String UNINSTALL_ACTION_LABEL = "uninstall" ;
 
public static void main(String args[]){
if (args== null ||args.length< 2 ) return ;
PackageInstaller pi= new PackageInstaller();
if (args[ 0 ].equals(INSTALL_ACTION_LABEL)){
pi.installApp(args[ 1 ]);
}
if (args[ 0 ].equals(REINSTALL_ACTION_LABEL)){
pi.reInstallApp(args[ 1 ]);
}
else if (args[ 0 ].equals(UNINSTALL_ACTION_LABEL)){
pi.unInstallApp(args[ 1 ]);
}
}
 
}

然后再源码环境下将该java程序编译为jar包
2.将编译好的jar包放入程序的assets目录下面,通过以下代码在程序中将该jar文件拷贝到/data/data/package/files/目录下面
?
代码片段,双击复制
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
try {
AssetManager assetManager = context.getResources().getAssets();
InputStream in = assetManager.open(JAR_NAME);
if (in == null ) {
return ;
}
int length = in.available();
byte fileByte[] = new byte [length];
in.read(fileByte, 0 , fileByte.length);
in.close();
OutputStream out = context.openFileOutput(JAR_NAME,
Context.MODE_WORLD_READABLE | Context.MODE_WORLD_WRITEABLE);
out.write(fileByte);
out.close();
} catch (Exception e) {
e.printStackTrace();
}

在有root权限的情况下,可以在shell中执行该jar包来进行安装和卸载:
?
代码片段,双击复制
01
02
String exportClassPath = "export CLASSPATH=/data/data/"
+ context.getPackageName() + "/files/installpackagejar.jar" ;

?
代码片段,双击复制
01
String INSTALL_ACTION_CMD = " exec app_process /system/bin packageName.StartMain install " ;

?
代码片段,双击复制
01
02
03
04
05
06
07
08
09
10
11
12
13
public boolean installApp(String path) {
File temp = new File(path);
if (!temp.exists())
return false ;
String cmd[] = { exportClassPath, INSTALL_ACTION_CMD + path };
try {
consoleExec(cmd);
} catch (IOException e) {
e.printStackTrace();
return false ;
}
return true ;
}

?
代码片段,双击复制
01
02
03
04
05
06
07
08
09
10
private void consoleExec(String[] cmd) throws IOException {
Process process = Runtime.getRuntime().exec( "su" );
DataOutputStream os = new DataOutputStream(process.getOutputStream());
for ( int i = 0 ; i < cmd.length; i++) {
os.writeBytes(cmd<i> + "\n" );
}
os.writeBytes( "exit\n" );
os.flush();
os.close();
}</i>

卸载:

	private void uninstall_1(String pkgName) {
		Uri packageURI = Uri.parse("package:" + pkgName);
		Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI);
		startActivity(uninstallIntent);
	}

总结:对第三方应用来说,安装,卸载最方便的方法是用Intent调用系统的安装卸载程序。静默安装需要将被安装的应用放在system/app 下,需要手机获得root权限,安装程序需要申请 android.permission.INSTALL_PACKAGES 权限,静默卸载同理。

你可能感兴趣的:(2013.8.23 apk的安装,卸载,静默安装)