'Trusted Web Activity - Address bar not hide (Chrome for Android 72)
I've followed this guide to learn how to use a Trusted Web Activity. All fine but the address bar still appear. At begin I think it was because when the app was looking for assetlinks.json the response was 404. Fixed it but no luck on removing the address bar. Am I missing something?
Chrome Version: 72.0.3626.96
Android Version: 7.1.2 (LineageOS 14.1)
assetlinks.json
[{
"relation": ["delegate_permission/common.handle_all_urls"],
"target" : { "namespace": "android_app", "package_name": "com.example.twa_test",
"sha256_cert_fingerprints": ["2A:32:7D:B7:4D:0B:A5:6A:72:47:86:A3:2F:A6:BB:D8:26:DE:AB:7E:8B:EA:C7:16:80:EA:C3:F1:50:E7:8E:D1"] }
}]
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.twa_test">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<meta-data
android:name="asset_statements"
android:resource="@string/asset_statements" />
<activity android:name="android.support.customtabs.trusted.LauncherActivity">
<!-- Edit android:value to change the url opened by the TWA -->
<meta-data
android:name="android.support.customtabs.trusted.DEFAULT_URL"
android:value="https://slexom.gitlab.io/namya/" />
<!-- This intent-filter adds the TWA to the Android Launcher -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!--
This intent-filter allows the TWA to handle Intents to open
airhorner.com.
-->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- Edit android:host to handle links to the target URL-->
<data
android:scheme="https"
android:host="slexom.gitlab.io/namya/" />
</intent-filter>
</activity>
</application>
</manifest>
res/values/strings.xml
<resources>
<string name="app_name">Namya</string>
<string name="asset_statements">
[{
\"relation\": [\"delegate_permission/common.handle_all_urls\"],
\"target\": {
\"namespace\": \"web\",
\"site\": \"https://slexom.gitlab.io/namya/\"}
}]
</string>
</resources>
build.gradle(Project)
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
maven { url "https://jitpack.io" }
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
build.gradle(Module: app)
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.example.twa_test"
minSdkVersion 16
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.github.GoogleChrome.custom-tabs-client:customtabs:3a71a75c9f'
}
Logcat
2019-02-08 18:19:01.918 10880-10880/? I/art: Late-enabling -Xcheck:jni
2019-02-08 18:19:02.352 10880-10880/com.example.twa_test W/System:
ClassLoader referenced unknown path: /data/app/com.example.twa_test-1/lib/arm
2019-02-08 18:19:02.403 10880-10880/com.example.twa_test I/InstantRun:
starting instant run server: is main process
2019-02-08 18:19:02.478 10880-10896/com.example.twa_test D/libEGL: loaded /system/lib/egl/libEGL_mali.so
2019-02-08 18:19:02.510 10880-10896/com.example.twa_test D/libEGL: loaded /system/lib/egl/libGLESv1_CM_mali.so
2019-02-08 18:19:02.660 10880-10880/com.example.twa_test W/art: Before Android 4.1, method android.graphics.PorterDuffColorFilter android.support.graphics.drawable.VectorDrawableCompat.updateTintFilter(android.graphics.PorterDuffColorFilter, android.content.res.ColorStateList, android.graphics.PorterDuff$Mode) would have incorrectly overridden the package-private method in android.graphics.drawable.Drawable
2019-02-08 18:19:02.727 10880-10896/com.example.twa_test D/libEGL: loaded /system/lib/egl/libGLESv2_mali.so
2019-02-08 18:19:02.920 10880-10880/com.example.twa_test I/art: Rejecting re-init on previously-failed class java.lang.Class<android.support.v4.view.ViewCompat$OnUnhandledKeyEventListenerWrapper>: java.lang.NoClassDefFoundError: Failed resolution of: Landroid/view/View$OnUnhandledKeyEventListener;
2019-02-08 18:19:02.920 10880-10880/com.example.twa_test I/art: at void android.support.v4.view.ViewCompat.setBackground(android.view.View, android.graphics.drawable.Drawable) (ViewCompat.java:2341)
2019-02-08 18:19:02.920 10880-10880/com.example.twa_test I/art: at void android.support.v7.widget.ActionBarContainer.<init>(android.content.Context, android.util.AttributeSet) (ActionBarContainer.java:62)
2019-02-08 18:19:02.920 10880-10880/com.example.twa_test I/art: at java.lang.Object java.lang.reflect.Constructor.newInstance0!(java.lang.Object[]) (Constructor.java:-2)
2019-02-08 18:19:02.920 10880-10880/com.example.twa_test I/art: at java.lang.Object java.lang.reflect.Constructor.newInstance(java.lang.Object[]) (Constructor.java:430)
2019-02-08 18:19:02.920 10880-10880/com.example.twa_test I/art: at android.view.View android.view.LayoutInflater.createView(java.lang.String, java.lang.String, android.util.AttributeSet) (LayoutInflater.java:645)
2019-02-08 18:19:02.920 10880-10880/com.example.twa_test I/art: at android.view.View android.view.LayoutInflater.createViewFromTag(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet, boolean) (LayoutInflater.java:787)
2019-02-08 18:19:02.920 10880-10880/com.example.twa_test I/art: at android.view.View android.view.LayoutInflater.createViewFromTag(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet) (LayoutInflater.java:727)
2019-02-08 18:19:02.920 10880-10880/com.example.twa_test I/art: at void android.view.LayoutInflater.rInflate(org.xmlpull.v1.XmlPullParser, android.view.View, android.content.Context, android.util.AttributeSet, boolean) (LayoutInflater.java:858)
2019-02-08 18:19:02.920 10880-10880/com.example.twa_test I/art: at void android.view.LayoutInflater.rInflateChildren(org.xmlpull.v1.XmlPullParser, android.view.View, android.util.AttributeSet, boolean) (LayoutInflater.java:821)
2019-02-08 18:19:02.920 10880-10880/com.example.twa_test I/art: at android.view.View android.view.LayoutInflater.inflate(org.xmlpull.v1.XmlPullParser, android.view.ViewGroup, boolean) (LayoutInflater.java:518)
2019-02-08 18:19:02.920 10880-10880/com.example.twa_test I/art: at android.view.View android.view.LayoutInflater.inflate(int, android.view.ViewGroup, boolean) (LayoutInflater.java:426)
2019-02-08 18:19:02.920 10880-10880/com.example.twa_test I/art: at android.view.View android.view.LayoutInflater.inflate(int, android.view.ViewGroup) (LayoutInflater.java:377)
2019-02-08 18:19:02.920 10880-10880/com.example.twa_test I/art: at android.view.ViewGroup android.support.v7.app.AppCompatDelegateImpl.createSubDecor() (AppCompatDelegateImpl.java:607)
2019-02-08 18:19:02.920 10880-10880/com.example.twa_test I/art: at void android.support.v7.app.AppCompatDelegateImpl.ensureSubDecor() (AppCompatDelegateImpl.java:518)
2019-02-08 18:19:02.920 10880-10880/com.example.twa_test I/art: at void android.support.v7.app.AppCompatDelegateImpl.onPostCreate(android.os.Bundle) (AppCompatDelegateImpl.java:299)
2019-02-08 18:19:02.920 10880-10880/com.example.twa_test I/art: at void android.support.v7.app.AppCompatActivity.onPostCreate(android.os.Bundle) (AppCompatActivity.java:98)
2019-02-08 18:19:02.920 10880-10880/com.example.twa_test I/art: at void android.app.Instrumentation.callActivityOnPostCreate(android.app.Activity, android.os.Bundle) (Instrumentation.java:1200)
2019-02-08 18:19:02.920 10880-10880/com.example.twa_test I/art: at android.app.Activity android.app.ActivityThread.performLaunchActivity(android.app.ActivityThread$ActivityClientRecord, android.content.Intent) (ActivityThread.java:2666)
2019-02-08 18:19:02.920 10880-10880/com.example.twa_test I/art: at void android.app.ActivityThread.handleLaunchActivity(android.app.ActivityThread$ActivityClientRecord, android.content.Intent, java.lang.String) (ActivityThread.java:2751)
2019-02-08 18:19:02.920 10880-10880/com.example.twa_test I/art: at void android.app.ActivityThread.-wrap12(android.app.ActivityThread, android.app.ActivityThread$ActivityClientRecord, android.content.Intent, java.lang.String) (ActivityThread.java:-1)
2019-02-08 18:19:02.920 10880-10880/com.example.twa_test I/art: at void android.app.ActivityThread$H.handleMessage(android.os.Message) (ActivityThread.java:1496)
2019-02-08 18:19:02.920 10880-10880/com.example.twa_test I/art: at void android.os.Handler.dispatchMessage(android.os.Message) (Handler.java:102)
2019-02-08 18:19:02.920 10880-10880/com.example.twa_test I/art: at void android.os.Looper.loop() (Looper.java:154)
2019-02-08 18:19:02.920 10880-10880/com.example.twa_test I/art: at void android.app.ActivityThread.main(java.lang.String[]) (ActivityThread.java:6186)
2019-02-08 18:19:02.920 10880-10880/com.example.twa_test I/art: at java.lang.Object java.lang.reflect.Method.invoke!(java.lang.Object, java.lang.Object[]) (Method.java:-2)
2019-02-08 18:19:02.920 10880-10880/com.example.twa_test I/art: at void com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run() (ZygoteInit.java:889)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at void com.android.internal.os.ZygoteInit.main(java.lang.String[]) (ZygoteInit.java:779)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: Caused by: java.lang.ClassNotFoundException: Didn't find class "android.view.View$OnUnhandledKeyEventListener" on path: DexPathList[[zip file "/data/app/com.example.twa_test-1/base.apk", zip file "/data/app/com.example.twa_test-1/split_lib_dependencies_apk.apk", zip file "/data/app/com.example.twa_test-1/split_lib_slice_0_apk.apk", zip file "/data/app/com.example.twa_test-1/split_lib_slice_1_apk.apk", zip file "/data/app/com.example.twa_test-1/split_lib_slice_2_apk.apk", zip file "/data/app/com.example.twa_test-1/split_lib_slice_3_apk.apk", zip file "/data/app/com.example.twa_test-1/split_lib_slice_4_apk.apk", zip file "/data/app/com.example.twa_test-1/split_lib_slice_5_apk.apk", zip file "/data/app/com.example.twa_test-1/split_lib_slice_6_apk.apk", zip file "/data/app/com.example.twa_test-1/split_lib_slice_7_apk.apk", zip file "/data/app/com.example.twa_test-1/split_lib_slice_8_apk.apk", zip file "/data/app/com.example.twa_test-1/split_lib_slice_9_apk.apk"],nativeLibraryDirectories=[/data/app/com.example.tw
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at java.lang.Class dalvik.system.BaseDexClassLoader.findClass(java.lang.String) (BaseDexClassLoader.java:56)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at java.lang.Class java.lang.ClassLoader.loadClass(java.lang.String, boolean) (ClassLoader.java:380)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at java.lang.Class java.lang.ClassLoader.loadClass(java.lang.String) (ClassLoader.java:312)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at void android.support.v4.view.ViewCompat.setBackground(android.view.View, android.graphics.drawable.Drawable) (ViewCompat.java:2341)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at void android.support.v7.widget.ActionBarContainer.<init>(android.content.Context, android.util.AttributeSet) (ActionBarContainer.java:62)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at java.lang.Object java.lang.reflect.Constructor.newInstance0!(java.lang.Object[]) (Constructor.java:-2)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at java.lang.Object java.lang.reflect.Constructor.newInstance(java.lang.Object[]) (Constructor.java:430)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at android.view.View android.view.LayoutInflater.createView(java.lang.String, java.lang.String, android.util.AttributeSet) (LayoutInflater.java:645)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at android.view.View android.view.LayoutInflater.createViewFromTag(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet, boolean) (LayoutInflater.java:787)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at android.view.View android.view.LayoutInflater.createViewFromTag(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet) (LayoutInflater.java:727)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at void android.view.LayoutInflater.rInflate(org.xmlpull.v1.XmlPullParser, android.view.View, android.content.Context, android.util.AttributeSet, boolean) (LayoutInflater.java:858)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at void android.view.LayoutInflater.rInflateChildren(org.xmlpull.v1.XmlPullParser, android.view.View, android.util.AttributeSet, boolean) (LayoutInflater.java:821)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at android.view.View android.view.LayoutInflater.inflate(org.xmlpull.v1.XmlPullParser, android.view.ViewGroup, boolean) (LayoutInflater.java:518)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at android.view.View android.view.LayoutInflater.inflate(int, android.view.ViewGroup, boolean) (LayoutInflater.java:426)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at android.view.View android.view.LayoutInflater.inflate(int, android.view.ViewGroup) (LayoutInflater.java:377)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at android.view.ViewGroup android.support.v7.app.AppCompatDelegateImpl.createSubDecor() (AppCompatDelegateImpl.java:607)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at void android.support.v7.app.AppCompatDelegateImpl.ensureSubDecor() (AppCompatDelegateImpl.java:518)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at void android.support.v7.app.AppCompatDelegateImpl.onPostCreate(android.os.Bundle) (AppCompatDelegateImpl.java:299)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at void android.support.v7.app.AppCompatActivity.onPostCreate(android.os.Bundle) (AppCompatActivity.java:98)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at void android.app.Instrumentation.callActivityOnPostCreate(android.app.Activity, android.os.Bundle) (Instrumentation.java:1200)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at android.app.Activity android.app.ActivityThread.performLaunchActivity(android.app.ActivityThread$ActivityClientRecord, android.content.Intent) (ActivityThread.java:2666)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at void android.app.ActivityThread.handleLaunchActivity(android.app.ActivityThread$ActivityClientRecord, android.content.Intent, java.lang.String) (ActivityThread.java:2751)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at void android.app.ActivityThread.-wrap12(android.app.ActivityThread, android.app.ActivityThread$ActivityClientRecord, android.content.Intent, java.lang.String) (ActivityThread.java:-1)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at void android.app.ActivityThread$H.handleMessage(android.os.Message) (ActivityThread.java:1496)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at void android.os.Handler.dispatchMessage(android.os.Message) (Handler.java:102)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at void android.os.Looper.loop() (Looper.java:154)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at void android.app.ActivityThread.main(java.lang.String[]) (ActivityThread.java:6186)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at java.lang.Object java.lang.reflect.Method.invoke!(java.lang.Object, java.lang.Object[]) (Method.java:-2)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at void com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run() (ZygoteInit.java:889)
2019-02-08 18:19:02.921 10880-10880/com.example.twa_test I/art: at void com.android.internal.os.ZygoteInit.main(java.lang.String[]) (ZygoteInit.java:779)
2019-02-08 18:19:03.284 10880-10880/com.example.twa_test D/LauncherActivity: Using URL from Manifest (https://slexom.gitlab.io/namya/).
2019-02-08 18:19:03.284 10880-10880/com.example.twa_test D/LauncherActivity: Launching Trusted Web Activity.
2019-02-08 18:19:03.470 10880-10923/com.example.twa_test I/Mali: Mali API Version : 401
2019-02-08 18:19:03.470 10880-10923/com.example.twa_test I/Mali: Mali REVISION: Linux-r4p0-00rel0 BUILD_DATE: 2014-11-10 20:23:11
2019-02-08 18:19:03.477 10880-10923/com.example.twa_test I/OpenGLRenderer: Initialized EGL, version 1.4
2019-02-08 18:19:03.477 10880-10923/com.example.twa_test D/OpenGLRenderer: Swap behavior 1
2019-02-08 18:19:03.598 10880-10880/com.example.twa_test W/art: Before Android 4.1, method int android.support.v7.widget.DropDownListView.lookForSelectablePosition(int, boolean) would have incorrectly overridden the package-private method in android.widget.ListView
Solution 1:[1]
I faced the same issue today, that's what I've learnt:
Before trying to test your android application test your statement here:
https://developers.google.com/digital-asset-links/tools/generator
Fill in domain, package and fingerprint, then click "Test Statement"
If you see
"Success! Host [your web app] grants app deep linking to [android package].", then your web app is configured the right way, and there's something wrong with your device or app.
Most likely you'll see
"Invalid input field(s)"
You can open Chrome console on the Network tab in order to look at the server output. Probably you're going to see something like
"Invalid site (URL cannot contain a path component, login information, query parameters or fragment identifiers)"
To fix this this you should put your assetlinks.json file to the root of your web app,
https://slexom.gitlab.io/.well-known/assetlinks.json
in your case.
You can checkout my sample repository. As you could see my file is accessible from https://antipovandrey.github.io/PWA/.well-known/assetlinks.json
Solution 2:[2]
You may have opted into having Google Play sign your releases with a key they generated, and only use your key for the upload.
If you did, go to Google Play Console Release Management -> App Signing and copy the App signing certificate SHA-256 fingerprint and put it into the assetlinks.json
file.
Solution 3:[3]
when use google SHA-256 or just change fingerprint code be sure to clear chrome cache about your previous app or check cache-control of .json
Solution 4:[4]
In my case, I was running the app in the wrong flavour then what I used for signing. Only the release version of my app was signed in using SHA key and I was running the app in debug build.
It ran as expected when I corrected the flavor.
Solution 5:[5]
For those who are still facing this problem, most likely in the assetlinks.json you are using SHA256 from the "Upload certificate" and not from the "App signing certificate". You can find both certificates in Google Play Console -> Release management -> App signing.
Solution 6:[6]
After struggling with this for a week and finally succeeding here are my two cents:
If you opt to let Google manage your key for you, there are two keys, the
App Signing Key
and the Upload key
.
After following the generic steps (Setup -> App integrity -> creating the Digital Asset Links JSON
)
[
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "PACKAGE.NAME.HERE",
"sha256_cert_fingerprints":["APP:SIGNING:CERTIFICATE:SHA_256:FINGERPRINT"]
}
}
]
and exposing it at:
https://your.domain/.well-known/assetlinks.json
(visit the url to verify the json MUST BE A LIST/ARRAY and NOT JUST THE JSON OBJECT ITSELF or verification will fail)
Be aware that a newly built package was signed with the Upload Key
and NOT The App Signing Key
so assetlink verification will fail if you try to test the locally built .apk directly and the URL bar will be visible.
To really test whether linking has worked, you have to download the app from the store (Production/Internal Test/Open Test etc.) because the app is signed by google with the App Signing certificate sha_256
after the release has been successfully rolled out to the store.
Solution 7:[7]
FYI: I was facing this problem from a few hours and I figured this problem and the problem was I was using different package names when I generated assetlinks.json
file from the actual packagename which I used while generating the android-project via bubblewrap init
command.
Happy to see that url bar is now hidden and its amazing!
Solution 8:[8]
The same story, assetlinks.json validates successfully, but url bar exists, advises about SHA-256 from google play console not working
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow