How to download and install apk in Xamarin Forms in code?

JustAlexJustAlex Member ✭✭

Hi,
could anybody provide really working example (link to example) how to download and install apk programmatically on Xamarin Forms platform.
There are lot of questions without answers about that on this forum . On stackoverflow there are a lot information about that, but for native Android mainly.

Answers

  • AlessandroCaliaroAlessandroCaliaro ITMember ✭✭✭✭✭
    Xamarin in Forms is a ui framework. For this features you have to use platform specific code
  • JustAlexJustAlex Member ✭✭

    Hi Alessandro,
    tnx for quick reply. So, there is nothing to do with Xamarin Forms. All must be done in Xamarin.Android and Xamarin.iOS.
    Well, question still the same - good, working, platform specific code example (or link to...) that could be used in Xamarin Forms project? :)

  • JoeMankeJoeManke USMember ✭✭✭✭✭
    edited June 2018

    You could download the file with a platform-agnostic web request. Once you have that, here's a couple tips I picked up on writing the file and installing it. This is all assuming you write the file to your app's internal storage.

    1. Create the file using Stream stream = Context.OpenFileOutput(string filename, FileCreationMode mode); and get a reference to the file using File file = Context.GetFileStreamPath(filename);
    2. For Android versions of Marshmallow (6.0) and earlier, mode should be FileCreationMode.WorldReadable and on Nougat (7.0) and higher mode should be FileCreationMode.Private.
    3. On Android Nougat and higher, add a FileProvider to your project and use it to get the URI you will add to your install intent. Uri uri = FileProvider.GetUriForFile(Context context, string authority, File file); Also add ActivityFlags.GrantReadUriPermission to the flags you give to the intent. On earlier versions, get the URI with uri = Uri.FromFile(file);
    4. Starting with Android Oreo (8.0) you also need the RequestInstallPackages permission in your Android manifest.

    The reasoning for the differences between Nougat and earlier versions is that using FileCreationMode.WorldReadable will throw a JavaSecurityException on Nougat and later. Using a FileProvider allows you to create a file with FileCreationMode.Private but still share it with other applications. However, earlier versions of Android cannot install a package using the content:// URI that the FileProvider returns.

  • AlessandroCaliaroAlessandroCaliaro ITMember ✭✭✭✭✭
    This is java code I use to install apk


    File file = new File(message);
    if(file.exists()) {
    final Uri uri = Uri.parse("file://" + message); // creo l'uri con il file
    Intent install = new Intent(Intent.ACTION_VIEW);
    install.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    //install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    install.setDataAndType(uri, "application/vnd.android.package-archive");
    startActivity(install);
  • AlessandroCaliaroAlessandroCaliaro ITMember ✭✭✭✭✭
    This is java code I have used to download and install but I don’t know if it works again

    private void downloadAndInstallApk(){

    //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 =getString(R.string.apk_name);
    destination += fileName;
    final Uri uri = Uri.parse("file://" + destination);

    //Delete update file if exists
    File file = new File(destination);
    if (file.exists())
    file.delete();

    //get url of app on server
    final String url = getString(R.string.update_app_url) + fileName;

    //set downloadmanager
    DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
    request.setDescription(getString(R.string.notification_description));
    request.setTitle(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) {
    String action = intent.getAction();
    if(manager.ACTION_DOWNLOAD_COMPLETE.equals(action)){

    Intent install = new Intent(Intent.ACTION_VIEW);
    install.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    //install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    install.setDataAndType(uri, "application/vnd.android.package-archive");
    startActivity(install);

    unregisterReceiver(this);
    finish();


    //installAPK(uri.getPath());
    }
    }
    };
    //register receiver for when .apk download is compete
    registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));

    }
  • RegeRege Member

    Dear All,

    AlessandroCaliarom maybe success get solution "download and install" method? If yes please write me your solution. Thank you.

    My CODE:
    public void updateVersion(String apkurl){ //apkurl: something.com/xyz.apk

    String destination = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/";
    String fileName = "AppName_1.apk"; //Download File name
    destination += fileName;
    final Uri uri = Uri.parse("file://" + destination); //Download file storage uri
    
    //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();
    }
    
    file.setReadable(true, false);
    //set downloadmanager
    DownloadManager.Request request = new DownloadManager.Request(Uri.parse(apkurl));
    request.setDescription(this.getString(R.string.notification_description));
    request.setTitle(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
    final String finalDestination = destination;
    BroadcastReceiver onComplete = new BroadcastReceiver() {
        public void onReceive(Context ctxt, Intent intent) {
    
            String installerPackageName = getIntent().getStringExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME);
            Intent install = new Intent(Intent.ACTION_VIEW);
            install.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME, installerPackageName);
            install.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION);
            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));
    

    }

    ERROR:
    java.lang.RuntimeException: Error receiving broadcast Intent { act=android.intent.action.DOWNLOAD_COMPLETE flg=0x10 pkg=com.something.application (has extras) } in com.something.application.MainActi[email protected]
    at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$-android_app_LoadedApk$ReceiverDispatcher$Args_52226(LoadedApk.java:1329)
    at android.app.-$Lambda$FilBqgnXJrN9Mgyks1XHeAxzSTk.$m$0(Unknown Source:4)
    at android.app.-$Lambda$FilBqgnXJrN9Mgyks1XHeAxzSTk.run(Unknown Source:0)
    at android.os.Handler.handleCallback(Handler.java:789)
    at android.os.Handler.dispatchMessage(Handler.java:98)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6944)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
    Caused by: android.os.FileUriExposedException: file:///storage/emulated/0/Download/AppName_1.apk exposed beyond app through Intent.getData()
    at android.os.StrictMode.onFileUriExposed(StrictMode.java:1958)
    at android.net.Uri.checkFileUriExposed(Uri.java:2356)
    at android.content.Intent.prepareToLeaveProcess(Intent.java:10511)
    at android.content.Intent.prepareToLeaveProcess(Intent.java:10465)
    at android.app.Instrumentation.execStartActivity(Instrumentation.java:1616)
    at android.app.Activity.startActivityForResult(Activity.java:4564)
    at android.support.v4.app.BaseFragmentActivityApi16.startActivityForResult(BaseFragmentActivityApi16.java:54)
    at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:68)
    at android.app.Activity.startActivityForResult(Activity.java:4522)
    at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:751)
    at android.app.Activity.startActivity(Activity.java:4883)
    at android.app.Activity.startActivity(Activity.java:4851)
    at com.something.application.MainActivity$6.onReceive(MainActivity.java:267)
    at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$-android_app_LoadedApk$ReceiverDispatcher$Args_52226(LoadedApk.java:1319)
    at android.app.-$Lambda$FilBqgnXJrN9Mgyks1XHeAxzSTk.$m$0(Unknown Source:4)
    at android.app.-$Lambda$FilBqgnXJrN9Mgyks1XHeAxzSTk.run(Unknown Source:0)
    at android.os.Handler.handleCallback(Handler.java:789)
    at android.os.Handler.dispatchMessage(Handler.java:98)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6944)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)

    Thank you!

Sign In or Register to comment.