6

So far my code looks like this:

1. Dowload the APK file and save it into internal storege:

Using DependencyServices

App.xaml.cs

    IDownloader downloader = DependencyService.Get<IDownloader>();

    protected override void OnStart(){
        downloader.OnFileDownloaded+=OnFileDownloaded;
        downloader.DownloadFile("http://localhost:8080/download","folder"); 
    }

    private void OnFileDownloaded(object sender,DownloadEventArgs e) {
        if(e.FileSaved) {
            App.Current.MainPage.DisplayAlert("XF Downloader","File Saved Successfully","Close"); 
        } else {
            App.Current.MainPage.DisplayAlert("XF Downloader","Error while saving the file","Close");
        }
    }

Android : AndroidDownloader.cs

[assembly: Dependency(typeof(NoguianaNucleo.Droid.AndroidDownloader))]
namespace NoguianaNucleo.Droid { 
  public class AndroidDownloader: IDownloader {
    public event EventHandler<DownloadEventArgs> OnFileDownloaded;

    public void DownloadFile(string url,string folder) {

        string pathToNewFolder = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal),folder);
        Directory.CreateDirectory(pathToNewFolder);

        try {
            WebClient webClient = new WebClient();
            webClient.DownloadFileCompleted+=new AsyncCompletedEventHandler(Completed);
            string pathToNewFile = Path.Combine(pathToNewFolder,"nucleo.apk");
            webClient.DownloadFileAsync(new Uri(url),pathToNewFile);
        } catch(Exception ex) {
            if(OnFileDownloaded!=null)
                OnFileDownloaded.Invoke(this,new DownloadEventArgs(false));
        }
    }

    private void Completed(object sender,AsyncCompletedEventArgs e) {
        if(e.Error!=null) {
            App.Current.MainPage.DisplayAlert("Error", e.Error.Message,"Ok");
            if(OnFileDownloaded!=null)
                OnFileDownloaded.Invoke(this,new DownloadEventArgs(false));
        } else {
            if(OnFileDownloaded!=null)
                OnFileDownloaded.Invoke(this,new DownloadEventArgs(true));
        }
    }
  }
}

2. Intall the APK file from the internal storege:

App.xaml.cs

    public void OpenApk(string filepath) {
        Java.IO.File file = new Java.IO.File(filepath);
        Intent install = new Intent(Intent.ActionView);

        // Old Approach
        if(Android.OS.Build.VERSION.SdkInt<Android.OS.BuildVersionCodes.N) {
            install.SetFlags(ActivityFlags.NewTask|ActivityFlags.GrantReadUriPermission);
            install.SetDataAndType(Android.Net.Uri.FromFile(file),"application/vnd.android.package-archive"); //mimeType
        } else {
            Android.Net.Uri apkURI = Android.Support.V4.Content.FileProvider.GetUriForFile(Android.App.Application.Context,Android.App.Application.Context.ApplicationContext.PackageName+".fileprovider",file);
            install.SetDataAndType(apkURI,"application/vnd.android.package-archive");
            install.AddFlags(ActivityFlags.NewTask);
            install.AddFlags(ActivityFlags.GrantReadUriPermission);
        }

        Android.App.Application.Context.StartActivity(install);
    }

This last function doesn't work. I think Android.Support its not support any more.

I also tried this:

   var downloadUri = Android.Net.Uri.Parse("/data/user/0/noguiana.nucleo/files/noguiana/nucleo.apk");
   Intent install = new Intent(Intent.ActionInstallPackage);
   install.AddFlags(ActivityFlags.GrantReadUriPermission);
   install.AddFlags(ActivityFlags.GrantWriteUriPermission);
   install.AddFlags(ActivityFlags.GrantPersistableUriPermission);
   install.SetDataAndType(downloadUri,"application/vnd.android.package-archive");     
   context.StartActivity(install);

Nothing works

Do you know other way to install APK by programmatically in Xamarin.Forms (Android)?

David Zomada
  • 167
  • 1
  • 5
  • 22
  • Have you checked this thread : https://stackoverflow.com/questions/64283181/xamarin-android-download-and-install-apk-programatically ? Don't forget to change support to androidx provider in manifest . – ColeX Dec 06 '21 at 06:43
  • I already cheked it. It has the same issiu I do, "Android.Support.V4.Content" is not supported – David Zomada Dec 09 '21 at 09:33
  • Two notes. 1 - whatever is saved to apps internal folder is not accessible to any other app besides the owner, don't save to internal storage, use Downloads directory. 2 - try using Launcher from Xamarin.Essentials to redirect installation to system https://learn.microsoft.com/en-us/xamarin/essentials/launcher?tabs=android – Maxim Saplin Dec 09 '21 at 19:35
  • I had been trying your advice but this sentence doesn't work: `string pathToNewFile = Path.Combine(Android.OS.Environment.DirectoryDownloads,"nucleo.apk");` + `webClient.DownloadFileAsync(new Uri(url),pathToNewFile);` – David Zomada Dec 13 '21 at 08:45
  • What is the meaning of `not work` ? The download failed or it throws any exception ? – ColeX Dec 14 '21 at 06:03
  • Is doesn't save the file into the downloads folder it worked when I use `System.Environment.SpecialFolder.Personal` but when I change the directory it fail. I think it is on the saving process – David Zomada Dec 14 '21 at 10:50
  • @MaximSaplin I finaly made it work, just the downloaded and save on the downloads directory. I tried to use the launcher to open and install the file but I coudn't use it because the directory looks to be diferent between the share code on Xamarin.Forms and the Xamarin.Android. How could I do? I tried also dependency services and intents... I don't know nothing else to try – David Zomada Dec 21 '21 at 09:44

1 Answers1

0

Use PackageInstaller instead. ActionView and ACTION_INSTALL_PACKAGE had been deprecated in API level 29.

Have you tried this solution? Android PackageInstaller not installing APK

Mailin
  • 1
  • Hi! If you think that the question is already answered kindly flag the question as duplicate, avoid posting links in the answer area that redirects to other SO questions. – Kuro Neko May 06 '22 at 02:23