一、通过Intent消息机制发送消息,调用系统应用进行,实现apk的安装/卸载
。
(1)
调用系统的安装应用,让系统自动进行apk的安装
1 | String fileName = "/data/data/com.zlc.ipanel.operate/FileOperate.apk" ; |
2 | Uri uri = Uri.fromFile( new File(fileName)); |
3 | Intent intent = new Intent(Intent.ACTION_VIEW); |
4 | intent.setDataAndType(uri, "application/vnd.android.package-archive" ); |
上诉安装不仅可以安装新的apk(从无到有),也可以用于更新旧的apk(版本更新),在进行版本更新的时候,必须保证两个apk的签名是一致的。
如果是一般应用,安装到data/分区下面,新的apk会替换旧的apk。
如果是系统应用,一般安装到system/app下面,更新之后,
system/app/下的旧apk仍然存在,系统会将新的apk被复制到data/app下。虽然同时存在两新旧apk,但运行时系统选择data分区的新apk运行,
如果执行卸载则是删除data分区的apk,再次启动程序运行的是system目录下旧的apk。
(2)启动系统的卸载应用,让系统自动卸载apk
2 | Uri packageURI = Uri.parse( "package:com.zlc.ipanel" ); |
4 | Intent intent = new Intent(Intent.ACTION_DELETE,packageURI); |
与apk安装不同的是,Intent消息这里改了:ACTION_DELETE,apk安装使用的是(ACTION_VIEW)
二、通过调用系统提供的接口packageManager对apk进行卸载、安装、获取权限等(静默安装) (1)需要平台签名(写个Android.mk在源码下编译最省事,当然网上也有很多其他方法,比如:singapk命令行签名) (2)由于调用的是未公开的API,所以需要引入源码(仅仅做一个马甲,不参与编译) (3)在AndroidManifest.xml添加安装apk的权限 <uses-permission android:name="android.permission.INSTALL_PACKAGES" /> (4)如果升级失败出现 Unable to open zip '/data/FileOperate.apk': Permission denied,说明是权限不够,有可能当前apk只有(-rw-------)权限,通过Runtime.exec方法修改权限之后再进行升级是可以成功的。
1 | PackageManager pm = this .getPackageManager(); |
2 | File file = new File( "/data/data/com.zlc.ipanel.operate/FileOperate.apk" ); |
3 | pm.installPackage(Uri.fromFile(file), null , |
4 | PackageManager.INSTALL_REPLACE_EXISTING, "com.zlc.ipanel" ); |
(5)下面举一个例子通过Eclipse来实现静默安装/卸载。 1)按照我们上面讲的静默安装需求一步步实现我们的操作。首先准备马甲(静默安装需要调用的接口) 由于调用了系统未公开的接口,而这些接口有些是通过aidl实现的,下面我们把需要的马甲修改一下。 PackageManager.java
02 | * Copyright (C) 2006 The Android Open Source Project |
04 | * Licensed under the Apache License, Version 2.0 (the "License"); |
05 | * you may not use this file except in compliance with the License. |
06 | * You may obtain a copy of the License at |
08 | * http://www./licenses/LICENSE-2.0 |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
17 | package android.content.pm; |
19 | import android.content.Context; |
20 | import android.net.Uri; |
23 | * Class for retrieving various kinds of information related to the application |
24 | * packages that are currently installed on the device. |
26 | * You can find this class through {@link Context#getPackageManager}. |
28 | public abstract class PackageManager { |
31 | * Flag parameter for {@link #installPackage} to indicate that you want to replace an already |
32 | * installed package, if one exists. |
35 | public static final int INSTALL_REPLACE_EXISTING = 0x00000002; |
41 | * Install a package. Since this may take a little while, the result will |
42 | * be posted back to the given observer. An installation will fail if the calling context |
43 | * lacks the {@link android.Manifest.permission#INSTALL_PACKAGES} permission, if the |
44 | * package named in the package file's manifest is already installed, or if there's no space |
45 | * available on the device. |
47 | * @param packageURI The location of the package file to install. This can be a 'file:' or a |
49 | * @param observer An observer callback to get notified when the package installation is |
50 | * complete. {@link IPackageInstallObserver#packageInstalled(String, int)} will be |
51 | * called when that happens. observer may be null to indicate that no callback is desired. |
52 | * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK}, |
53 | * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}. |
54 | * @param installerPackageName Optional package name of the application that is performing the |
55 | * installation. This identifies which market the package came from. |
57 | public abstract void installPackage( |
58 | Uri packageURI, IPackageInstallObserver observer, int flags, |
59 | String installerPackageName); |
63 | * Attempts to delete a package. Since this may take a little while, the result will |
64 | * be posted back to the given observer. A deletion will fail if the calling context |
65 | * lacks the {@link android.Manifest.permission#DELETE_PACKAGES} permission, if the |
66 | * named package cannot be found, or if the named package is a "system package". |
67 | * (TODO: include pointer to documentation on "system packages") |
69 | * @param packageName The name of the package to delete |
70 | * @param observer An observer callback to get notified when the package deletion is |
71 | * complete. {@link android.content.pm.IPackageDeleteObserver#packageDeleted(boolean)} will be |
72 | * called when that happens. observer may be null to indicate that no callback is desired. |
73 | * @param flags - possible values: {@link #DONT_DELETE_DATA} |
77 | public abstract void deletePackage( |
78 | String packageName, IPackageDeleteObserver observer, int flags); |
安装成功的回调接口IPackageInstallObserver.java(修改过的马甲)
01 | package android.content.pm; |
03 | import android.os.RemoteException; |
05 | public interface IPackageInstallObserver { |
06 | public class Stub implements IPackageInstallObserver{ |
07 | public void packageInstalled(String packageName, int returnCode) |
08 | throws RemoteException { |
09 | // TODO Auto-generated method stub |
卸载成功的回调接口IPackageDeleteObserver.java(修改过的马甲)
1 | package android.content.pm; |
3 | public interface IPackageDeleteObserver { |
4 | public class Stub implements IPackageDeleteObserver{ |
5 | public void packageDeleted(String packageName, int returnCode) { |
6 | // TODO Auto-generated method stub |
2)马甲准备好之后,就开始实现我们的操作逻辑。
实现静默安装/卸载的方法,并且注册回调(无论失败成功都会返回对应值)
02 | public static void installApkDefaul(Context context,String fileName,String pakcageName){ |
03 | Log.d(TAG, "jing mo an zhuang" ); |
04 | File file = new File(fileName); |
08 | Log.d(TAG, "jing mo an zhuang out" ); |
09 | installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; |
10 | PackageManager pm = context.getPackageManager(); |
11 | IPackageInstallObserver observer = new MyPakcageInstallObserver(); |
12 | pm.installPackage(Uri.fromFile(file), observer, installFlags, pakcageName); |
15 | public static void uninstallApkDefaul(Context context,String packageName){ |
16 | PackageManager pm = context.getPackageManager(); |
17 | IPackageDeleteObserver observer = new MyPackageDeleteObserver(); |
18 | pm.deletePackage(packageName, observer, 0 ); |
21 | private static class MyPackageDeleteObserver extends IPackageDeleteObserver.Stub{ |
23 | public void packageDeleted(String packageName, int returnCode) { |
24 | // TODO Auto-generated method stub |
25 | Log.d(TAG, "returnCode = " +returnCode); //返回1代表卸载成功 |
30 | private static class MyPakcageInstallObserver extends IPackageInstallObserver.Stub{ |
32 | public void packageInstalled(String packageName, int returnCode) |
33 | throws RemoteException { |
34 | // TODO Auto-generated method stub |
35 | Log.i(TAG, "returnCode = " + returnCode); //返回1代表安装成功 |
3)主要的逻辑实现之后,在AndroidManifest.xml 添加安装和卸载的权限
1 | < uses-permission android:name = "android.permission.INSTALL_PACKAGES" /> |
2 | < uses-permission android:name = "android.permission.DELETE_PACKAGES" /> |
4)运行Eclipse,生成该应用的apk,下面就要进行系统签名了。写一个脚本来来实现替换成系统签名
使用签名包签名首先我们要去源码里面取出下面这几个文件platform.x509.pem、platform.pk8、signapk.jar
脚本1.bat (
和生成的apk以及上面三个文件放到同一个目录下面,一般为工程下面的bin目录)
1 | java -jar signapk.jar platform.x509.pem platform.pk8 FileUpdateControl.apk 1.apk |
2 | adb uninstall com.zlc.ipanel.operate |
5)当下载到系统里面的apk权限不够时(静默安装提示权限问题,
有可能当前apk只有(-rw-------)权限
)
可以使用下面三种方式修改权限
1.使用Runtime来启动一个线程修改权限
2 | Runtime.getRuntime().exec( "chmod 777 " + file.getCanonicalPath()); |
3 | } catch (IOException e) { |
4 | // TODO Auto-generated catch block |
2.写一个native接口直接通过jni调用c的接口修改权限。 3.使用FileUtils,这个类默认是隐藏的,官方sdk中不包含这个类,所以代码如果要使用这个类,需要将工程放到android源码中编译 FileUtils.setPermissions(f.getAbsolutePath(), FileUtils.S_IRUSR | FileUtils.S_IWUSR | FileUtils.S_IRGRP | FileUtils.S_IROTH, -1, -1) ;
三、其他apk安装的方法
(1)通过cmd窗口 adb 命令,install / uninstall apk。
(2)cp apk 到 system/app目录下,系统会自动安装
(3)直接通过代码调用pm命令执行apk的安装和卸载
1 |
execCommand("pm", "install", "-f", filePath);//安装apk,filePath为apk文件路径,如/sdcard/operate.apk |
2 |
execCommand("pm", "uninstall", packageName);//卸载apk,packageName为包名,如com.zlc.ipanel |
|