TWA是谷歌最新提供的一种将web页面移植到Android APP的方法。目前,Chrome on Android, version 72及以上的版本支持了TWA功能.
TWA有什么不同?
- TWA(Trusted Web activity)的内容是被信任的,APP和网页是来自同一个开发者。这时是使用Digital Asset Links来做校验的。
- TWA是基于web开发的,其实是运行在用户的浏览器里,所以TWA的页面必须是可以在普通浏览器里也可以运行的。比如,如果是基于Native提供JSBridge运行,就无法使用TWA。
- 用户浏览器的更新与Android系统和开发者的APP是独立的,这样可以带来更好的兼容性,既节省APP了大小,又可以让APP使用最新浏览器的特性。
- 宿主APP不能直接访问TWA的内容或者其他状态比如cookies和localStorage。但是,开发者可以使用URL来传递数据。比如:query parameters, 自定义HTTP headers, 和intent URIs。
使用场景
目前看来TWA在使用上主要有两种场景:
-
不写一行Java,让WEB变成Native APP。
对于只有网页产品的小公司而言,可以不写一行Java代码,直接套一个宿主APP就把网页包装成一个APP,并且可以将这个APP上架到谷歌play。(这种方式在体验上有点像在浏览器里增加一个桌面快捷方式。只是不会显示url输入框。可以下载google play里的"google map go"来体验一下。在浏览器里使用类似PWA的技术,可以让页面快速加载,并且接收push,体验上和Native已经很像了) -
在APP内部可以使用系统浏览器打开WEB页面。
对于已经存在的APP,其中有一些web页面,也可以使用TWA来打开web页面,这样可以使用用户的常用浏览器(目前只支持chrome)。网页就可以使用浏览器中的用户信息,比如cookie或者localstorage等。但是无法JSBridge通信。
尝试一下
Google提供了一个Github的demo,可以使用这个demo来体验一下。需要下载Chrome dev版本或者canary版本来调试。如果只是配置,还是会看到浏览器上面的url输入框,需要跑一下项目readme下面的debug设置,忽略页面校验,才可以隐藏。
Demo演示
TWA需要建立APP与页面之间的连接之后,才可以移除URL输入框。
-
没有处理之前:
- 处理之后:
-
对于已有的APP体验:
可以看出,TWA在隐藏了URL Bar之后在体验上和Native APP很相近了,而且加上可以使用PWA来支持PUSH和离线打开,给用户的体验也会不错。
原理简析
对于只由web页面的TWA。manifest的Activity是这样配置的(来自上文的demo):
<activity android:name="android.support.customtabs.trusted.LauncherActivity"
android:label="${launcherName}">
<meta-data android:name="android.support.customtabs.trusted.DEFAULT_URL"
android:value="${defaultUrl}" />
<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.VIEW"/>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="https"
android:host="${hostName}"/>
</intent-filter>
</activity>
其实打开的是google提供的一个Activity,这个Activity是通过Gradle引入的:implementation 'com.github.GoogleChrome:custom-tabs-client:e446d08014'
。
看下这个Activity里做了什么操作?
主要就是连接上chrome的service,所以在测试demo的时候,如果chrome没有启动,页面会直接白屏,不知道发布之后的版本会不会好一些:
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//.... 省略
this.mServiceConnection = new LauncherActivity.TwaCustomTabsServiceConnection();
CustomTabsClient.bindCustomTabsService(this, chromePackage, this.mServiceConnection);
}
连上之后再使用TrustedWebUtils.launchAsTrustedWebActivity
来启动页面:
public static void launchAsTrustedWebActivity(Context context, CustomTabsSession session, CustomTabsIntent intent, Uri uri) {
session.validateRelationship(2, uri, (Bundle)null);
IBinder binder = BundleCompat.getBinder(intent.intent.getExtras(), "android.support.customtabs.extra.SESSION");
//...
intent.intent.putExtra("android.support.customtabs.extra.LAUNCH_AS_TRUSTED_WEB_ACTIVITY", true);
intent.launchUrl(context, uri);
}
原理看上去也是非常的简单。就是去发了个intent,让浏览器启动一个页面。