Optimize Custom Tabs (Beta)
Stay organized with collections
Save and categorize content based on your preferences.
AI-generated Key Takeaways
-
The web view APIs for ads utilize app signals to enhance monetization for web publishers and protect advertisers from spam within Custom Tabs.
-
Communication for ad events is facilitated through a postMessage channel with the
CustomTabsSession
by the Google Mobile Ads SDK, triggered by AdSense code, Google Publisher Tag, or IMA for HTML5. -
Implementation involves modifying the
onCustomTabsServiceConnected()
callback to utilizeMobileAds.registerCustomTabsSession()
for establishing the postMessage channel connection and enriching ad tags with SDK signals. -
Prerequisites include a Chrome Custom Tabs implementation, associating your app to a website with Digital Asset Links, and utilizing Google Mobile Ads SDK 23.0.0 or higher.
The web view APIs for ads makes app signals available to the tags in your
CustomTabSession
,
helping to improve monetization for the web publishers that provided the content
and to protect advertisers from spam.
How it works
Communication with the Google Mobile Ads SDK only happens in response to ad events triggered by any of the following:
The Google Mobile Ads SDK facilitates communication by opening a postMessage
channel with the CustomTabsSession
provided by the Android framework.
Prerequisites
- Google Mobile Ads SDK 23.0.0 or higher.
- An existing Chrome Custom Tabs implementation in your mobile app. See Warm-up and pre-fetch: using the Custom Tabs Service.
- Associate your mobile app to a website using Digital Asset Links. For instructions, see PostMessage for TWA.
Add the following
<meta-data>
tag in yourAndroidManifest.xml
file to bypass the check for theAPPLICATION_ID
. If you miss this step and don't provide the<meta-data>
tag, the Google Mobile Ads SDK throws anIllegalStateException
on app start.<!--BypassAPPLICATION_IDcheckforwebviewAPIsforads--> <meta-data android:name="com.google.android.gms.ads.INTEGRATION_MANAGER" android:value="webview"/>
Implementation
Within your Chrome Custom Tabs implementation, modify the code in the
onCustomTabsServiceConnected()
callback. Replace newSession()
with MobileAds.registerCustomTabsSession()
. This establishes a connection with the
postMessage channel to enrich the ad tags with SDK signals. A Digital Asset Link
is needed to connect the postMessage channel. Optionally, you can set the
CustomTabsCallback
parameter to listen for Chrome Custom Tab events.
You should still be able to send messages from the CustomTabsSession
received
from the Google Mobile Ads SDK but the port could change when the SDK requests
a new channel that overrides the existing one.
The following code snippet shows how to register a CustomTabsSession
using the
Google Mobile Ads SDK:
Kotlin
importcom.google.android.gms.ads.MobileAds
classMainActivity:ComponentActivity(){
privatevarcustomTabsClient:CustomTabsClient? =null
privatevarcustomTabsSession:CustomTabsSession? =null
overridefunonCreate(savedInstanceState:Bundle?){
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Get the default browser package name, this will be null if
// the default browser does not provide a CustomTabsService.
valpackageName=CustomTabsClient.getPackageName(applicationContext,null);
if(packageName==null){
// Do nothing as service connection is not supported.
return
}
CustomTabsClient.bindCustomTabsService(
applicationContext,
packageName,
object:CustomTabsServiceConnection(){
overridefunonCustomTabsServiceConnected(
name:ComponentName,client:CustomTabsClient,
){
customTabsClient=client
// Warm up the browser process.
customTabsClient?.warmup(0L)
// Create a new browser session using the Google Mobile Ads SDK.
customTabsSession=MobileAds.registerCustomTabsSession(
this@MainActivity.applicationContext,
client,
// Checks the "Digital Asset Link" to connect the postMessage channel.
ORIGIN,
// Optional parameter to receive the delegated callbacks.
customTabsCallback
)
// Create a new browser session if the Google Mobile Ads SDK is
// unable to create one.
if(customTabsSession==null){
customTabsSession=client.newSession(customTabsCallback)
}
// Pass the custom tabs session into the intent.
valcustomTabsIntent=CustomTabsIntent.Builder(customTabsSession).build()
customTabsIntent.launchUrl(this@MainActivity,
Uri.parse("YOUR_URL"))
}
overridefunonServiceDisconnected(componentName:ComponentName){
// Remove the custom tabs client and custom tabs session.
customTabsClient=null
customTabsSession=null
}
})
}
// Listen for events from the CustomTabsSession delegated by the Google Mobile Ads SDK.
privatevalcustomTabsCallback:CustomTabsCallback=object:CustomTabsCallback(){
@Synchronized
overridefunonNavigationEvent(navigationEvent:Int,extras:Bundle?){
// Called when a navigation event happens.
}
@Synchronized
overridefunonMessageChannelReady(extras:Bundle?){
// Called when the channel is ready for sending and receiving messages on both
// ends.
// This frequently happens, such as each time the SDK requests a
// new channel.
}
@Synchronized
overridefunonPostMessage(message:String,extras:Bundle?){
// Called when a tab controlled by this CustomTabsSession has sent a postMessage.
}
overridefunonRelationshipValidationResult(
relation:Int,requestedOrigin:Uri,result:Boolean,extras:Bundle?
){
// Called when a relationship validation result is available.
}
overridefunonActivityResized(height:Int,width:Int,extras:Bundle){
// Called when the tab is resized.
}
overridefunextraCallback(callbackName:String,args:Bundle?){
}
overridefunextraCallbackWithResult(callbackName:String,args:Bundle?):Bundle? {
returnnull
}
}
companionobject{
// Replace this URL with an associated website.
constvalORIGIN="https://www.google.com"
}
}
Java
importcom.google.android.gms.ads.MobileAds;
class MainActivityextendsComponentActivity{
// Replace this URL with an associated website.
privatestaticfinalStringORIGIN="https://www.google.com";
privateCustomTabsClientcustomTabsClient;
privateCustomTabsSessioncustomTabsSession;
@Override
protectedvoidonCreate(@NullableBundlesavedInstanceState){
super.onCreate(savedInstanceState);
// Get the default browser package name, this will be null if
// the default browser does not provide a CustomTabsService.
StringpackageName=CustomTabsClient.getPackageName(getApplicationContext(),null);
if(packageName==null){
// Do nothing as service connection is not supported.
return;
}
CustomTabsClient.bindCustomTabsService(
getApplicationContext(),
packageName,
newCustomTabsServiceConnection(){
@Override
publicvoidonCustomTabsServiceConnected(@NonNullComponentNamename,
@NonNullCustomTabsClientclient){
customTabsClient=client;
// Warm up the browser process.
customTabsClient.warmup(0);
// Create a new browser session using the Google Mobile Ads SDK.
customTabsSession=MobileAds.registerCustomTabsSession(
MainActivity.this.getApplicationContext(),
client,
// Checks the "Digital Asset Link" to connect the postMessage channel.
ORIGIN,
// Optional parameter to receive the delegated callbacks.
customTabsCallback);
// Create a new browser session if the Google Mobile Ads SDK is
// unable to create one.
if(customTabsSession==null){
customTabsSession=client.newSession(customTabsCallback);
}
// Pass the custom tabs session into the intent.
CustomTabsIntentintent=newCustomTabsIntent.Builder(customTabsSession).build();
intent.launchUrl(MainActivity.this,Uri.parse("YOUR_URL"));
}
@Override
publicvoidonServiceDisconnected(ComponentNamecomponentName){
// Remove the custom tabs client and custom tabs session.
customTabsClient=null;
customTabsSession=null;
}
}
);
}
// Listen for events from the CustomTabsSession delegated by the Google Mobile Ads SDK.
privatefinalCustomTabsCallbackcustomTabsCallback=newCustomTabsCallback(){
@Override
publicvoidonNavigationEvent(intnavigationEvent,@NullableBundleextras){
// Called when a navigation event happens.
super.onNavigationEvent(navigationEvent,extras);
}
@Override
publicvoidonMessageChannelReady(@NullableBundleextras){
// Called when the channel is ready for sending and receiving messages on both
// ends.
// This frequently happens, such as each time the SDK requests a
// new channel.
super.onMessageChannelReady(extras);
}
@Override
publicvoidonPostMessage(@NonNullStringmessage,@NullableBundleextras){
// Called when a tab controlled by this CustomTabsSession has sent a postMessage.
super.onPostMessage(message,extras);
}
@Override
publicvoidonRelationshipValidationResult(intrelation,@NonNullUrirequestedOrigin,
booleanresult,@NullableBundleextras){
// Called when a relationship validation result is available.
super.onRelationshipValidationResult(relation,requestedOrigin,result,extras);
}
@Override
publicvoidonActivityResized(intheight,intwidth,@NonNullBundleextras){
// Called when the tab is resized.
super.onActivityResized(height,width,extras);
}
@Override
publicvoidextraCallback(@NonNullStringcallbackName,@NullableBundleargs){
super.extraCallback(callbackName,args);
}
@Nullable
@Override
publicBundleextraCallbackWithResult(@NonNullStringcallbackName,@NullableBundleargs){
returnsuper.extraCallbackWithResult(callbackName,args);
}
};
}