Search code examples
delphiandroid-13

How do I call the default mapping app in Android 13 from my Delphi app?


In Delphi 11.3, I'm trying to send a user in my Android app to the device's default mapping app (Google Maps, Waze,...) using an intent. The purpose of the intent is to request directions from the current location to another based on the Lat/Lng coordinates. It worked fine in previous Android & Delphi versions, but this code is not working in Android 13. From what I've read about permissions, it appears as though there are more restrictions beyond Andriod 11.

Anyway, when I click the Navigate button in my app, I keep getting the 'Receiver not found' message.

My AndroidManifest.xml shows these locations permissions:

android:targetSdkVersion="32" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />

Here's my code for the Navigate button click event:

procedure TMainForm.NavigateBtnClick(Sender: TObject);
var
  {$IFDEF ANDROID}
    Intent: JIntent;  //Declares the intent object
  {$ENDIF}
  LGoogleMapsURL: String;
begin
   // Populate a string to send to Mapping app
   LGoogleMapsURL:= 'google.navigation:q=37.422219,-122.08364&mode=d';
  
  {$IFDEF MSWINDOWS}
    WebBrowser1.Navigate(LGoogleMapsURL);
  {$ENDIF}

  {$IFDEF ANDROID}
      Intent := TJIntent.Create;
      Intent.setData(StrToJURI(LGoogleMapsURL));
      Intent.setAction(TJIntent.JavaClass.ACTION_VIEW);
      Intent.putExtra(TJIntent.JavaClass.EXTRA_TEXT, StringToJString(LGoogleMapsURL));
      if MainActivity.getPackageManager.queryIntentActivities(Intent, TJPackageManager.JavaClass.MATCH_DEFAULT_ONLY).size > 0 then
        begin          
          MainActivity.startActivity(Intent);
        end
      else
        ShowMessage('Receiver not found');
  {$ENDIF}
end;

Is this no longer valid for use in Android 13 or is something missing?


Solution

  • In order to make your example work, I needed to:

    Modify AndroidManifest.template.xml, to change the <queries> tag to:

        <queries>
    <%queries-child-elements%>
            <package android:name="com.google.android.apps.maps" />
        </queries>
    

    (see here)

    ..and alter the code:

      URI := TJnet_Uri.JavaClass.parse(StringToJString('google.navigation:q=37.422219,-122.08364&mode=d'));
      Intent := TJIntent.JavaClass.init(TJIntent.JavaClass.ACTION_VIEW, URI);
      Intent.setPackage(StringToJString('com.google.android.apps.maps'));
      if Intent.resolveActivity(TAndroidHelper.Context.getPackageManager) <> nil then
        TAndroidHelper.Context.startActivity(Intent);
    

    i.e. using queryIntentActivities isn't really necessary, unless you actually want to see which activities can handle the intent. URI is of type: Jnet_Uri

    If you want to query other packages, presumably you will need to have corresponding entries for them in the <queries> tag