Chrome Custom Tabs最佳实践
本文是 Chrome Custom Tabs 官方文檔的按照自己的理解的整理譯文
什么是Chrome Custom Tabs(CCT)?
當(dāng)開發(fā)者是去打開一個(gè)URL時(shí)候往往有兩種方式:WebView和打開瀏覽器。目前這兩種方式皆有不足,WebView不與瀏覽器共享狀態(tài),維護(hù)開銷大;打開瀏覽器是一個(gè)重量級(jí)的操作并且瀏覽器不可定制化。此時(shí)谷歌爸爸給了我們新的選擇,CCT讓我們?cè)诰W(wǎng)絡(luò)體驗(yàn)上有了很多的控制,使本地和Web內(nèi)容更加無縫之間的轉(zhuǎn)換,而無需采取WebView的方式。CCT允許應(yīng)用定制瀏覽器的外觀和樣式,如下:
- Toolbar顏色
- 打開關(guān)閉時(shí)的切換動(dòng)畫
- 添加Toolbar的Actions,添加Overflow Menu 和底部Toolbar
CCT還允許開發(fā)人員預(yù)啟動(dòng)Chrome和更快的內(nèi)容預(yù)抓取加載。
現(xiàn)在可以在Github上測(cè)試這些 sample.
怎么選擇Chrome Custom Tabs vs WebView?
WebView是對(duì)于展示自己域名下或本地的網(wǎng)頁內(nèi)容很好的一種解決方案,因?yàn)槟憧赡軙?huì)去網(wǎng)頁內(nèi)容做很多自定義的內(nèi)容。而如果引導(dǎo)用戶去第三方的網(wǎng)址時(shí),建議您使用CCT,理由如下:
- 易于實(shí)現(xiàn)。無需建代碼來管理請(qǐng)求,權(quán)限授予和Cookie
- UI上的自定義上文已提到
- 導(dǎo)航:瀏覽器提供了一個(gè)可回調(diào)的外部導(dǎo)航模塊
- 性能優(yōu)化:
- 在后臺(tái)瀏覽器的預(yù)加熱,避免從應(yīng)用程序竊取資源。
- 提前提供一個(gè)合適的URL到瀏覽器,它可以進(jìn)行投機(jī)性的工作,加快頁面加載時(shí)間
- 生命周期管理:通過提高“foreground”的重要級(jí)來防止CCT防止被系統(tǒng)被消滅
- 共享Cookie和權(quán)限模塊,用戶不必再次登錄到他們已經(jīng)連接或者重新授權(quán)他們已經(jīng)授權(quán)的網(wǎng)站
- 使用CCT用戶依舊可以從Data Saver(Chrome插件:幫助用戶節(jié)省瀏覽時(shí)的數(shù)據(jù)使用量)獲益
- 更好的完成設(shè)備自動(dòng)同步
- 簡(jiǎn)單的定制模式
- 更快速的返回到本地應(yīng)用
- You want to use the latest browser implementations on devices pre-Lollipop (auto updating WebView) instead of older WebViews.
使用條件?
需要安裝Chrome45或以上版本,支持的Android版本(Jellybean(4.1)以上)。
‘com.android.support:customtabs:24.2.0’
}
當(dāng)你完成添加依賴你可能有兩個(gè)配置需要自定義:
- 自定義選項(xiàng)卡的UI和交互
- 使頁面加載速度更快,并使應(yīng)用程序保活
UI的自定義你可能會(huì)使用到 CustomTabsIntent 和 CustomTabsIntent.Builder; 性能的改進(jìn)通過使用CustomTabsClient 來連接Custom Tabs service,預(yù)加熱Chrome以及讓它知道那個(gè)URL將被打開.
快速使用
String url = ¨https://paul.kinlan.me/¨; CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(); CustomTabsIntent customTabsIntent = builder.build(); customTabsIntent.launchUrl(this, Uri.parse(url));設(shè)置Toolbar顏色
builder.setToolbarColor(colorInt);自定義Action Buttons
作為開發(fā)者你將擁有呈現(xiàn)給用戶的Chrome標(biāo)簽內(nèi)的操作按鈕的所有控制。
在大多數(shù)情況下,這將是一個(gè)主要的作用,如分享,或者你的用戶將執(zhí)行另一種常見的活動(dòng)。
用戶點(diǎn)擊操作按鈕調(diào)用的PendingIntent通過Bundle由Chrome傳遞過來。該圖標(biāo)是高度最好是24dp和24-48dp的寬度。
// Adds an Action Button to the Toolbar. // 'icon' is a Bitmap to be used as the image source for the // action button.// 'description' is a String be used as an accessible description for the button.// 'pendingIntent is a PendingIntent to launch when the action button // or menu item was tapped. Chrome will be calling PendingIntent#send() on // taps after adding the url as data. The client app can call // Intent#getDataString() to get the url.// 'tint' is a boolean that defines if the Action Button should be tinted.builder.setActionButton(icon, description, pendingIntent, tint);自定義菜單
Chrome瀏覽器CCT將始終會(huì)有前進(jìn),頁面信息,刷新三個(gè)圖標(biāo),菜單上會(huì)有“查找頁面”和“在瀏覽器中打開”兩項(xiàng)。作為開發(fā)者你還可以添加多達(dá)5個(gè)菜單項(xiàng)。
菜單項(xiàng)是通過調(diào)用 CustomTabsIntent.Builder#addMenuItem 和帶有標(biāo)題的PendingIntent,然后Chrome會(huì)將用戶的行為作為參數(shù)傳遞過來。
builder.addMenuItem(menuItemTitle, menuItemPendingIntent);設(shè)置切換動(dòng)畫
很多Android應(yīng)用程序中使用自定義動(dòng)畫來過渡Android上的Activities切換。 CCT并沒有什么不同,你可以改變的打開和關(guān)閉(當(dāng)用戶按下后退)動(dòng)畫,讓他們與你的應(yīng)用程序的其他部分相一致。
builder.setStartAnimations(this, R.anim.slide_in_right, R.anim.slide_out_left); builder.setExitAnimations(this, R.anim.slide_in_left, R.anim.slide_out_right);預(yù)加熱Chrome加速加載頁面
默認(rèn)情況下,當(dāng)CustomTabsIntent#launchUrl 被調(diào)用時(shí)它會(huì)啟動(dòng)Chrome和URL,這會(huì)占用寶貴的時(shí)間和影響切換平滑的感覺。
我們知道用戶需要近乎瞬時(shí)的體驗(yàn),所以我們提供一個(gè)可以讓應(yīng)用連接并告訴Chrome預(yù)加熱瀏覽器和本地組件的服務(wù)。同時(shí)我們也可以告訴Chrome瀏覽器你設(shè)置的用戶將會(huì)訪問的網(wǎng)址,然后Chrome將會(huì)執(zhí)行一下步驟:
- DNS預(yù)解析主域
- DNS預(yù)解析最有可能的子資源
- 預(yù)連接到目的地,包括HTTPS / TLS。
預(yù)加熱Chrome的過程如下:
- 使用 CustomTabsClient#bindCustomTabsService 連接到服務(wù)
- 一旦服務(wù)連接,調(diào)用 CustomTabsClient#warmup 在后臺(tái)啟動(dòng)Chrome
- 調(diào)用 CustomTabsClient#newsession 來創(chuàng)建一個(gè)新的會(huì)話。本次會(huì)話是用于所有請(qǐng)求的API
- (可選)當(dāng)創(chuàng)建一個(gè)會(huì)話的時(shí)候添加參數(shù) CustomTabsCallback,可以知道頁面是否加載完成
- 通過 CustomTabsSession#mayLaunchUrl 加載一個(gè)頁面可以告訴Chrome那個(gè)頁面是用戶最有可能去加載的
- 調(diào)用 CustomTabsIntent.Builder 構(gòu)造函數(shù)傳遞創(chuàng)建的 CustomTabsSession
連接到Chrome Service
CustomTabsClient#bindCustomTabsService 簡(jiǎn)化了連接到Custom Tabs service的流程,創(chuàng)建 CustomTabsServiceConnection,并使用 onCustomTabsServiceConnected 得到 CustomTabsClient的一個(gè)實(shí)例。操作如下
// Package name for the Chrome channel the client wants to connect to. This // depends on the channel name. // Stable = com.android.chrome // Beta = com.chrome.beta // Dev = com.chrome.dev public static final String CUSTOM_TAB_PACKAGE_NAME = "com.android.chrome"; // Change when in stableCustomTabsServiceConnection connection = new CustomTabsServiceConnection() {@Overridepublic void onCustomTabsServiceConnected(ComponentName name, CustomTabsClient client) {mCustomTabsClient = client;}@Overridepublic void onServiceDisconnected(ComponentName name) {} }; boolean ok = CustomTabsClient.bindCustomTabsService(this, mPackageNameToBind, connection);Warm up the Browser Process
boolean warmup(long flags)
返回 true 代表成功.
預(yù)加熱瀏覽器進(jìn)程和加載庫文件。此操作是異步的,返回值表示請(qǐng)求是否被接受。多次調(diào)用成功亦返回true
創(chuàng)建Tab session
boolean newSession(CustomTabsCallback callback)
會(huì)話被用于隨后與CustomTabsCallback相連接的回調(diào),并產(chǎn)生相互的標(biāo)簽。這里提供的回調(diào)與創(chuàng)建會(huì)話相關(guān)聯(lián)。所創(chuàng)建的會(huì)話的任何更新(見下面的自定義選項(xiàng)卡回調(diào))通過該回調(diào)接收。返回值表示會(huì)話是否已成功創(chuàng)建。多個(gè)調(diào)用相同CustomTabsCallback或者空值將返回false。
設(shè)置可能打開的URL
boolean mayLaunchUrl(Uri url, Bundle extras, List otherLikelyBundles)
該方法告訴瀏覽器一個(gè)未來可能加載的URL。warmup() 首先會(huì)被調(diào)用,最有可能的URL必須首先指定。(可選)可以提供其它可能的URL列表。它們被視為不太可能相比第一個(gè),并且以降序進(jìn)行排序。這些額外的URL可能會(huì)被忽略。這種方法以前所有的請(qǐng)求都將被deprioritized。返回值表示操作是否成功完成。
自定義選項(xiàng)卡Connection Callback
void onNavigationEvent(int navigationEvent, Bundle extras)
自定義選項(xiàng)卡有用戶行為發(fā)生時(shí)將被調(diào)用。該 navigationEvent int是定義的6種頁面狀態(tài)。請(qǐng)參閱下面的詳細(xì)信息。
如果用戶沒有安裝了最新版本的Chrome會(huì)發(fā)生什么?
自定義選項(xiàng)卡使用帶有附加功能鍵的ACTION_VIEW意圖定制UI。這意味著,在默認(rèn)情況下頁面將會(huì)在系統(tǒng)瀏覽器,或用戶的默認(rèn)瀏覽器。
如果用戶安裝了Chrome瀏覽器并且設(shè)置默認(rèn)的瀏覽器,它會(huì)自動(dòng)拿起額外設(shè)備和呈現(xiàn)的自定義UI。另外,也可以為其他瀏覽器使用意圖額外提供一個(gè)類似的定制接口。
如何檢查Chrome是否支持CCT?
所有版本的Chrome都支持CCT暴露出來的一個(gè)服務(wù)。要檢查是否支持自定義選項(xiàng)卡,嘗試綁定到該服務(wù)。如果成功,則可以安全使用自定義選項(xiàng)卡。
最佳實(shí)踐
Connect to the Custom Tabs service and call warmup()
通過這樣的方式你最多可以節(jié)省700ms,700ms差不多是界定卡與不卡的時(shí)間。在Activity的 onStart() 去連接Custom Tab service, 連接后調(diào)用 warmup(). 這一操作將作為低優(yōu)先級(jí)的進(jìn)程,這意味著它不會(huì)對(duì)你的應(yīng)用程序性能的負(fù)面影響,但加載鏈接時(shí)會(huì)給出一個(gè)大的性能提升。
Pre-render content
預(yù)渲染將使外部?jī)?nèi)容瞬間打開。所以,如果你的用戶至少點(diǎn)擊鏈接的50%的可能性,調(diào)用mayLaunchUrl()這個(gè)方法會(huì)提前下載并渲染網(wǎng)頁內(nèi)容,但不可避免的會(huì)有一點(diǎn)流量和電量的消耗。如果用戶正在使用收費(fèi)的數(shù)據(jù)流量,或者手機(jī)電量不足,那么這個(gè)方法不會(huì)生效。所以我們完全不用自己考慮性能優(yōu)化。
備選方案
如果用戶的手機(jī)上沒有安裝Chrome,那么打開默認(rèn)瀏覽器可能并不是最好的用戶體驗(yàn)。所以如果在bindService那一步失敗了,無論是打開默認(rèn)瀏覽器還是WebView,選擇一個(gè)你認(rèn)為最好的備選方案。
Add your app as the referrer
很多網(wǎng)站都會(huì)統(tǒng)計(jì)自己的流量是從哪兒來的,所以最好告訴他們是你的帥氣APP給他們帶來了流量:
intent.putExtra(Intent.EXTRA_REFERRER, Uri.parse(Intent.URI_ANDROID_APP_SCHEME + "//" + context.getPackageName()));自定義動(dòng)畫
自定義動(dòng)畫將讓你的應(yīng)用程序?qū)⒕W(wǎng)站內(nèi)容更平滑的過渡。確保完成動(dòng)畫和動(dòng)畫開始是相對(duì)應(yīng)的,這會(huì)幫助用戶了解他們已經(jīng)回到了應(yīng)用程序。
//Setting custom enter/exit animationsCustomTabsIntent.Builder intentBuilder = new CustomTabsIntent.Builder();intentBuilder.setStartAnimations(this, R.anim.slide_in_right, R.anim.slide_out_left);intentBuilder.setExitAnimations(this, android.R.anim.slide_in_left,android.R.anim.slide_out_right);//Open the Custom Tab intentBuilder.build().launchUrl(context, Uri.parse("https://developer.chrome.com/"));為ActionButton添加一個(gè)Icon
添加ActionButton可以讓用戶更多的了解應(yīng)用有那些功能。你可以創(chuàng)建描述該操作的文本的位圖,如果沒有一個(gè)很好的圖標(biāo)來表示你的操作按鈕執(zhí)行的操作,記住位圖的最大尺寸為24dp高x寬48dp。
String shareLabel = getString(R.string.label_action_share);Bitmap icon = BitmapFactory.decodeResource(getResources(),android.R.drawable.ic_menu_share);//Create a PendingIntent to your BroadCastReceiver implementationIntent actionIntent = new Intent(this.getApplicationContext(), ShareBroadcastReceiver.class);PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, actionIntent, 0); //Set the pendingIntent as the action to be performed when the button is clicked. intentBuilder.setActionButton(icon, shareLabel, pendingIntent);多個(gè)瀏覽器的選擇
用戶可以安裝多個(gè)支持CCT的瀏覽器。如果有一個(gè)以上的瀏覽器支持自定義選項(xiàng)卡或者其中沒有一個(gè)是首選瀏覽器,那么可以詢問用戶想如何打開鏈接.另外添加一個(gè)可以選擇默認(rèn)瀏覽器的選項(xiàng),這樣可以讓用戶自由的去選擇是否使用CCT.
/*** Returns a list of packages that support Custom Tabs.*/ public static ArrayList getCustomTabsPackages(Context context) {PackageManager pm = context.getPackageManager();// Get default VIEW intent handler.Intent activityIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.example.com"));// Get all apps that can handle VIEW intents.List resolvedActivityList = pm.queryIntentActivities(activityIntent, 0);ArrayList packagesSupportingCustomTabs = new ArrayList<>();for (ResolveInfo info : resolvedActivityList) {Intent serviceIntent = new Intent();serviceIntent.setAction(ACTION_CUSTOM_TABS_CONNECTION);serviceIntent.setPackage(info.activityInfo.packageName);// Check if this package also resolves the Custom Tabs service.if (pm.resolveService(serviceIntent, 0) != null) {packagesSupportingCustomTabs.add(info);}}return packagesSupportingCustomTabs;}使用本地應(yīng)用處理鏈接
一些URL可以通過本地應(yīng)用程序進(jìn)行處理。如果用戶安裝了Twitter的應(yīng)用程序,那么點(diǎn)擊鏈接后更期望在Twitter中打開。所以在應(yīng)用程序打開一個(gè)URL之前,最好先檢查本機(jī)是否有方法可以代替。
定義Toolbar顏色
如果你希望用戶覺得內(nèi)容是應(yīng)用程序的一部分,那么可以設(shè)置Toolbar顏色為Primary color。如果你考慮讓用戶知道該頁面已經(jīng)離開了你的App那么千萬不要自定義Toolbar顏色。
添加分享
大多數(shù)情況下用戶都會(huì)想要分享這個(gè)鏈接但是CCT默認(rèn)不添加,所以最好自己加上
//Sharing content from CustomTabs with on a BroadcastReceiverpublic void onReceive(Context context, Intent intent) {String url = intent.getDataString();if (url != null) {Intent shareIntent = new Intent(Intent.ACTION_SEND);shareIntent.setType("text/plain");shareIntent.putExtra(Intent.EXTRA_TEXT, url);Intent chooserIntent = Intent.createChooser(shareIntent, "Share url");chooserIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);context.startActivity(chooserIntent);}}定義關(guān)閉按鈕
如果你希望用戶感覺像CCT是一個(gè)對(duì)話框可以使用默認(rèn)的“X”按鈕。如果你希望用戶感覺到CCT是App的一部分可以使用后退箭頭。
//Setting a custom back buttonCustomTabsIntent.Builder intentBuilder = new CustomTabsIntent.Builder();intentBuilder.setCloseButtonIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_arrow_back));處理內(nèi)部鏈接
當(dāng)攔截到由android:autoLink或者WebView產(chǎn)生的內(nèi)部鏈接點(diǎn)擊時(shí),最好讓應(yīng)用程序自己去處理,CCT只處理外部鏈接。
WebView webView = (WebView)findViewById(R.id.webview); webView.setWebViewClient(new WebViewClient() {@Overridepublic boolean shouldOverrideUrlLoading(WebView view, String url) {return true;}@Overridepublic void onLoadResource(WebView view, String url) {if (url.startsWith("http://www.example.com")) {//Handle Internal Link...} else {//Open Link in a Custom TabUri uri = Uri.parse(url);CustomTabsIntent.Builder intentBuilder =new CustomTabsIntent.Builder(mCustomTabActivityHelper.getSession());//Open the Custom Tab intentBuilder.build().launchUrl(context, url)); }} });連擊處理
確保用戶點(diǎn)擊鏈接后到打開CCT之間不要超過100ms,否則用戶會(huì)覺得反應(yīng)遲鈍,并嘗試多次點(diǎn)擊。當(dāng)然卡頓是無法避免的,所以在用戶多次點(diǎn)擊后確保只打開CCT一次。
轉(zhuǎn)載請(qǐng)注明出處:http://blog.csdn.net/just_sanpark/article/details/52249051
參考 http://qq157755587.github.io/2016/08/12/custom-tabs-best-practices/
總結(jié)
以上是生活随笔為你收集整理的Chrome Custom Tabs最佳实践的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android 打开网页之CustomT
- 下一篇: USB协议学习笔记 - CUSTOM H