浏览代码

打印机蓝牙权限、搜索、连接功能

周素华 10 月之前
父节点
当前提交
cbcb40f247

+ 1 - 1
android/app/src/main/AndroidManifest.xml

@@ -54,7 +54,7 @@
54 54
 
55 55
 
56 56
     <application
57
-        android:name="${applicationName}"
57
+        android:name=".app.MyApplication"
58 58
         android:icon="@drawable/ic_launcher"
59 59
         android:label="${APP_NAME}"
60 60
         android:requestLegacyExternalStorage="true">

+ 1 - 1
android/app/src/main/java/com/szls/lszlgl/MainActivity.java

@@ -20,6 +20,6 @@ public class MainActivity extends FlutterActivity {
20 20
         GeneratedPluginRegister.registerGeneratedPlugins(flutterEngine);
21 21
 
22 22
         //插件实例的注册,就是自己写个类,然后实现Flutter提供的FlutterPlugin接口
23
-        flutterEngine.getPlugins().add(new BluetoothPlugin());
23
+        flutterEngine.getPlugins().add(new BluetoothPlugin(this));
24 24
     }
25 25
 }

+ 24 - 0
android/app/src/main/java/com/szls/lszlgl/app/MyApplication.java

@@ -0,0 +1,24 @@
1
+package com.szls.lszlgl.app;
2
+
3
+import android.app.Application;
4
+import android.content.Context;
5
+
6
+/**
7
+ * 自定义Application
8
+ *
9
+ * @author zhangbin
10
+ */
11
+public class MyApplication extends Application {
12
+    private static MyApplication instance;
13
+
14
+    @Override
15
+    public void onCreate() {
16
+
17
+        super.onCreate();
18
+        instance = this;
19
+    }
20
+
21
+    public static MyApplication getInstance() {
22
+        return instance;
23
+    }
24
+}

+ 272 - 35
android/app/src/main/java/io/flutter/plugins/BluetoothPlugin.java

@@ -1,53 +1,123 @@
1 1
 package io.flutter.plugins;
2 2
 
3 3
 import android.Manifest;
4
+import android.annotation.SuppressLint;
4 5
 import android.bluetooth.BluetoothAdapter;
6
+import android.bluetooth.BluetoothDevice;
7
+import android.content.BroadcastReceiver;
5 8
 import android.content.Context;
9
+import android.content.Intent;
10
+import android.content.IntentFilter;
11
+import android.content.SharedPreferences;
12
+import android.content.pm.PackageManager;
13
+import android.location.LocationManager;
6 14
 import android.os.Build;
15
+import android.text.TextUtils;
7 16
 import android.util.Log;
8 17
 import android.view.View;
9 18
 import android.widget.Toast;
10 19
 
11 20
 import androidx.annotation.NonNull;
21
+import androidx.core.app.ActivityCompat;
22
+import androidx.fragment.app.FragmentActivity;
12 23
 
13 24
 import com.permissionx.guolindev.PermissionX;
25
+import com.szls.lszlgl.MainActivity;
14 26
 
15 27
 import java.security.Permission;
16 28
 import java.util.List;
29
+import java.util.concurrent.ExecutorService;
30
+import java.util.concurrent.LinkedBlockingDeque;
31
+import java.util.concurrent.ThreadFactory;
32
+import java.util.concurrent.ThreadPoolExecutor;
33
+import java.util.concurrent.TimeUnit;
17 34
 
18 35
 import dev.fluttercommunity.plus.androidintent.IntentSender;
19 36
 import dev.fluttercommunity.plus.androidintent.MethodCallHandlerImpl;
20 37
 import io.flutter.embedding.engine.plugins.FlutterPlugin;
38
+import io.flutter.embedding.engine.plugins.activity.ActivityAware;
39
+import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
21 40
 import io.flutter.plugin.common.BinaryMessenger;
41
+import io.flutter.plugin.common.EventChannel;
22 42
 import io.flutter.plugin.common.MethodCall;
23 43
 import io.flutter.plugin.common.MethodChannel;
24 44
 
45
+import io.flutter.plugin.common.EventChannel.EventSink;
46
+import io.flutter.plugin.common.EventChannel.StreamHandler;
47
+import io.flutter.plugins.bean.BlueDeviceInfo;
48
+import io.flutter.plugins.utils.BluetoothUtils;
49
+import io.flutter.plugins.utils.PrintUtil;
50
+
25 51
 public class BluetoothPlugin implements FlutterPlugin, MethodChannel.MethodCallHandler {
26 52
 
27 53
     private String methodChannelName = "io.flutter.plugins/bluetooth";
28 54
     private MethodChannel methodChannel;
29 55
 
56
+    private ExecutorService executorService;
57
+
58
+    private static final String USER_DEFINED = "自定义";
59
+    private static final String delimiterStr = "_NIMBOT_";
60
+
61
+    private String printNameStart = "";
62
+
63
+    OnDiscoveryDeviceStreamHandler onDiscoveryDeviceStreamHandler;
64
+    private EventChannel onReceiveDeviceChannel;
65
+    public EventChannel.EventSink onReceiveSink;
66
+
67
+    private BlueDeviceInfo itemPosition;
68
+
69
+//    private MainActivity _mainActivity;
30 70
 
71
+
72
+    Context _applicationContext;
31 73
     private BluetoothAdapter mBluetoothAdapter;
32 74
 
33
-    public BluetoothPlugin() {
75
+
76
+    public BluetoothPlugin(MainActivity activity) {
34 77
         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
78
+//        _mainActivity = activity;
79
+
80
+        //注册广播
81
+        IntentFilter intentFilter = new IntentFilter();
82
+        intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
83
+        intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
84
+        intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
85
+        intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
86
+        intentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
87
+        intentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
88
+        intentFilter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST);
89
+        Log.d("ble", "初始化:注册广播 ");
90
+        activity.registerReceiver(receiver, intentFilter);
91
+        Log.d("ble", "初始化: 注册完成");
92
+
93
+        //注册线程池
94
+        ThreadFactory threadFactory = runnable -> {
95
+            Thread thread = new Thread(runnable);
96
+            thread.setName("connect_activity_pool_%d");
97
+            return thread;
98
+        };
99
+        executorService = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingDeque<>(1024), threadFactory, new ThreadPoolExecutor.AbortPolicy());
100
+
35 101
 
36 102
     }
37 103
 
38 104
     @Override
39 105
     public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
40 106
         setupChannels(flutterPluginBinding.getBinaryMessenger(), flutterPluginBinding.getApplicationContext());
107
+
108
+
41 109
     }
42 110
 
43 111
     private void setupChannels(BinaryMessenger binaryMessenger, Context applicationContext) {
44 112
 
45
-        methodChannel = new MethodChannel(binaryMessenger, methodChannelName);
46
-        applicationContext = applicationContext.getApplicationContext();
47
-        applicationContext.
113
+        _applicationContext = applicationContext.getApplicationContext();
48 114
 
115
+        methodChannel = new MethodChannel(binaryMessenger, methodChannelName + "/methods");
49 116
         methodChannel.setMethodCallHandler(this);
50 117
 
118
+        onReceiveDeviceChannel = new EventChannel(binaryMessenger, methodChannelName + "/onDiscoveryDevice");
119
+        onDiscoveryDeviceStreamHandler = new OnDiscoveryDeviceStreamHandler();
120
+        onReceiveDeviceChannel.setStreamHandler(onDiscoveryDeviceStreamHandler);
51 121
     }
52 122
 
53 123
     @Override
@@ -59,14 +129,28 @@ public class BluetoothPlugin implements FlutterPlugin, MethodChannel.MethodCallH
59 129
     public void onMethodCall(@NonNull MethodCall methodCall, @NonNull MethodChannel.Result result) {
60 130
         switch (methodCall.method) {
61 131
 
62
-            case "isSupportBle":
132
+            case "isBleOpen":
63 133
                 Log.d("ble", "isSupportBle");
64
-                result.success(true);
134
+                result.success(mBluetoothAdapter.isEnabled());
135
+                break;
136
+            case "isSDKIntGreaterOrEqual":
137
+                Log.d("ble", "isSDKIntGreaterOrEqual");
138
+                result.success(Build.VERSION.SDK_INT >= Build.VERSION_CODES.S);
65 139
                 break;
66
-            case "startScan":
67
-                Log.d("ble", "startScan");
68
-                startScan(result);
140
+            case "startBluetoothDiscovery":
141
+                Log.d("ble", "startBluetoothDiscovery");
142
+                startBluetoothDiscovery(result);
69 143
                 break;
144
+            case "startBluetoothPair":
145
+                Log.d("ble", "startBluetoothPair");
146
+                startBluetoothPair(methodCall, result);
147
+                break;
148
+            case "startBluetoothConnect":
149
+                Log.d("ble", "startBluetoothConnect :"+methodCall.arguments);
150
+                startBluetoothConnect(methodCall, result);
151
+                break;
152
+
153
+
70 154
             case "autoLogin":
71 155
 
72 156
                 break;
@@ -74,58 +158,211 @@ public class BluetoothPlugin implements FlutterPlugin, MethodChannel.MethodCallH
74 158
 
75 159
                 break;
76 160
             case "currentAccount":
77
-                 break;
161
+                break;
78 162
             case "logout":
79
-                 break;
163
+                break;
80 164
             case "markAllMessagesRead":
81
-                 break;
82
-            default:
83
-            {
165
+                break;
166
+            default: {
84 167
                 result.notImplemented();
85 168
                 break;
86 169
             }
87 170
         }
88 171
     }
89 172
 
90
-
91 173
     private void teardownChannels() {
92 174
         methodChannel.setMethodCallHandler(null);
93 175
         methodChannel = null;
176
+//        // 注销广播接收器
177
+//        if (mBluetoothAdapter != null && mBluetoothAdapter.isDiscovering()) {
178
+//            mBluetoothAdapter.cancelDiscovery();
179
+//        }
180
+//        requireActivity().unregisterReceiver(receiver);
94 181
     }
95 182
 
183
+    void startBluetoothDiscovery(@NonNull MethodChannel.Result result) {
184
+
185
+        if (ActivityCompat.checkSelfPermission(_applicationContext, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
186
+
187
+            Log.d("ble", "checkSelfPermission false");
188
+            return;
189
+        }
190
+
191
+        if (mBluetoothAdapter.isDiscovering()) {
96 192
 
97
-    void startScan(@NonNull MethodChannel.Result result) {
193
+            if (mBluetoothAdapter.cancelDiscovery()) {
194
+                executorService.execute(() -> {
195
+                    try {
196
+                        //取消后等待1s后再次搜索
197
+                        Thread.sleep(1000);
198
+                        mBluetoothAdapter.startDiscovery();
199
+                        Log.d("ble", "测试:开始搜索7");
200
+                    } catch (InterruptedException e) {
201
+                        Log.d("ble", "测试:开始搜索8");
202
+                        e.printStackTrace();
203
+                    }
204
+                });
98 205
 
99
-        Log.d("ble", "开始搜索 ");
100
-        if (!mBluetoothAdapter.isEnabled()) {
101
-            result.success(1); //
206
+
207
+            }
102 208
         } else {
103
-            permissionRequest();
209
+            Log.d("ble", "测试:开始搜索9");
210
+            mBluetoothAdapter.startDiscovery();
211
+            Log.d("ble", "测试:开始搜索10");
104 212
         }
105 213
     }
106 214
 
107
-    private void permissionRequest() {
108
-        String[] permissions;
109
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
110
-            permissions = new String[]{Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT};
111
-        } else {
112
-            permissions = new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION};
215
+    void startBluetoothPair(@NonNull MethodCall methodCall, @NonNull MethodChannel.Result result) {
216
+
217
+        if (ActivityCompat.checkSelfPermission(_applicationContext, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
218
+            return;
219
+        }
220
+        if (mBluetoothAdapter.isDiscovering()) {
221
+            mBluetoothAdapter.cancelDiscovery();
113 222
         }
223
+        Log.d("ble", "startBluetoothPair");
224
+        String deviceMac = methodCall.arguments.toString();
225
+        String[] deviceInfoList = deviceMac.split(delimiterStr);
226
+        itemPosition = new BlueDeviceInfo(deviceInfoList[0], deviceInfoList[1], Integer.parseInt(deviceInfoList[2]));
227
+        BluetoothDevice bluetoothDevice = mBluetoothAdapter.getRemoteDevice(itemPosition.getDeviceHardwareAddress());
228
+
229
+        executorService.submit(() -> {
230
+//            requireActivity().runOnUiThread(() -> {
231
+//                bind.spinKit.setVisibility(View.GONE);
232
+//                fragment = new MyDialogLoadingFragment("配对中");
233
+//                fragment.show(requireActivity().getSupportFragmentManager(), "pairing");
234
+//            });
235
+            Log.d("ble", "配对: 开始");
236
+            boolean returnValue = false;
237
+            try {
238
+                returnValue = BluetoothUtils.createBond(bluetoothDevice);
239
+            } catch (Exception e) {
240
+                Log.d("ble", "闪退日志" + e.getMessage());
241
+            }
242
+            Log.d("ble", "配对: 进行中:" + returnValue);
243
+        });
244
+    }
114 245
 
246
+    void startBluetoothConnect(@NonNull MethodCall methodCall, @NonNull MethodChannel.Result result) {
115 247
 
248
+        if (ActivityCompat.checkSelfPermission(_applicationContext, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
249
+            return;
250
+        }
251
+        if (mBluetoothAdapter.isDiscovering()) {
252
+            mBluetoothAdapter.cancelDiscovery();
253
+        }
116 254
 
117
-        PermissionX.init(requireActivity())
118
-                .permissions(permissions)
119
-                .request(this::handlePermissionResult);
255
+        String deviceInfo = methodCall.arguments.toString();
256
+        String[] deviceInfoList = deviceInfo.split(delimiterStr);
257
+        for(int i =0; i < deviceInfoList.length ; i++){
258
+            Log.d("ble", i+":"+deviceInfoList[i]);
259
+        }
260
+        Log.d("ble", "startBluetoothConnect : ---"+deviceInfo + "----0:"+deviceInfoList[0]);
261
+        itemPosition = new BlueDeviceInfo(deviceInfoList[0], deviceInfoList[1], Integer.parseInt(deviceInfoList[2]));
262
+        BluetoothDevice bluetoothDevice = mBluetoothAdapter.getRemoteDevice(itemPosition.getDeviceHardwareAddress());
263
+
264
+        executorService.submit(() -> {
265
+//            requireActivity().runOnUiThread(() -> {
266
+//                bind.spinKit.setVisibility(View.GONE);
267
+//                fragment = new MyDialogLoadingFragment("连接中");
268
+//                fragment.show(requireActivity().getSupportFragmentManager(), "CONNECT");
269
+//            });
270
+
271
+            BlueDeviceInfo blueDeviceInfo = new BlueDeviceInfo(bluetoothDevice.getName(), bluetoothDevice.getAddress(), itemPosition.getConnectState());
272
+            PrintUtil.setConnectedType(-1);
273
+            int connectResult = PrintUtil.connectBluetoothPrinter(blueDeviceInfo.getDeviceHardwareAddress());
274
+            Log.d("ble", "测试:连接结果 " + connectResult);
275
+            result.success(connectResult);
276
+
277
+        });
120 278
     }
121 279
 
122
-    private void handlePermissionResult(boolean allGranted, List<String> grantedList, List<String> deniedList) {
123
-        if (allGranted) {
124
-            Log.d("ble", "handleAllPermissionsGranted ");
125
-//            handleAllPermissionsGranted();
126
-        } else {
127
-            Log.d("ble", "权限打开失败 ");
280
+
281
+
282
+    private final BroadcastReceiver receiver = new BroadcastReceiver() {
283
+
284
+
285
+        @SuppressLint("MissingPermission")
286
+        @Override
287
+        public void onReceive(Context context, Intent intent) {
288
+            String action = intent.getAction();
289
+            //蓝牙发现
290
+            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
291
+                Log.v("ble", "测试:搜索中");
292
+                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
293
+
294
+                if (device != null) {
295
+                    @SuppressLint("MissingPermission") String deviceName = device.getName();
296
+                    String deviceHardwareAddress = device.getAddress();
297
+                    @SuppressLint("MissingPermission") int deviceStatus = device.getBondState();
298
+
299
+
300
+                    @SuppressLint("MissingPermission") boolean supportBluetoothType = device.getType() == BluetoothDevice.DEVICE_TYPE_CLASSIC || device.getType() == BluetoothDevice.DEVICE_TYPE_DUAL;
301
+                    boolean supportPrintName;
302
+
303
+
304
+                    if (USER_DEFINED.equals(printNameStart)) {
305
+                        printNameStart = "";
306
+                    }
307
+
308
+                    if (TextUtils.isEmpty(printNameStart)) {
309
+                        supportPrintName = deviceName != null;
310
+                    } else {
311
+                        supportPrintName = deviceName != null && deviceName.startsWith(printNameStart);
312
+                    }
313
+
314
+                    if (supportBluetoothType && supportPrintName) {
315
+
316
+                        Log.d("ble", "测试:打印机名称- " + deviceName + ",设备地址:" + deviceHardwareAddress + ",设备类型:" + device.getType() + ", 设备状态:"+deviceStatus);
317
+                        Log.d("ble", "sink:" + onReceiveSink + ":" + "onDiscoveryDeviceStreamHandler" +  (onDiscoveryDeviceStreamHandler != null) + "onDiscoveryDeviceStreamHandler.sink != null:" + (onDiscoveryDeviceStreamHandler.sink));
318
+                        if (onDiscoveryDeviceStreamHandler != null && onDiscoveryDeviceStreamHandler.sink != null) {
319
+                            onDiscoveryDeviceStreamHandler.sink.success(deviceName+delimiterStr+deviceHardwareAddress+delimiterStr+deviceStatus);
320
+                        }
321
+                    }
322
+
323
+                }
324
+
325
+            } else if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) {
326
+                Log.v("ble", "测试:开始搜索");
327
+//                bind.spinKit.setVisibility(View.VISIBLE);
328
+            } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
329
+                Log.v("ble", "测试:搜索结束");
330
+//                bind.spinKit.setVisibility(View.GONE);
331
+            } else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
332
+                int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1);
333
+                Log.d("ble", "测试:配对状态改变:0 " + state);
334
+                if(itemPosition != null) {
335
+                    itemPosition.setConnectState(state);
336
+                    if (onDiscoveryDeviceStreamHandler != null && onDiscoveryDeviceStreamHandler.sink != null) {
337
+                        onDiscoveryDeviceStreamHandler.sink.success(itemPosition.getDeviceName()+delimiterStr+itemPosition.getDeviceHardwareAddress()+delimiterStr+itemPosition.getConnectState());
338
+                    }
339
+                }
340
+            } else if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(action)) {
341
+//                if (fragment != null) {
342
+//                    fragment.dismiss();
343
+//                }
344
+            }
128 345
         }
346
+    };
347
+
348
+
349
+}
350
+
351
+
352
+class OnDiscoveryDeviceStreamHandler implements EventChannel.StreamHandler {
353
+
354
+    public EventChannel.EventSink sink;
355
+
356
+    @Override
357
+    public void onListen(Object o, EventChannel.EventSink eventSink) {
358
+
359
+        Log.d("ble", "OnDiscoveryDeviceStreamHandler: onListen");
360
+        sink = eventSink;
129 361
     }
362
+    @Override
363
+    public void onCancel(Object o) {
130 364
 
365
+        Log.e("zhousuhua","OnReceiveDataStreamHandler=== onCancel");
366
+        sink = null;
367
+    }
131 368
 }

+ 58 - 0
android/app/src/main/java/io/flutter/plugins/bean/BlueDeviceInfo.java

@@ -0,0 +1,58 @@
1
+package io.flutter.plugins.bean;
2
+
3
+import androidx.annotation.Nullable;
4
+
5
+public class BlueDeviceInfo {
6
+
7
+
8
+    String deviceName;
9
+    String deviceHardwareAddress;
10
+    int connectState;
11
+
12
+    public BlueDeviceInfo(String deviceName, String deviceHardwareAddress, int connectState) {
13
+        this.deviceName = deviceName;
14
+        this.deviceHardwareAddress = deviceHardwareAddress;
15
+        this.connectState = connectState;
16
+    }
17
+
18
+    public String getDeviceName() {
19
+        return deviceName;
20
+    }
21
+
22
+    public void setDeviceName(String deviceName) {
23
+        this.deviceName = deviceName;
24
+    }
25
+
26
+    public String getDeviceHardwareAddress() {
27
+        return deviceHardwareAddress;
28
+    }
29
+
30
+    public void setDeviceHardwareAddress(String deviceHardwareAddress) {
31
+        this.deviceHardwareAddress = deviceHardwareAddress;
32
+    }
33
+
34
+    public int getConnectState() {
35
+        return connectState;
36
+    }
37
+
38
+    public void setConnectState(int connectState) {
39
+        this.connectState = connectState;
40
+    }
41
+
42
+
43
+    @Override
44
+    public int hashCode() {
45
+        return deviceName.hashCode();
46
+    }
47
+
48
+    @Override
49
+    public boolean equals(@Nullable Object obj) {
50
+        BlueDeviceInfo blueDeviceInfo = (BlueDeviceInfo) obj;
51
+        if (blueDeviceInfo != null) {
52
+            return deviceName.equals(blueDeviceInfo.deviceName);
53
+        }
54
+
55
+        return false;
56
+
57
+    }
58
+}

+ 31 - 0
android/app/src/main/java/io/flutter/plugins/utils/BluetoothUtils.java

@@ -0,0 +1,31 @@
1
+package io.flutter.plugins.utils;
2
+
3
+import android.bluetooth.BluetoothDevice;
4
+
5
+import java.lang.reflect.Method;
6
+
7
+/**
8
+ * 蓝牙工具类,用于处理蓝牙设备配对等操作。
9
+ * @author zhangbin
10
+ */
11
+public class BluetoothUtils {
12
+
13
+    /**
14
+     * 与设备配对
15
+     *
16
+     * @param btDevice 要配对的蓝牙设备
17
+     * @return 配对是否成功
18
+     * @throws Exception 反射调用可能引发异常
19
+     */
20
+    public static boolean createBond(BluetoothDevice btDevice) throws Exception {
21
+        // 获取 BluetoothDevice 类的类对象
22
+        Class<?> btClass = BluetoothDevice.class;
23
+
24
+        // 获取 createBond 方法的引用
25
+        Method createBondMethod = btClass.getMethod("createBond");
26
+        // 调用 createBond 方法,返回配对结果
27
+        return (Boolean) createBondMethod.invoke(btDevice);
28
+    }
29
+
30
+
31
+}

+ 214 - 0
android/app/src/main/java/io/flutter/plugins/utils/PrintUtil.java

@@ -0,0 +1,214 @@
1
+package io.flutter.plugins.utils;
2
+
3
+
4
+import android.app.Application;
5
+import android.content.res.AssetManager;
6
+import android.graphics.Bitmap;
7
+import android.graphics.BitmapFactory;
8
+import android.graphics.Canvas;
9
+import android.graphics.Color;
10
+import android.graphics.Paint;
11
+import android.util.Log;
12
+import android.widget.Toast;
13
+
14
+import com.gengcon.www.jcprintersdk.JCPrintApi;
15
+import com.gengcon.www.jcprintersdk.callback.Callback;
16
+import com.gengcon.www.jcprintersdk.callback.PrintCallback;
17
+import com.szls.lszlgl.app.MyApplication;
18
+
19
+import java.io.File;
20
+import java.io.InputStream;
21
+import java.util.ArrayList;
22
+import java.util.List;
23
+
24
+/**
25
+ * 打印工具类
26
+ *
27
+ * @author zhangbin
28
+ */
29
+public class PrintUtil {
30
+    private static final String TAG = "PrintUtil";
31
+    private static int mConnectedType = -1;
32
+    /**
33
+     * 单例实例,使用 volatile 保证多线程可见性和有序性
34
+     */
35
+    private static volatile JCPrintApi api;
36
+
37
+    /**
38
+     * 回调接口,用于处理打印机状态变化事件
39
+     */
40
+    private static final Callback CALLBACK = new Callback() {
41
+        private static final String TAG = "PrintUtil";
42
+
43
+        /**
44
+         * 连接成功回调
45
+         *
46
+         * @param address 设备地址,蓝牙为蓝牙 MAC 地址,WIFI 为 IP 地址
47
+         * @param type   连接类型,0 表示蓝牙连接,1 表示 WIFI 连接
48
+         */
49
+        @Override
50
+        public void onConnectSuccess(String address, int type) {
51
+            mConnectedType = type;
52
+        }
53
+
54
+        /**
55
+         * 断开连接回调
56
+         * 当设备断开连接时,将调用此方法。
57
+         */
58
+        @Override
59
+        public void onDisConnect() {
60
+            mConnectedType = -1;
61
+        }
62
+
63
+        /**
64
+         * 电量变化回调
65
+         * 当设备电量发生变化时,将调用此方法。
66
+         *
67
+         * @param powerLevel 电量等级,取值范围为 1 到 4,代表有 1 到 4 格电,满电是 4 格
68
+         */
69
+        @Override
70
+        public void onElectricityChange(int powerLevel) {
71
+
72
+        }
73
+
74
+        /**
75
+         * 监测上盖状态变化回调
76
+         * 当上盖状态发生变化时,将调用此方法。目前该回调仅支持 H10/D101/D110/D11/B21/B16/B32/Z401/B3S/B203/B1/B18 系列打印机。
77
+         *
78
+         * @param coverStatus 上盖状态,0 表示上盖打开,1 表示上盖关闭
79
+         */
80
+        @Override
81
+        public void onCoverStatus(int coverStatus) {
82
+
83
+        }
84
+
85
+        /**
86
+         * 监测纸张状态变化
87
+         * 当纸张状态发生变化时,将调用此方法。目前该回调仅支持H10/D101/D110/D11/B21/B16/B32/Z401/B203/B1/B18 系列打印机。
88
+         *
89
+         * @param paperStatus 0为不缺纸 1为缺纸
90
+         */
91
+        @Override
92
+        public void onPaperStatus(int paperStatus) {
93
+
94
+        }
95
+
96
+        /**
97
+         * 监测标签rfid读取状态变化
98
+         * 当标签rfid读取状态发生变化时,将调用此方法。
99
+         *
100
+         * @param rfidReadStatus 0为未读取到标签RFID 1为成功读取到标签RFID 目前该回调仅支持H10/D101/D110/D11/B21/B16/B32/Z401/B203/B1/B18 系列打印机。
101
+         */
102
+        @Override
103
+        public void onRfidReadStatus(int rfidReadStatus) {
104
+
105
+        }
106
+
107
+
108
+        /**
109
+         * 监测碳带rfid读取状态变化
110
+         * 当碳带rfid读取状态发生变化时,将调用此方法。
111
+         *
112
+         * @param ribbonRfidReadStatus 0为未读取到碳带RFID 1为成功读取到碳带RFID 目前该回调仅支持B18/B32/Z401/P1/P1S 系列打印机。
113
+         */
114
+        @Override
115
+        public void onRibbonRfidReadStatus(int ribbonRfidReadStatus) {
116
+
117
+        }
118
+
119
+        /**
120
+         * 监测碳带状态变化
121
+         * 当纸张状态发生变化时,将调用此方法
122
+         *
123
+         * @param ribbonStatus 0为无碳带 1为有碳带 目前该回调仅支持B18/B32/Z401/P1/P1S系列打印机。
124
+         */
125
+        @Override
126
+        public void onRibbonStatus(int ribbonStatus) {
127
+
128
+        }
129
+
130
+
131
+        /**
132
+         * 固件异常回调,需要升级
133
+         * 当设备连接成功但出现固件异常时,将调用此方法,表示需要进行固件升级。
134
+         */
135
+        @Override
136
+        public void onFirmErrors() {
137
+
138
+        }
139
+    };
140
+
141
+
142
+    /**
143
+     * 获取 JCPrintApi 单例实例
144
+     *
145
+     * @return JCPrintApi 实例
146
+     */
147
+    public static JCPrintApi getInstance() {
148
+        // 双重检查锁定以确保只初始化一次实例
149
+        if (api == null) {
150
+            synchronized (PrintUtil.class) {
151
+                if (api == null) {
152
+                    api = JCPrintApi.getInstance(CALLBACK);
153
+                    //api.init已废弃,使用initSdk替代,方法名含义更准确
154
+
155
+                    api.initSdk(MyApplication.getInstance());
156
+                    //获取内置目录路径
157
+                    File directory = MyApplication.getInstance().getFilesDir();
158
+                    //获取自定义字体路径
159
+                    File customFontDirectory = new File(directory, "custom_font");
160
+                    api.initDefaultImageLibrarySettings(customFontDirectory.getAbsolutePath(), "");
161
+
162
+                }
163
+            }
164
+        }
165
+
166
+        return api;
167
+
168
+    }
169
+
170
+
171
+    /**
172
+     * 通过打印机mac地址进行蓝牙连接开启打印机(同步)
173
+     *
174
+     * @param address 打印机地址
175
+     * @return 成功与否
176
+     */
177
+    public static int connectBluetoothPrinter(String address) {
178
+        // 获取单例实例以确保线程安全
179
+        JCPrintApi localApi = getInstance();
180
+        //api.openPrinterByAddress(address),使用connectBluetoothPrinter替代,方法名含义更准确
181
+        return localApi.connectBluetoothPrinter(address);
182
+    }
183
+
184
+    /**
185
+     * 关闭打印机
186
+     */
187
+    public static void close() {
188
+        // 获取单例实例以确保线程安全
189
+        JCPrintApi localApi = getInstance();
190
+        localApi.close();
191
+    }
192
+
193
+
194
+    public static int getConnectedType() {
195
+        return mConnectedType;
196
+    }
197
+
198
+    public static void setConnectedType(int connectedType) {
199
+        mConnectedType = connectedType;
200
+    }
201
+
202
+    /**
203
+     * 检查打印机是否连接
204
+     *
205
+     * @return 连接状态代码
206
+     */
207
+    public static int isConnection() {
208
+        // 获取单例实例以确保线程安全
209
+        JCPrintApi localApi = getInstance();
210
+        return localApi.isConnection();
211
+    }
212
+
213
+
214
+}

+ 76 - 7
lib/page/print/connect_print_page.dart

@@ -1,6 +1,7 @@
1 1
 import 'package:flutter/material.dart';
2 2
 import 'package:flutter/services.dart';
3 3
 import 'package:lszlgl/base/base_lifecycle_state.dart';
4
+import 'package:lszlgl/service/print_service.dart';
4 5
 import 'package:signature/signature.dart';
5 6
 import 'package:lszlgl/widget/button.dart';
6 7
 
@@ -41,6 +42,8 @@ class _ConnectPrintPageState extends BaseLifecycleState<ConnectPrintPage> {
41 42
   final submitEnable = false.notifier<bool>();
42 43
 
43 44
   late List<ServiceModel> serviceList;
45
+  late List<BlueDeviceInfo> deviceList;
46
+  late List<String> deviceMacList;
44 47
 
45 48
   @override
46 49
   void initState() {
@@ -48,21 +51,27 @@ class _ConnectPrintPageState extends BaseLifecycleState<ConnectPrintPage> {
48 51
     serviceList = [
49 52
       ServiceModel(name: '搜索', icon: imgHomeListPzjc, onTap: () => startScan()),
50 53
     ];
54
+    deviceList = [];
55
+    deviceMacList = [];
51 56
   }
52 57
 
53 58
   /// 去连接
54 59
   Future<void> startScan() async {
55 60
 
56
-    int result = await BluetoothPlugin.instance.startScan();
57
-    if(result == 1) {
58
-      // 蓝牙未开启
59
-      MyNavigator.showToast('蓝牙未开启');
60
-    }
61
+    setState(() {
62
+      deviceList = [];
63
+      deviceMacList = [];
64
+    });
65
+    await PrintService.startBluetoothDiscovery();
61 66
   }
62 67
 
63 68
   /// 去打印
64
-  void startPrint() {
65
-
69
+  Future<void> startConnect(BlueDeviceInfo deviceInfo) async {
70
+    if(deviceInfo.connectStateStr == '未配对') {
71
+      await PrintService.startBluetoothPair(deviceInfo);
72
+    } else if(deviceInfo.connectStateStr == '已配对') {
73
+      await PrintService.startBluetoothConnect(deviceInfo);
74
+    }
66 75
   }
67 76
 
68 77
   @override
@@ -85,6 +94,22 @@ class _ConnectPrintPageState extends BaseLifecycleState<ConnectPrintPage> {
85 94
     } else {
86 95
       nextEnable.value = true;
87 96
     }
97
+
98
+    BluetoothPlugin.instance.onReceiveDataStream.listen((deviceInfo) {
99
+      if(deviceInfo != null) {
100
+        if(deviceMacList.contains(deviceInfo.deviceMac)) {
101
+          setState(() {
102
+            deviceMacList.removeWhere((element) => element == deviceInfo.deviceMac);
103
+            deviceList.removeWhere((element) => element.deviceMac == deviceInfo.deviceMac);
104
+          });
105
+        }
106
+        setState(() {
107
+          deviceMacList.add(deviceInfo.deviceMac);
108
+          deviceList.add(deviceInfo);
109
+        });
110
+      }
111
+    });
112
+
88 113
   }
89 114
 
90 115
   @override
@@ -109,6 +134,11 @@ class _ConnectPrintPageState extends BaseLifecycleState<ConnectPrintPage> {
109 134
             serviceList.length,
110 135
                 (index) => buildServiceItem(serviceList[index]),
111 136
           ).toList(),
137
+
138
+          ...List.generate(
139
+            deviceList.length,
140
+                (index) => buildDeviceItem(deviceList[index]),
141
+          ).toList(),
112 142
         ],
113 143
       ),
114 144
     );
@@ -157,4 +187,43 @@ class _ConnectPrintPageState extends BaseLifecycleState<ConnectPrintPage> {
157 187
       ),
158 188
     );
159 189
   }
190
+
191
+  Widget buildDeviceItem(BlueDeviceInfo deviceInfo) {
192
+    return GestureDetector(
193
+      onTap: () {
194
+        // 连接
195
+        startConnect(deviceInfo);
196
+      },
197
+      child: Container(
198
+        margin: const EdgeInsets.only(left: 12, right: 12, bottom: 22),
199
+        padding: const EdgeInsets.symmetric(vertical: 10),
200
+        clipBehavior: Clip.hardEdge,
201
+        decoration: BoxDecoration(
202
+          borderRadius: const BorderRadius.all(Radius.circular(12)),
203
+          boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.1), offset: const Offset(0, 5), blurRadius: 4)],
204
+          image: const DecorationImage(image: AssetImage(imgHomeListBg), fit: BoxFit.fill),
205
+        ),
206
+        child: Row(
207
+          mainAxisAlignment: MainAxisAlignment.spaceAround,
208
+          children: [
209
+            Text(
210
+              deviceInfo.deviceName,
211
+              textAlign: TextAlign.center,
212
+              style: const TextStyle(color: Color(0xFF333333), fontSize: 15, fontWeight: FontWeight.w500),
213
+            ),
214
+            Text(
215
+              deviceInfo.deviceMac,
216
+              textAlign: TextAlign.center,
217
+              style: const TextStyle(color: Color(0xFF333333), fontSize: 15, fontWeight: FontWeight.w500),
218
+            ),
219
+            Text(
220
+              deviceInfo.connectStateStr,
221
+              textAlign: TextAlign.center,
222
+              style: const TextStyle(color: Color(0xFF333333), fontSize: 15, fontWeight: FontWeight.w500),
223
+            ),
224
+          ],
225
+        ),
226
+      ),
227
+    );
228
+  }
160 229
 }

+ 3 - 2
lib/page/print/print_page.dart

@@ -5,6 +5,7 @@ import 'package:lszlgl/page/print/connect_print_page.dart';
5 5
 import 'package:signature/signature.dart';
6 6
 import 'package:lszlgl/widget/button.dart';
7 7
 
8
+import '../../service/print_service.dart';
8 9
 import '../home/home_page.dart';
9 10
 
10 11
 class PrintPageArgs {
@@ -59,8 +60,8 @@ class _PrintPageState extends BaseLifecycleState<PrintPage> {
59 60
   }
60 61
 
61 62
   /// 去打印
62
-  void startPrint() {
63
-
63
+  Future<void> startPrint() async {
64
+    // await PrintService.startBluetoothPair(deviceInfo);
64 65
   }
65 66
 
66 67
   @override

+ 106 - 11
lib/plugin/bluetooth_plugin.dart

@@ -1,6 +1,10 @@
1 1
 import 'dart:io';
2 2
 
3 3
 import 'package:flutter/services.dart';
4
+import 'package:logger/logger.dart';
5
+
6
+import '../main.dart';
7
+import '../router/my_navigator.dart';
4 8
 
5 9
 class BluetoothPlugin {
6 10
   factory BluetoothPlugin() => _instance;
@@ -8,28 +12,119 @@ class BluetoothPlugin {
8 12
   static final BluetoothPlugin _instance = BluetoothPlugin._();
9 13
   static BluetoothPlugin get instance => _instance;
10 14
 
11
-  final MethodChannel _channel = const MethodChannel("io.flutter.plugins/bluetooth");
15
+   final String delimiterStr = "_NIMBOT_";
16
+  final MethodChannel _channel = const MethodChannel("io.flutter.plugins/bluetooth/methods");
17
+  final EventChannel _onReceiveDataStream = const EventChannel('io.flutter.plugins/bluetooth/onDiscoveryDevice');
18
+
19
+
20
+  //是否打开蓝牙
21
+  Future<bool> isBleOpen() async {
22
+    if (Platform.isIOS) {
23
+      return true;
24
+    }
25
+    return _channel.invokeMethod('isBleOpen').then<bool>((d) => d);
26
+  }
27
+
28
+  //安卓版本是否大于等于31
29
+  Future<bool> isSDKIntGreaterOrEqual31() async {
30
+    if (Platform.isIOS) {
31
+      return true;
32
+    }
33
+    return _channel.invokeMethod('isSDKIntGreaterOrEqual').then<bool>((d) => d);
34
+  }
12 35
 
13 36
   //开始扫描
14
-  Future<int> startScan() async {
37
+  Future<int> startBluetoothDiscovery() async {
15 38
     if (Platform.isIOS) {
16 39
       return 0;
17 40
     }
18
-    return _channel.invokeMethod('startScan').then<int>((d) => d);
41
+    return _channel.invokeMethod('startBluetoothDiscovery').then<int>((d) => d);
19 42
   }
20 43
 
21
-  //设备是否支持蓝牙
22
-  Future<bool> isSupportBle() async {
44
+  //开始配对
45
+  Future<int> startBluetoothPair(BlueDeviceInfo deviceInfo) async {
23 46
     if (Platform.isIOS) {
24
-      return true;
47
+      return 0;
48
+    }
49
+    return _channel.invokeMethod('startBluetoothPair').then<int>((d) => d);
50
+  }
51
+
52
+  //开始连接
53
+  Future<int> startBluetoothConnect(BlueDeviceInfo deviceInfo) async {
54
+
55
+    if (Platform.isIOS) {
56
+      return 0;
25 57
     }
26
-    return _channel.invokeMethod('isSupportBle').then<bool>((d) => d);
58
+    String deviceInfoStr = deviceInfo.deviceName+delimiterStr+deviceInfo.deviceMac+delimiterStr+deviceInfo.connectState;
59
+    return _channel.invokeMethod('startBluetoothConnect', deviceInfoStr).then<int>((d) => d);
27 60
   }
28 61
 
29
-  //打开蓝牙
30
-  Future open() async {
31
-    if (Platform.isAndroid) {
32
-      _channel.invokeMethod('open');
62
+  //开始连接
63
+  Future<int> startBluetoothPrint(BlueDeviceInfo deviceInfo) async {
64
+
65
+    if (Platform.isIOS) {
66
+      return 0;
33 67
     }
68
+    String deviceInfoStr = deviceInfo.deviceName+delimiterStr+deviceInfo.deviceMac+delimiterStr+deviceInfo.connectState;
69
+    return _channel.invokeMethod('startBluetoothPrint', deviceInfoStr).then<int>((d) => d);
70
+  }
71
+
72
+
73
+
74
+
75
+  /// 接收数据监听
76
+  Stream<BlueDeviceInfo?> get onReceiveDataStream async* {
77
+
78
+    yield* _onReceiveDataStream
79
+        .receiveBroadcastStream()
80
+        .map((buffer) {
81
+
82
+      String str = buffer;
83
+      List<String> strList = str.split(delimiterStr);
84
+
85
+      if(strList.length == 3) {
86
+        BlueDeviceInfo deviceInfo = BlueDeviceInfo(deviceName: strList[0], deviceMac: strList[1], connectState: strList[2]);
87
+        return deviceInfo;
88
+      }
89
+      return null;
90
+    });
91
+  }
92
+
93
+
94
+}
95
+
96
+
97
+class BlueDeviceInfo {
98
+
99
+  String deviceName;
100
+  String deviceMac;
101
+  String connectState;
102
+
103
+  String? _connectStateStr;
104
+
105
+  BlueDeviceInfo({required this.deviceName, required this.deviceMac, required this.connectState});
106
+
107
+
108
+  String get connectStateStr {
109
+
110
+    if(_connectStateStr != null) {
111
+     return _connectStateStr!;
112
+    }
113
+
114
+    if(connectState == '10') {
115
+      _connectStateStr = "未配对";
116
+    }
117
+    if(connectState == '11') {
118
+      _connectStateStr = "配对中";
119
+    }
120
+    if(connectState == '12') {
121
+      _connectStateStr = "已配对";
122
+    }
123
+    return _connectStateStr ?? "未知";
124
+  }
125
+
126
+  @override
127
+  String toString() {
128
+    return {'deviceName:': deviceName, "mac:": deviceMac, "state:": connectState}.toString();
34 129
   }
35 130
 }

+ 107 - 0
lib/service/print_service.dart

@@ -0,0 +1,107 @@
1
+
2
+
3
+import 'package:lszlgl/utils/permission_utils.dart';
4
+import 'package:permission_handler/permission_handler.dart';
5
+
6
+import '../plugin/bluetooth_plugin.dart';
7
+import '../router/my_navigator.dart';
8
+
9
+class PrintService {
10
+  PrintService._();
11
+
12
+  //是否打开蓝牙
13
+  static Future<bool> isBleOpen() async {
14
+    return await BluetoothPlugin.instance.isBleOpen();
15
+  }
16
+
17
+  //安卓版本是否大于等于31
18
+  static Future<bool> isSDKIntGreaterOrEqual() async {
19
+    return await BluetoothPlugin.instance.isSDKIntGreaterOrEqual31();
20
+  }
21
+
22
+  //是否支持蓝牙操作
23
+  static Future<bool> canExecAction() async {
24
+    if (await isBleOpen()) {
25
+
26
+      bool allGranted = false;
27
+      String permissionName = '';
28
+      // permissionRequest
29
+     if(await isSDKIntGreaterOrEqual()) {
30
+
31
+       if (await PermissionHandler.handleWith(Permission.bluetoothScan)) {
32
+         allGranted = true;
33
+       } else {
34
+         permissionName = Permission.bluetoothScan.toString();
35
+         allGranted = false;
36
+       }
37
+       if(await PermissionHandler.handleWith(Permission.bluetoothConnect)) {
38
+         allGranted = true;
39
+       } else {
40
+         permissionName = '$permissionName ${Permission.bluetoothConnect}';
41
+         allGranted = false;
42
+       }
43
+     }
44
+      //所有权限申请通过
45
+      if (await PermissionHandler.handleWith(Permission.location)) {
46
+        allGranted = true;
47
+      } else {
48
+        permissionName = Permission.location.toString();
49
+        allGranted = false;
50
+      }
51
+     if(allGranted) {
52
+       return true;
53
+     } else {
54
+       MyNavigator.showToast('权限打开失败:$permissionName');
55
+       return false;
56
+     }
57
+    } else {
58
+      // 蓝牙未开启
59
+      MyNavigator.showToast('蓝牙未开启');
60
+      return false;
61
+    }
62
+  }
63
+
64
+  //开始扫描
65
+  static Future<int> startBluetoothDiscovery() async {
66
+
67
+    if(await canExecAction()) {
68
+      return await BluetoothPlugin.instance.startBluetoothDiscovery();
69
+    } else {
70
+      return 0;
71
+    }
72
+  }
73
+
74
+  //开始配对
75
+  static Future<int> startBluetoothPair(BlueDeviceInfo deviceInfo) async {
76
+
77
+    if(await canExecAction()) {
78
+      return await BluetoothPlugin.instance.startBluetoothPair(deviceInfo);
79
+    } else {
80
+      return 0;
81
+    }
82
+  }
83
+
84
+  //开始连接
85
+  static Future<int> startBluetoothConnect(BlueDeviceInfo deviceInfo) async {
86
+
87
+    if(await canExecAction()) {
88
+      return await BluetoothPlugin.instance.startBluetoothConnect(deviceInfo);
89
+    } else {
90
+      return 0;
91
+    }
92
+  }
93
+
94
+  //开始打印
95
+  static Future<int> startBluetoothPrint(BlueDeviceInfo deviceInfo) async {
96
+
97
+    if(await canExecAction()) {
98
+      return await BluetoothPlugin.instance.startBluetoothPrint(deviceInfo);
99
+    } else {
100
+      return 0;
101
+    }
102
+  }
103
+
104
+
105
+}
106
+
107
+

+ 75 - 0
lib/utils/permission_utils.dart

@@ -0,0 +1,75 @@
1
+import 'package:flutter/material.dart';
2
+import 'package:permission_handler/permission_handler.dart';
3
+
4
+import '../router/my_navigator.dart';
5
+
6
+
7
+class PermissionHandler {
8
+  static Future<bool> handleWith(Permission permission,
9
+      {bool showTip = true}) async {
10
+    if (await permission.request().isGranted ||
11
+        await permission.request().isLimited) {
12
+      return true;
13
+    }
14
+
15
+    if (await permission.isPermanentlyDenied ||
16
+        await permission.isRestricted ||
17
+        await permission.isDenied) {
18
+      if (showTip) {
19
+
20
+        MyNavigator.showDialog(
21
+          builder: (_) => PermissionAlertDialog(permission: permission),
22
+        );
23
+      }
24
+    }
25
+    return false;
26
+  }
27
+}
28
+
29
+class PermissionAlertDialog extends StatelessWidget {
30
+  final Permission permission;
31
+
32
+  const PermissionAlertDialog({Key? key, required this.permission}) : super(key: key);
33
+
34
+  @override
35
+  Widget build(BuildContext context) {
36
+    String content = '';
37
+    if (this.permission is PermissionWithService) {
38
+      if (this.permission == Permission.location) {
39
+        content = '请前往系统设置打开定位权限';
40
+      }
41
+    }
42
+
43
+    if (this.permission is Permission) {
44
+      if (this.permission == Permission.photos) {
45
+        content = '请前往系统设置打开相册权限';
46
+      } else if (this.permission == Permission.camera) {
47
+        content = '请前往系统设置打开相机权限';
48
+      } else if (this.permission == Permission.microphone) {
49
+        content = '请前往系统设置打开麦克风权限';
50
+      } else if (this.permission == Permission.storage) {
51
+        content = '请前往系统设置打开存储权限';
52
+      } else if (this.permission == Permission.bluetoothScan) {
53
+        content = '请前往系统设置打开蓝牙权限';
54
+      } else {
55
+        content = '请前往系统设置打开该权限';
56
+      }
57
+    }
58
+
59
+    return AlertDialog(
60
+      title: Text('提示'),
61
+      content: Text(content),
62
+      backgroundColor: Colors.white,
63
+      elevation: 24,
64
+      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
65
+      actions: <Widget>[
66
+        TextButton(
67
+          child: Text('知道了'),
68
+          onPressed: () {
69
+            // XRouter.pop(context);
70
+          },
71
+        ),
72
+      ],
73
+    );
74
+  }
75
+}