387

I made this with help from Android download binary file problems and Install Application programmatically on Android.

I want to make auto-update and auto-install at once. It is local so it's non-market application.

Here is my code for it:

public void Update(String apkurl){
    try {
        URL url = new URL(apkurl);
        HttpURLConnection c = (HttpURLConnection) url.openConnection();
        c.setRequestMethod("GET");
        c.setDoOutput(true);
        c.connect();

        String PATH = Environment.getExternalStorageDirectory() + "/download/";
        File file = new File(PATH);
        file.mkdirs();
        File outputFile = new File(file, "app.apk");
        FileOutputStream fos = new FileOutputStream(outputFile);

        InputStream is = c.getInputStream();

        byte[] buffer = new byte[1024];
        int len1 = 0;
        while ((len1 = is.read(buffer)) != -1) {
            fos.write(buffer, 0, len1);
        }
        fos.close();
        is.close();//till here, it works fine - .apk is download to my sdcard in download file

        Intent promptInstall = new Intent(Intent.ACTION_VIEW)
            .setData(Uri.parse(PATH+"app.apk"))
            .setType("application/android.com.app");
        startActivity(promptInstall);//installation is not working

    } catch (IOException e) {
        Toast.makeText(getApplicationContext(), "Update error!", Toast.LENGTH_LONG).show();
    }
}  

My permissions are INTERNET, WRITE_EXTERNAL_STORAGE, INSTALL_PACKAGES, and DELETE_PACKAGES.

When Intent promptInstall is loaded, the app crashes =/

So, am I missing permissions or is my code incorrect, or is there a better way to do this?

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
Uroš Podkrižnik
  • 8,607
  • 5
  • 21
  • 31
  • it doesn't even come to catch. it crashes before catch. in debug log it says ActivityThread.performLaunchActivity(ActivityThread$ActivityRecord, Intent) line: 2496 – Uroš Podkrižnik Feb 11 '11 at 10:31
  • 5
    You should remove the INSTALL_PACKAGES and DELETE_PACKAGES permissions as they will not actually be granted to your application and so have no bearing on how it works, but may produce confusing warnings in the logs when they are refused. – Chris Stratton Aug 27 '11 at 16:49
  • 2
    I assume that after the install, the apk is still in that download directory. How do you detect that the install was successful and delete the apk so it doesn't waste space? – Fraggle Apr 04 '12 at 20:38
  • I used this method in my application, with the change below. It works fine on 2.3.x devices and on 3.2 devices on which I've tested it. However, on 4.x devices, I get "java.io.FileNotFoundException: " on the line: InputStream is = c.getInputStream();. I have permissions INTERNET and WRITE_EXTERNAL_STORAGE. What am I missing? – Richard C Aug 08 '12 at 09:22
  • http://stackoverflow.com/questions/9406265/url-file-not-found-exception/9406341#9406341 solved my problem. – Richard C Aug 08 '12 at 09:40
  • 2
    It only worked for me when I removed `c.setDoOutput(true);`. See http://stackoverflow.com/questions/12496789/file-not-found-exception-when-using-getinputstream – Stephen Hosking Oct 16 '13 at 05:07
  • I have commented this line and worked for me thnx : c.setDoOutput(true); – Zied R. Mar 14 '16 at 15:37
  • Working Xamarin translation here - https://stackoverflow.com/a/69774124/1399272 – Bondolin Oct 29 '21 at 20:13

4 Answers4

423

I solved the problem. I made mistake in setData(Uri) and setType(String).

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);
startActivity(intent);

That is correct now, my auto-update is working. Thanks for help. =)

Edit 20.7.2016:

After a long time, I had to use this way of updating again in another project. I encountered a number of problems with old solution. A lot of things have changed in that time, so I had to do this with a different approach. Here is the code:

    //get destination to update file and set Uri
    //TODO: First I wanted to store my update .apk file on internal storage for my app but apparently android does not allow you to open and install
    //aplication with existing package from there. So for me, alternative solution is Download directory in external storage. If there is better
    //solution, please inform us in comment
    String destination = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/";
    String fileName = "AppName.apk";
    destination += fileName;
    final Uri uri = Uri.parse("file://" + destination);

    //Delete update file if exists
    File file = new File(destination);
    if (file.exists())
    //file.delete() - test this, I think sometimes it doesnt work
        file.delete();

    //get url of app on server
    String url = Main.this.getString(R.string.update_app_url);

    //set downloadmanager
    DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
    request.setDescription(Main.this.getString(R.string.notification_description));
    request.setTitle(Main.this.getString(R.string.app_name));

    //set destination
    request.setDestinationUri(uri);

    // get download service and enqueue file
    final DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
    final long downloadId = manager.enqueue(request);

    //set BroadcastReceiver to install app when .apk is downloaded
    BroadcastReceiver onComplete = new BroadcastReceiver() {
        public void onReceive(Context ctxt, Intent intent) {
            Intent install = new Intent(Intent.ACTION_VIEW);
            install.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            install.setDataAndType(uri,
                    manager.getMimeTypeForDownloadedFile(downloadId));
            startActivity(install);

            unregisterReceiver(this);
            finish();
        }
    };
    //register receiver for when .apk download is compete
    registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
Jon
  • 9,156
  • 9
  • 56
  • 73
Uroš Podkrižnik
  • 8,607
  • 5
  • 21
  • 31
  • 32
    Is there any way that the prompt to the user could be avoided? I'm attempting to update an app in an automated fashion as part of a test suite, and need to avoid reliance on a user to accept the download. – Sam Dec 08 '11 at 02:52
  • 6
    If there are no external storage how to download internal stroage & after downloading it will delete the apk file? – Piraba Mar 09 '12 at 12:14
  • 9
    @TomBennett No, the prompt cannot be avoided, for security reasons. Packages can only be installed if your app is signed with the same signature as the ROM - http://stackoverflow.com/a/15660063/832776 – Oleg Vaskevich Jun 11 '13 at 22:01
  • @juro the codes works well so far, it allows me to download and store the apk in SD card, and at the end of installation, it display "Application not installed", did I miss out something? – Sunny Jun 25 '13 at 09:10
  • 1
    @TomBennett and anyone else who might still be interested, The situation has changed somewhat over the last two years this question was originally asked. APKs can now be installed remotely through Google Play. The user still gets a set of permissions to accept in order to install an app, but that prompt can now be done over the Google Play web site (so it should be much easier to automate for your test suite with tools like Selenium). And also, now Google Play supports limited Beta releases, thus allowing you to automate the testing process before your app gets into production. – Stephan Branczyk Jul 08 '13 at 21:46
  • "application/vnd.android.package-archive" Can anyone explain this ? and where to write the google play URL of that Application? – Ahmad Arslan May 05 '14 at 11:52
  • 2
    Starting from targetSdk 24, you need to use FileProvider, as I've shown here: http://stackoverflow.com/a/40936215/878126 – android developer Dec 02 '16 at 15:57
  • 6
    Downloading worked for me, but starting the intent to install did not. I used this answer and then the following to trigger the install http://stackoverflow.com/a/40131196/2276198 – Alan May 16 '17 at 15:39
  • 3
    Downloading was working but I was getting an error that there was no activity found to handle intent. Hard coding the mime type to "application/vnd.android.package-archive" resolved it for me. – philcruz Jul 16 '17 at 20:36
  • App failed to install. Changing this line got it work. install.setDataAndType(uri,"application/vnd.android.package-‌​archive"); stackoverflow.com/a/4604922/3079364 – user3079364 – user3079364 Aug 16 '17 at 13:30
  • what if I don't have an external storage? will cache or file directory work? – Benjamin G Oct 03 '17 at 02:12
  • 1
    It's work below SDK 24, after need to use FileProvider https://stackoverflow.com/questions/38200282/android-os-fileuriexposedexception-file-storage-emulated-0-test-txt-exposed FileProvider Guide https://www.dev2qa.com/how-to-use-android-fileprovider-to-share-files-between-apps/ – Txuver Jhi Wei May 14 '19 at 09:40
  • Note that in order for the install to work on Android N you need to add the following to the manifest: – ClayHerendeen Jul 11 '19 at 16:54
  • 2
    @UrošPodkrižnik I am getting `There was problem while parsing the package` dialog on update click any update? – Sagar Aug 01 '19 at 08:06
  • this solution still work in 2020, very useful – Sruit A.Suk Mar 23 '20 at 15:13
  • Does this still work on Android 11? – Bencri Jul 02 '20 at 07:46
  • This code is pretty old and most of the variables and methods doesn't exists – Windgate May 14 '21 at 14:02
  • Getting the same error as @Sagar. "There was problem while parsing the package". It seems that the file is automatically removed before it is used for installation... – birgersp May 20 '21 at 18:52
  • I spent HOURS trying to get the download to work, only to realize it failed (silently) because of security constraints with using my web server. This saved me: https://stackoverflow.com/a/59260670/2583765 – birgersp May 21 '21 at 08:49
  • `but apparently android does not allow you to open and install aplication with existing package from there` -> I downloaded the apk file in application's `filesDir` and it worked for the same package. – Rajat Sangrame Oct 04 '21 at 12:53
72

For ICS I´ve implemented your code and made a class that extends AsyncTask. I hope you appreciate it! Thanks for your code and solution.

public class UpdateApp extends AsyncTask<String,Void,Void>{
    private Context context;
    public void setContext(Context contextf){
        context = contextf;
    }

    @Override
    protected Void doInBackground(String... arg0) {
        try {
            URL url = new URL(arg0[0]);
            HttpURLConnection c = (HttpURLConnection) url.openConnection();
            c.setRequestMethod("GET");
            c.setDoOutput(true);
            c.connect();

            String PATH = "/mnt/sdcard/Download/";
            File file = new File(PATH);
            file.mkdirs();
            File outputFile = new File(file, "update.apk");
            if(outputFile.exists()){
                outputFile.delete();
            }
            FileOutputStream fos = new FileOutputStream(outputFile);

            InputStream is = c.getInputStream();

            byte[] buffer = new byte[1024];
            int len1 = 0;
            while ((len1 = is.read(buffer)) != -1) {
                fos.write(buffer, 0, len1);
            }
            fos.close();
            is.close();

            Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.setDataAndType(Uri.fromFile(new File("/mnt/sdcard/Download/update.apk")), "application/vnd.android.package-archive");
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // without this flag android returned a intent error!
            context.startActivity(intent);


        } catch (Exception e) {
            Log.e("UpdateAPP", "Update error! " + e.getMessage());
        }
        return null;
    }
}   

To use it, in your main activity call by this way:

atualizaApp = new UpdateApp();
atualizaApp.setContext(getApplicationContext());
atualizaApp.execute("http://serverurl/appfile.apk");
Jared Rummler
  • 37,824
  • 19
  • 133
  • 148
ldmuniz
  • 828
  • 6
  • 5
  • True....
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); solved my problem. Thanks.
    – Omid Mafakher Oct 23 '12 at 12:01
  • 3
    downloaded .apk file is OK, but while installing from code I get this error there is a problem parsing the package. But when I pull from emulator that .apk and install it manually everything works fine. Can you tell me what is the problem ? – Big.Child Dec 01 '12 at 09:26
  • It still ask user for confirmation. Can somehow we can bypass that confirmation. The device i am using is rooted so i think any kind of permission is feasible. – jeevs Jul 09 '13 at 10:16
  • 6
    @Big.Child did you download the apk to a publicly accessible folder? I downloaded it to my application's files dir at first, but that was giving me the parse error. I now download it to `Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)` and that works for me. – Jasper de Vries Nov 20 '13 at 10:24
  • "application/vnd.android.package-archive" Can anyone explain this ? and where to write the google play URL of that Application? – Ahmad Arslan May 05 '14 at 11:53
  • 3
    Please for the love of god use getExternalCacheDir().getAbsolutePath(). Saving to the Downloads folder just leaves junk on the device when the user uninstalls the application. Trust me, no one who intentionally downloads an apk on the web will want to keep the apk in the downloads folder. – JonShipman Oct 21 '15 at 17:41
  • 1
    Than you for your answer. Really helped me. But i faced with `java.io.FileNotFoundException`. The problem was in this line: `urlConnection.setDoOutput(true);`. Apparently this line in JAVA forces the http protocol to change a GET to a POST regardless of specifying the GET. – akelec May 15 '16 at 12:47
  • @Idmuniz Hey may I check with you if the code above is meant for the download and install of apk from the specified URL? –  Jun 04 '18 at 01:28
  • @Idmuniz It does not work. Do you have any ideas? –  Jun 08 '18 at 05:54
  • 1
    Hi! Sorry for the long delay answering. I think that last updates may deprecated some functions for security reasons. Unfortunately, I'm using ionic to develop mobile apps, so, I don't know why the script above doesn't work anymore. – ldmuniz Jun 11 '18 at 15:09
  • 1
    i m using same code only with internal storage path not working . rest executing your code as it is.. – Ankesh Roy Aug 22 '19 at 16:19
  • Is it possible to make the update fully automatic without user interaction (clicking update or install) ? – W.M. Oct 01 '20 at 17:47
  • I guess so, because that code doesn't need user interaction. You can call it programatically in your application... BUT, Android changed A LOT since I wrote this.. I'm sure it need some changes to accomplish new secutiry policies – ldmuniz Oct 09 '20 at 00:58
8
/*  
 *  Code Prepared by **Muhammad Mubashir**.
 *  Analyst Software Engineer.
    Email Id : muhammad.mubashir.bscs@gmail.com
    Skype Id : muhammad.mubashir.ansari
    Code: **August, 2011.**

    Description: **Get Updates(means New .Apk File) from IIS Server and Download it on Device SD Card,
                 and Uninstall Previous (means OLD .apk) and Install New One.
                 and also get Installed App Version Code & Version Name.**

    All Rights Reserved.
*/
package com.SelfInstall01;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import com.SelfInstall01.SelfInstall01Activity;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.AlertDialog.Builder;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class SelfInstall01Activity extends Activity 
{
    class PInfo {
        private String appname = "";
        private String pname = "";
        private String versionName = "";
        private int versionCode = 0;
        //private Drawable icon;
        /*private void prettyPrint() {
            //Log.v(appname + "\t" + pname + "\t" + versionName + "\t" + versionCode);
        }*/
    }
    public int VersionCode;
    public String VersionName="";
    public String ApkName ;
    public String AppName ;
    public String BuildVersionPath="";
    public String urlpath ;
    public String PackageName;
    public String InstallAppPackageName;
    public String Text="";

    TextView tvApkStatus;
    Button btnCheckUpdates;
    TextView tvInstallVersion;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        //Text= "Old".toString();
        Text= "New".toString();


        ApkName = "SelfInstall01.apk";//"Test1.apk";// //"DownLoadOnSDcard_01.apk"; //      
        AppName = "SelfInstall01";//"Test1"; //

        BuildVersionPath = "http://10.0.2.2:82/Version.txt".toString();
        PackageName = "package:com.SelfInstall01".toString(); //"package:com.Test1".toString();
        urlpath = "http://10.0.2.2:82/"+ Text.toString()+"_Apk/" + ApkName.toString();

        tvApkStatus =(TextView)findViewById(R.id.tvApkStatus);
        tvApkStatus.setText(Text+" Apk Download.".toString());


        tvInstallVersion = (TextView)findViewById(R.id.tvInstallVersion);
        String temp = getInstallPackageVersionInfo(AppName.toString());
        tvInstallVersion.setText("" +temp.toString());

        btnCheckUpdates =(Button)findViewById(R.id.btnCheckUpdates);
        btnCheckUpdates.setOnClickListener(new OnClickListener() 
        {       
            @Override
            public void onClick(View arg0) 
            {
                GetVersionFromServer(BuildVersionPath); 

                if(checkInstalledApp(AppName.toString()) == true)
                {   
                    Toast.makeText(getApplicationContext(), "Application Found " + AppName.toString(), Toast.LENGTH_SHORT).show();


                }else{
                    Toast.makeText(getApplicationContext(), "Application Not Found. "+ AppName.toString(), Toast.LENGTH_SHORT).show();          
                }               
            }
        });

    }// On Create END.

    private Boolean checkInstalledApp(String appName){
        return getPackages(appName);    
    }

    // Get Information about Only Specific application which is Install on Device.
    public String getInstallPackageVersionInfo(String appName) 
    {
        String InstallVersion = "";     
        ArrayList<PInfo> apps = getInstalledApps(false); /* false = no system packages */
        final int max = apps.size();
        for (int i=0; i<max; i++) 
        {
            //apps.get(i).prettyPrint();        
            if(apps.get(i).appname.toString().equals(appName.toString()))
            {
                InstallVersion = "Install Version Code: "+ apps.get(i).versionCode+
                    " Version Name: "+ apps.get(i).versionName.toString();
                break;
            }
        }

        return InstallVersion.toString();
    }
    private Boolean getPackages(String appName) 
    {
        Boolean isInstalled = false;
        ArrayList<PInfo> apps = getInstalledApps(false); /* false = no system packages */
        final int max = apps.size();
        for (int i=0; i<max; i++) 
        {
            //apps.get(i).prettyPrint();

            if(apps.get(i).appname.toString().equals(appName.toString()))
            {
                /*if(apps.get(i).versionName.toString().contains(VersionName.toString()) == true &&
                        VersionCode == apps.get(i).versionCode)
                {
                    isInstalled = true;
                    Toast.makeText(getApplicationContext(),
                            "Code Match", Toast.LENGTH_SHORT).show(); 
                    openMyDialog();
                }*/
                if(VersionCode <= apps.get(i).versionCode)
                {
                    isInstalled = true;

                    /*Toast.makeText(getApplicationContext(),
                            "Install Code is Less.!", Toast.LENGTH_SHORT).show();*/

                    DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() 
                    {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            switch (which)
                            {
                            case DialogInterface.BUTTON_POSITIVE:
                                //Yes button clicked
                                //SelfInstall01Activity.this.finish(); Close The App.

                                DownloadOnSDcard();
                                InstallApplication();
                                UnInstallApplication(PackageName.toString());

                                break;

                            case DialogInterface.BUTTON_NEGATIVE:
                                //No button clicked

                                break;
                            }
                        }
                    };

                    AlertDialog.Builder builder = new AlertDialog.Builder(this);
                    builder.setMessage("New Apk Available..").setPositiveButton("Yes Proceed", dialogClickListener)
                        .setNegativeButton("No.", dialogClickListener).show();

                }    
                if(VersionCode > apps.get(i).versionCode)
                {
                    isInstalled = true;
                    /*Toast.makeText(getApplicationContext(),
                            "Install Code is better.!", Toast.LENGTH_SHORT).show();*/

                    DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() 
                    {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            switch (which)
                            {
                            case DialogInterface.BUTTON_POSITIVE:
                                //Yes button clicked
                                //SelfInstall01Activity.this.finish(); Close The App.

                                DownloadOnSDcard();
                                InstallApplication();
                                UnInstallApplication(PackageName.toString());

                                break;

                            case DialogInterface.BUTTON_NEGATIVE:
                                //No button clicked

                                break;
                            }
                        }
                    };

                    AlertDialog.Builder builder = new AlertDialog.Builder(this);
                    builder.setMessage("NO need to Install.").setPositiveButton("Install Forcely", dialogClickListener)
                        .setNegativeButton("Cancel.", dialogClickListener).show();              
                }
            }
        }

        return isInstalled;
    }
    private ArrayList<PInfo> getInstalledApps(boolean getSysPackages) 
    {       
        ArrayList<PInfo> res = new ArrayList<PInfo>();        
        List<PackageInfo> packs = getPackageManager().getInstalledPackages(0);

        for(int i=0;i<packs.size();i++) 
        {
            PackageInfo p = packs.get(i);
            if ((!getSysPackages) && (p.versionName == null)) {
                continue ;
            }
            PInfo newInfo = new PInfo();
            newInfo.appname = p.applicationInfo.loadLabel(getPackageManager()).toString();
            newInfo.pname = p.packageName;
            newInfo.versionName = p.versionName;
            newInfo.versionCode = p.versionCode;
            //newInfo.icon = p.applicationInfo.loadIcon(getPackageManager());
            res.add(newInfo);
        }
        return res; 
    }


    public void UnInstallApplication(String packageName)// Specific package Name Uninstall.
    {
        //Uri packageURI = Uri.parse("package:com.CheckInstallApp");
        Uri packageURI = Uri.parse(packageName.toString());
        Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI);
        startActivity(uninstallIntent); 
    }
    public void InstallApplication()
    {   
        Uri packageURI = Uri.parse(PackageName.toString());
        Intent intent = new Intent(android.content.Intent.ACTION_VIEW, packageURI);

//      Intent intent = new Intent(android.content.Intent.ACTION_VIEW);

        //intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        //intent.setFlags(Intent.ACTION_PACKAGE_REPLACED);

        //intent.setAction(Settings. ACTION_APPLICATION_SETTINGS);

        intent.setDataAndType
        (Uri.fromFile(new File(Environment.getExternalStorageDirectory() + "/download/"  + ApkName.toString())), 
        "application/vnd.android.package-archive");

        // Not open this Below Line Because...
        ////intent.setClass(this, Project02Activity.class); // This Line Call Activity Recursively its dangerous.

        startActivity(intent);  
    }
    public void GetVersionFromServer(String BuildVersionPath)
    {
        //this is the file you want to download from the remote server          
        //path ="http://10.0.2.2:82/Version.txt";
        //this is the name of the local file you will create
        // version.txt contain Version Code = 2; \n Version name = 2.1;             
        URL u;
        try {
            u = new URL(BuildVersionPath.toString());

            HttpURLConnection c = (HttpURLConnection) u.openConnection();           
            c.setRequestMethod("GET");
            c.setDoOutput(true);
            c.connect();

            //Toast.makeText(getApplicationContext(), "HttpURLConnection Complete.!", Toast.LENGTH_SHORT).show();  

            InputStream in = c.getInputStream();

            ByteArrayOutputStream baos = new ByteArrayOutputStream();

            byte[] buffer = new byte[1024]; //that stops the reading after 1024 chars..
            //in.read(buffer); //  Read from Buffer.
            //baos.write(buffer); // Write Into Buffer.

            int len1 = 0;
            while ( (len1 = in.read(buffer)) != -1 ) 
            {               
                baos.write(buffer,0, len1); // Write Into ByteArrayOutputStream Buffer.
            }

            String temp = "";     
            String s = baos.toString();// baos.toString(); contain Version Code = 2; \n Version name = 2.1;

            for (int i = 0; i < s.length(); i++)
            {               
                i = s.indexOf("=") + 1; 
                while (s.charAt(i) == ' ') // Skip Spaces
                {
                    i++; // Move to Next.
                }
                while (s.charAt(i) != ';'&& (s.charAt(i) >= '0' && s.charAt(i) <= '9' || s.charAt(i) == '.'))
                {
                    temp = temp.toString().concat(Character.toString(s.charAt(i))) ;
                    i++;
                }
                //
                s = s.substring(i); // Move to Next to Process.!
                temp = temp + " "; // Separate w.r.t Space Version Code and Version Name.
            }
            String[] fields = temp.split(" ");// Make Array for Version Code and Version Name.

            VersionCode = Integer.parseInt(fields[0].toString());// .ToString() Return String Value.
            VersionName = fields[1].toString();

            baos.close();
        }
        catch (MalformedURLException e) {
            Toast.makeText(getApplicationContext(), "Error." + e.getMessage(), Toast.LENGTH_SHORT).show();
            e.printStackTrace();
        } catch (IOException e) {           
            e.printStackTrace();
            Toast.makeText(getApplicationContext(), "Error." + e.getMessage(), Toast.LENGTH_SHORT).show();
        }
            //return true;
    }// Method End.

    // Download On My Mobile SDCard or Emulator.
    public void DownloadOnSDcard()
    {
        try{
            URL url = new URL(urlpath.toString()); // Your given URL.

            HttpURLConnection c = (HttpURLConnection) url.openConnection();
            c.setRequestMethod("GET");
            c.setDoOutput(true);
            c.connect(); // Connection Complete here.!

            //Toast.makeText(getApplicationContext(), "HttpURLConnection complete.", Toast.LENGTH_SHORT).show();

            String PATH = Environment.getExternalStorageDirectory() + "/download/";
            File file = new File(PATH); // PATH = /mnt/sdcard/download/
            if (!file.exists()) {
                file.mkdirs();
            }
            File outputFile = new File(file, ApkName.toString());           
            FileOutputStream fos = new FileOutputStream(outputFile);

            //      Toast.makeText(getApplicationContext(), "SD Card Path: " + outputFile.toString(), Toast.LENGTH_SHORT).show();

            InputStream is = c.getInputStream(); // Get from Server and Catch In Input Stream Object.

            byte[] buffer = new byte[1024];
            int len1 = 0;
            while ((len1 = is.read(buffer)) != -1) {
                fos.write(buffer, 0, len1); // Write In FileOutputStream.
            }
            fos.close();
            is.close();//till here, it works fine - .apk is download to my sdcard in download file.
            // So please Check in DDMS tab and Select your Emulator.

            //Toast.makeText(getApplicationContext(), "Download Complete on SD Card.!", Toast.LENGTH_SHORT).show();
            //download the APK to sdcard then fire the Intent.
        } 
        catch (IOException e) 
        {
            Toast.makeText(getApplicationContext(), "Error! " +
                    e.toString(), Toast.LENGTH_LONG).show();
        }           
    }
}
Jason Aller
  • 3,541
  • 28
  • 38
  • 38
Muhammad Mubashir
  • 1,591
  • 1
  • 21
  • 18
5

Thank you for sharing this. I have it implemented and working. However:

1) I install ver 1 of my app (working no problem)
2) I place ver 2 on the server. the app retrieves ver2 and saves to SD card and prompts user to install the new package ver2
3) ver2 installs and works as expected
4) Problem is, every time the app starts it wants the user to re-install version 2 again.

So I was thinking the solution was simply delete the APK on the sdcard, but them the Async task wil simply retrieve ver2 again for the server.

So the only way to stop in from trying to install the v2 apk again is to remove from sdcard and from remote server.

As you can imagine that is not really going to work since I will never know when all users have received the lastest version.

Any help solving this is greatly appreciated.

I IMPLEMENTED THE "ldmuniz" method listed above.

NEW EDIT: Was just thinking all me APK's are named the same. Should I be naming the myapk_v1.0xx.apk and and in that version proactivily set the remote path to look for v.2.0 whenever it is released?

I tested the theory and it does SOLVE the issue. You need to name your APK file file some sort of versioning, remembering to always set your NEXT release version # in your currently released app. Not ideal but functional.

Zumbarlal Saindane
  • 1,199
  • 11
  • 24
mxride
  • 91
  • 2
  • 5
  • 3
    Before you start the updating process, check with your server whether you have a new update pending or not. If the server returns Success, then start the update procedure (downloading, saving and installing the new update), else simply don't do anything. That is, if(there is any new update available) { "atualizaApp.execute("http://serverurl/appfile.apk");" } else { //do nothing } – Sarvan Aug 04 '14 at 07:39
  • For who come here in future: check version of saved apk, check version from server and check installed version, if all is the same, nothing to worry. You only download from server when server_version > saved in sd card and only install when sd_card > installed version, just to help – Tarcisio Wensing Jul 05 '18 at 13:42