2021年9月27日 星期一

Flutter wifi_iot範例加簡單註解

Flutter 好用套件wifi_iot
wifi_iot | Flutter Package (pub.dev)
目前版本^0.3.8 Published Sep 22, 2021

Plugin Flutter which can handle WiFi connections (AP, STA)

Becareful, some commands as no effect on iOS because Apple don't let us to do whatever we want...

雖然功能有限,但是做基本的物聯網APP開發已足夠,以下範例取自https://pub.dev/packages/wifi_iot/example 並且我已刪除WIFI STA內容

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:wifi_iot/wifi_iot.dart';
import 'dart:io' show Platform;


const NetworkSecurity AP_DEFAULT_SECURITY = NetworkSecurity.WPA;
const String AP_DEFAULT_SSID = "AP_SSID";
const String AP_DEFAULT_PASSWORD = "AP_PASSWORD";

//父狀態主頁(樣式+Wifi ststus)
class FlutterWifiIoT extends StatefulWidget {
FlutterWifiIoT({
Key? key
,
}) : super(key: key);

@override
_FlutterWifiIoTState createState() => _FlutterWifiIoTState();
//建立status
}

class _FlutterWifiIoTState extends State<FlutterWifiIoT> {


List<WifiNetwork?>?
_htResultNetwork; //WIFI可連清單
Map<String, bool>? _htIsNetworkRegistered = Map(); //WIFI SSID儲存清單與狀態

bool _isEnabled = false; //WIFI是否開啟
bool _isConnected = false; //WIFI是否已連接
bool _isWifiEnableOpenSettings = false; //是否被動開啟(Android 10)
bool _isWifiDisableOpenSettings = false; //是否被動關閉(Android 10)

final TextStyle textStyle = TextStyle(color: Colors.white);

@override
initState() {
WiFiForIoTPlug
in.isEnabled().then((val) {
_isEnabled = val;
});

WiFiForIoTPlugin.isConnected().then((val) {
_isConnected = val;
});

super.initState();
}


//使用函式庫載入WIFI列表
Future<List<WifiNetwork>> loadWifiList() async {
List<WifiNetwork> htResultNetwork
;
try {
htResultNetwork =
await WiFiForIoTPlugin.loadWifiList();
} on PlatformException {
htResultNetwork = <WifiNetwork>[]
;
}

return htResultNetwork;
}

//檢查是否已註冊SSID方法(存到Map ket,value)
isRegisteredWifiNetwork(String ssid) async {
bool bIsRegistered
;

try {
bIsRegistered =
await WiFiForIoTPlugin.isRegisteredWifiNetwork(ssid);
} on PlatformException {
bIsRegistered =
false;
}

setState(() {
_htIsNetworkRegistered![ssid] = bIsRegistered;
});
}

///Main body
Widget getWidgets() {
WiFiForIoTPlug
in.isConnected().then((val) {
setState(() {
_isConnected = val; //WIFI 為已連線狀態
});
});

// disable scanning for ios as not supported
//IOS手機無法支援WIFI清單功能
if (_isConnected || Platform.isIOS) {
_htResultNetwork = null;
}

//如果是Android, 且存在可連線網路, 否則不會載入WIFI清單
if (_htResultNetwork != null && _htResultNetwork!.length > 0) {
List<ListTile> htNetworks = <ListTile>[]
;

_htResultNetwork!.forEach((oNetwork) {
//將可連線網路跑一遍
PopupCommand oCmdConnect = PopupCommand("Connect", oNetwork!.ssid!);
PopupCommand oCmdRemove = PopupCommand("Remove", oNetwork.ssid!);

List<PopupMenuItem<PopupCommand>> htPopupMenuItems = [];

//加到popupMenu(選項為可連線)
htPopupMenuItems.add(
PopupMenuItem<PopupCommand>(
value: oCmdConnect
,
child: const Text('Connect'),
),
);

setState(() {
isRegisteredWifiNetwork(oNetwo
rk.ssid!);
//辨識這個SSID是否已儲存至系統,並在value中用布林表示
if (_htIsNetworkRegistered!.containsKey(oNetwork.ssid) &&
_htIsNetworkRegistered![oNetwork.ssid]!) {
htPopupMenuItems.add(
PopupMenuItem<PopupCommand>(
value: oCmdRemove
,
child: const Text('Remove'),
),//已儲存就可以提供刪除選項
);
}

htNetworks.add(
ListTile(
titl
e: Text("" +
oNetwo
rk.ssid! +
((_htIsNetworkRegistered!.containsKey(oNetwork.ssid) &&
_htIsNetworkRegistered![oNetwork.ssid]!)
?
" *"
: "")),//加入網路名稱,如果已註冊就標示*
trailing: PopupMenuButton<PopupCommand>(
padding: EdgeInse
ts.zero,
onSelected: (PopupCommand poCommand) {
//加入子元素(連線/刪除選項), 會判斷htPopupMenuItems傳進來的value
switch (poCommand.command) {
case "Connect":
WiFiForIoTPlug
in.connect(AP_DEFAULT_SSID,
password: AP_DEFAULT_PASSWORD,
joinOnce: true,
security: AP_DEFAULT_SECURITY);
break;
case "Remove":
WiFiForIoTPlug
in.removeWifiNetwork(poCommand.argument);
break;
default:
break;
}
}
,
itemBuilder: (BuildContext context) => htPopupMenuItems,
),
),
);
});
});

return ListView(
padding: kMaterialListPadding
,
children: htNetworks,
);
} else {
//如果是IOS, Android搜尋結果為0時進入這邊
return SingleChildScrollView(
chil
d: SafeArea(
chil
d: Column(
children: Platfo
rm.isIOS
? getButtonWidgetsForiOS()
: getButtonWidgetsForAndroid()
,
),
),
);
}
}

List<Widge
t> getButtonWidgetsForAndroid() {
List<Widget> htPrimaryWidgets = <Widget>[]
;

WiFiForIoTPlugin.isEnabled().then((val) {
setState(() {
_isEnabled = val;
});
});

if (_isEnabled) {
htPrimaryWidgets.addAll([
SizedBox(height: 10),
Text("Wifi Enabled"),
MaterialButton(
color: Colo
rs.blue,
child: Text("Disable", style: textStyle),
onPressed: () {
WiFiForIoTPlug
in.setEnabled(false,
shouldOpenSettings: _isWifiDisableOpenSettings
)
;
},
),
]);

WiFiForIoTPlugin.isConnected().then((val) {
setState(() {
_isConnected = val;
});
});

if (_isConnected) {
//已經連上Wifi, 回傳連線資訊
htPrimaryWidgets.addAll(<Widget>[
Text("Connected"),
FutureBuilder(
future: WiFiForIoTPlug
in.getSSID(),
initialData: "Loading..",
builder: (BuildContext context, AsyncSnapshot<String?> ssid) {
return Text("SSID: ${ssid.data}");
}),
FutureBuilder(
future: WiFiForIoTPlug
in.getBSSID(),
initialData: "Loading..",
builder: (BuildContext context, AsyncSnapshot<String?> bssid) {
return Text("BSSID: ${bssid.data}");
}),
FutureBuilder(
future: WiFiForIoTPlug
in.getCurrentSignalStrength(),
initialData: 0,
builder: (BuildContext context, AsyncSnapshot<int?> signal) {
return Text("Signal: ${signal.data}");
}),
FutureBuilder(
future: WiFiForIoTPlug
in.getFrequency(),
initialData: 0,
builder: (BuildContext context, AsyncSnapshot<int?> freq) {
return Text("Frequency : ${freq.data}");
}),
FutureBuilder(
future: WiFiForIoTPlug
in.getIP(),
initialData: "Loading..",
builder: (BuildContext context, AsyncSnapshot<String?> ip) {
return Text("IP : ${ip.data}");
}),
MaterialButton(
color: Colo
rs.blue,
child: Text("Disconnect", style: textStyle),
onPressed: () {
WiFiForIoTPlug
in.disconnect();
},
),
CheckboxListTile(
title:
const Text("Disable WiFi on settings"),
subtitle: const Text("Available only on android API level >= 29"),
value: _isWifiDisableOpenSettings,
onChanged: (bool? setting) {
if (setting != null) {
setState(() {
_isWifiDisableOpenSettings = setting;
});
}
}
)
//Android API29以上可以被動接收WIFI info
]);
} else {
//未連上WIFI, 顯示WIFI搜尋
htPrimaryWidgets.addAll(<Widget>[
Text("Disconnected"),
MaterialButton(
color: Colo
rs.blue,
child: Text("Scan", style: textStyle),
onPressed: () async {
_htResultNetwork = await loadWifiList();
setState(() {});
},
),
CheckboxListTile(
title:
const Text("Disable WiFi on settings"),
subtitle: const Text("Available only on android API level >= 29"),
value: _isWifiDisableOpenSettings,
onChanged: (bool? setting) {
if (setting != null) {
setState(() {
_isWifiDisableOpenSettings = setting;
});
}
}
)
])
;
}
}
else {
//WIFI設定未開啟
htPrimaryWidgets.addAll(<Widget>[
SizedBox(height: 10),
Text("Wifi Disabled"),
MaterialButton(
color: Colo
rs.blue,
child: Text("Enable", style: textStyle),
onPressed: () {
setState(() {
WiFiForIoTPlug
in.setEnabled(true,
shouldOpenSettings: _isWifiEnableOpenSettings
)
;
});
},
),
CheckboxListTile(
title:
const Text("Enable WiFi on settings"),
subtitle: const Text("Available only on android API level >= 29"),
value: _isWifiEnableOpenSettings,
onChanged: (bool? setting) {
if (setting != null) {
setState(() {
_isWifiEnableOpenSettings = setting;
});
}
}
)
])
;
}

return htPrimaryWidgets;
}

List<Widge
t> getButtonWidgetsForiOS() {
List<Widget> htPrimaryWidgets = <Widget>[]
;

WiFiForIoTPlugin.isEnabled().then((val) => setState(() {
_isEnabled = val;
}));

if (_isEnabled) {
htPrimaryWidgets.a
dd(Text("Wifi Enabled"));
WiFiForIoTPlugin.isConnected().then((val) => setState(() {
_isConnected = val;
}));

String? _sSSID;

if (_isConnected) {
//IOS 顯示連線(SSID)
htPrimaryWidgets.addAll(<Widget>[
Text("Connected"),
FutureBuilder(
future: WiFiForIoTPlug
in.getSSID(),
initialData: "Loading..",
builder: (BuildContext context, AsyncSnapshot<String?> ssid) {
_sSSID = ss
id.data;

return Text("SSID: ${ssid.data}");
}),
]);

if (_sSSID == AP_DEFAULT_SSID) {
//IOS連上指定SSID
htPrimaryWidgets.addAll(<Widget>[
MaterialButton(
color: Colo
rs.blue,
child: Text("Disconnect", style: textStyle),
onPressed: () {
WiFiForIoTPlug
in.disconnect();
},
),
]);
} else {
//IOS未上指定SSID, 提供按鈕直接連
htPrimaryWidgets.addAll(<Widget>[
MaterialButton(
color: Colo
rs.blue,
child: Text("Connect to '$AP_DEFAULT_SSID'", style: textStyle),
onPressed: () {
WiFiForIoTPlug
in.connect(AP_DEFAULT_SSID,
password: AP_DEFAULT_PASSWORD,
joinOnce: true,
security: NetworkSecurity.WPA);
},
),
]);
}
}
else {
//IOS未上網路, 一樣提供按鈕直接連
htPrimaryWidgets.addAll(<Widget>[
Text("Disconnected"),
MaterialButton(
color: Colo
rs.blue,
child: Text("Connect to '$AP_DEFAULT_SSID'", style: textStyle),
onPressed: () {
WiFiForIoTPlug
in.connect(AP_DEFAULT_SSID,
password: AP_DEFAULT_PASSWORD,
joinOnce: true,
security: NetworkSecurity.WPA);
},
),
]);
}
}
else {
//IOS WIFI是關閉的, 給設定可以硬連
htPrimaryWidgets.addAll(<Widget>[
Text("Wifi Disabled?"),
MaterialButton(
color: Colo
rs.blue,
child: Text("Connect to '$AP_DEFAULT_SSID'", style: textStyle),
onPressed: () {
WiFiForIoTPlug
in.connect(AP_DEFAULT_SSID,
password: AP_DEFAULT_PASSWORD,
joinOnce: true,
security: NetworkSecurity.WPA);
},
),
]);
}

return htPrimaryWidgets;
}

@override
Widg
et build(BuildContext poContext) {
return MaterialApp(
title: Platfo
rm.isIOS ?
"WifiFlutter Example iOS" : "WifiFlutter Example Android",
home: Scaffold(
appBa
r: AppBar(
title: Platfo
rm.isIOS
? Text('WifiFlutter Example iOS')
: Text('WifiFlutter Example Android'),
actions: _isConnected
? <Widget>[
PopupMenuButton<String>(
onSelected: (value) {
switch (value) {
case "disconnect":
WiFiForIoTPlug
in.disconnect();
break;
case "remove":
WiFiForIoTPlug
in.getSSID().then(
(val) => WiFiForIoTPlug
in.removeWifiNetwork(val!));
break;
default:
break;
}
}
,
itemBuilder: (BuildContext context) =>
<PopupMenuItem<String>>[
PopupMenuItem<String>(
value:
"disconnect",
child: const Text('Disconnect'),
),
PopupMenuItem<String>(
value:
"remove",
child: const Text('Remove'),
),
],
),
]
:
null,
),
body: getWidgets(),
),
);
}
}

class PopupCommand {
Stri
ng command;
String argument;

PopupCommand(this.command, this.argument);
}

//頁面樣式(無狀態)
class CardDemo extends StatelessWidget {
final TextEditingController _textFieldController = TextEditingController();
final List listData = [
{
"title": "物料站 1 ",
"context": "相關編號....",
},
{
"title": "物料站 2 ",
"context": "相關編號....",
}
]
;

@override
Widg
et build(BuildContext context) {
return ListView(
childre
n: listData.map((value) {
return Card(
margi
n: EdgeInsets.all(10), //外邊距
child: Column(
//縱向排列元件
children: <Widget>[
ListTile(
titl
e: Text(value["title"], style: TextStyle(fontSize: 28)),
subtitle: Text(value["context"],
overflow: TextOverflow.ellipsis,
maxLines: 2, //文字溢位
style: TextStyle(fontSize: 18, color: Colors.black)),
onTap: () => _displayDialog(context),
),
],
),
);
}).toList(),
);
}

_displayDialog(BuildContext context) async {
return showDialog(
context: context
,
builder: (context) {
return AlertDialog(
titl
e: Text('Material Password'),
content: TextField(
controlle
r: _textFieldController,
textInputAction: TextInputAction.go,
keyboardType: TextInputType.numberWithOptions(),
decoration: InputDecoration(hintText: "Password"),
),
actions: <Widget>[
new FlatButton(
child:
new Text('Cancel'),
onPressed: () {
Navigat
or.of(context).pop();
},
),
new FlatButton(
child:
new Text('Comfirm'),
onPressed: () {
_displayDialog2(context)
;
},
)
]
,
);
});
}

_displayDialog2(BuildContext context) async {
return showDialog(
context: context
,
builder: (context) {
return AlertDialog(
titl
e: Text('Material Name'),
content: TextField(
controlle
r: _textFieldController,
textInputAction: TextInputAction.go,
keyboardType: TextInputType.numberWithOptions(),
decoration: InputDecoration(hintText: "Password"),
),
actions: <Widget>[
new FlatButton(
child:
new Text('Cancel'),
onPressed: () {
Navigat
or.of(context).pop();
},
),
new FlatButton(
child:
new Text('Comfirm'),
onPressed: () {
Navigat
or.push(context,
MaterialPageRoute(builder: (context) => XDChooseWifi()));
},
)
]
,
);
});
}

} 

沒有留言:

張貼留言

docker-mac Desktop清除容器log

 最近Docker遇到這個問題 Error grabbing logs: invalid character '{' looking for beginning of object key string. 建議的解法是刪除整個log檔,大家可以參考以下教學 htt...