• After 15+ years, we've made a big change: Android Forums is now Early Bird Club. Learn more here.

Download And Install App Programmatically

Cruzeberry

Lurker
Sep 13, 2017
6
1
Hello,

I'm currently working on an application that has been built so that it can manage upgrading and downgrading of versions away from the Play Store using my company's web servers. This worked fine until we tried compiling against Nougat.

The following is our code to download and install the new apk file:

// New file
File newAPKFile = new File(context.getExternalFilesDir(null), newfileName);
FileOutputStream fos = new FileOutputStream(newAPKFile);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
fos = context.openFileOutput(newAPKFile.getName(), context.MODE_PRIVATE);
} else {
fos = context.openFileOutput(newAPKFile.getName(), context.MODE_WORLD_READABLE| context.MODE_WORLD_WRITEABLE);
}
// Download the new APK file
InputStream is = httpConn.getInputStream();
byte[] buffer = new byte[1024];
int len1 = 0;
while ((len1 = is.read(buffer)) != -1) {
fos.write(buffer, 0, len1);
}
fos.flush();
fos.close();
is.close();
// Start the standard installation window
File fileLocation = new File(context.getExternalFilesDir(null), newfileName);
Intent downloadIntent;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Uri apkUri = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".fileProvider", fileLocation);
downloadIntent = new Intent(Intent.ACTION_VIEW);
downloadIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
downloadIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
downloadIntent.setDataAndType(apkUri, "application/vnd.android.package-archive");
} else {
downloadIntent = new Intent(Intent.ACTION_VIEW);
downloadIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
downloadIntent.setDataAndType(Uri.fromFile(fileLocation), "application/vnd.android.package-archive");
}
context.startActivity(downloadIntent);​


This is what I'm getting in logcat:

Process: com.google.android.packageinstaller, PID: 3807
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:318)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:243)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:761)
Caused by: java.lang.SecurityException: Permission Denial: opening provider android.support.v4.content.FileProvider from ProcessRecord{d42d519 3807:com.google.android.packageinstaller/u0a17} (pid=3807, uid=10017) that is not exported from uid 10085
at android.os.Parcel.readException(Parcel.java:1683)
at android.os.Parcel.readException(Parcel.java:1636)
at android.app.ActivityManagerProxy.getContentProvider(ActivityManagerNative.java:4169)
at android.app.ActivityThread.acquireProvider(ActivityThread.java:5434)
at android.app.ContextImpl$ApplicationContentResolver.acquireUnstableProvider(ContextImpl.java:2267)
at android.content.ContentResolver.acquireUnstableProvider(ContentResolver.java:1515)
at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1129)
at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:982)
at android.content.ContentResolver.openInputStream(ContentResolver.java:702)
at com.android.packageinstaller.PackageInstallerActivity$StagingAsyncTask.doInBackground(PackageInstallerActivity.java:732)
at com.android.packageinstaller.PackageInstallerActivity$StagingAsyncTask.doInBackground(PackageInstallerActivity.java:723)
at android.os.AsyncTask$2.call(AsyncTask.java:304)


Anybody got any ideas on this?
 
I have tried a few things on that page, got me a little further...

I'm now getting "There was a problem parsing the package", with this in logcat:

W/zipro: Error opening archive /data/user_de/0/com.google.android.packageinstaller/cache/package158645152.apk: Invalid file
Is this to do with where I am storing the file? No idea what that .apk file name is, must be autogenerated by the process?
 
Upvote 0
Hi, the code I'm using is as follows: (I have just been through and added some more debug lines and the size of the file in the location I'm downloading to appears to be 0, so it could be that I'm not saving the file correctly?)

// The following sets the connection for downloading the new apk
URL url = new URL("https://ourserver.com/ourApplication.apk");
URLConnection conn = url.openConnection();
HttpURLConnection httpConn = (HttpURLConnection) conn;
httpConn.setAllowUserInteraction(false);
httpConn.setInstanceFollowRedirects(true);
httpConn.setRequestMethod("GET");
httpConn.connect();
int checkConn = httpConn.getResponseCode();

// The following sets up the filename for saving the apk to the device
// Also create a file output stream to write to the file
File newAPKFile = new File(context.getExternalFilesDir(null), newfileName);
FileOutputStream fos = new FileOutputStream(newAPKFile);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
fos = context.openFileOutput(newAPKFile.getName(), context.MODE_PRIVATE);
} else {
fos = context.openFileOutput(newAPKFile.getName(), context.MODE_WORLD_READABLE| context.MODE_WORLD_WRITEABLE);
}

// Download the new APK file
InputStream is = httpConn.getInputStream();
byte[] buffer = new byte[1024];
int len1 = 0;
while ((len1 = is.read(buffer)) != -1) {
fos.write(buffer, 0, len1);
}
fos.flush();
fos.close();
is.close();

// Start the standard installation window
File fileLocation = new File(context.getExternalFilesDir(null), newfileName);
Intent downloadIntent;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Uri apkUri = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".fileProvider", fileLocation);
downloadIntent = new Intent(Intent.ACTION_VIEW);
downloadIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
downloadIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
downloadIntent.setDataAndType(apkUri, "application/vnd.android.package-archive");
List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(downloadIntent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resInfoList) {
String packageName = resolveInfo.activityInfo.packageName;
context.grantUriPermission(packageName, apkUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
} else {
downloadIntent = new Intent(Intent.ACTION_VIEW);
downloadIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
downloadIntent.setDataAndType(Uri.fromFile(fileLocation), "application/vnd.android.package-archive");
}
context.startActivity(downloadIntent);
 
Upvote 0
Yes, have you tried running your application in debug mode, and interactively debugging it by using breakpoints and stepping through the code.
If you don't know how to do this, please read the following thread as a starting point:

https://androidforums.com/threads/please-read-me-before-posting.987318/

You should also show your code in [code][/code] tags, with proper indentation, to make it as readable as possible.
Thanks.
 
Upvote 0
For anyone else that struggles with this, I've resolved the issue now! I changed the following:

Code:
FileOutputStream fos = new FileOutputStream(newAPKFile);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
fos = context.openFileOutput(newAPKFile.getName(), context.MODE_PRIVATE);
} else {
fos = context.openFileOutput(newAPKFile.getName(), context.MODE_WORLD_READABLE| context.MODE_WORLD_WRITEABLE);
}

to this:

Code:
FileOutputStream fos;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
   File newAPKFile = new File(context.getExternalFilesDir(null), newfileName);
   fos = new FileOutputStream(newAPKFile);
} else {
   fos = context.openFileOutput(newfileName, context.MODE_WORLD_READABLE| context.MODE_WORLD_WRITEABLE);
}

The full (working) code is as follows:

Code:
   FileOutputStream fos;
   if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
      File newAPKFile = new File(context.getExternalFilesDir(null), newfileName);
      fos = new FileOutputStream(newAPKFile);
   } else {
      fos = context.openFileOutput(newfileName, context.MODE_WORLD_READABLE| context.MODE_WORLD_WRITEABLE);
   }
              
   // Download the new APK file
   InputStream is = httpConn.getInputStream();
   byte[] buffer = new byte[1024];
   int len1 = 0;
   while ((len1 = is.read(buffer)) != -1) {
      fos.write(buffer, 0, len1);
   }
   fos.flush();
   fos.close();
   is.close();

// Start the standard installation window
 Intent downloadIntent;
 if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
      File fileLocation = new File(context.getExternalFilesDir(null), newfileName);
      Uri apkUri = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".fileProvider", fileLocation);

      downloadIntent = new Intent(Intent.ACTION_VIEW);
      downloadIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
      downloadIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
      downloadIntent.setDataAndType(apkUri, "application/vnd.android.package-archive");

      List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(downloadIntent, PackageManager.MATCH_DEFAULT_ONLY);
      for (ResolveInfo resolveInfo : resInfoList) {
         String packageName = resolveInfo.activityInfo.packageName;
         context.grantUriPermission(packageName, apkUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
      }

   } else {
      File fileLocation = new File(context.getFilesDir(), newfileName);
      downloadIntent = new Intent(Intent.ACTION_VIEW);
      downloadIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
      downloadIntent.setDataAndType(Uri.fromFile(fileLocation), "application/vnd.android.package-archive");
   }
    context.startActivity(downloadIntent);

Hope this helps someone!
 
  • Like
Reactions: Deleted User
Upvote 0

BEST TECH IN 2023

We've been tracking upcoming products and ranking the best tech since 2007. Thanks for trusting our opinion: we get rewarded through affiliate links that earn us a commission and we invite you to learn more about us.

Smartphones