android 实现静默安装、卸载(图)

android中应用的安装卸载,大家(用android设备的)肯定不陌生。这里就来浅谈android应用的安装、卸载的实现方式。

1.系统安装程序

android自带了一个安装程序---/system/app/PackageInstaller.apk.大多数情况下,我们手机上安装应用都是通过这个apk来安装的。代码使用也非常简单:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

/* 安装apk */

public static void installApk(Context context, String fileName) {

Intent intent = new Intent();

intent.setAction(Intent.ACTION_VIEW);

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

intent.setDataAndType(Uri.parse("file://" + fileName),

"application/vnd.android.package-archive");

context.startActivity(intent);

}

/* 卸载apk */

public static void uninstallApk(Context context, String packageName) {

Uri uri = Uri.parse("package:" + packageName);

Intent intent = new Intent(Intent.ACTION_DELETE, uri);

context.startActivity(intent);

}

通过发一个Intent,把应用所在的路径封装整uri.之后默认启动了PackageInstaller.apk来安装程序了。
但是此种情况下,仅仅是个demo而已,很难达到开发者的需求。如:

  • 界面不好
  • 什么时候安装完了,卸载完了呢?

为了达到自己的需求,相信很多人都会接着来监听系统安装卸载的广播,继续接下来的代码逻辑。

2.监听系统发出的安装广播

在安装和卸载完后,android系统会发一个广播

  • android.intent.action.PACKAGE_ADDED(安装)
  • android.intent.action.PACKAGE_REMOVED(卸载)

咱们就监听这广播,来做响应的逻辑处理。实现代码:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

public class MonitorSysReceiver extends BroadcastReceiver{

@Override

public void onReceive(Context context, Intent intent){

//接收安装广播

if (intent.getAction().equals("android.intent.action.PACKAGE_ADDED")) {

//TODO

}

//接收卸载广播

if (intent.getAction().equals("android.intent.action.PACKAGE_REMOVED")) {

//TODO

}

}

}

AndroidMenifast.xml里配置:

?


1

2

3

4

5

6

<receiver android:name=".MonitorSysReceiver">

<intent-filter>

<action android:name="android.intent.action.PACKAGE_ADDED" />

<action android:name="android.intent.action.PACKAGE_REMOVED" />

</intent-filter>

</receiver>

到此,确实安装卸载的整体流程都知道了,但是这个效果肯定是无法达到项目的需求。
一般这种应用商店类的项目,肯定是会要自定义提示框效果的安装卸载功能,而不是调用系统的安装程序。
那咱就要想法子实现静默安装、卸载咯。
网上有很多法子,如执行adb install 或pm install -r命令安装。但我想这并不可靠。记得之前有做过一个应用来执行linux命令,是通过RunTime来执行命令的。
后来发现其实并不靠谱,还不如直接用C代码来实现。
下面这种调用系统隐藏api接口来实现静默安装卸载,是比较大众靠谱的,实现自定义的提示界面。O(∩_∩)O~

3.系统隐藏的api

隐藏api,顾名思义,普通情况下肯定是调用不到的。翻翻源码\frameworks\base\core\java\android\content\pm目录下PackageManager.java,应该发现
在注释行里有加上@hide声明。调用的安装下载接口如下:

?


1

2

3

public abstract void installPackage(Uri packageURI,

IPackageInstallObserver observer, int flags,

String installerPackageName);

?


1

2

public abstract void deletePackage(String packageName,

IPackageDeleteObserver observer, int flags);

并且都是抽象方法,需要咱们实现。

看参数里IPackageInstallObserver  observer一个aidl回调通知接口,当前目录中找到这接口:

?


1

2

3

4

5

6

7

8

9

package android.content.pm;

/**

* API for installation callbacks from the Package Manager.


@hide

*/

oneway interface IPackageInstallObserver {

void packageInstalled(in String packageName, int returnCode);

}

好吧,这里有现成的干货,咱拿过来直接用呗(当然如果没有源码的那就算了,那能实现的只是demo)。具体步骤:

  • 从源码中拷贝要使用的aidl回调接口:IPackageInstallObserver.aidl、IPackageDeleteObserver.aidl当然完全可以拷贝整个pm目录,这样就不会报错了O(∩_∩)O~。
  • 作者项目里面用到了pm,所以把PackageManager.java以及涉及到的一些文件也拷贝过来了,不然eclipse报找不到PackageManager对象。结构如下:

    (注:此处的包名android.content.pm一定要和源码目录结构一致,不然源码里编译会提示找不到aidl接口。一切朝源码编译看齐)
    此处有2种方式实现:
    1.直接只取IPackageDeleteObserver.aidl和IPackagerInstallObserver.aidl、IPackageMoveObserver.aidl等要使用的接口,然后通过bindService来和系统连接服务,然后直接调用接口即可(这种没有方式作者没试过,不过原理上来说应该是可行的,除非系统没有这个Service实现这个接口。有需求的可以深究下)
    2.作者此处的方法是直接拷贝了源码PackageManager.java等文件过来,不过靠过来之后eclipse会提示一些接口错误,但这里作者把上面那几个.java文件都放空了,因为用不到,只是为了编译过才拷贝了那么多文件。最简单的就是直接拷贝4个文件即可:
    PackageManager.java
    IPackageDeleteObserver.aidl
    IPackagerInstallObserver.aidl
    IPackageMoveObserver.aidl
    然后把PackageManager.java中报的异常的接口都注释掉即可


  • 实现回调接口,代码如下

    ?


    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    class MyPakcageInstallObserver extends IPackageInstallObserver.Stub {

    Context cxt;

    String appName;

    String filename;

    String pkname;

    public MyPakcageInstallObserver(Context c, String appName,

    String filename,String packagename) {

    this.cxt = c;

    this.appName = appName;

    this.filename = filename;

    this.pkname = packagename;

    }

    @Override

    public void packageInstalled(String packageName, int returnCode) {

    Log.i(TAG, "returnCode = " + returnCode);// 返回1代表安装成功

    if (returnCode == 1) {

    //TODO

    }

    Intent it = new Intent();

    it.setAction(CustomAction.INSTALL_ACTION);

    it.putExtra("install_returnCode", returnCode);

    it.putExtra("install_packageName", packageName);

    it.putExtra("install_appName", appName); cxt.sendBroadcast(it);

    }

    }

    卸载回调接口同上。

  • 调用PackageManager.java隐藏方法,代码如下:

    ?


    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    /**

    * 静默安装

    * */

    public static void autoInstallApk(Context context, String fileName,

    String packageName, String APPName) {

    Log.d(TAG, "jing mo an zhuang:" + packageName + ",fileName:" + fileName);

    File file = new File(fileName);

    int installFlags = 0;

    if (!file.exists())

    return;

    installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;

    if (hasSdcard()) {

    installFlags |= PackageManager.INSTALL_EXTERNAL;

    }

    PackageManager pm = context.getPackageManager();

    try {

    IPackageInstallObserver observer = new MyPakcageInstallObserver(

    context, APPName, appId, fileName,packageName,type_name);

    Log.i(TAG, "########installFlags:" + installFlags+"packagename:"+packageName);

    pm.installPackage(Uri.fromFile(file), observer, installFlags,

    packageName);

    } catch (Exception e) {

    }

    }

    卸载调用同上

很多码友联系,这里经常出错,现整理参考代码如下(下面代码有些格式问题)

?


1

2

3

4

5

6

7

8

9

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

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

package cn.thear;

import java.io.File;

import android.content.ContentResolver;

import android.content.ContentValues;

import android.content.Context;

import android.content.Intent;

import android.content.SharedPreferences;

import android.content.pm.IPackageDeleteObserver;

import android.content.pm.IPackageInstallObserver;

import android.content.pm.IPackageMoveObserver;

import android.content.pm.PackageManager;

import android.net.Uri;

import android.os.Environment;

import android.os.RemoteException;

import android.util.Log;

public class ApkOperateManager {

public static String TAG = "ApkOperateManager";

/***安装apk */

public static void installApk(Context context, String fileName) {

Intent intent = new Intent();

intent.setAction(Intent.ACTION_VIEW);

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

intent.setDataAndType(Uri.parse("file://" + fileName),

"application/vnd.android.package-archive");

context.startActivity(intent);

}

/**卸载apk */

public static void uninstallApk(Context context, String packageName) {

Uri uri = Uri.parse("package:" + packageName);

Intent intent = new Intent(Intent.ACTION_DELETE, uri);

context.startActivity(intent);

}

/**

* 静默安装

* */

public static void installApkDefaul(Context context, String fileName,

String packageName, String APPName, String appId, String type_name) {

Log.d(TAG, "jing mo an zhuang:" + packageName + ",fileName:" + fileName

+ ",type_name:" + type_name);

File file = new File(fileName);

int installFlags = 0;

if (!file.exists())

return;

installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;

if (hasSdcard()) {

installFlags |= PackageManager.INSTALL_EXTERNAL;

}

PackageManager pm = context.getPackageManager();

// try {  try {

IPackageInstallObserver observer = new MyPakcageInstallObserver(

context, APPName, appId, fileName, packageName, type_name);

Log.i(TAG, "########installFlags:" + installFlags + "packagename:"

+ packageName);

pm.installPackage(Uri.fromFile(file), observer, installFlags,

packageName);

} catch (Exception e) {

((MarketApplication) context).setApp_detail_status(appId,

MarketApplication.APP_STATUS_NOTEXIT);

}

}

/* 静默卸载 */

public static void uninstallApkDefaul(Context context, String action,

String packageName) {

PackageManager pm = context.getPackageManager();

IPackageDeleteObserver observer = new MyPackageDeleteObserver(context,

action, packageName);

pm.deletePackage(packageName, observer, 0);

}

/* 静默卸载回调 */

private static class MyPackageDeleteObserver extends

IPackageDeleteObserver.Stub {

Context cxt;

String action;

String pkname;

public MyPackageDeleteObserver(Context c, String action, String pkname) {

this.cxt = c;

this.action = action;

this.pkname = pkname;

}

@Override

public void packageDeleted(String packageName, int returnCode) {

Log.d(TAG, "returnCode = " + returnCode + ",action:" + action

+ "packageName:" + packageName + ",pkname:" + pkname);// 返回1代表卸载成功

if (returnCode == 1) {//TODO 以下是删除数据库记录,只做参考

/*SharedPreferences installedAPPInfo = cxt.getSharedPreferences(

"installedAPPInfo", Context.MODE_WORLD_READABLE);

if (installedAPPInfo.contains(packageName)) {

String appId = installedAPPInfo.getString(packageName,

"no this appId");

((MarketApplication) cxt.getApplicationContext())

.setApp_detail_status(appId,

MarketApplication.APP_STATUS_NOTEXIT);

installedAPPInfo.edit().remove(packageName).commit();

ContentResolver conResolver = cxt.getContentResolver();

conResolver.delete(InstalledAppInfo.CONTENT_URI,

InstalledAppInfo.APP_PKNAME + " = " + "‘" + pkname

+ "‘", null);

}

MarketApplication ma = ((MarketApplication) cxt

.getApplicationContext());

Log.e(TAG, "###packageDeleted###111size:"

+ ma.getManagerLists().size());

ma.removeManagerItem(pkname);

ma.removeUpdateItem(pkname);

Log.e(TAG, "##packageDeleted####22222size:"

+ ma.getManagerLists().size());*/

}

Intent it = new Intent();

it.setAction(action);

it.putExtra("uninstall_returnCode", returnCode);

cxt.sendBroadcast(it);

}

}

/* 静默安装回调 */

private static class MyPakcageInstallObserver extends

IPackageInstallObserver.Stub {

Context cxt;

String appName;

String appId;

String filename;

String pkname;

String type_name;

public MyPakcageInstallObserver(Context c, String appName,

String appId, String filename, String packagename,

String type_name) {

this.cxt = c;

this.appName = appName;

this.appId = appId;

this.filename = filename;

this.pkname = packagename;

this.type_name = type_name;

}

@Override

public void packageInstalled(String packageName, int returnCode) {

MarketApplication ma = ((MarketApplication) cxt

.getApplicationContext());

Log.i(TAG,

"returnCode = " + returnCode + ","

+ ma.getApp_detail_status(appId));// 返回1代表安装成功

Intent it = new Intent();

it.setAction(CustomAction.INSTALL_ACTION);

it.putExtra("install_returnCode", returnCode);

it.putExtra("install_packageName", packageName);

it.putExtra("install_appName", appName);

it.putExtra("install_appId", appId);

if (returnCode == 1) {

//ma.getAPPList();

//ma.setManagerLists();

if (ma.getApp_detail_status(appId) == MarketApplication.APP_STATUS_UPDATITNG) {

ma.removeUpdateItem(pkname);

cxt.sendBroadcast(it);

return;

}

SharedPreferences installedAPPInfo = cxt.getSharedPreferences(

"installedAPPInfo", Context.MODE_WORLD_READABLE);

installedAPPInfo.edit().putString(packageName, appId).commit();

// 保存信息到数据库

if (appId != null && appName != null && pkname != null

&& type_name != null) {

ContentResolver conResolver = cxt.getContentResolver();

ContentValues values = new ContentValues();

values.put(InstalledAppInfo.APP_ID, appId);

values.put(InstalledAppInfo.APP_NAME, appName);

values.put(InstalledAppInfo.APP_PKNAME, pkname);

values.put(InstalledAppInfo.APP_TYPENAME, type_name);

Uri result = conResolver.insert(

InstalledAppInfo.CONTENT_URI, values);

Log.i(TAG,

"#########install suscess...result:"

+ result.toString());

}

ma.setApp_detail_status(appId,

MarketApplication.APP_STATUS_INSTALLED);

}

File f = new File(filename);

if (f.exists()) {

f.delete();

}

cxt.sendBroadcast(it);

}

}

/**

* sd卡不存在

*/

public static final int NO_SDCARD = -1;

/**

* 移动应用到SD Card

*

* @param context

* @param pkname

* @return

*/

public static void movePackage(Context context, String pkname) {

PackageManager pm = context.getPackageManager();

MovePackageObserver mpo = new MovePackageObserver();

pm.movePackage(pkname, mpo, PackageManager.INSTALL_EXTERNAL);

}

/**

* 移动应用的回调

*/

public static class MovePackageObserver extends IPackageMoveObserver.Stub {

public MovePackageObserver() {

}

@Override

public void packageMoved(String packageName, int returnCode)

throws RemoteException {

Log.i(TAG, "packagename:" + packageName + ",returnCode:"

+ returnCode);

}

}

/**

* 判断有无sd卡

* */

public static boolean hasSdcard() {

String status = Environment.getExternalStorageState();

if (status.equals(Environment.MEDIA_MOUNTED)

|| status.equals("/mnt/sdcard")) {

Log.i(TAG, "has sdcard....");

return true;

} else {

return false;

}

}

}

自此,静默安装卸载代码实现。最后在AndroidMenifast.xml中要注册权限和添加为系统用户组,如果eclipse编译的话,并记得签名(不会的话戳这里)

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

package="xxx.xxx.xxxx"

android:installLocation="internalOnly"

android:versionCode="1"

android:versionName="1.0.19"

android:sharedUserId="android.uid.system"

>

<uses-sdk android:minSdkVersion="4"/>

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

<uses-permission android:name="android.permission.INTERNET" />

<uses-permission android:name="android.permission.INSTALL_PACKAGES" />

<uses-permission android:name="android.permission.DELETE_PACKAGES" />

<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

...

</manifest>

注:最后特别注意一点,因为下载的apk等只有rw----- root可读写权限,必须用个办法来给下载的apk赋权限,让系统级应用可以打开操作。这里作者是通过一个jni来调用C层接口,实现给指定的apk赋权限。然后执行安装apk过程

permission_change.cpp

?


1

2

3

4

5

6

7

8

9

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

#include <jni.h>

#include <string.h>

#include <android/log.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <stdio.h>

#define LOGI printf

#define LOGE printf

static const char *classPathName = "com/utils/PermissionNative"; //此处包名视java层native包名而定

typedef union{

JNIEnv* env;

void* venv;

}UnionJNIEnvToVoid;

static jboolean ChangePermission(const char* str)

{

const char* p;

char tmp_path[50];

memset(tmp_path,0,sizeof(tmp_path));

p = str+5;

while(p < str+strlen(str))

{

if(*p ==‘/‘)

{

memcpy(tmp_path,str,p-str);

if(chmod(tmp_path,0755) == -1)

{

LOGI("chmod  %s failed!\n",tmp_path);

return JNI_FALSE;//

}

LOGI("tmp_path_chmod = %s\n",tmp_path);

}

p++;

}

if(chmod(str,0755) == -1)

{

LOGI("chmod  %s failed!\n",str);

return JNI_FALSE;//

}

return JNI_TRUE;//

}

static jboolean   PermissionChange(JNIEnv *env, jobject thiz,jstring path)

{

const char* str;

str = env->GetStringUTFChars(path,false);

if(str == NULL)

{

return JNI_FALSE;

}

if(ChangePermission(str))

{

env->ReleaseStringUTFChars(path,str);

return JNI_TRUE;//JNI_FALSE

} else {

env->ReleaseStringUTFChars(path,str);

return JNI_FALSE;//

}

}

static JNINativeMethod methods[] = {

{"native_permission_change", "(Ljava/lang/String;)Z", (void*)PermissionChange },

};

/*

* Register several native methods for one class.

*/

static int registerNativeMethods(JNIEnv* env, const char* className,

JNINativeMethod* gMethods, int numMethods)

{

jclass clazz;

clazz = env->FindClass(className);

if (clazz == NULL) {

LOGI("Native registration unable to find class ‘%s‘\n", className);

return JNI_FALSE;

}

LOGI("FindClass succ\n");

if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {

LOGI("RegisterNatives failed for ‘%s‘\n", className);

return JNI_FALSE;

}

LOGI("RegisterNatives succ\n");

return JNI_TRUE;

}

/*

* Register native methods for all classes we know about.

*

* returns JNI_TRUE on success.

*/

static int registerNatives(JNIEnv* env)

{

if (!registerNativeMethods(env,classPathName,

methods, sizeof(methods) / sizeof(methods[0]))) {

return JNI_FALSE;

}

LOGI("registerNatives succ\n");

return JNI_TRUE;

}

// -------------------------------------------------------------------------

/*

* This is called by the VM when the shared library is first loaded.

*/

jint JNI_OnLoad(JavaVM* vm, void* reserved)

{

UnionJNIEnvToVoid uenv;

uenv.venv = NULL;

jint result = -1;

JNIEnv* env = NULL;

LOGI("JNI_OnLoad begin\n");

if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK) {

LOGI("ERROR: GetEnv failed\n");

goto bail;

}

LOGI("GetEnv succ\n");

env = uenv.env;

if (registerNatives(env) != JNI_TRUE) {

LOGI("ERROR: registerNatives failed\n");

goto bail;

}

LOGI("registerNatives succ!");

result = JNI_VERSION_1_4;

bail:

return result;

}

Android.mk如下:

?


1

2

3

4

5

6

7

8

9

LOCAL_PATH :=$(call my-dir)

include $(CLEAR_VARS)

LOCAL_PRELINK_MODULE :=false

LOCAL_MODULE_TAGS := eng

LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog

LOCAL_SRC_FILES :=permission_change.cpp

LOCAL_MODULE :=libpermission_change_jni

include $(BUILD_SHARED_LIBRARY)

4.拷贝apk

条件:

  1. 获取系统权限
  2. 拷贝apk到data/app

注:4.2和4.0上以测试通过,不过没有回调提示的,需要自己代码实现

5.效果图

最最后,眼见为实:附上效果图(注ddms截图有色差,不知道咋解决,有知道的请告之,万分感谢):

6.补充说明

遇到很多朋友实现静默安装时,来问很多各式各样的问题,这里我说明下:

我只是提供了一种我实现的方式,并不是个公共的模板,大家实现的时候肯定会遇到很多问题,有些编译不过,或者那些类找不到,参数不对等等,我也感到很无力。

这里我只是记录自己工作中实现时大的方向,并且所有相关的代码都在里面。如果有哪些模糊不明白的,欢迎大家来咨询;但是像一些编译问题我觉得大家还是自己解决,并且各个环境不一样,我也不一定能解决。

最后我只能很确切的保证,以上方式是绝对可行的。但是也有局限性,并不是所有平台都能通用的,只能是系统用户组的apk才能调用隐藏接口,并需要签名(不同平台的签名肯定是不一样的)。具体原因可以看我后面的一篇介绍签名的文章

时间: 2024-10-08 12:17:22

android 实现静默安装、卸载(图)的相关文章

Android实现静默安装

一般情况下,Android系统安装apk会出现一个安装界面,用户可以点击确定或者取消来进行apk的安装. 但在实际的项目需求中,有一种需求,就是希望apk在后台安装(不出现安装界面的提示),这种安装方式称为静默安装. Android实现静默安装的方式有很多,这里只介绍一种比较简单易理解的方法,就是调用Android未公开的API(installPackage)来实现. 下面通过一种简单的Demo来简单实现静默安装,界面如下: 当点击"静默安装"的按钮时,会在后台安装360手机卫士的ap

android 实现静默安装、卸载

方法1:[使用调用接口方法,由于安装卸载应用程序的部分API是隐藏的,所以必须下载Android系统源码,在源码下开发并编译之后使用MM命令编译生成APK文件] import java.io.File; import android.app.Activity; import android.os.Bundle; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.

Java代码实现APP普通安装卸载和静默安装卸载

两者差异 执行普通安装.卸载,将会弹出确认安装.卸载的提示框,与在文件管理器中打开APK文件实现安装.卸载相同. 执行静默安装.卸载,正常状态下,前台无任何反应,APP在后台完成安装和卸载.该功能一般也被称为"后台安装". 普通安装 核心代码: Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType( Uri.fromFile(new File(apkPath)), "application/

Android 中静默安装

静默安装原理: 1.需要获取root的操作权限 2.通过命令式的方式直接进行安装APK.在使用 Android Studio debug安装的时候可以看到控制台上的命令 那么就直接上代码吧: /**<p>项目名:singno</p>  * <p>包名: com.singno</p>  * <p>文件名:VersionManager.java</p>  * <p>版本信息: 2.1.0</p>  * <p&

android实现静默安装demo

1.须要RootTools.jar 2.运行脚本 public class InstallerActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main)

Android随笔之——静默安装、卸载

随笔之所以叫随笔,就是太随意了,说起来,之前的闹钟系列随笔还没写完,争取在十月结束之前找时间把它给写了吧.今天要讲的Android APK的静默安装.卸载.网上关于静默卸载的教程有很多,更有说要调用隐藏API,在源码下用MM命令编译生成APK的,反正我能力有限,没一一研究过,这里选择一种我试验成功的来讲. 静默安装.卸载的好处就是你可以偷偷摸摸,干点坏事什么的,哈哈~ 一.准备工作 要实现静默安装.卸载,首先你要有root权限,能把你的静默安装.卸载程序移动到system/app目录下. 1.用

Android apk的安装、卸载、更新升级(通过Eclipse实现静默安装)

一.通过Intent消息机制发送消息,调用系统应用进行,实现apk的安装/卸载 . (1) 调用系统的安装应用,让系统自动进行apk的安装 String fileName = "/data/data/com.zlc.ipanel.operate/FileOperate.apk";  Uri uri = Uri.fromFile(new File(fileName));  Intent intent = new Intent(Intent.ACTION_VIEW);  intent.se

Android 静默安装和智能安装的实现方法

1 简介 最近研究了Android的静默安装和智能安装,于是写博客记录一下. 静默安装就是无声无息的在后台安装apk,没有任何界面提示. 智能安装就是有安装界面,但全部是自动的,不需要用户去点击. 首先强调两点: 静默安装必须要root权限 智能安装必须要用户手动开启无障碍服务 2 原理 静默安装.卸载的原理就是利用pm install命令来安装apk,pm uninstall 来卸载apk. 智能安装是利用android系统提供的无障碍服务AccessibilityService,来模拟用户点

Android 无需root实现apk的静默安装

转载请注明出处:http://blog.csdn.net/yyh352091626/article/details/50533137 Android的静默安装似乎是一个很有趣很诱人的东西,但是,用普通做法,如果手机没有root权限的话,似乎很难实现静默安装,因为Android并不提供显示的Intent调用,一般是通过以下方式安装apk: Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFi