Reputation: 4256
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
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
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
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
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
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
Reputation: 8101
Try rooting your device and then running the program from the device, instead of using an emulator.
Upvotes: 0