zoukankan      html  css  js  c++  java
  • android --静默安装

    【此篇文章为转载文章】

    最近需要实现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> + " ");
    }
    os.writeBytes("exit ");
    os.flush();
    os.close();
    }</i>
  • 相关阅读:
    JavaScript 按位与和逻辑与
    JavaScript跨域问题
    前端-知识+能力感触
    堆&堆排序
    Java中的数据类型和引用
    基础算法之选择排序
    基于TCP协议的网络通讯流程
    Java基础之封装
    个人主页
    算法基础之希尔排序
  • 原文地址:https://www.cnblogs.com/new0801/p/6175821.html
Copyright © 2011-2022 走看看