鸿蒙 WiFi 打开流程

本文详细解析了鸿蒙HarmonyOS4.0中手机平台WiFi界面代码,涉及Toggle组件、WiFiModel的switchWiFiActiveStatus方法,以及从应用到系统级WiFi启用过程中的各个服务和接口调用,展示了从用户交互到硬件驱动的完整流程。

这里鸿蒙的代码使用的是开源鸿蒙HarmonyOS 4.0的代码基线
这里我们是针对手机平台代码分析,首先界面部分代码都在:applications/standard/settings/product/phone
然后我们只关心WiFi相关的,看界面代码applications/standard/settings/product/phone/src/main/ets/pages/wifi.ets

187  build() {
188    Column() {
189      GridContainer({ gutter: ConfigData.GRID_CONTAINER_GUTTER_24, margin: ConfigData.GRID_CONTAINER_MARGIN_24 }) {
190        Column() {
191          HeadComponent({ headName: $r('app.string.wifiTab'), isActive: true });
192
193          Row() {
194            Text($r('app.string.wifiTab'))
195              .fontSize($r('sys.float.ohos_id_text_size_body1'))
196              .fontColor($r('sys.color.ohos_id_color_text_primary'))
197              .fontWeight(FontWeight.Medium)
198              .textAlign(TextAlign.Start)
199
200            Blank()
201
202            Toggle({ type: ToggleType.Switch, isOn: this.isWiFiEnabled })
203              .width('36vp')
204              .height('20vp')
205              .selectedColor('#007DFF')
206              .onChange((isOn: boolean) => {
207                this.switchWiFiActiveStatus(isOn);    ---> 打开 WiFi 触发
208              });
209          }
    ……… ………  ……… ……… ………  ……… 
386  switchWiFiActiveStatus(isOn: boolean) {
387    // make the ui change quickly
388    this.isWiFiEnabled = isOn;
389    LogUtil.info(MODULE_TAG + 'curr enable status : ' + this.isWiFiEnabled);
390
391    // delay the wifi status change event
392    if (this.switchDebounceFlag) {
393      clearTimeout(this.switchDebounceFlag);
394    }
395
396    if (this.timerId != -1) {
397      clearTimeout(this.timerId);
398    }
399
400    this.switchDebounceFlag = setTimeout(() => {
401      if (this.isWiFiEnabled) {
402        LogUtil.info(MODULE_TAG + 'enable wifi');
403        WifiModel.enableWiFi();      ---> 这里是使能WiFi,跟着流程接着看
404      } else {
405        LogUtil.info(MODULE_TAG + 'disable wifi');
406        WifiModel.disableWifi();
407      }
408      this.switchDebounceFlag = undefined;
409      this.timeLimits();
410    }, 500);
411  }

/applications/standard/settings/product/phone/src/main/ets/model/wifiImpl/WifiModel.ts

280  enableWiFi() {
281    if (wifi.isWifiActive() === true) {
282      LogUtil.info(MODULE_TAG + 'wifi is already active');
283      return;
284    }
285    let ret: boolean = wifi.enableWifi();   ---> 这里的WiFi是:import wifi from '@ohos.wifi';
286    LogUtil.info(MODULE_TAG + 'enable WiFi result is : ' + ret);
287    return ret;
288  }

所以只要找到 @ohos.wifi::enableWifi 方法即可,看这个路径下的配置文件/foundation/communication/wifi/wifi/ 就知道在这里搜下:

// foundation/communication/wifi/wifi/frameworks/native/src/wifi_device_impl.cpp
ErrCode WifiDeviceImpl::EnableWifi()
{
    std::lock_guard<std::mutex> lock(mutex_);
    RETURN_IF_FAIL(GetWifiDeviceProxy());
    return client_->EnableWifi();      ---> 对应的就是相应的代理
}
// /foundation/communication/wifi/wifi/frameworks/native/src/wifi_device_proxy.cpp
ErrCode WifiDeviceProxy::EnableWifi()
{
    if (mRemoteDied) {
        WIFI_LOGE("failed to `%{public}s`,remote service is died!", __func__);
        return WIFI_OPT_FAILED;
    }
    MessageOption option;
    MessageParcel data;
    MessageParcel reply;
    if (!data.WriteInterfaceToken(GetDescriptor())) {
        WIFI_LOGE("Write interface token error: %{public}s", __func__);
        return WIFI_OPT_FAILED;
    }
    data.WriteInt32(0);
    // 主要就是发送 WIFI_SVR_CMD_ENABLE_WIFI 消息给Stub端,我们看下这个消息 WIFI_SVR_CMD_ENABLE_WIFI = 0x1001,表示open wifi
    int error = Remote()->SendRequest(static_cast<uint32_t>(DevInterfaceCode::WIFI_SVR_CMD_ENABLE_WIFI), data, reply, option);
    if (error != ERR_NONE) {
        WIFI_LOGE("Set Attr(%{public}d) failed,error code is %{public}d",
            static_cast<int32_t>(DevInterfaceCode::WIFI_SVR_CMD_ENABLE_WIFI), error);
        return WIFI_OPT_FAILED;
    }

    int exception = reply.ReadInt32();
    if (exception) {
        return WIFI_OPT_FAILED;
    }
    WriteWifiStateHiSysEvent(HISYS_SERVICE_TYPE_STA, WifiOperType::ENABLE);
    return ErrCode(reply.ReadInt32());
}
// 对应Stub 端 /foundation/communication/wifi/wifi/services/wifi_standard/wifi_framework/wifi_manage/wifi_device_stub.cpp
void WifiDeviceStub::OnEnableWifi(uint32_t code, MessageParcel &data, MessageParcel &reply)
{
    WIFI_LOGD("run %{public}s code %{public}u, datasize %{public}zu", __func__, code, data.GetRawDataSize());
    ErrCode ret = EnableWifi();     ---> 找Stub的实现是哪个类即可
    reply.WriteInt32(0);
    reply.WriteInt32(ret);
    return;
}
// 对应这个类:/foundation/communication/wifi/wifi/services/wifi_standard/wifi_framework/wifi_manage/wifi_device_service_impl.cpp
// 这里我们只看和流程相关的,剩下的省内掉
ErrCode WifiDeviceServiceImpl::EnableWifi()
{
	…………………………
    do {
 	…………………………
        IStaService *pService = WifiServiceManager::GetInstance().GetStaServiceInst();
        if (pService == nullptr) {
            WIFI_LOGE("Create %{public}s service failed!", WIFI_SERVICE_STA);
            break;
        }
     …………………………
        errCode = pService->EnableWifi();   // 这里的pService就是 IStaService
	…………………………
}

那我们就看 IStaService 的 EnableWifi方法,但是发现IStaService 的实现是foundation/communication/wifi/wifi/services/wifi_standard/wifi_framework/wifi_manage/wifi_sta/sta_interface.cpp

ErrCode StaInterface::EnableWifi()
{
    WIFI_LOGI("Enter StaInterface::EnableWifi.\n");
    if(pStaService == nullptr) {
        pStaService = new (std::nothrow) StaService();
        if (pStaService == nullptr) {
            WIFI_LOGE("New StaService failed.\n");
            return WIFI_OPT_FAILED;
        }
        if (pStaService->InitStaService(staCallback) != WIFI_OPT_SUCCESS) {
            WIFI_LOGE("InitStaService failed.\n");
            delete pStaService;
            pStaService = nullptr;
            return WIFI_OPT_FAILED;
        }
    }

    if (pStaService->EnableWifi() != WIFI_OPT_SUCCESS) {     ---> 我们还是只关心打开相关的流程
        WIFI_LOGE("EnableWifi failed.\n");
        DisableWifi();
        return WIFI_OPT_FAILED;
    }
    return WIFI_OPT_SUCCESS;
}
// 接着看 StaService 里面的EnableWifi 方法:foundation/communication/wifi/wifi/services/wifi_standard/wifi_framework/wifi_manage/wifi_sta/sta_service.cpp
ErrCode StaService::EnableWifi() const
{
    WIFI_LOGI("Enter StaService::EnableWifi.\n");
    CHECK_NULL_AND_RETURN(pStaStateMachine, WIFI_OPT_FAILED);
    pStaStateMachine->SendMessage(WIFI_SVR_CMD_STA_ENABLE_WIFI, STA_CONNECT_MODE);    ---> 状态机里面处理
    return WIFI_OPT_SUCCESS;
}

看状态机里面如何处理这个 WIFI_SVR_CMD_STA_ENABLE_WIFI,对应的定义
#define WIFI_SVR_CMD_STA_ENABLE_WIFI 0x2001

// foundation/communication/wifi/wifi/services/wifi_standard/wifi_framework/wifi_manage/wifi_sta/sta_state_machine.cpp
bool StaStateMachine::InitState::ExecuteStateMsg(InternalMessage *msg)
{
    if (msg == nullptr) {
        return false;
    }

    WIFI_LOGI("InitState-msgCode=%{public}d is received.\n", msg->GetMessageName());
    bool ret = NOT_EXECUTED;
    switch (msg->GetMessageName()) {
        case WIFI_SVR_CMD_STA_ENABLE_WIFI: {
            ret = EXECUTED;
            pStaStateMachine->operationalMode = msg->GetParam1();
            pStaStateMachine->StartWifiProcess();
            break;
        }

        case WIFI_SVR_CMD_STA_OPERATIONAL_MODE:
            break;

        default:
            WIFI_LOGI("InitState-msgCode=%d not handled.\n", msg->GetMessageName());
            break;
    }
    return ret;
}

void StaStateMachine::StartWifiProcess()
{
    WifiSettings::GetInstance().SetWifiState(static_cast<int>(WifiState::ENABLING));
    staCallback.OnStaOpenRes(OperateResState::OPEN_WIFI_OPENING);
    int res;
    if (WifiOprMidState::RUNNING == WifiConfigCenter::GetInstance().GetWifiScanOnlyMidState()) {
        res = static_cast<int>(WIFI_IDL_OPT_OK);
    } else {
        res = WifiStaHalInterface::GetInstance().StartWifi();    ---> 启动WiFi 
    }

    if (res == static_cast<int>(WIFI_IDL_OPT_OK)) {
        WIFI_LOGI("Start wifi successfully!");
        if (WifiStaHalInterface::GetInstance().WpaAutoConnect(false) != WIFI_IDL_OPT_OK) {
            WIFI_LOGI("The automatic Wpa connection is disabled failed.");
        }

        /* callback the InterfaceService that wifi is enabled successfully. */
        WifiSettings::GetInstance().SetWifiState(static_cast<int>(WifiState::ENABLED));
        staCallback.OnStaOpenRes(OperateResState::OPEN_WIFI_SUCCEED);
        /* Sets the MAC address of WifiSettings. */
        std::string mac;
        if ((WifiStaHalInterface::GetInstance().GetStaDeviceMacAddress(mac)) == WIFI_IDL_OPT_OK) {
            WifiSettings::GetInstance().SetMacAddress(mac);
            std::string realMacAddress;
            WifiSettings::GetInstance().GetRealMacAddress(realMacAddress);
            if (realMacAddress.empty()) {
                WifiSettings::GetInstance().SetRealMacAddress(mac);
            }
        } else {
            WIFI_LOGI("GetStaDeviceMacAddress failed!");
        }
#ifndef OHOS_ARCH_LITE
        WIFI_LOGI("Register netsupplier");
        WifiNetAgent::GetInstance().OnStaMachineWifiStart();
#endif
        /* Initialize Connection Information. */
        InitWifiLinkedInfo();
        InitLastWifiLinkedInfo();
        WifiSettings::GetInstance().SaveLinkedInfo(linkedInfo);
        SyncDeviceConfigToWpa();
#ifndef OHOS_ARCH_LITE
        ChipCapability::GetInstance().InitializeChipCapability();
#endif
        /* The current state of StaStateMachine transfers to SeparatedState after
         * enable supplicant.
         */
        SwitchState(pSeparatedState);
    } else {
        /* Notify the InterfaceService that wifi is failed to enable wifi. */
        LOGE("StartWifi failed, and errcode is %d.", res);
        WifiSettings::GetInstance().SetWifiState(static_cast<int>(WifiState::DISABLED));
        WifiSettings::GetInstance().SetUserLastSelectedNetworkId(INVALID_NETWORK_ID);
        staCallback.OnStaOpenRes(OperateResState::OPEN_WIFI_FAILED);
    }
}

看下 WifiStaHalInterface::GetInstance().StartWifi(); —> 启动WiFi 的流程

// foundation/communication/wifi/wifi/services/wifi_standard/wifi_framework/wifi_manage/idl_client/wifi_sta_hal_interface.cpp
WifiErrorNo WifiStaHalInterface::StartWifi(void)
{
    CHECK_NULL_AND_RETURN(mIdlClient, WIFI_IDL_OPT_FAILED);
    return mIdlClient->StartWifi();    // 而  mIdlClient = new (std::nothrow) WifiIdlClient;
}
// 所以看/foundation/communication/wifi/wifi/services/wifi_standard/wifi_framework/wifi_manage/idl_client/wifi_idl_client.cpp
WifiErrorNo WifiIdlClient::StartWifi(void)
{
    CHECK_CLIENT_NOT_NULL;
    return Start();  
}

这里 wifi_idl_client 实现了与 Wifi HAL 进行 RPC 通信的客户端,那服务端必然就是 Wifi HAL,后续我们再去记录具体的,这里我们只关心流程,就直接贴上远端(服务端)的代码位置
foundation/communication/wifi/wifi/services/wifi_standard/wifi_hal/wifi_hal_crpc_server.c

// wifi_hal_crpc_server.c  可以看到代码位置已经是wifi_hal了,就验证了我们上面的那句话
 ret += PushRpcFunc("Start", RpcStart);   ---> Start 对应的方法是 RpcStart
 
 // foundation/communication/wifi/wifi/services/wifi_standard/wifi_hal/wifi_hal_crpc_sta.c
 int RpcStart(RpcServer *server, Context *context)
{
    if (server == NULL || context == NULL) {
        return HAL_FAILURE;
    }
    WifiErrorNo err = Start();    ---> 看这个
    WriteBegin(context, 0);
    WriteInt(context, err);
    WriteEnd(context);
    return HAL_SUCCESS;
}
// foundation/communication/wifi/wifi/services/wifi_standard/wifi_hal/wifi_hal_sta_interface.c
WifiErrorNo Start(void)
{
    LOGI("Ready to start wifi");
    if (StartSupplicant() != WIFI_HAL_SUCCESS) {    ---》 启动 supplicant,主要是去加载对应的库文件,这个很熟悉了
        LOGE("wpa_supplicant start failed!");
        return WIFI_HAL_OPEN_SUPPLICANT_FAILED;
    }
    LOGI("wpa_supplicant start successfully!");

    if (AddWpaIface(0) != WIFI_HAL_SUCCESS) {    ---》 添加wlan0 接口
        LOGE("Failed to add wpa interface!");
        StopWpaAndWpaHal(0);
        return WIFI_HAL_CONN_SUPPLICANT_FAILED;
    }

    if (ConnectSupplicant() != WIFI_HAL_SUCCESS) {    ---》看代码其实就是得到操作wpa的方法,一一对应起来
        LOGE("SupplicantHal connect wpa_supplicant failed!");
        StopWpaAndWpaHal(0);
        return WIFI_HAL_CONN_SUPPLICANT_FAILED;
    }
#ifdef HDI_INTERFACE_SUPPORT
    if (HdiStart() != WIFI_HAL_SUCCESS) {
        LOGE("[STA] Start hdi failed!");
        return WIFI_HAL_FAILED;
    }
    if (RegisterHdiStaCallbackEvent() != WIFI_HAL_SUCCESS) {
        LOGE("[STA] Start RegisterHdiStaCallbackEvent failed!");
        return WIFI_HAL_FAILED;
    }
#endif
    LOGI("Start wifi successfully");
    return WIFI_HAL_SUCCESS;
}

至此几步完成后,就可以返回 WIFI_HAL_SUCCESS了,在通过RPC回调告诉上层状态,OK,整个鸿蒙 4.0基线的 WiFi 打开流程差不多就梳理完毕了,这里有个疑问,在Android代码我们处理wpa_supplicant,另外还有加载驱动的流程,但这里没有看到,等后续再细看下。

<think>我们正在讨论HarmonyOS中如何打开本地文件。根据用户的问题,他需要知道在鸿蒙系统中如何访问设备上存储的文件。 在HarmonyOS中,打开本地文件通常可以通过使用文件管理应用或者通过编程方式(在开发应用时)来实现。对于普通用户,使用内置的文件管理器是最直接的方式。对于开发者,可能需要使用HarmonyOS提供的文件操作API。 根据引用[1]和[2],我们并没有直接得到关于打开本地文件的方法,但我们可以根据HarmonyOS的一般操作逻辑来回答。 对于普通用户: 1. 在手机桌面上找到“文件管理”应用(通常系统会预装),点击打开。 2. 在文件管理中,可以浏览内部存储和外部存储(如SD卡)中的文件,按照分类(如图片、音频、视频、文档等)或目录结构进行浏览。 3. 点击文件即可使用相应的应用打开(例如,点击一个图片文件会使用图库打开,点击一个PDF文件可能会使用WPS或系统自带的阅读器打开)。 对于开发者: 如果想在自己的应用中打开本地文件,可以使用HarmonyOS的文件操作API。以下是一个简单的示例,展示如何读取一个文本文件: 首先,需要在config.json中申请文件存储权限: ```json { "reqPermissions": [ { "name": "ohos.permission.READ_MEDIA" }, { "name": "ohos.permission.WRITE_MEDIA" } ] } ``` 然后,在代码中可以使用类似以下的方式读取文件: ```java // 以Stage模型为例 import ohos.app.Context; import ohos.global.resource.RawFileEntry; import ohos.global.resource.Resource; import ohos.global.resource.ResourceManager; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; public String readTextFileFromRaw(Context context, String fileName) { ResourceManager resourceManager = context.getResourceManager(); RawFileEntry rawFileEntry = resourceManager.getRawFileEntry("resources/rawfile/" + fileName); try { Resource resource = rawFileEntry.openRawFile(); InputStream inputStream = resource.getInputStream(); ByteArrayOutputStream result = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int length; while ((length = inputStream.read(buffer)) != -1) { result.write(buffer, 0, length); } return result.toString("UTF-8"); } catch (IOException e) { e.printStackTrace(); } return null; } ``` 注意:上述代码是读取应用资源目录下的文件。如果要读取设备上的任意文件,需要使用文件选择器或者通过绝对路径访问(需要用户授权)。 另外,HarmonyOS还提供了FilePicker组件,可以让用户选择文件: ```java Intent intent = new Intent(); Operation operation = new Intent.OperationBuilder() .withAction("android.intent.action.GET_CONTENT") .build(); intent.setOperation(operation); intent.addFlags(Intent.FLAG_NOT_OHOS); startAbilityForResult(intent, REQUEST_CODE_PICK_FILE); ``` 然后在onAbilityResult中处理返回的文件URI。 由于HarmonyOS的API可能会更新,建议参考最新的官方文档。 根据用户的问题,他可能只是作为普通用户想要打开本地文件,所以重点应放在使用文件管理应用上。 因此,我们可以这样回答: 在HarmonyOS中,您可以使用内置的“文件管理”应用来打开本地文件。请按照以下步骤操作: 1. 在主屏幕上找到“文件管理”应用图标(通常是一个文件夹图标),点击打开。 2. 在文件管理应用中,您可以看到不同的分类,如“图片”、“视频”、“音频”、“文档”等。您可以直接点击这些分类,然后选择文件打开。 3. 您也可以点击底部的“浏览”标签,然后浏览设备内部存储的文件夹,找到您想要打开的文件。 4. 点击文件后,系统会自动使用相应的应用程序打开该文件。 如果您没有找到文件管理应用,可能是被卸载了,您可以在应用市场中搜索“文件管理”重新安装。 对于开发者,请参考HarmonyOS官方文档中的文件管理API。 生成相关问题: 1. 如何在HarmonyOS中分享文件? 2. HarmonyOS的文件管理应用有哪些特色功能? 3. 如何在HarmonyOS应用中实现文件的上传和下载?</think>在HarmonyOS打开本地文件主要通过系统预装的**文件管理应用**实现,以下是具体操作步骤: ### 📁 方法一:通过文件管理应用(普通用户) 1. **定位应用** 在桌面找到「文件管理」应用(图标通常为蓝色文件夹📁),点击进入。 2. **浏览文件** - 顶部分类标签:直接访问「图片」「视频」「文档」「音频」等分类文件 - 目录浏览:点击「浏览」标签 > 选择「内部存储」> 逐级进入目标文件夹 3. **打开文件** 点击文件后,系统会自动调用关联应用打开(如PDF用WPS、图片用图库) > ⚠️ 提示:若文件管理应用被卸载,可通过「应用市场」搜索「文件管理」重新安装 ### 💻 方法二:开发者模式(调试场景) 若需通过代码访问本地文件(如开发调试),参考以下流程: 1. **启用开发者模式** 设置 > 关于手机 > 连续点击「HarmonyOS版本」7次激活开发者模式 2. **ADB连接设备** ```bash # 在SDK目录执行(示例路径) cd D:\HarmonyOS\Sdk\toolchains .\hdc tmode port 5555 # 开启调试端口 .\hdc connect 192.168.x.x # 连接设备IP[^1] ``` 3. **文件操作代码示例(Java)** ```java // 读取内部存储文件 File file = new File(context.getFilesDir(), "test.txt"); try (InputStream is = new FileInputStream(file)) { // 处理文件流 } ``` ### 🌐 特殊文件类型处理 | 文件类型 | 打开方式 | |----------------|-----------------------------------| | **办公文档** | 使用预装的WPS Office或下载第三方应用 | | **压缩包** | 需安装解压软件(如ZArchiver) | | **开发者文件** | 通过DevEco Studio的Device File Explorer查看 | ### 📌 注意事项 1. 访问系统保护目录(如`Android/data`)需Root权限 2. 外接U盘/SD卡文件需在「浏览」标签页选择对应存储设备 3. 隐私文件建议存放在「保密柜」(设置 > 安全 > 文件保密柜) --- ### 🔍 相关问题 1. HarmonyOS如何通过WiFi连接电脑传输文件? 2. 鸿蒙系统的文件保密柜功能如何使用?[^2] 3. 开发者如何通过hdc命令导出设备本地文件? 4. HarmonyOS支持哪些第三方文件管理器应用? [^1]: 华为开发者文档:鸿蒙设备无线调试指南 [^2]: 鸿蒙服务中心操作手册:文件安全管理章节
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值