Android Tutorial Version safe APK installation

As explained in this tutorial all store apps will soon be forced to target the latest SDK.

This means that we can no longer rely on the OS backwards compatibility features and need to handle the behavior changes ourselves.

Starting from Android 8 (API 26) each app needs to explicitly request a special permission to install other apps. The global "install applications from unknown sources" option was removed.
First we check whether we already have permission:
B4X:
Private Sub CanRequestPackageInstalls As Boolean
   Dim ctxt As JavaObject
   ctxt.InitializeContext
   Dim PackageManager As JavaObject = ctxt.RunMethod("getPackageManager", Null)
   Return PackageManager.RunMethod("canRequestPackageInstalls", Null)
End Sub

If not we open the relevant settings page:
B4X:
MsgboxAsync("Please allow me to install applications.", "")
Wait For Msgbox_Result(Result As Int)
Dim in As Intent
in.Initialize("android.settings.MANAGE_UNKNOWN_APP_SOURCES", "package:" & Application.PackageName)
StartActivity(in)

SS-2017-12-26_17.01.57.png


We will then wait for Activity_Resume and check the value of CanRequestPackageInstalls again.

The last step is to start the installation intent.


The following non-dangerous permission is required:
B4X:
AddPermission(android.permission.REQUEST_INSTALL_PACKAGES)

A full example is attached. It also checks that the "installation from unknown source" option is enabled and that the external storage is writable.

Example updated and is now based on FileProvider class.
 

Attachments

  • InstallAPK.zip
    131.5 KB · Views: 3,382
Last edited:

Mahares

Expert
Licensed User
Longtime User
Can you install several apk's in succession? I tried the below code, but it installs only the first app. Thank you
B4X:
Private Sub SendInstallIntent
For Each ApkName As String In  File.ListFiles(File.DirAssets)
  If ApkName.EndsWith(".apk") Then
    File.copy(File.DirAssets, ApkName, Starter.SharedFolder, ApkName)
    Dim i As Intent
    If phone.SdkVersion >= 24 Then
        i.Initialize("android.intent.action.INSTALL_PACKAGE", CreateFileProviderUri(Starter.SharedFolder, ApkName))
        i.Flags = Bit.Or(i.Flags, 1) 'FLAG_GRANT_READ_URI_PERMISSION
    Else
        i.Initialize(i.ACTION_VIEW, "file://" & File.Combine(Starter.SharedFolder, ApkName))
        i.SetType("application/vnd.android.package-archive")
    End If
    StartActivity(i)
  End If
 Next   
End Sub
 

udg

Expert
Licensed User
Longtime User
A couple of hitches

In Manifest there are two identical copies of "AddApplicationText( <provider" (lines 19..40).
New FileProvider uses <files-path name="name" path="shared" /> instead of <external-files-path name="name" path="" /> as shown in post#1.
My understandig is that
files-path represents files in the files/ subdirectory of an app's internal storage area, so your example makes use of sub-dir "shared" inside it
external-files-path represents files in the root of an app's external storage area (DirDefaultExternal?).

udg
 
Last edited:

Erel

B4X founder
Staff member
Licensed User
Longtime User
Only one glitch. The redundant AddApplicationText was removed.

files-path represents files in the files/ subdirectory of an app's internal storage area, so your example makes use of sub-dir "shared" inside it
external-files-path represents files in the root of an app's external storage area
That's true. It is better and safer than sharing from the external storage (when possible).
 
Top