Launch external apps from Delphi Android apps

It is common to make your Android apps able to launch and send data to external apps by using intents. But there are also situations when you want your Android app to only launch an external app without passing any data.

This tutorial will show you how to implement this feature :

General basics

As you know, there are two kind of Android apps :

  • Apps that have a visible icon on the OS app launcher for a manual starting/launching (like in most apps), their “<intent-filter>” in the “AndroidManifest.xml” file is like this :
<intent-filter>
   <action android:name="android.intent.action.MAIN" />
   <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
   <action android:name="android.intent.action.MAIN" />
   <category android:name="android.intent.category.DEFAULT" />
</intent-filter> 
  • Apps with no visible icon, and their “<intent-filter>” in the “AndroidManifest.xml” file is like this :
<intent-filter>
   <action android:name="android.intent.action.MAIN" />
   <category android:name="android.intent.category.DEFAULT" />
</intent-filter> 

As long as these apps have an intent filter’s action with the value “android.intent.action.MAIN”, they can be launched from another app. By sending an explicit intent to the target app to be started as a main entry point, but will not receive data.

Writing the intent in Delphi

First, add the AndroidAPI Delphi units to the uses clauses, inside the compiler conditional directives :

uses
... 
{$IF Defined(ANDROID)}
Androidapi.JNI.GraphicsContentViewText,
Androidapi.JNI.Net,
Androidapi.JNI.App,
Androidapi.helpers;
{$ENDIF}

Now we will implement the procedure by using the (try … except) instruction, inside the conditional directives :

  • In the first part, we write the code for :
    • Creating an intent.
    • Setting the package name of the target app, using “setPackage” (in the example below, “com.lecturepress.app2” is the target app).
    • We set the action “ACTION_MAIN”.
    • Then, we pass the intent to the Java procedure “startActivity”.
  • In the exception part, we will catch the “ActivityNotFoundException” exception raised by “startActivity” when the target app (the package name associated with the intent) is not found on the device. We need a specific code for opening Google Play store (or any other app store) with the page of our target app to download it when it is not installed on the user device.

{$IF Defined(ANDROID)}
var
Intent: JIntent;
{$ENDIF}
begin
{$IF Defined(ANDROID)
Intent := TJIntent.Create;
try Intent.setPackage(StringToJString('com.lecturepress.app2')); Intent.setAction(TJIntent.JavaClass.ACTION_MAIN);
SharedActivity.startActivity(Intent);
except Intent.setAction(TJIntent.JavaClass.ACTION_VIEW); Intent.setData(StrToJURI('https://play.app.goo.gl/?link=https://play.google.com/store/apps/details?id=com.lecturepress.app2')); tandroidhelper.Activity.startActivity(Intent); end; {$ENDIF}
end;

Bonus : write a ready-to-use procedure

Let’s write a procedure with the target app’s package name as a parameter.


procedure OpenApp(PN : string);
{$IF Defined(ANDROID)}
var
Intent: JIntent;
{$ENDIF}
begin
{$IF Defined(ANDROID)
Intent := TJIntent.Create;
try Intent.setPackage(StringToJString(PN)); Intent.setAction(TJIntent.JavaClass.ACTION_MAIN);
SharedActivity.startActivity(Intent);
except Intent.setAction(TJIntent.JavaClass.ACTION_VIEW); Intent.setData(StrToJURI('https://play.app.goo.gl/?link=https://play.google.com/store/apps/details?id=' + PN)); tandroidhelper.Activity.startActivity(Intent); end; {$ENDIF}
end;

We can call that procedure by using our example app :

OpenApp('com.lecturepress.app2');

Leave a Reply