前言

ReactNative中无法直接实时监听WIFI的状态,但得益于RN可以直接和原生层进行通信的特点,可以在原生层注册广播,实时监听WIFI变化并通过BridgeRN发送状态事件,RN层实时监听事件,获取WIFI状态。

原生层订阅广播

首先在android/app/src/main/AndroidManifest.xml中添加网络状态权限:

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

打开android目录下的应用主文件:android/app/src/main/java/com/<工程名>/MainApplication.java,找到onCreate方法,在方法内订阅广播,如下:

public void onCreate() {
    super.onCreate();
    SoLoader.init(this, /* native exopackage */ false);
    initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
    // 添加以下广播订阅代码,监听广播实时传递wifi状态
    BroadcastReceiver receiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            ReactContext reactContext = getReactNativeHost().getReactInstanceManager().getCurrentReactContext();
            if (reactContext == null) {
                return;
            }
            // 事件名称,RN层通过订阅该名称的事件实时接收wifi状态
            String eventName = "wifi-status";
            // wifi是否连接
            if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
                NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
                if (info != null && info.getState().equals(NetworkInfo.State.DISCONNECTED)) {
                    // 断开连接
                    reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                        .emit(eventName, "201");
                } else if (info != null && info.getState().equals(NetworkInfo.State.CONNECTED)) {
                    // 建立连接
                    reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                        .emit(eventName, "200");
                }
            }
            // wifi是否打开
            if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
                int wifistate = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_DISABLED);
                if (wifistate == WifiManager.WIFI_STATE_DISABLED) {
                    // 关闭wifi
                    reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                        .emit(eventName, "204");
                } else if (wifistate == WifiManager.WIFI_STATE_ENABLED) {
                    // 打开wifi
                    reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                        .emit(eventName, "203");
                }
            }
        }
    };
    // 注册广播
    IntentFilter filter = new IntentFilter();
    filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
    filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
    filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
    registerReceiver(receiver, filter);
}

RN前端监听wifi状态事件并获取所连wifiSSID

首先安装react-native-wifi-reborn用于获取wifi信息:

yarn add react-native-wifi-reborn

需要注意的时,在Android10以上系统,需要获取位置权限才能扫描wifi并获取wifi信息,因此,将请求权限与获取当前所连wifiSSID封装为一个工具类,如下:

import {PermissionsAndroid} from 'react-native';
import WifiManager from 'react-native-wifi-reborn';

export default class WifiUtil {
    // 请求位置权限
    static async grantPermission() {
        const granted = await PermissionsAndroid.request(
            PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
            {
                title: '请求位置权限',
                message: '需要位置权限以扫描附近的WIFI网络', // 指定message,若第一次用户拒绝了,可以弹出一个说明框再次进行请求
                buttonPositive: '确定',
                // buttonNegative: '取消',
            },
        );
        return granted === PermissionsAndroid.RESULTS.GRANTED;
    }

    // 获取当前所连wifi的SSID
    static async getCurrentWifiSSID() {
        const ssid = await WifiManager.getCurrentWifiSSID().then(
            id => id,
            () => null,
        );
        return ssid;
    }
}

在需要监听wifi状态的控件中即可请求权限并监听广播传来的事件,如下:

import React, {useEffect} from 'react';
import {View, Text} from 'react-native';

import WifiUtil from '../util/WifiUtil';

export default function App() {
    useEffect(() => {
        // 获取位置权限
        WifiUtil.grantPermission().then(wifiGranted => {
            if (!wifiGranted) {
                console.log('网络位置权限请求失败,可能无法扫描WIFI信息并自动获取当前WIFI的SSID');
            }
            // 获取ssid
            WifiUtil.getCurrentWifiSSID().then(ssid => {
                if (ssid) {
                    console.log(`ssid = ${ssid}`);
                } else {
                    console.log('未获取到SSID');
                }
            });
        });
    }, []);
    
    useEffect(() => {
        // 监听wifi状态事件
        const messageEmitter = DeviceEventEmitter.addListener('wifi-status', (code: string) => {
            switch (code) {
                case “200”:
                    console.log('wifi连接已建立 ...');
                    WifiUtil.getCurrentWifiSSID().then(ssid => {
                        if (ssid) {
                            console.log(`ssid = ${ssid}`);
                        } else {
                            console.log('未获取到SSID');
                        }
                    });
                    break;
                case “201”:
                    console.log('wifi连接已断开 ...');
                    break;
                case “203”:
                    console.log('wifi已打开 ...');
                    break;
                case “204”:
                    console.log('wifi已关闭 ...');
                    break;
                default:
                    console.log('未知状态 ...');
            }
        });
        return () => {
            messageEmitter.remove(); // 销毁事件
        };
    }, []);
    
    return (
        <View>
            <Text>App</Text>
        </View>
    );
}