Umesh
Umesh

Reputation: 4256

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

Greetings and a happy new year to all my fellow programmers.

My code downloads an apk file from a remote server. I need to initiate the installation procedure through code, without user having to explicitly install it. The catch is that i cannot use an SD card download the apk file.

I can navigate to the data/data/files folder and can see my file downloaded. The only problem is that i cannot get it installed. This is what i get

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

I understand that Android does not give permission to access the data directory. My question is how can i download and install an application(apk) without using a SD card. This application is not intended to be published in the market. I have tried using both the Internal Storage using

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

and the cache directory

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

Both give the same result .. "Permission denied"

When i change the code to incorporate an SD card the application works perfectly, but using an SD card is not an option.

Surely there must be a way to do this. It is hard to believe that such a handicap exist in the Android O/S.

Has anybody done this? Any workarounds? Any pointers would be helpful.

Upvotes: 4

Views: 10702

Answers (6)

enesgonez
enesgonez

Reputation: 226

Also you can use

downloadedFile.setReadable(true, false);

with

fileOutputStream = openFileOutput(fileName, Context.MODE_PRIVATE);

There are two setReadable method. The first has one parameter and the second one has two parameters.

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

Upvotes: 1

wangzhengyi
wangzhengyi

Reputation: 876

when you send intent to install apk, you can use this function to change mode for apk directory.

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;
}

And before you send intent, check chmod is it alreay success.

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

Upvotes: 0

Goufalite
Goufalite

Reputation: 2363

For me I deleted the apk file right after the startActivity, which is asynchronous.

Too bad there is no better description of the parsing error (file not found, access denied, corrupted file in package,...)

Upvotes: 0

hanung
hanung

Reputation: 358

It it caused by android application can not read from another application file if it is written using PRIVATE mode.

You can do this:

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);

Be careful though, because that file is now world-visible, and can be seen by any application in the same device, if they know the file location.

Upvotes: 13

tianwei
tianwei

Reputation: 1879

No need to root. You can just use linux command chmod to do it.

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;
}

in your program,it can be invoked like this:

    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);

Then you can install the app.apk as wished.

Upvotes: 2

Shashank Kadne
Shashank Kadne

Reputation: 8101

Try rooting your device and then running the program from the device, instead of using an emulator.

Upvotes: 0

Related Questions