1

I'm using the DownloadManager to download the apk from url. Download completes, I get the onReceive in my BroadcastReceiver for DownloadManager.ACTION_DOWNLOAD_COMPLETE.

Some Coding: I download the apk file from an url to the download directory.

DownloadManager.Request r = new DownloadManager.Request(mUri);
r.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "myapp.apk");
r.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
DownloadManager dm = (DownloadManager) activity.getSystemService(Context.DOWNLOAD_SERVICE);
SharedPreferences mSharedPref = activity.getSharedPreferences("package", Context.MODE_PRIVATE);
mSharedPref.edit().putLong("downloadID", dm.enqueue(r)).commit();

onReceive

File apkFile = new File(Environment.DIRECTORY_DOWNLOADS + "myapp.apk");
Intent promptInstall = new Intent(Intent.ACTION_VIEW).setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
startActivity(promptInstall);

Problems:

  • The file is there, I want to execute it but I package-installer is not shown
  • Even though I see the file in my phones download folder, I if I want to install it there is no package-installer to choose
  • I'm not sure if I do the file and pathing stuff right..
  • I get an parsing error from android when I try to open the file

Someone got an idea please?

Zuop
  • 584
  • 5
  • 7
  • 21
  • 1
    unless the device has been set to allow side-loading, how do you expect to be able to run this apk? This sort of thing is exactly how malicious code would want to work - download arbitrary executables from unknown sources and run them. – Marc B Jan 07 '15 at 15:03
  • 1
    I dont expect to run it automatically. I want the prompt where the User can choose to open the downloaded file with the package installer. So there is User interaction needed, its nor malicious.. – Zuop Jan 07 '15 at 15:04
  • This is not malicious as it launches the installer, no the user is prompted to install the APK or not. Can you output the exact `apkFile`'s path? – shkschneider Jan 07 '15 at 15:05
  • The path I log in the onReceive is: apkFile.getPath() = "Download/myapp.apk" apkFile.getAbsolutePath() = "/Download/myapp.apk" – Zuop Jan 07 '15 at 15:15

3 Answers3

1

I recently had to do something like this, hope it helps:

EDIT: Couple of notes, apkurl is a string to the download location. Make the byte buffer big enough for your response

    try {

        String PATH = Environment.getExternalStorageDirectory() + "/download/";
        File file = new File(PATH);
        file.mkdirs();
        // Create a file on the external storage under download
        File outputFile = new File(file, "app.apk");
        FileOutputStream fos = new FileOutputStream(outputFile);

        HttpGet m_httpGet = null;
        HttpResponse m_httpResponse = null;

        // Create a http client with the parameters
        HttpClient m_httpClient = setupHttpClient();
        String result = null;

        try {

            // Create a get object
            m_httpGet = new HttpGet(apkurl);

            // Execute the html request
            m_httpResponse = m_httpClient.execute(m_httpGet);
            HttpEntity entity = m_httpResponse.getEntity();

            // See if we get a response
            if (entity != null) {

                InputStream instream = entity.getContent();
                byte[] buffer = new byte[1024];

                // Write out the file
                int len1 = 0;
                while ((len1 = instream.read(buffer)) != -1) {
                    fos.write(buffer, 0, len1);
                }
                fos.close();
                instream.close();// till here, it works fine - .apk is download to my sdcard in download file

            }

        } catch (ConnectTimeoutException cte) {
            // Toast.makeText(MainApplication.m_context, "Connection Timeout", Toast.LENGTH_SHORT).show();
            return false;
        } catch (Exception e) {
            return false;
        } finally {
            m_httpClient.getConnectionManager().closeExpiredConnections();
        }

        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setDataAndType(
                Uri.fromFile(new File(Environment.getExternalStorageDirectory() + "/download/" + "app.apk")),
                "application/vnd.android.package-archive");
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        MainApplication.getApp().getApplicationContext().startActivity(intent);

        // System.exit(0);

    } catch (IOException e) {
        Debug.ERROR(CLASSNAME, METHODNAME, "Failed to update new apk");
        return false;
    } catch (Exception e1) {
        Debug.ERROR(CLASSNAME, METHODNAME, "Failed to update new apk");
        return false;
    }

    return true;
Chris Handy
  • 366
  • 1
  • 5
  • 1
    Honestly I tried to aviod the Http and Stream things simply with the DownloadManager.. If nothing helps I'll give it a try – Zuop Jan 07 '15 at 15:13
  • 1
    Give it a try with the intent for starting a apk install. The rest was downloading an apk from a get just for reference. Ensure you have permissions to read/write from the storage – Chris Handy Jan 07 '15 at 15:17
  • YES! It works now that I took the Intent part of your example. It seems to breake with the paths.. Thank you very much. – Zuop Jan 07 '15 at 15:28
  • if you're still there: I tested it again and have some trouble. I can choose the package installer in the prompt but ONLY from the intent prompt... if i go to the download directory and open/touch on the file the package installer is not in the select list... – Zuop Jan 20 '15 at 16:07
  • I am not too sure what you mean here sorry. Are you saying that if you use the intent, then you get the prompt to install the apk. However if you use something like ESFileExplorer then click on the apk it doesn't do anything? If that is the case what phone are you using? – Chris Handy Jan 20 '15 at 16:12
  • I tested it on several phones, I try to explain more detailed: If the download finished, I start the Intent for the user to choose, what to do with the downloaded file. Now he can choose the package-installer and everything is fine. But if he declines, the prompt disappears. The users closes the app. Now he wants to install it by going into the download folder where the file is (Home -> Downloads) and wants to install it. Here it's not possible to select the package-installer anymore.. I wonder why – Zuop Jan 20 '15 at 16:17
  • Make sure that the file is named something like "myapplication.apk". If this is the case and it is still not working, install a different file explorer on the device as all of the file explorers that I have used prompt the user to install any .apk files – Chris Handy Jan 20 '15 at 16:22
  • I write to: /mnt/sdcard/download/anyName.apk I read from: /mnt/sdcard/download/anyName.apk I tested it on a Honeywell, Samsung GT2 and Lenovo LifeTab, Nexus 4... all the same behavior.. after downloading the prompt comes with the package installer and if i decline and want to execute it "manually" via the integrated "Download" app (no external explorer stuff) I can't choose the installer anymore, on my Nexus 4 it opens it with HTML Viewer without questioning.. I'm sorry if I'm annoying you :D thanks anyway – Zuop Jan 20 '15 at 16:29
  • It sounds like it is to do with the "Download" app. If this is a major issue I would put a button in the app called "manual install" which fires an intent to install the cached version again. – Chris Handy Jan 20 '15 at 16:38
  • please see my new answer :) – Zuop Jan 20 '15 at 17:02
0

Make sure you have the android.permission.INSTALL_PACKAGES permission declared in your AndroidManifest.xml.

Then get your APK path:

File apkFile = new File(Environment.getExternalStorageDirectory() + "/download/" + "app.apk");

Now run the Intent:

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
shkschneider
  • 17,833
  • 13
  • 59
  • 112
  • android.permission.INSTALL_PACKAGES is for system apps, I dont want to use this because I expect it to not work for non-rooted devices – Zuop Jan 07 '15 at 15:12
  • 1
    Fine, but check your path. I believe that is the one error in your code. – shkschneider Jan 07 '15 at 15:13
0

All downloads you do with the device...

To clarify what I mean with "Downloads" here is a screenshot. This is the standart download folder for Android 5 on Nexus 4. When I click on the apk inside this, I dont get the prompt to install a .apk. Instead the HTML-Viewer or other useless stuff shows up to choose...

One possible mistake could be the DownloadManager.. maybe he "tags" the downloaded file wrong so its not interpreted as an apk file, I don't know... but I call

promptInstall.setDataAndType(Uri.fromFile(new File(Environment.getExternalStorageDirectory() + "/download/myapp.apk")), "application/vnd.android.package-archive");

all downloads... inside..

Zuop
  • 584
  • 5
  • 7
  • 21
  • My app apk downloads do no appear in this folder for my nexus devices I have always had to user "ESFileExplorer" or equivalent to access them – Chris Handy Jan 20 '15 at 17:49
  • That's because I say `DownloadManager.Request r = new DownloadManager.Request(mUri); r.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "myApp.apk");` Found something pointing to the web server... http://stackoverflow.com/questions/27822218/download-apk-from-url-and-execute/27822393?noredirect=1#comment44482155_27822393 lets see – Zuop Jan 21 '15 at 10:02
  • * http://stackoverflow.com/questions/7296829/how-to-download-apk-as-apk-not-as-zip – Zuop Jan 21 '15 at 10:08
  • fyi: for most devices it works now that i added `DownloadManager.Request r = new DownloadManager.Request(mUri); r.setMimeType("application/vnd.android.package-archive");` – Zuop Jan 27 '15 at 16:36