如何正确的在Flutter中添加webview

Posted 前端码农小王

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何正确的在Flutter中添加webview相关的知识,希望对你有一定的参考价值。

前言

为什么要在flutter中引入webview?这不是废话么,当然是为了加载一个网页,这不是移动端最基本的需求么,哈哈!说的真不错,接下来我要是告诉你我的用法,你可能要大吃一惊。我的用处很简单,那就是在webview中再加载一个flutter编译成web的项目。有没有吓到你。别怕,我这么做的原因很简单,就是为了热更新。可能在flutter中实现热更新的方法有很多,但我敢说我这么做就是最好的热更新方式。当我内容发生变更是时候,我不需要继续去审核,只需要在服务器中,更新内容,我的热更新就实现了!是不是听着很动心,那就赶紧学起来吧。

安装

在Flutter应用开发中,由于官方并没有提供类似Webview的网页加载组件,所以如果项目中涉及网页加载就需要使用第三方插件库。网上第三方插件库很多,我不推荐,自行百度搜索比较,用法基本雷同,webview_flutter是Flutter官方开发和维护的网页加载插件库。所以今天我讲讲它的使用方法

1.在pubspec.yaml文件中添加依赖脚本(并运行隐式flutter pub get)

dependencies:flutter:sdk: fluttercupertino_icons: ^1.0.2webview_flutter: ^3.0.4 

2.使用

import 'package:flutter/material.dart';
import 'dart:io';
import 'package:webview_flutter/webview_flutter.dart';

class WebviewApp extends StatefulWidget const WebviewApp(Key? key) : super(key: key);@overrideState<WebviewApp> createState() => _WebviewAppState();


class _WebviewAppState extends State<WebviewApp> @overridevoid initState() super.initState();if (Platform.isandroid) WebView.platform = AndroidWebView();@overrideWidget build(BuildContext context) return const WebView(initialUrl: 'https://www.baidu.com',javascriptMode: JavascriptMode.unrestricted,);
 

好了,这样我们就成功引入了webview,并在webview中加载了百度首页。你高兴的去运行项目,结果却傻眼了,终端一片红,好了,我来说说爆红的解决方案。

运行项目遇到的问题

One or more plugins require a higher Android SDK version.

  • 解决方案:找到 项目根目录\\android\\app\\build.gradle,修改如下配置:
android compileSdkVersion 32
 

Error: uses-sdk:minSdkVersion 16 cannot be smaller than version 19 declared in library

  • 解决方案:找到 项目根目录\\android\\app\\build.gradle,修改如下配置:
defaultConfig applicationId "com.example.flutter_jsbridge_js"minSdkVersion 20targetSdkVersion 30versionCode flutterVersionCode.toInteger()versionName flutterVersionName
 

net:ERR_CLEARTEXT_NOT_PERMITTED

这时候运行项目已经已经不会报错了,但是webview却显示一串神奇代码:net:ERR_CLEARTEXT_NOT_PERMITTED,这是因为从 Android 9(API 级别 28)开始,明文支持默认处于禁用状态。

  • 解决方案:

1.创建文件:/xml/network_security_config.xml

目录路径:“项目根目录/android/app/main/res”

<?xml version="1.0" encoding="utf-8"?>
<network-security-config><domain-config cleartextTrafficPermitted="true"><domain includeSubdomains="true">api.example.com(to be adjusted)</domain></domain-config>
</network-security-config> 

2.对AndroidManifest.xml文件做修改:

<?xml version="1.0" encoding="utf-8"?>
<manifest ...><uses-permission android:name="android.permission.INTERNET" /><application...android:networkSecurityConfig="@xml/network_security_config"...>...</application>
</manifest> 

这时候再去运行项目,就可以正常运行了,画面显示正常,如果你还需要遇到其他问题,可以留言一起解决。

最后

为大家准备了一个前端资料包。包含54本,2.57G的前端相关电子书,《前端面试宝典(附答案和解析)》,难点、重点知识视频教程(全套)。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

如何从 webview flutter 中删除 Header 并在底部导航图标中添加下划线

【中文标题】如何从 webview flutter 中删除 Header 并在底部导航图标中添加下划线【英文标题】:How to remove Header from webview flutter and add underline in bottom navigation icon 【发布时间】:2021-09-01 00:30:22 【问题描述】:

    我无法从 web 视图中删除标题。有没有办法删除 webview 网站的标题并将应用程序标题应用到 web 视图,这样网站标题就被删除了,我们的应用栏作为标题显示在应用程序上。

    我想在底部导航栏下的 svg 图标上添加黄色下划线,但我无法添加,请帮帮我。 Home page of my app

import 'dart:async';
import 'package:url_launcher/url_launcher.dart';
import 'dart:io';
/* import 'package:titled_navigation_bar/titled_navigation_bar.dart' ;*/
import 'package:flutter_svg/flutter_svg.dart';

/* import 'package:flutter_webview_plugin/flutter_webview_plugin.dart'; */
import 'package:webview_flutter/webview_flutter.dart';

/* import 'package:md2_tab_indicator/md2_tab_indicator.dart'; */

/*import 'package:flutter_inappwebview/flutter_inappwebview.dart'; */
main() 
  runApp(MyApp());


// ignore: use_key_in_widget_constructors
class MyApp extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return MaterialApp(home: SplashScreen()); // define it once at root level.
  


// ignore: use_key_in_widget_constructors
class SplashScreen extends StatefulWidget 
  @override
  State<StatefulWidget> createState() 
    return SplashScreenState();
  


class SplashScreenState extends State<SplashScreen> 
  @override
  void initState() 
    super.initState();

    if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();

    Timer(
        // ignore: prefer_const_constructors
        Duration(seconds: 1),
        () => Navigator.pushReplacement(
            context, MaterialPageRoute(builder: (context) => HomeScreen())));
  

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      backgroundColor: Colors.black,
      body: Center(child: Image.asset('assets/splash.jpeg')),
    );
  


// ignore: use_key_in_widget_constructors
class HomeScreen extends StatefulWidget 
  @override
  _MyAppState createState() => _MyAppState();


class _MyAppState extends State<HomeScreen> 
  final Completer<WebViewController> _controller =
      Completer<WebViewController>();

  num _stackToView = 1;
  int _selectedTabIndex = 0;
  // ignore: prefer_final_fields
  List _pages = [
    // ignore: prefer_const_constructors
    Text("Home"),
    // ignore: prefer_const_constructors
    Text("Wishlist"),
    // ignore: prefer_const_constructors
    Text("Search"),
    // ignore: prefer_const_constructors
    Text("Bookings"),
    // ignore: prefer_const_constructors
    Text("Menu"),

    Text("call"),
  ];

  _changeIndex(int index) 
    setState(() 
      _selectedTabIndex = index;
    );
  

  void _handleLoad(String value) 
    setState(() 
      _stackToView = 0;
    );
  

  @override
  Widget build(BuildContext context) 
    final textTheme = Theme.of(context).textTheme;
    final colorScheme = Theme.of(context).colorScheme;
    return Scaffold(
      appBar: AppBar(
          /*  automaticallyImplyLeading: false, */
          leading: Padding(
            padding: EdgeInsets.all(10.0),
            child: SvgPicture.asset("assets/svg/VW-logo.svg"),

            /* leadingWidth: 35, */
          ),
          actions: [
            IconButton(
              icon: SvgPicture.asset("assets/svg/new.svg", color: Colors.black),
              onPressed: () ,
            ),
            IconButton(
              icon: SvgPicture.asset("assets/svg/Page-1.svg"),
              onPressed: () 
                _launchURL();
              ,
            ),
          ],
          backgroundColor: Colors.white),
      body:
          /* const WebView(
        initialUrl: 'https://www.google.com/',
        javascriptMode: JavascriptMode.unrestricted,
      ), */

          /* Center(child: _pages[_selectedTabIndex]), */
          IndexedStack(
        index: _selectedTabIndex,
        children: [
          Column(
            children: <Widget>[
              Expanded(
                  child: WebView(
                initialUrl: "https://www.veenaworld.com/",
                javascriptMode: JavascriptMode.unrestricted,
                onPageFinished: _handleLoad,
                onWebViewCreated: (WebViewController webViewController) 
                  _controller.complete(webViewController);
                ,
              )),
            ],
          ),
          Container(
            child: Center(child: _pages[_selectedTabIndex]),
          ),
        ],
      ),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _selectedTabIndex,
        onTap: _changeIndex,
        type: BottomNavigationBarType.fixed,
        /*    backgroundColor: Colors.blue.shade900, */
        selectedLabelStyle: textTheme.caption,
        unselectedLabelStyle: textTheme.caption,
        /*  Container(   
       decoration: BoxDecoration(
          border: Border(
            bottom: BorderSide(width: 1.0, color: Colors.black),
          ),
        ), 
        ), */
        selectedItemColor: Colors.black,
        unselectedItemColor: Colors.black.withOpacity(.60),
        items: [
          BottomNavigationBarItem(
              icon: SvgPicture.asset("assets/svg/home-alt2.svg",
                  color: Colors.black),
              title: Text("Home")),
          BottomNavigationBarItem(
              icon: SvgPicture.asset("assets/svg/favourite.svg",
                  color: Colors.black),
              title: Text("Wishlist")),
          BottomNavigationBarItem(
              icon: SvgPicture.asset("assets/svg/search.svg",
                  color: Colors.black),
              title: Text("Search")),
          BottomNavigationBarItem(
              icon: SvgPicture.asset("assets/svg/bag.svg", color: Colors.black),
              title: Text("Bookings")),
          BottomNavigationBarItem(
              icon: SvgPicture.asset("assets/svg/hamburger.svg",
                  color: Colors.black),
              title: Text("Menu"))
        ],
      ),
    );
  


_launchURL() async 
  const url = 'https://www.google.com/';
  if (await canLaunch(url)) 
    await launch(url);
   else 
    throw 'Could not launch $url';
  



【问题讨论】:

也许你可以挂上onPageFinished 并执行一些类似let appBar = document.getElementById("appBar"); appBar.parentNode.removeChild(appBar); 的js,有两个问题......好吧,这只是第一个...... 除了使用flutter web view requests之外,没有javascript实现会导致繁重的调试sme其他解决方案 我认为无法使用 Flutter 对 webview 内容进行任何更改,只能执行一些 js.... 一个选项可能是您发送 yourpage.com?dontshowappbar=true 并将其隐藏webapp 或更改 webview 中的 user-agent 并在 webapp 或服务器端进行处理 【参考方案1】:

对于操纵 WebView,我认为没有办法做到这一点,也许您可​​以使用像堆栈这样的技巧来隐藏 WebView appbar,如下所示:

  @override
  Widget build(BuildContext context) 
    final textTheme = Theme.of(context).textTheme;
    final colorScheme = Theme.of(context).colorScheme;
    return Scaffold(
      // appBar: AppBar(
      //     /*  automaticallyImplyLeading: false, */
      //     leading: Padding(
      //       padding: EdgeInsets.all(10.0),
      //       child: SvgPicture.asset("assets/images/Helmet.svg"),
      //
      //       /* leadingWidth: 35, */
      //     ),
      //     actions: [
      //       IconButton(
      //         icon: SvgPicture.asset("assets/images/Helmet.svg",
      //             color: Colors.black),
      //         onPressed: () ,
      //       ),
      //     ],
      //     backgroundColor: Colors.white),
      body: Stack(
        children: [
          IndexedStack(
            index: _selectedTabIndex,
            children: [
              Column(
                children: <Widget>[
                  Expanded(
                      child: WebView(
                    initialUrl: "https://www.veenaworld.com/",
                    javascriptMode: JavascriptMode.unrestricted,
                    onPageFinished: _handleLoad,
                    onWebViewCreated: (WebViewController webViewController) 
                      _controller.complete(webViewController);
                    ,
                  )),
                ],
              ),
              Container(
                child: Center(child: _pages[_selectedTabIndex]),
              ),
            ],
          ),
          AppBar(
            /*  automaticallyImplyLeading: false, */
            leading: Padding(
              padding: EdgeInsets.all(10.0),
              child: SvgPicture.asset("assets/images/Helmet.svg"),

              /* leadingWidth: 35, */
            ),
            actions: [
              IconButton(
                icon: SvgPicture.asset("assets/images/Helmet.svg",
                    color: Colors.black),
                onPressed: () ,
              ),
            ],
            backgroundColor: Colors.white,
          ),
        ],
      ),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _selectedTabIndex,
        onTap: _changeIndex,
        type: BottomNavigationBarType.fixed,
        /*    backgroundColor: Colors.blue.shade900, */
        selectedLabelStyle: textTheme.caption,
        unselectedLabelStyle: textTheme.caption,
        /*  Container(
       decoration: BoxDecoration(
          border: Border(
            bottom: BorderSide(width: 1.0, color: Colors.black),
          ),
        ),
        ), */
        selectedItemColor: Colors.black,
        unselectedItemColor: Colors.black.withOpacity(.60),
        items: [
          BottomNavigationBarItem(
              icon: SvgPicture.asset("assets/images/Helmet.svg",
                  color: Colors.black),
              title: Text("Home")),
          BottomNavigationBarItem(
              icon: SvgPicture.asset("assets/images/Helmet.svg",
                  color: Colors.black),
              title: Text("Wishlist")),
          BottomNavigationBarItem(
              icon: SvgPicture.asset("assets/images/Helmet.svg",
                  color: Colors.black),
              title: Text("Search")),
          BottomNavigationBarItem(
              icon: SvgPicture.asset("assets/images/Helmet.svg",
                  color: Colors.black),
              title: Text("Bookings")),
          BottomNavigationBarItem(
              icon: SvgPicture.asset("assets/images/Helmet.svg",
                  color: Colors.black),
              title: Text("Menu"))
        ],
      ),
    );
  

【讨论】:

以上是关于如何正确的在Flutter中添加webview的主要内容,如果未能解决你的问题,请参考以下文章

如何在我的 Flutter 应用中添加渐变背景?

如何正确地将库模块依赖项添加到 Flutter Plugin 的 Android 文件夹? [关闭]

如何在 Flutter 中添加 Webview?

Flutter - 如何在蜂巢中添加和检索数据?

flutter WebViewController如何添加header

无法在 Flutter 中正确对齐小部件