flutter 结合uni 做小程序探索

flutter 结合uni 做小程序探索,第1张

flutter web其实出来也有一段时间了,最近在用flutter做一个跨端的APP,由于又加入了小程序端,所以在探索怎么通过flutter web来做小程序。

一、实现原理
通过flutter web将程序打包成手机浏览器能访问的网页,然后用uni中的webview来展示这个页面,最后通过uni打包成小程序发布,这样一个通过flutter实现的小程序基本就处理完毕了。

二、小程序登录问题
由于项目需要获取微信用户的openid,所以需要在小程序端做小程序登录处理,这里就涉及到小程序跟flutter交互的问题。目前我的处理办法是,使用uni创建一个登陆页面用于微信用户在小程序端登录:

<template>
	<view class="content">
			
			
			<image src="../../static/dog_logo.png" mode="aspectFill" style="width: 200rpx;height: 200rpx;margin-top: 200rpx;"></image>
			<text style="margin-top: 30rpx;">恋爱狗</text>
		<button class="login" type="primary" @tap="wxLogin">
			授权登录
		</button>
	
	</view>
</template>

<script>
	import {
		wxLogin,
	} from '@/api/network.js';
	export default {
		data() {
			return {
				errordata:'',
			}
		},
		onShow() {
			
		},
		
		onLoad() {

		},
		methods: {
			message(event) {
				console.log("发的东西呢")
				console.log(event.detail.data);
			},
			wxLogin() {
				// 获取code 小程序专有,用户登录凭证。
				uni.getUserProfile({
					desc: "获取用户基本资料",
					lang: 'zh_CN',
					success: (user) => {
						//获取成功基本资料后开启登录,因为基本资料首先要授权
						uni.login({
							provider: 'weixin',
							success: function(code_res) {
								if (code_res.errMsg == "login:ok") {
									let code = code_res.code;
									uni.navigateTo({
										url:"./home?code="+code+"&nickName="+user.userInfo.nickName+"&avatarUrl="+user.userInfo.avatarUrl
									})
								}
							}
						});
					},
					fail: (res) => {
						uni.showModal({
							title:"用户拒绝授权",
							showCancel:false
						})
					}
				});
			},
		}
	}
</script>

<style>
	.content {
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
	}

	.logo {
		height: 200rpx;
		width: 200rpx;
		margin-top: 200rpx;
		margin-left: auto;
		margin-right: auto;
		margin-bottom: 50rpx;
	}


	.login {
		height: 100rpx;
		width: 500rpx;
		margin-top: 400rpx;
		margin-left: auto;
		margin-right: auto;
		
	}


.text-area {
		display: flex;
		justify-content: center;
	}

	.title {
		font-size: 36rpx;
		color: #8f8f94;
	}
	
</style>

通过uni提供的小程序登录功能获取到code以及用户的相关信息,然后跳转到集成webview的页面,通过页面传参的方式把用户信息传到flutter端,home.vue代码如下:

<template>
	<view class="content">
		<web-view :src="url" @message="message"></web-view>
	</view>
</template>

<script>
	import {
		wxLogin,
	} from '@/api/network.js';
	export default {
		data() {
			return {
				title: 'Hello',
				url: ''
			}
		},
		onShow() {
			
		},
		onLoad(e) {
			this.url="https://url/#/SplashPage?code="+e.code+"&nickName="+e.nickName+"&avatarUrl="+e.avatarUrl;
		},
		methods: {
			
		}
	}
</script>

<style>
	.content {
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
	}

	.logo {
		height: 200rpx;
		width: 200rpx;
		margin-top: 200rpx;
		margin-left: auto;
		margin-right: auto;
		margin-bottom: 50rpx;
	}

	.text-area {
		display: flex;
		justify-content: center;
	}

	.title {
		font-size: 36rpx;
		color: #8f8f94;
	}
</style>

在flutter端接收传递过来的信息通过接口将该用户在系统的信息获取过来用以将微信号跟系统账户绑定。
关于flutter端接收链接传参的 *** 作如下,在main.dart中做如下更改,由于我flutter端是用的fish_redux做的路由管理,所以该方法可能仅对fish_redux有用:


import 'dart:collection';
import 'dart:convert';
import 'dart:io';
import 'package:fish_redux/fish_redux.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:tree_flutter/app_route.dart';
import 'package:tree_flutter/cache/local_storage.dart';
import 'package:tree_flutter/cache/userinfo_cache_manager.dart';
import 'package:tree_flutter/constants/global_events.dart';
import 'package:tree_flutter/constants/global_theme_styles.dart';
import 'package:tree_flutter/generated/l10n.dart';
import 'package:tree_flutter/net/api_work.dart';
import 'package:tree_flutter/utils/base_tools.dart';
import 'package:tree_flutter/utils/toast_tools.dart';


void main() {
//  println(name+"---------");
  LocalStorage.checnLocalThemeResources().then((e) =>runApp(MyApp()));
// runApp((MyApp()));
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}



class _MyAppState extends State<MyApp> with WidgetsBindingObserver{
  // This widget is the root of your application.


  @override
  void initState() {
    // TODO: implement initState
    WidgetsBinding.instance.addObserver(this);
    super.initState();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    print("--" + state.toString());
    switch (state) {
      case AppLifecycleState.inactive: // 处于这种状态的应用程序应该假设它们可能在任何时候暂停。
        break;
      case AppLifecycleState.resumed:// 应用程序可见,前台
      // GlobalThemeStyles.instan/ce.setStatusBarWhiteForeground(false);
      //   eventBus.fire("authtoken");

        break;
      case AppLifecycleState.paused: // 应用程序不可见,后台
        break;
      case AppLifecycleState.detached:
      // TODO: Handle this case.
        break;
    }
  }
  @override
  Widget build(BuildContext context) {
    return ScreenUtilInit(builder: ()=>MaterialApp(
      title: 'title',
      showSemanticsDebugger: false,
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
      ],
      locale: GlobalThemeStyles.themeLocale,
      supportedLocales: <Locale>[
        const Locale('en', 'US'), // 美国英语
        const Locale('zh', 'CN'), // 中文简体
      ],
      onGenerateRoute: (RouteSettings settings) {
        if(BaseTools.IS_WEB){
          Map<String, dynamic> map = BaseTools.urlToMap(settings.name);
          if (!BaseTools.isEmpty(settings.arguments)) {
            println(settings.arguments.toString());
          }
          if (!BaseTools.isEmpty(map)) {
            return MaterialPageRoute<Object>(builder: (BuildContext context) {
              return AppRoute.global.buildPage(
                  settings.name.replaceAll("/", "").split("?")[0], map);
            });
          } else {
            return MaterialPageRoute<Object>(builder: (BuildContext context) {
              return AppRoute.global.buildPage(
                  settings.name.replaceAll("/", "").split("?")[0],
                  settings.arguments);
            });
          }
        }
        return MaterialPageRoute<Object>(builder: (BuildContext context) {
          return AppRoute.global.buildPage(settings.name, settings.arguments);
        });
      },
      home:  AppRoute.global.buildPage(RoutePath.SPLASH_PAGE, null),
      // initialRoute: RoutePath.SplashPage,
    ),
      designSize: Size(375, 667),
    );
  }
}

其中核心部分在:

   if(BaseTools.IS_WEB){
          Map<String, dynamic> map = BaseTools.urlToMap(settings.name);
          if (!BaseTools.isEmpty(settings.arguments)) {
            println(settings.arguments.toString());
          }
          if (!BaseTools.isEmpty(map)) {
            return MaterialPageRoute<Object>(builder: (BuildContext context) {
              return AppRoute.global.buildPage(
                  settings.name.replaceAll("/", "").split("?")[0], map);
            });
          } else {
            return MaterialPageRoute<Object>(builder: (BuildContext context) {
              return AppRoute.global.buildPage(
                  settings.name.replaceAll("/", "").split("?")[0],
                  settings.arguments);
            });
          }
        }

urlToMap方法具体代码如下:

  static Map<String,dynamic> urlToMap(String url){
    Map<String,dynamic > map=new HashMap();

    if(isEmpty(url)||!url.contains("?")){
     
      return null;
    }else{
      List<String> urlList=url.split("?");
      urlList=urlList[urlList.length-1].split("&");
      for(int i=0;i<urlList.length;i++){
        map[urlList[i].split("=")[0]]=urlList[i].split("=")[1];
      }
      println(map.toString());
    }
    return map;
  }

三、关于微信小程序支付问题
由于flutter无法直接调用小程序的支付,所以要使用小程序支付功能稍微有些复杂,具体实现还是要通过uni让小程序跟flutter端建立连接。
1.首先在flutter端做好生成订单以及通过接口获取微信小程序支付需要的相关的数据,然后通过flutter端打开uni页面,具体实现如下:
首先导入:

import 'dart:js' as js;

然后:

      js.context.callMethod("testPay",["./orderPay?timeStamp="+paydata["timestamp"].toString()+"&nonceStr="+paydata["nonce_str"].toString()+"&package="+paydata["prepay_id"].toString()+"&paySign="+paydata["sign"].toString()]);

通过dart.js提供的callMethod来与uni页面进行通信,其中testPay代表函数名称,这个函数怎么定义下面会说,然后后面数组里面的是传参。

在flutter下面的web文件夹下面有一个index.html文件,上面的testPay需要定义在这个文件下面:

<!DOCTYPE html>
<html>
<head>
  <!--
    If you are serving your web app in a path other than the root, change the
    href value below to reflect the base path you are serving from.

    The path provided below has to start and end with a slash "/" in order for
    it to work correctly.

    For more details:
    * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base

    This is a placeholder for base href that will be replaced by the value of
    the `--base-href` argument provided to `flutter build`.
  -->
  <base href="$FLUTTER_BASE_HREF">

  <meta charset="UTF-8">
  <meta content="IE=Edge" http-equiv="X-UA-Compatible">
  <meta name="description" content="A new Flutter project.">

  <!-- iOS meta tags & icons -->
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style" content="black">
  <meta name="apple-mobile-web-app-title" content="tree_flutter">
  <link rel="apple-touch-icon" href="icons/Icon-192.png">

  <title>恋爱树</title>
  <link rel="manifest" href="manifest.json">
</head>
<body>
  <!-- This script installs service_worker.js to provide PWA functionality to
       application. For more information, see:
       https://developers.google.com/web/fundamentals/primers/service-workers -->

  <script type="text/javascript"
          src="https://res.wx.qq.com/open/js/jweixin-1.3.2.js"></script>
  <script type="text/javascript"
          src="https://js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.1.5.2.js"></script>
  <script>
       function testPay(timeStamp) {
	          uni.navigateTo({
				url:timeStamp
			});
	    }
    var serviceWorkerVersion = null;
    var scriptLoaded = false;
    function loadMainDartJs() {
      if (scriptLoaded) {
        return;
      }
      scriptLoaded = true;
      var scriptTag = document.createElement('script');
      scriptTag.src = 'main.dart.js';
      scriptTag.type = 'application/javascript';
      document.body.append(scriptTag);
    }

    if ('serviceWorker' in navigator) {
      // Service workers are supported. Use them.
      window.addEventListener('load', function () {
        // Wait for registration to finish before dropping the             
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)