Download And Install App Programmatically

Download And Install App Programmatically
February 20, 2020 14 Comments Android Development,Development Pushpendra Kumar

Hey guys welcome to the most interesting tutorial, which is as “Programmatically install and download apk from a custom Android application”. Here I am going to give you answer of your question How to download and install app programmatically in android. In addition, For doing that we will create a sample app. If you are new to android then go through with the video tutorial link attached

Download and install app programmatically

Here, I am letting you know few basic steps for doing this in very pure manner. Let’s say you have already created your android application with java. And now you are looking few decent steps. Which make your work very easy for downloading the android application and install it in phones programmatically. In other words, You are looking very simple steps for doing this task with latest android version with API level 29. So let’s begin now.

Add few lines of code inside your android manifest file. Which is named as AndroidManifest.xml

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

Above code is related with permissions!

After that, We will look into the deep of android manifest file. And add the following code.

        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths" />
        </provider>

This is code for provide. In Actually this is useful for file reading from the storage. This code you need to write under the application tag. 

Now you have to add the provider_paths.xml in you res->xml folder. And the cod of this file is give below.

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path
        name="external"
        path="." />
    <external-files-path
        name="external_files"
        path="." />
    <cache-path
        name="cache"
        path="." />
    <external-cache-path
        name="external_cache"
        path="." />
    <files-path
        name="files"
        path="." />
</paths>

This file is useful for finding the path of the file with the help of FileProvider.java class. And the navigation of above code is given below.

provider_path
How to install android APK programmatically

Wonderful, After that create a GenericFileProvider.java class inside your package directory. And make sure this file should be inside that folder, where your MainActivity.java file does exist. And the code of this file will be like that.

package com.colourmoon.downloadapk;

import androidx.core.content.FileProvider;

public class GenericFileProvider extends FileProvider {
   //This file would be empty. 
}

In addition, This file would be empty. This file automatically initiated from Androidmanifest.xml file. And it’s initiates the functionality of FileProvider, It self.  

Java code for downloading, Installing and Permissions for API Level 29

After that, Create the main activity as mention below.

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
import java.util.Objects;

import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;

public class MainActivity extends AppCompatActivity {

    private static final int PERMISSION_REQUEST_CODE = 200;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        Button btn_click = findViewById(R.id.btn_click);
        btn_click.setOnClickListener(new View.OnClickListener() {
            @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
            @Override
            public void onClick(View v) {
                if (checkPermission()) {
                    UpdateApp atualizaApp = new UpdateApp();
                    atualizaApp.setContext(MainActivity.this);
                    atualizaApp.execute("https://example.com/apks/my_apk.apk");
                } else {
                    requestPermission();
                }
            }
        });
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode == PERMISSION_REQUEST_CODE) {
            if (grantResults.length > 0) {

                boolean locationAccepted = grantResults[0] == PackageManager.PERMISSION_GRANTED;
                boolean cameraAccepted = grantResults[1] == PackageManager.PERMISSION_GRANTED;
                if (locationAccepted && cameraAccepted) {
                    UpdateApp updateApp = new UpdateApp();
                    updateApp.setContext(MainActivity.this);
                    updateApp.execute("https://example.com/apks/my_apk.apk");
                }
            }
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    private boolean checkPermission() {
        int result = ContextCompat.checkSelfPermission(getApplicationContext(), WRITE_EXTERNAL_STORAGE);
        int result1 = ContextCompat.checkSelfPermission(getApplicationContext(), READ_EXTERNAL_STORAGE);

        return result == PackageManager.PERMISSION_GRANTED && result1 == PackageManager.PERMISSION_GRANTED;
    }

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    private void requestPermission() {
        ActivityCompat.requestPermissions(this, new String[]{WRITE_EXTERNAL_STORAGE, READ_EXTERNAL_STORAGE}, PERMISSION_REQUEST_CODE);
    }

    public class UpdateApp extends AsyncTask<String, Integer, String> {
        private ProgressDialog mPDialog;
        private Context mContext;

        void setContext(Activity context) {
            mContext = context;
            context.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mPDialog = new ProgressDialog(mContext);
                    mPDialog.setMessage("Please wait...");
                    mPDialog.setIndeterminate(true);
                    mPDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                    mPDialog.setCancelable(false);
                    mPDialog.show();
                }
            });
        }

        @Override
        protected String doInBackground(String... arg0) {
            try {

                URL url = new URL(arg0[0]);
                HttpURLConnection c = (HttpURLConnection) url.openConnection();
                c.setRequestMethod("GET");
                c.setDoOutput(true);
                c.connect();
                int lenghtOfFile = c.getContentLength();

                String PATH = Objects.requireNonNull(mContext.getExternalFilesDir(null)).getAbsolutePath();
                File file = new File(PATH);
                boolean isCreate = file.mkdirs();
                File outputFile = new File(file, "my_apk.apk");
                if (outputFile.exists()) {
                    boolean isDelete = outputFile.delete();
                }
                FileOutputStream fos = new FileOutputStream(outputFile);

                InputStream is = c.getInputStream();

                byte[] buffer = new byte[1024];
                int len1;
                long total = 0;
                while ((len1 = is.read(buffer)) != -1) {
                    total += len1;
                    fos.write(buffer, 0, len1);
                    publishProgress((int) ((total * 100) / lenghtOfFile));
                }
                fos.close();
                is.close();
                if (mPDialog != null)
                    mPDialog.dismiss();
                installApk();
            } catch (Exception e) {
                Log.e("UpdateAPP", "Update error! " + e.getMessage());
            }
            return null;
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            if (mPDialog != null)
                mPDialog.show();

        }


        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            if (mPDialog != null) {
                mPDialog.setIndeterminate(false);
                mPDialog.setMax(100);
                mPDialog.setProgress(values[0]);
            }
        }

        @Override
        protected void onPostExecute(String result) {
            if (mPDialog != null)
                mPDialog.dismiss();
            if (result != null)
                Toast.makeText(mContext, "Download error: " + result, Toast.LENGTH_LONG).show();
            else
                Toast.makeText(mContext, "File Downloaded", Toast.LENGTH_SHORT).show();
        }


        private void installApk() {
            try {
                String PATH = Objects.requireNonNull(mContext.getExternalFilesDir(null)).getAbsolutePath();
                File file = new File(PATH + "/my_apk.apk");
                Intent intent = new Intent(Intent.ACTION_VIEW);
                if (Build.VERSION.SDK_INT >= 24) {
                    Uri downloaded_apk = FileProvider.getUriForFile(mContext, mContext.getApplicationContext().getPackageName() + ".provider", file);
                    intent.setDataAndType(downloaded_apk, "application/vnd.android.package-archive");
                    List<ResolveInfo> resInfoList = mContext.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
                    for (ResolveInfo resolveInfo : resInfoList) {
                        mContext.grantUriPermission(mContext.getApplicationContext().getPackageName() + ".provider", downloaded_apk, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
                    }
                    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
                    startActivity(intent);
                } else {
                    intent.setAction(Intent.ACTION_VIEW);
                    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                    intent.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true);
                    intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                }
                startActivity(intent);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

Wonderful! In addition, I want to tell you that. This code contains the code of Run time permission for API Level 29. And also, We can say that,  It’s contains code for run time permission in android for API level more than 21. And this code also contains the procedure for storing and reading the file from the phone directory. After that, I will tell about the activity_main.xml file. So have look at the below code!

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/btn_click"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Download!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Wonderful! All Developers. In Conclusion I would like to give you the best wishes. Finally you have achieved your goal with the help of this tutorial. If you want any tutorial on different topic or you want to enhance the above tutorial, Then you can comment into the comment box. 

Below I am giving you some related links. Please go through with that also.

Wish you a HAPPY CODING 😎😎😎☺️

Tags
About The Author
Pushpendra Kumar I am passionate about mobile application development and professional developer at Colour Moon Technologies Pvt Ltd (www.thecolourmoon.com). This website I have made so that I can meet with new challenges and can share here.
Leave Comment
  1. 1

    AffiliateLabz

    Great content! Super high-quality! Keep it up! 🙂

    Reply
  2. 1

    ปั้มไลค์

    Like!! I blog quite often and I genuinely thank you for your information. The article has truly peaked my interest.

    Reply
  3. 1

    rizupz

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

    Reply
  4. 1

    Mansoor

    Thank you for this tutorial. this is perfect

    Reply
  5. 1

    Nikunj Palsana

    Shown error “there was a problem parsing the package” in android 10 I also allow for Unknown Source.
    What to do for this error?

    Reply
    1. 1

      Pushpendra Kumar

      If you are getting this error, means you should cross check the package name and APK name of the app file. And one more thing I would like to ask. APK is getting download in your device or not?

      Reply
  6. 1

    Aahin

    Hey Pushpendra, even I’m getting “There was a problem parsing the package” in Android 8.
    I allowed Installation from Unknown Source as well.
    And, file is not getting downloaded.

    Reply
    1. 1

      Pushpendra Kumar

      Hi, Please try after uninstalling the application. It Happens some time.

      Reply
  7. 1

    Vipin

    Thank you for sharing this. I have it implemented and working.
    It’s a very usefull for me . Thanks a lot.

    Reply
  8. 1

    Ravindra

    Hi, I checked this but its not working in my case.. download case implemented in service class but its thrown exception at InputStream is = c.getInputStream();

    Reply
    1. 1

      Pushpendra Kumar

      Might be you are missing something, Please cross check the permissions.

      Reply
  9. 1

    Matt

    Shown: E/UpdateAPP: Update error! http://51.77.123.184/packages/arman.apk
    What to do for this error?

    Reply
    1. 1

      Pushpendra Kumar

      Please make sure, You have given the proper URL, Wherever your APK exist.

      Reply
  10. 1

    Everton

    Realy great job!

    Just one thing.

    “This is code for provide. In Actually this is useful for file reading from the storage. This code you need to write under the application tag. ”

    it has to be INSIDE the application tag, at least for me it works only this way.

    Reply

Leave a reply

Your email address will not be published. Required fields are marked *