关于flutter:Flutter-Webview添加Cookie的正确姿势

40次阅读

共计 4738 个字符,预计需要花费 12 分钟才能阅读完成。

场景

h5 页面要从 cookie 外面取数据,所以须要在 flutter webview 的 cookie 外面塞一些数据,设置的数据多达十几条;依照网上查的应用形式来设置,通过 fiddler 抓包发现,只能失效一条,来来回回试了很屡次都只有一条,心态崩了

起初看到 cookie 设置数据也是相似键值对外面套键值对,眉头一皱; 计上心来,变换下后就胜利了,记录下正确的写法吧

正确姿态

引入

  • 应用的是 flutter 官网保护的 webview 插件
webview_flutter: ^0.3.22+1

谬误示例

  • 这是最坑的一个,widget 都都没写全,就写了俩个回调,这么写只会失效一条
WebViewController _controller;
onWebViewCreated: (WebViewController wvc) {_controller = wvc;}

onPageFinished: (String value) {_controller.evaluateJavascript( 'document.cookie ="SESSIONID=612bc4822b6996d6f335a963c20eb541fba72985; path=/"')
}
  • 这个只写了一条 cookie,这个是没问题的,和下面的区别就是,这个应用双引号包住单引号,只写了一条的应用也是让人肝痛
setSessionID() async {String sessionID = await LocalStorage.get("sessionID");
  if (Platform.isIOS) {_controller.evaluateJavascript("document.cookie ='sessionID=${sessionID}'").then<String>((res) {print("webViewController.evaluateJavascript========>${res}");
      _onListCookies(_controller, context);
    });
  } else {_controller.evaluateJavascript('document.cookie ="sessionID=${sessionID};"').then<String>((res) {print("webViewController.evaluateJavascript========>${res}");
      _onListCookies(_controller, context);
    });
  }
}

多条 cookie 增加正确写法

  • 推敲半天试出来的正确写法,cookie 的设置须要在页面加载完之后设置
///webview 控制器
WebViewController _controller;
String _url = "写入你的链接";

WebView(
    initialUrl: _url,
    javascriptMode: JavascriptMode.unrestricted,
    onWebViewCreated: (controller) {_controller = controller;},
    onPageFinished: (url) {
        // 页面加载完结
        String cookie =
            "document.cookie ='name=IAmDaShuaiBi';document.cookie ='id=233'";
        _controller.evaluateJavascript(cookie);
    },
    userAgent: "test;app/1.0.0",
)
  • 最重要的变动就是每条 cookie 都要用 document.cookie 作为 key,这是最最最要害的

优化写法

  • 下面的写法是写成一行,写成一行是很致命的操作,让赋值操作会变得很蛊惑,优化下
///webview 控制器
WebViewController _controller;
String _url = "写入你的链接";

WebView(
    initialUrl: _url,
    javascriptMode: JavascriptMode.unrestricted,
    onWebViewCreated: (controller) {_controller = controller;},
    onPageFinished: (url) {
        // 页面加载完结
        String cookie = '''document.cookie ='nameOne=IAmDaShuaiBi';
          document.cookie = 'idOne=233';
          document.cookie = 'nameTwo=IAmDaShuaiBi';
          document.cookie = 'idTwo=233';
          document.cookie = 'nameThree=IAmDaShuaiBi';
          document.cookie = 'idThree=233';
        ''';
        _controller.evaluateJavascript(cookie);
    },
    userAgent: "test;app/1.0.0",
)
  • ok,搞定

补充(弹窗封装,优化列表数据源)

  • 就这么点内容就水了一片文章,显得我是个水笔,为了证实我不是个水笔,再补充个开发小技巧

成果

  • 来看下封装后的应用
  • 数据源 List 的泛型能够随便,showKey 是你指定显示在弹窗列表上的字段
showBottomSingleDialog(
    context,
    list: list,
    showKey: 'name',
    callback: (item) {print(item.name);
        print(item.id);
    },
);
  • 效果图

阐明

底部单列表弹窗是十分实用的弹窗,然而可能大家常常有这样的一种应用体验,传数据源,个别都是传一个 List 类型,外部的泛型最最最常见的就是:String 和固定的实体;说下这俩种状况的问题所在

  • String:显然该泛型,外部解决解决起来非常简单,间接拿 String 值展现就行,回调间接把抉择的 String 返回;这种 String 类型存在一个十分致命的的问题,在应用前后都存在问题

    • 应用前:咱们必须把数据类型转换成 List<String> 类型,咱们数据源个别都是通过接口获取,接口外面 List 数据源外面的泛型形形色色的,往往须要做循环转化成 List<String> 类型去应用
    • 应用后:点击抉择后,拿到咱们抉择的展现名,接口提交往往是须要该种抉择类型的 id,一般来说还须要去做遍历拿出抉择名称对应的 id,而后保留做提交操作
  • 规定实体:应用规定的泛型实体,有一个益处,能够防止在应用后去遍历比照,而后去取 id 的操作,所以他只存在应用前的麻烦

    • 应用前:这里咱们必须把拿到的数据源转换符合要求的 List 规定实体泛型,这步操作就能够把 id 等信息一起放在规定的实体外面,抉择之后也能够间接从实体外面拿了

吐槽 :尽管下面俩种状况,第二种显著优于第一种,然而理论开发中,往往不假思索的用第一种,因为第一种不必去新建一个 class 啊!而后用起来就蛋痛了;有没有一种办法能够一劳永逸的办法呢,数据的 list 泛型轻易用,只用指定泛型实体用于展现的 key;而后在回调外面又能拿到咱们传的实体呢?通过 dart 弱小的动静类型,加一些奇妙转换是齐全能够的

实现思路

java 里能够通过泛型 + 反射;而后指定一个展现的 key,实践上也是能够实现,我没试过,大家能够试试

实现思路

实现办法还是很简略的,这里说下思路就行了

实现步骤

  • 数据源定义为 List<E> 类型,而后指定一个展现的 key

    • 泛型不指定的话,会默认为动静类型,这样的话,便有了很大的操作空间
  • 遍历这个 List,而后拿到遍历列表时的实体
  • 将实体转换成 Map 类型,通过指定的 key,获取展现内容就行了
  • 回调时,传进去选的实体就 ok,似不似很简略

举例

  • 引入:flutter_picker
flutter_picker: ^1.1.5
  • 实现
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_picker/Picker.dart';

typedef ParamSingleCallback<E> = Void Function(E data);

void showBottomSingleDialog<E>(
    BuildContext context, {
        @required List<E> list,
        @required ParamSingleCallback<E> callback,
        String title = '请抉择',
        String showKey = '',
    }) {List<PickerItem<E>> pickList = [];
    for (E item in list) {
        String showContent;
        if (showKey == '') {
            // 兼容泛型为 String 的状况
            showContent = item as String;
        } else {
            // 将实体转成 map,通过设置的 key 指定展现的字段
            var map = json.decode(jsonEncode(item));
            showContent = map[showKey];
        }

        pickList.add(
            PickerItem(text: Text(showContent),
                value: item,
            ),
        );
    }

    Picker(adapter: PickerDataAdapter<E>(data: pickList),
        hideHeader: false,
        title: Text(title),
        cancelText: "勾销",
        confirmText: "确定",
        onConfirm: (Picker picker, List value) async {
            // 必须做一个延时操作, 先执行回调外部的 pop, 不然 pop 页面无奈回传值
            await Future.delayed(Duration(milliseconds: 10));
            callback(picker.getSelectedValues()[0]);
        },
    ).showModal(context);
}

应用

  • 数据源
class InfoBean {
    String name;
    int id;

    InfoBean({this.id, this.name});

    /// jsonDecode(jsonStr) 办法中会调用实体类的这个办法。如果实体类中没有这个办法,会报错。Map toJson() {Map map = Map();
        map["name"] = this.name;
        map["id"] = this.id;
        return map;
    }
}

/// 创立数据源
List<InfoBean> list = [];
for (var i = 0; i < 10; i++) {list.add(InfoBean(name: "姓名 -$i", id: i));
}
  • 应用

    • 这中央指不指定泛型都是能够的,不指定泛型默认为动静类型,item 点的时候没有提醒,能够凭着本人的记忆写 key 值,只有是 key 是对,齐全能拿到数据
/// 指定泛型
showBottomSingleDialog<InfoBean>(
    context,
    list: list,
    showKey: 'name',
    callback: (item) {print(item.name);
        print(item.id);
    },
);

/// 不指定泛型
showBottomSingleDialog(
    context,
    list: list,
    showKey: 'name',
    callback: (item) {print(item.name);
        print(item.id);
    },
);
  • 成果试用

    • https://cnad666.gitee.io/flutter_use/#/dialog

最初

代码地址

  • Github:范例我的项目代码地址

正文完
 0