当前位置: 首页 > 知识库问答 >
问题:

如何使用TWA全屏制作Android应用(沉浸式)

訾朗
2023-03-14

我们制作了一个Android应用程序,当前使用WebView全屏显示网络内容。

这是可行的,但性能在很大程度上取决于WebVeiw组件的版本,并且在Chrome浏览器更新时并不总是更新(在不同的Android版本中,WebView组件和Chrome浏览器之间存在相对复杂的关系)。从谷歌关于这一主题的演示中,我们得出结论,使用TWA,我们可能会获得更好、更一致的性能,因为TWA功能与Chrome浏览器一起更新。因此,当TWA不存在时(我们的应用程序运行在Android 4.4及更高版本上),我们希望使用TWA并回退到WebView。

该应用程序需要执行更多的逻辑,而不仅仅是显示网络内容,所以我们不能只在清单中定义TWA/WebView。检查使用TWA的能力,并在MainActivity.java中启动TWA或回到WebView。但是,当使用TWA时,URL/地址栏和底部导航栏仍然可见。

URL/地址栏:据我们所知,要使TWA不显示URL/地址栏,TWA中显示的域必须有一个/。知名/资产链接。“匹配”Android应用程序证书的json文件。下面是两个页面,其中有关于这方面的信息和有用的链接https://developers.google.com/web/android/trusted-web-activity/integration-guide和https://developer.android.com/training/app-links/verify-site-associations.资产链。json是使用https://developers.google.com/digital-asset-links/tools/generator并成功地与https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=website_url

在虚拟设备(Android API级别29,Chromev83)的测试中,我们启用了Chrome的启用命令行标志,并在终端中

$ adb shell "echo '_ --disable-digital-asset-link-verification-for-url=\"website_url"' > /data/local/tmp/chrome-command-line"

之后,Chrome会显示一条警告消息,但URL/地址栏仍然存在。

底部导航栏:Chrome v80及更新版本应支持使用浸入式选项移除底部导航栏:https://bugs.chromium.org/p/chromium/issues/detail?id=965329#c18尽管使用创建全屏应用程序所述的选项(https://developer.android.com/training/system-ui/immersive#java)底部的导航栏仍在显示。

我们如何删除URL/地址栏和底部导航栏,基本上我们如何使TWA全屏显示的网页内容?

我们查看了以下示例应用程序,以了解我们需要做些什么才能让TWA工作,但没有发现任何有效的方法(尽管我们错过了一些重要的东西,这并非不可想象):

  • https://github.com/GoogleChromeLabs/svgomg-twa
  • https://github.com/tsuyosh/TrustedWebActivitiesDemo
  • https://github.com/GoogleChrome/android-browser-helper
  • https://github.com/elliatab/TwaDemo
  • https://github.com/thanhtungka91/TwaDemoJava

我们项目档案的相关内容:

显示json

    <application
        android:name="main_application"
        android:hardwareAccelerated="true"
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:banner="@drawable/banner"
        android:label="@string/app_name"
        android:usesCleartextTraffic="true"
        android:networkSecurityConfig="@xml/network_security_config"
        android:theme="@style/AppTheme" >
        <activity
            android:name="main_activity"
            android:hardwareAccelerated="true"
            android:label="@string/app_name"
            android:launchMode = "singleInstance"
            android:keepScreenOn="true" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.LAUNCHER" />
                <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
    </application>

主要活动。JAVA

public class MainActivity extends Activity implements IServiceCallbacks {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Set up looks of the view
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        View decorView = getWindow().getDecorView();
        decorView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {
            @Override
            public void onSystemUiVisibilityChange(int visibility) {
                // Note that system bars will only be "visible" if none of the
                // LOW_PROFILE, HIDE_NAVIGATION, or FULLSCREEN flags are set.
                if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
                    // bars are visible => user touched the screen, make the bars disappear again in 2 seconds
                    Handler handler = new Handler();
                    handler.postDelayed(new Runnable() {
                        public void run() {
                            hideBars();
                        }
                    }, 2000);
                } else {
                    // The system bars are NOT visible => do nothing
                }
            }
        });
        decorView.setKeepScreenOn(true);
        setContentView(R.layout.activity_main);

        // create Trusted Web Access or fall back to a WebView
        String chromePackage = CustomTabsClient.getPackageName(this, TrustedWebUtils.SUPPORTED_CHROME_PACKAGES, true);
        if (chromePackage != null) {
            if (!chromeVersionChecked) {
                TrustedWebUtils.promptForChromeUpdateIfNeeded(this, chromePackage);
                chromeVersionChecked = true;
            }

            if (savedInstanceState != null && savedInstanceState.getBoolean(MainActivity.TWA_WAS_LAUNCHED_KEY)) {
                this.finish();
            } else {
                this.twaServiceConnection = new MainActivity.TwaCustomTabsServiceConnection();
                CustomTabsClient.bindCustomTabsService(this, chromePackage, this.twaServiceConnection);
            }
        } else {
            // set up WebView
        }
    }


    private class TwaCustomTabsServiceConnection extends CustomTabsServiceConnection {
        public void onCustomTabsServiceConnected(ComponentName componentName, CustomTabsClient client) {
            CustomTabsSession session = MainActivity.this.getSession(client);
            CustomTabsIntent intent = MainActivity.this.getCustomTabsIntent(session);
            Uri url = Uri.parse("http://our_url");
            TrustedWebUtils.launchAsTrustedWebActivity(MainActivity.this, intent, url);
            MainActivity.this.twaWasLaunched = true;
        }

        public void onServiceDisconnected(ComponentName componentName) {
        }
    }


    protected void hideBars() {
        if (getWindow() != null) {
            View decorView = getWindow().getDecorView();
            decorView.setSystemUiVisibility(
                // Hide the nav bar and status bar
                View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_FULLSCREEN
                // Set the content to appear under the system bars so that the
                // content doesn't resize when the system bars hide and show.
                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                // Enables regular immersive mode
                | View.SYSTEM_UI_FLAG_IMMERSIVE
            );
        }
        // Remember that you should never show the action bar if the
        // status bar is hidden, so hide that too if necessary.
        ActionBar actionBar = getActionBar();
        if (actionBar != null) {
            actionBar.hide();
        }
    }
}

建筑格拉德尔

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    repositories {
        jcenter()
        google()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:4.0.0'
    }
}

allprojects {
    repositories {
        jcenter()
        google()
        maven { url "https://jitpack.io" }
    }
}

建筑格拉德尔

apply plugin: 'com.android.application'

android {
    compileSdkVersion 29
    buildToolsVersion '29.0.2'

    defaultConfig {
        applicationId application_id
        minSdkVersion 19
        targetSdkVersion 29

    }

    buildTypes {
        release {
            minifyEnabled true
            debuggable false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }
        debug {
            minifyEnabled false
            debuggable true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
            jniDebuggable true
            renderscriptDebuggable true
            renderscriptOptimLevel 3
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
    implementation 'androidx.leanback:leanback:1.0.0'
    implementation 'androidx.recyclerview:recyclerview:1.1.0'
    implementation 'androidx.cardview:cardview:1.0.0'
    implementation 'androidx.webkit:webkit:1.2.0'
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'com.github.GoogleChrome.custom-tabs-client:customtabs:master'
}

/.知名/资产链接。json

[
  {
    "relation": ["delegate_permission/common.handle_all_urls"],
    "target" :  { "namespace": "android_app", "package_name": "our package name",
                  "sha256_cert_fingerprints": ["11:22:33:44"]
                }
  },
  {
    "relation": ["delegate_permission/common.handle_all_urls"],
    "target" :  { "namespace": "android_app", "package_name": "our other package name",
                  "sha256_cert_fingerprints": ["11:22:33:44"]
                }
  }
]

共有1个答案

景翰音
2023-03-14

关于数字资产链接验证,我建议安装彼得的资产链接工具,并使用它来检查配置。请务必再次检查快速入门指南中关于应用签名的部分,因为使用时签名会更改,导致验证失败应用程序从Play商店下载(您必须更新assetlinks.json才能使其工作)。

您似乎也在使用自定义选项卡客户端库,该库已被弃用,并建议移动到android-Browers-helper,这是受信任网络活动的推荐库。如果你确实想使用一个较低级别的库,androidx.browser将是一个可以使用的库(我真的建议使用android-Browvers-helper

android-Browner-helper包含一个LauncherActive,它使事情变得非常简单,因为大多数方面都可以从AndreidManifest.xml进行配置,但它也希望从主屏幕启动受信任的网络活动。twa-Basic演示演示了如何使用LauncherActive

对于其他用例,可以使用TwaLauncher(它是由LauncherActive本身使用的)。twa自定义启动器演示了如何使用它。LauncherActive的源代码也可以是helpul。

最后,如果目标是简单地从主屏幕启动一个渐进式Web应用程序,那么Bubblewrap就是一个节点。js命令行工具,可自动执行该过程。

关于沉浸式模式,下面是它在twa-Basic演示中的设置方式。如果使用TwaLauncher,要使用的LauncherActive代码在这里。

使用Bubblewrap时,在创建项目以沉浸式模式启动应用程序时,为显示模式选择全屏

好处:由于您提到希望使用WebView回退实现,您可能有兴趣了解android browser helper附带WebView回退功能(默认情况下禁用)。twa webview fallback演示演示了如何使用它。

 类似资料:
  • 在全屏沉浸式模式下,是否可以禁用打开主导航栏的左滑动手势,以便只能从顶部滑动打开它?在开发全屏游戏时,必须围绕防止用户意外打开它进行如此繁重的设计,这非常烦人。 提前感谢。 编辑: 很抱歉只是为了澄清我说的是一个水平锁定的全屏游戏,在沉浸式模式下,禁用使主android导航栏/通知栏出现的左滑动手势,我希望有一种方法可以只让它打开通过从顶部滑动。

  • 我想隐藏导航栏。如果使用者从外到内给手指下药,请出示。我测试以下代码: 怎么能把这三项加起来呢?我所缺少的。

  • 使用本文档了解 After Effects 中的沉浸式视频效果。 After Effects 提供了本机沉浸式视频效果来编辑您的 VR/360 视频。您可以使用许多动态过渡、效果和字幕来编辑和增强沉浸式视频体验。您可以在 After Effects 中使用不同的沉浸式视频效果体验无缝的后期制作工作流程。 沉浸式视频效果的 GPU 要求 使用计算机 GPU 进行沉浸式视频效果渲染。确保将视频渲染首选

  • 本文向大家介绍Android UI体验之全屏沉浸式透明状态栏样式,包括了Android UI体验之全屏沉浸式透明状态栏样式的使用技巧和注意事项,需要的朋友参考一下 前言:    Android 4.4之后谷歌提供了沉浸式全屏体验, 在沉浸式全屏模式下, 状态栏、 虚拟按键动态隐藏, 应用可以使用完整的屏幕空间, 按照 Google 的说法, 给用户一种 身临其境 的体验。而Android 5.0之

  • 所以我有一个活动,我希望它全屏显示,显示标题栏和系统按钮(后退,最小化…)。我确实从开发人员那里获取了一段代码。Androidcom,它确实会全屏显示,但当我按下屏幕时,标题会弹回来,按钮也会弹出来,我希望只有当我的手指在屏幕的上/下滑动时,它才会弹出。 我的活动看起来像:

  • 本文向大家介绍Android 高仿QQ 沉浸式状态栏,包括了Android 高仿QQ 沉浸式状态栏的使用技巧和注意事项,需要的朋友参考一下 前言: 在进入今天正题前,还是老样子先谈谈感想吧,最近感觉整个都失去了方向感,好迷茫!找工作又失败了,难道Android真的饱和了?这两天我一直没出门,除了下楼哪外卖就是宅宿舍了,静想了许久,我还是不能忘了初心,我相信我找不到工作的原因有很多,最关键的还是要技