繁体   English   中英

从内部存储器下载并安装应用程序 (apk) - 无 SD 卡

[英]Download and install an application (apk) from internal memory - no SD card

向我所有的程序员伙伴们问好,新年快乐。

我的代码从远程服务器下载了一个 apk 文件。 我需要通过代码启动安装过程,而无需用户显式安装。 问题是我不能使用 SD 卡下载 apk 文件。

我可以导航到 data/data/files 文件夹并可以看到我下载的文件。 唯一的问题是我无法安装它。 这就是我得到的

 '/data/data/org.obs.testinstall.main/files/app.apk': Permission denied 

我了解 Android 不授予访问数据目录的权限。 我的问题是如何在不使用 SD 卡的情况下下载和安装应用程序(apk)。 此应用程序不打算在市场上发布。 我尝试使用内部存储

FileOutputStream fos = openFileOutput("app.apk", Context.MODE_PRIVATE);

和缓存目录

File file = getCacheDir();
File outputFile = new File(file, "app.apk");

两者都给出相同的结果..“权限被拒绝”

当我更改代码以合并 SD 卡时,应用程序可以完美运行,但不能选择使用 SD 卡。

肯定有办法做到这一点。 很难相信 Android 操作系统中存在这样的障碍。

有人做过吗? 任何解决方法? 任何指针都会有所帮助。

如果使用PRIVATE模式写入,它是由android应用程序引起的,无法从另一个应用程序文件中读取。

你可以这样做:

String fileName = "tmp.apk";
FileOutputStream fos = openFileOutput(fileName,
        MODE_WORLD_READABLE | MODE_WORLD_WRITEABLE);

// write the .apk content here ... flush() and close()

// Now start the standard instalation window
File fileLocation = new File(context.getFilesDir(), fileName);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(fileLocation),
                       "application/vnd.android.package-archive");
context.startActivity(intent);

不过要小心,因为该文件现在是全世界可见的,并且可以被同一设备中的任何应用程序看到,如果他们知道文件位置的话。

无需root。 你可以使用 linux 命令 chmod 来完成它。

public static String exec(String[] args) {
    String result = "";
    ProcessBuilder processBuilder = new ProcessBuilder(args);
    Process process = null;
    InputStream errIs = null;
    InputStream inIs = null;
    try {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int read = -1;
        process = processBuilder.start();
        errIs = process.getErrorStream();
        while ((read = errIs.read()) != -1) {
            baos.write(read);
        }
        baos.write('\n');
        inIs = process.getInputStream();
        while ((read = inIs.read()) != -1) {
            baos.write(read);
        }
        byte[] data = baos.toByteArray();
        result = new String(data);
    } catch (IOException e) {
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            if (errIs != null) {
                errIs.close();
            }
            if (inIs != null) {
                inIs.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (process != null) {
            process.destroy();
        }
    }
    return result;
}

在您的程序中,可以像这样调用它:

    String[] args1 = { "chmod", "705", "/data/data/org.obs.testinstall.main/files/" };
    exec(args1);
    String[] args2 = { "chmod", "604", "/data/data/org.obs.testinstall.main/files/app.apk" };
    exec(args2);

然后您可以根据需要安装 app.apk。

你也可以使用

downloadedFile.setReadable(true, false);

fileOutputStream = openFileOutput(fileName, Context.MODE_PRIVATE);

有两个 setReadable 方法。 第一个有一个参数,第二个有两个参数。

setReadable(boolean readable)
setReadable(boolean readable, boolean ownerOnly)

对我来说,我在startActivity之后删除了 apk 文件,这是异步的。

太糟糕了,没有更好的解析错误描述(文件未找到,访问被拒绝,包中的文件损坏,......)

当您发送安装 apk 的意图时,您可以使用此功能更改 apk 目录的模式。

private static boolean changeMode(String filePath, String prefixPath) {
    if (TextUtils.isEmpty(prefixPath) || !filePath.startsWith(prefixPath)) {
        return true;
    }

    try {
        String[] args1 = { "chmod", "705", prefixPath};
        Runtime.getRuntime().exec(args1);
    } catch (IOException e) {
        e.printStackTrace();
        return false;
    }

    String subPath = filePath.split(prefixPath)[1];
    String[] subArr = subPath.split(File.separator);
    for (String path : subArr) {
        if (!TextUtils.isEmpty(path)) {
            prefixPath = prefixPath + File.separator + path;
            try {
                if (!prefixPath.endsWith(".apk")) {
                    String[] progArray1 = {"chmod", "705", prefixPath};
                    Runtime.getRuntime().exec(progArray1);
                } else {
                    String[] progArray2 = {"chmod", "604", prefixPath};
                    Runtime.getRuntime().exec(progArray2);
                }
            } catch (IOException e) {
                e.printStackTrace();
                return false;
            }
        }
    }
    return true;
}

在您发送意图之前,请检查 chmod 是否已经成功。

    boolean chmodRes = changeMode(filePath, context.getCacheDir().getAbsolutePath())
            && changeMode(filePath, context.getFilesDir().getAbsolutePath());
    if (!chmodRes) {
        return false;
    }

尝试生根您的设备,然后从设备运行程序,而不是使用模拟器。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM