Flutter从入门到放弃总结

flutter_webview_plugin & fluro 实现 app webview 所有功能

安装

核心webview实现

import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
import './login.dart';
import '../bottom_navigation_widget.dart';
import '../utils/storage.dart';
import '../router/custome_router.dart';

_setUrl (String url) {
  if (url.indexOf('?')> -1) {
    return '$url&v=${DateTime.now().millisecondsSinceEpoch}';
  } else {
    return '$url?v=${DateTime.now().millisecondsSinceEpoch}';
  }
}

class WebWiew extends StatefulWidget {
  String url;
  String sessionId;
  String token;
  WebWiew(
    this.url,
    [this.sessionId,
    this.token,]
  );
  @override
  _WebWiewState createState() => _WebWiewState();
}

class _WebWiewState extends State<WebWiew> {
  FlutterWebviewPlugin flutterWebviewPlugin = FlutterWebviewPlugin();
  String title = "页面跳转中";
  String _thisUrl = '';
  String _intUrl = '';

  //获取h5页面标题
  getWebTitle() async {
    String script = 'window.document.title';
    var title = await
    flutterWebviewPlugin.evalJavascript(script);
    setState(() {
      this.title = title.replaceAll('\"',' ');
    });
  }

  @override
  void initState() {
    super.initState();
    flutterWebviewPlugin.onStateChanged.listen((WebViewStateChanged webViewState) async {
      print('onStateChanged');
      switch (webViewState.type) {
      case WebViewState.finishLoad:
        break;
      case WebViewState.shouldStart:
        break;
      case WebViewState.startLoad:
        break;
      case WebViewState.abortLoad:
        break;
      }
    });

    /**
     * 监听页面加载url
    */
    flutterWebviewPlugin.onUrlChanged.listen((String url) {
      setState(() {
        _thisUrl = url;
      });
      if (_intUrl == ''){
        setState(() {
          _intUrl = url;
        });
      }
      print(url);
      getWebTitle();
      if (url.indexOf('authorize.html') > -1) {
        clearToken();
        flutterWebviewPlugin.stopLoading();
        // 关闭webView 跳转到app登录页
        flutterWebviewPlugin.close();
        Navigator.of(context).pushAndRemoveUntil(
          MaterialPageRoute(builder: (BuildContext context) => Login()),
          (route) => route == null
        );
      }
    });
  }

  @override
  Widget build(BuildContext context) {
     return Container(
       child: WebviewScaffold(
           url:  _setUrl(widget.url),
           // 默认加载地址
           appBar: AppBar(
             title: Text(title),
             leading:Container(
               padding: EdgeInsets.only(left:4.0),
               child: InkWell(
                 child: Icon(Icons.arrow_back_ios),
                 onTap: () {
                   Navigator.of(context).pushAndRemoveUntil(
                       // 使用自定义的动画跳转路由
                       CustomRoute(BottomNavigationWidget()),
                       //  MaterialPageRoute(builder: (BuildContext context) => BottomNavigationWidget()),
                           (route) => route == null
                   );
                 },
               ),
             ),
           ),
           scrollBar: false,
           withZoom: false,
           headers: {
             'app-session-id': widget.sessionId,
             'x-auth-token': widget.token,
           }
       )
     );
  }

  @override
  void dispose() {
    flutterWebviewPlugin.dispose();
    super.dispose();
  }
  void setHeaders () {
    // flutterWebviewPlugin
  }
}

fluro 使用

/// application.dart
import 'package:fluro/fluro.dart';

class Application {
  static Router router;
}
/// route_handlers.dart
var rootHandler = Handler(
    handlerFunc: (BuildContext context, Map<String, List<String>> params) {
  return Home();
});

var mycenterHandler = Handler(
    handlerFunc: (BuildContext context, Map <String, dynamic> params) {
      String sessionId = params['sessionId']?.first;
      String token = params['token']?.first;
      String id = params['arg1']?.first;
      String agency = params['arg2']?.first;
      return WebWiew('${baseUrl}static/mycenter.html', sessionId, token);
});

var withoutLoginPageHandler = Handler(
    handlerFunc: (BuildContext context, Map <String, dynamic> params) {
          String url = params['url']?.first;
          print(url);
          return WebWiew(Uri.decodeComponent(url));
    }
);
/// routers.dart
import 'package:flutter/material.dart';
import 'package:fluro/fluro.dart';
import './route_handlers.dart';

class Routes {
  static String root = '/';
  static String myCenter = '/mycenter';
  static String withoutLoginPage = '/withoutLoginPage';


  static void configureRoutes(Router router){
    router.notFoundHandler= new Handler(
      handlerFunc: (BuildContext context, Map<String, List<String>> params){
        print('ERROR====>ROUTE WAS NOT FONUND!!!');
        return null;
      }
    );

    router.define(root, handler: rootHandler);
    router.define(myCenter, handler: mycenterHandler);
    router.define('withoutLoginPage/:url', handler: withoutLoginPageHandler);
  }
}


封装一个HTTP请求

import 'dart:io';
import 'dart:convert';
import 'dart:async';
import 'package:cookie_jar/cookie_jar.dart';
import 'package:dio/dio.dart';
import '../config/config.dart';
import '../common/eventBus.dart';
import '../utils/storage.dart';
import '../utils/tools.dart';


class HttpUtils {
  /// global dio object
  static Dio dio;

  /// http request methods
  static const String GET = 'get';
  static const String POST = 'post';
  static const String PUT = 'put';
  static const String PATCH = 'patch';
  static const String DELETE = 'delete';


  /// request method
  static Future<Map> request (
    String url,
    { data, method}) async {
    data = data ?? {};
    method = method ?? 'GET';
    data.forEach((key, value) {
      if (url.indexOf(key) != -1) {
        url = url.replaceAll(':$key', value.toString());
      }
    });

    /// 打印请求相关信息:请求地址、请求方式、请求参数
    print('请求地址:【' + method + '  ' + url + '】');
    print('请求参数:' + jsonEncode(data));

    Dio dio = createInstance();
    var result;
    try {
      Response response = await dio.request(
          url,
          data: FormData.from(data),
          options: new Options(
              method: method,
              contentType: ContentType.parse("application/x-www-form-urlencoded;charset=utf-8"),
          )
      );
      if (response.statusCode != 200) {
        toastError('请求服务器失败');
        return null;
      } else {
        result = jsonDecode(response.data);
        return result;
      }
      /// 打印响应相关信息
      print('响应数据:' + response.toString());
    } on DioError catch (e) {
      /// 打印请求失败相关信息
      print('请求出错:' + e.toString());
      toastError('请求服务器失败');
    }
  }

  /// 创建 dio 实例对象
  static Dio createInstance () {
    if (dio == null) {
      /// 全局属性:请求前缀、连接超时时间、响应超时时间
      BaseOptions options = new BaseOptions(
        baseUrl: baseUrl,
        connectTimeout: 15000,
        receiveTimeout: 30000,
        contentType: ContentType.JSON,
        responseType: ResponseType.plain,
      );
      dio = new Dio(options);
//      Fiddler抓包设置代理
//       (dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (client){
//         client.findProxy = (url){
//           return "PROXY 192.168.50.85:8888";
//         };
//       };
      dio.interceptors.add(InterceptorsWrapper(
          onRequest:(RequestOptions options){
            // 来自app的请求 后期可以做特殊处理
            options.headers["x-auth-from"] = 'fromApp';
            // 在请求被发送之前做一些事情
            return options; //continue
          },
          onResponse:(Response response) {
            // 在返回响应数据之前做一些预处理
            if(response.toString() == 'InvalidToken') {
              print('请求拦截数据====未登录 跳转登录页面======');
              eventBus.fire(LoginEvent(true));
              clearToken();
              return null;
            }  else {
              var _token = response.headers['x-auth-token'];
              if (_token != null) setToken(_token[0]);
              var sessionId =  response.headers['app-session-id'];
              if (sessionId != null) setSessionId(sessionId[0]);
              return response; // continue
            }
          },
          onError: (DioError e) {
            // 当请求失败时做一些预处理
            return e;//continue
          }
      ));
      var cj = new CookieJar();
      dio.interceptors.add(CookieManager(cj));
    }

    // 获取cookie
    // List results = cj.loadForRequest(Uri.parse(baseUrl));
    // if (results.length >= 1) {
    //   setSessionId(results[1].toString().split(';')[0].split('=')[1]);
    // }
    return dio;
  }

  /// 清空 dio 对象
  static clear () {
    dio = null;
  }
}

HTTP使用

Future refreshToken () async {
  final prefs = await SharedPreferences.getInstance();
  var result = await HttpUtils.request(
      api['refreshToken'],
      method: HttpUtils.POST,
      data: {
        'x-auth-token': prefs.getString('token')
      }
    );
    return result;
}

持续增加中……

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,110评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,443评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,474评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,881评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,902评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,698评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,418评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,332评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,796评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,968评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,110评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,792评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,455评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,003评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,130评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,348评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,047评论 2 355

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,103评论 1 32
  • 昨天跟我广州的同学沟通了一下,我鼓励他这个月推荐8个人直接上D,他也觉得可以挑战一下,昨晚他就组织了十几个人建立一...
    吕健全阅读 271评论 0 0
  • 文/悠然 图/网络 01 前几日刚结束的《中国诗词大会》第三季总决赛上,来自杭州的外卖小哥雷海为逆袭夺冠,火遍网络...
    悠然不知岁阅读 687评论 0 1
  • 今天冬至节,听了冬至节的故事,吃饺子、唱九九消寒歌,做了九九消寒图,讲了新年到就是生肖猪年了。一起看了昆虫的世界,...
    宝兰儿阅读 282评论 0 0
  • 所谓益友,定要是你生活中的一缕阳光,在你感觉冷了,潮湿了,给你一丝光亮的温暖。没有一丁点讨好的意味和无事献殷勤的嫌...
    小雨的海阅读 137评论 0 2