MacOS下配置flutter开发环境

fvm

flutter

安装 fvm

1
2
brew tap leoafarias/fvm
brew install fvm

安装 flutter

1
2
3
4
5
6
7
8
9
10
11
12
13
# 查看所有 flutter 版本
fvm releases

# 安装指定版本的 flutter
fvm install 3.3.4

# 选中版本
fvm global 3.3.4

# 查看 flutter 位置
fvm destroy
# 输出,这个地址就是 flutter 的安装位置
Are you sure you want to destroy the directory "/Users/xxx/fvm" ? y/N:

配置 flutter 环境变量

当前 fvm 安装后命令行输入 flutter 仍然无法使用,需要配置环境变量

1
open ~/.zshrc

输入

1
export PATH="$PATH:[PATH_OF_FLUTTER_GIT_DIRECTORY]/bin"

将其中 [PATH_OF_FLUTTER_GIT_DIRECTORY] 改为上面获取到的地址

1
2
3
source ~/.zshrc
# 查看 flutter 位置
which flutter

这样 flutter 环境就配置成功了,输入 flutter doctor 即可查看开发环境配置。

MacOS安装git

Git官网

安装

首先需要安装 homebrew,前一篇文章中已经安装,接下来直接使用命令安装。

1
brew install git

一切顺利的话等待安装成功就可以直接使用了

MacOS安装homebrew软件包管理器

Homebrew

Homebrew 是 MacOS 上的一个软件包管理器

官网地址

安装

1
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

国内网络安装可能会失败,可以尝试使用镜像地址

1
/bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"

稍等片刻即可安装成功

环境变量

通过官网地址安装成功后有可能会出现

1
zsh: command not fond: brew

命令行输入:

1
sudo vim ~/.bash_profile

点击 i 插入

1
export PATH="/opt/homebrew/bin:$PATH"

按 esc 退出编辑模式 输入 :wq 保存

输入命令,激活文件

1
source ~/.bash_profile

windows下vscode终端乱码问题解决

flutter输出内容一直有部分文字乱码,索性搜索了下如何解决

检查当前终端编码方式

1
chcp

我的电脑提示

1
活动代码页: 936

GBK2312 的代码页编号是 936,然后改成utf-8的编码即可

1
chcp 65001

flutter中使用webview对接百度地图JS_SDK

适用于 flutter 3.3.4

安装依赖

1
2
3
flutter_inappwebview: ^5.7.2+3
geolocator: ^8.2.1
permission_handler: ^9.2.0

配置 assets

1
2
3
flutter:
assets:
- assets/static/baidu-map-html/

在项目对应位置创建 index.html,复制下面的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Baidu Map</title>
<style type="text/css">
html {
height: 100%;
}
body {
height: 100%;
margin: 0px;
padding: 0px;
}
#container {
height: 100%;
}
</style>
<script
type="text/javascript"
src="https://api.map.baidu.com/api?v=3.0&ak=填写你自己的ak"
></script>
</head>
<body>
<div id="container"></div>
<script>
var map = new BMap.Map("container", {
coordsType: 5, // coordsType指定输入输出的坐标类型,3为gcj02坐标,5为bd0ll坐标,默认为5。
// 指定完成后API将以指定的坐标类型处理您传入的坐标
}); // 创建地图实例
var point = new BMap.Point(120.733491, 31.263752); // 创建点坐标
map.centerAndZoom(point, 15); // 初始化地图,设置中心点坐标和地图级别
map.enableScrollWheelZoom(true); //开启鼠标滚轮缩放
</script>
</body>
</html>

geolocator 配置

创建一个 dart 文件

初始化地图,使用 callAsyncJavaScript 注入脚本,实现地图操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import 'dart:convert';
import 'dart:developer';

import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:geolocator/geolocator.dart';

class WebviewBaiduMap extends StatefulWidget {
final Map<String, dynamic> data;
const WebviewBaiduMap({Key? key, required this.data}) : super(key: key);

@override
State<WebviewBaiduMap> createState() => _WebviewBaiduMapState();
}

class _WebviewBaiduMapState extends State<WebviewBaiduMap> {
@override
Widget build(BuildContext context) {
InAppWebViewController? mapViewController;
const String htmlUrl = 'assets/static/baidu-map-html/index.html';

/// 申请定位权限
/// 授予定位权限返回true, 否则返回false
Future<bool> requestLocationPermission() async {
//获取当前的权限
var status = await Permission.location.status;
if (status == PermissionStatus.granted) {
//已经授权
return true;
} else {
//未授权则发起一次申请
status = await Permission.location.request();
if (status == PermissionStatus.granted) {
return true;
} else {
return false;
}
}
}

// ? 获取用户位置
void _getUserLocation() async {
bool hasLocationPermission = await requestLocationPermission();
if (!hasLocationPermission) return;
Position position = await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
final newLocal = GpsUtil.gps84_To_bd09(position.latitude, position.longitude);
// 获取定位后添加用户位置
mapViewController?.callAsyncJavaScript(
functionBody: '''
var userPoint = new BMap.Point(longitude, latitude);
var marker = new BMap.Marker(userPoint);
map.addOverlay(marker);
''',
arguments: {
'latitude': newLocal[0],
'longitude': newLocal[1],
},
);
}

// ? 获取车辆位置
void _getVehicleLocation({bool? setCenter}) {
final data = widget.data;
List<double> newLocal = [31.2660528, 120.7407351];

mapViewController?.callAsyncJavaScript(
functionBody: '''
var point = new BMap.Point(longitude, latitude);
var marker = new BMap.Marker(point);
map.addOverlay(marker); // 添加标记
map.panTo(point); // 地图中心点移动到指定位置
''',
arguments: {
'latitude': newLocal[0],
'longitude': newLocal[1],
},
);
}

return Scaffold(
resizeToAvoidBottomInset: false,
body: ConstrainedBox(
constraints: const BoxConstraints.expand(),
child: Stack(
fit: StackFit.expand,
children: [
SizedBox(
width: double.infinity,
height: double.infinity,
child: InAppWebView(
initialFile: htmlUrl,
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(javaScriptEnabled: true),
android: AndroidInAppWebViewOptions(),
ios: IOSInAppWebViewOptions(),
),
onWebViewCreated: ((controller) {
log('网页创建');
}),
onProgressChanged: ((controller, progress) {
log('load $progress');
}),
onLoadStart: ((controller, url) {
log('load start $url');
}),
onLoadStop: ((controller, url) {
log('load stop $url');
setState(() {
mapViewController = controller;
});
_getVehicleLocation();
_getUserLocation();
}),
onLoadHttpError: ((controller, url, statusCode, description) {
log('$url $description');
}),
onLoadError: ((controller, url, code, message) {
log('$url $message');
}),
onLoadResource: ((controller, resource) {
log('load resource');
}),
),
),
const Positioned(
top: 0,
left: 0,
right: 0,
// 这里可以在右上角放一个返回按钮
child: Container(),
),
],
),
),
);
}
}

flutter中使用geolocator获取当前经纬度

geolocator插件地址

geolocator 插件是一个Flutter定位插件,支持 Android,iOS,macOS,Web,Windows中定位。

使用前需要针对不同平台配置权限,按照官网步骤完成即可。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import 'package:geolocator/geolocator.dart';

/// 确定设备当前位置。
///
/// 当位置服务未启用或权限 `Future`将返回一个错误。
Future<Position> _determinePosition() async {
bool serviceEnabled;
LocationPermission permission;

// 测试位置服务是否启用。
serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
// 位置服务未启用,请勿继续访问位置和请求用户的应用程序来启用位置服务。
return Future.error('位置服务已禁用。');
}

permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {
//权限被拒绝,根据Android指南你的应用程序现在应该显示一个解释性的UI。
return Future.error('位置权限被拒绝');
}
}

if (permission == LocationPermission.deniedForever) {
// 权限永远被拒绝,请适当处理。
return Future.error(
'位置权限被永久拒绝,我们不能请求权限。');
}

// 当我们到达这里,得到许可,我们就可以继续访问设备的位置。
return await Geolocator.getCurrentPosition();
}

flutter中对接百度地图

开发环境

flutter: 3.3.4
baidu_map: 3.2.1

官方文档: Flutter插件

添加依赖

pubspec.yaml

1
2
3
4
5
dependencies:
flutter_baidu_mapapi_base: ^3.2.1
flutter_baidu_mapapi_map: ^3.2.1
flutter_baidu_mapapi_search: ^3.2.1
flutter_baidu_mapapi_utils: ^3.2.1

lib/main.dart

1
2
3
4
5
6
7
8
9
10
11
12
13
import 'package:flutter_baidu_mapapi_base/flutter_baidu_mapapi_base.dart' show BMFMapSDK, BMF_COORD_TYPE;
import 'package:flutter_baidu_mapapi_map/flutter_baidu_mapapi_map.dart';

// 同意隐私权限
BMFMapSDK.setAgreePrivacy(true);

if (Platform.isIOS) {
BMFMapSDK.setApiKeyAndCoordType('请输入百度开放平台申请的iOS端API KEY', BMF_COORD_TYPE.BD09LL);
} else if (Platform.isAndroid) {
// Android 目前不支持接口设置Apikey,
// 请在主工程的Manifest文件里设置,详细配置方法请参考[https://lbs.baidu.com/ 官网][https://lbs.baidu.com/)demo
BMFMapSDK.setCoordType(BMF_COORD_TYPE.BD09LL);
}

android/app/build.gradle

这一步是配置代码混淆,按官网文档就行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
android {
buildTypes {
release {
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled true
useProguard true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
}
}

android/app/proguard-rules.pro

1
2
3
4
-keep class com.baidu.** {*;}
-keep class vi.com.** {*;}
-keep class com.baidu.vi.** {*;}
-dontwarn com.baidu.**

android/app/src/main/java/com/xx/xxx/MyApplication.java

com/xx/xxx 代表你的包名

1
2
3
4
5
6
7
8
9
10
11
package com.xx.xxx;

import com.baidu.mapapi.base.BmfMapApplication;

public class MyApplication extends BmfMapApplication {

@Override
public void onCreate() {
super.onCreate();
}
}

android/app/src/main/AndroidManifest.xml

这一步需要设置 android:name 路径为包名 + 上面创建的文件中 class 名,如果不加这个 SDK 无法初始化,地图会黑屏

1
2
3
<application android:name="com.xx.xxx.MyApplication">
<meta-data android:name="com.baidu.lbsapi.API_KEY" android:value="请在此输入您在开放平台上申请的API_KEY" />
</application>

js pdf打印时内容截断问题解决

为可能会被截断的元素添加

1
page-break-inside: avoid;

page-break-inside CSS 属性调整当前元素内的分页符。

1
2
page-break-inside: auto;
page-break-inside: avoid;

auto 初始值。自动换页(既不强制也不禁止)。

avoid 避免在元素内部换行。

注意设置 avoid 的元素不要太大,否则打印时如果元素处于截断处,会生成大段空白。