Android 11 heeft wijzigingen aangebracht in de manier waarop apps kunnen communiceren met andere apps die de gebruiker op het apparaat heeft geïnstalleerd. Meer informatie over deze wijzigingen vindt u in de Android-documentatie .
Wanneer een Android-app met aangepaste tabbladen SDK-niveau 30 of hoger gebruikt, kunnen er wijzigingen nodig zijn. Dit artikel bespreekt de wijzigingen die mogelijk voor die apps nodig zijn.
In het eenvoudigste geval kunnen aangepaste tabbladen worden gestart met een korte regel zoals deze:
new CustomTabsIntent.Builder().build()
.launchUrl(this, Uri.parse("https://www.example.com"));
Toepassingen die op deze manier toepassingen starten of zelfs aanpassingen aan de gebruikersinterface toevoegen, zoals het wijzigen van de kleur van de werkbalk of het toevoegen van een actieknop , hoeven geen wijzigingen in de toepassing door te voeren.
Voorkeur voor native apps
Maar als u de best practices volgt, zijn er mogelijk toch enkele wijzigingen nodig.
De eerste relevante best practice is dat applicaties de voorkeur moeten geven aan een native app om de intentie af te handelen in plaats van een aangepast tabblad, als er een app is geïnstalleerd die dit kan.
Op Android 11 en hoger
Android 11 introduceert een nieuwe Intent-vlag, FLAG_ACTIVITY_REQUIRE_NON_BROWSER
, wat de aanbevolen manier is om een native app te openen, aangezien de app hiervoor geen pakketbeheerquery's hoeft te declareren.
static boolean launchNativeApi30(Context context, Uri uri) {
Intent nativeAppIntent = new Intent(Intent.ACTION_VIEW, uri)
.addCategory(Intent.CATEGORY_BROWSABLE)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_REQUIRE_NON_BROWSER);
try {
context.startActivity(nativeAppIntent);
return true;
} catch (ActivityNotFoundException ex) {
return false;
}
}
De oplossing is om te proberen de Intent te starten en FLAG_ACTIVITY_REQUIRE_NON_BROWSER
te gebruiken om Android te vragen browsers te vermijden bij het starten.
Als er geen native app wordt gevonden die deze Intent kan verwerken , wordt er een ActivityNotFoundException
gegenereerd.
Vóór Android 11
Ook al is de applicatie gericht op Android 11 of API-niveau 30, oudere Android-versies begrijpen de vlag FLAG_ACTIVITY_REQUIRE_NON_BROWSER
niet. In deze gevallen moeten we dus de Package Manager raadplegen:
private static boolean launchNativeBeforeApi30(Context context, Uri uri) {
PackageManager pm = context.getPackageManager();
// Get all Apps that resolve a generic url
Intent browserActivityIntent = new Intent()
.setAction(Intent.ACTION_VIEW)
.addCategory(Intent.CATEGORY_BROWSABLE)
.setData(Uri.fromParts("http", "", null));
Set<String> genericResolvedList = extractPackageNames(
pm.queryIntentActivities(browserActivityIntent, 0));
// Get all apps that resolve the specific Url
Intent specializedActivityIntent = new Intent(Intent.ACTION_VIEW, uri)
.addCategory(Intent.CATEGORY_BROWSABLE);
Set<String> resolvedSpecializedList = extractPackageNames(
pm.queryIntentActivities(specializedActivityIntent, 0));
// Keep only the Urls that resolve the specific, but not the generic
// urls.
resolvedSpecializedList.removeAll(genericResolvedList);
// If the list is empty, no native app handlers were found.
if (resolvedSpecializedList.isEmpty()) {
return false;
}
// We found native handlers. Launch the Intent.
specializedActivityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(specializedActivityIntent);
return true;
}
De hier gebruikte aanpak is om de Pakketbeheerder te raadplegen voor applicaties die een generieke http
intentie ondersteunen. Deze applicaties zijn waarschijnlijk browsers.
Zoek vervolgens naar applicaties die items verwerken voor de specifieke URL die we willen starten. Dit retourneert de instellingen van zowel browsers als native applicaties om die URL te verwerken.
Verwijder nu alle browsers uit de eerste lijst uit de tweede lijst, zodat u alleen de native apps overhoudt.
Als de lijst leeg is, weten we dat er geen native handlers zijn en retourneren we false. Anders starten we de intent voor de native handler.
Alles bij elkaar optellen
We moeten ervoor zorgen dat we voor elke gelegenheid de juiste methode gebruiken:
static void launchUri(Context context, Uri uri) {
boolean launched = Build.VERSION.SDK_INT >= 30 ?
launchNativeApi30(context, uri) :
launchNativeBeforeApi30(context, uri);
if (!launched) {
new CustomTabsIntent.Builder()
.build()
.launchUrl(context, uri);
}
}
Build.VERSION.SDK_INT
geeft de informatie die we nodig hebben. Als deze gelijk is aan of groter is dan 30, kent Android de FLAG_ACTIVITY_REQUIRE_NON_BROWSER
en kunnen we proberen een native app te starten met de nieuwe aanpak. Anders proberen we te starten met de oude aanpak.
Als het starten van een native app mislukt, starten we een Custom Tabs.
Er zit een zekere boilerplate in deze best practice. We werken eraan om dit eenvoudiger te maken door de complexiteit in een bibliotheek te verankeren. Houd de updates voor de ondersteuningsbibliotheek voor Android-browser-helper in de gaten.
Browsers detecteren die aangepaste tabbladen ondersteunen
Een ander veelvoorkomend patroon is het gebruik van de PackageManager om te detecteren welke browsers aangepaste tabbladen op het apparaat ondersteunen . Veelvoorkomende toepassingen hiervoor zijn het instellen van het pakket in de Intent om het dialoogvenster voor het doorverwijzen van app-ambiguaties te vermijden of het kiezen met welke browser verbinding moet worden gemaakt bij verbinding met de service voor aangepaste tabbladen .
Wanneer ontwikkelaars API-niveau 30 targeten, moeten ze een query-sectie toevoegen aan hun Android-manifest, waarin een intent-filter wordt gedeclareerd die overeenkomt met browsers met ondersteuning voor aangepaste tabbladen.
<queries>
<intent>
<action android:name=
"android.support.customtabs.action.CustomTabsService" />
</intent>
</queries>
Met de opmaak werkt de bestaande code die wordt gebruikt om te zoeken naar browsers die aangepaste tabbladen ondersteunen, zoals verwacht.
Veelgestelde vragen
V: De code die naar aangepaste tabbladen zoekt, genereert query's voor applicaties die https://
intents kunnen verwerken, maar het queryfilter declareert alleen een android.support.customtabs.action.CustomTabsService
-query. Zou er geen query voor https://
intents moeten worden gedeclareerd?
A: Wanneer u een queryfilter declareert, worden de antwoorden op een query naar de PackageManager gefilterd, niet de query zelf. Omdat browsers die aangepaste tabbladen ondersteunen de CustomTabsService declareren, worden deze niet uitgefilterd. Browsers die geen aangepaste tabbladen ondersteunen, worden wel uitgefilterd.
Conclusie
Dat zijn alle wijzigingen die nodig zijn om een bestaande integratie van aangepaste tabbladen aan te passen zodat deze werkt met Android 11. Als u meer wilt weten over het integreren van aangepaste tabbladen in een Android-app, begint u met de implementatiehandleiding en bekijkt u vervolgens de best practices voor het bouwen van een eersteklas integratie.
Laat het ons weten als u vragen of feedback heeft!