目录
引言
安装失败的原因
如何编译so文件的x86_64版本
下载源代码
安装NDK
代码编译
安装MQTT软件包
避免MQTT软件包自动升级
设置libs
客户端程序的编写
运行测试
结语
参考文献
引言
在上周的博客(如何在鸿蒙API9和x86模拟器中使用MQTT-CSDN博客)中介绍了我的学生有个需求:他在写鸿蒙APP时无法将MQTT库加入到设备中,由于他没有鸿蒙的真机,只能用DevEco Studio中通过的模拟器来实现,而自带的模拟器只支持API9和API6,而下载的MQTT库是支持API11的。今天就来说说在API9中如何实现MQTT客户端,使用的DevEco Studio版本是3.11。
安装失败的原因
官方有个MQTT软件包:ohpm/mqtt,我写作本文时最新的版本是2.14,针对的是API12。可以将其降级为2.0.5-rc.0或者2.0.6使其支持API9,但是由于其是从C语言版本移植过来的,依赖C语言的库文件(libmqttasync.so),而官方仓库中只提供了ARM版本的,所以在真机上可以用,但是在基于x86的本机模拟器上没法用,会出现”Failure[ERR_INSTALL_PARSE_NATIVE_SO_FAILED]“错误。如果要使用就需要使用NDK重新编译该软件包中C语言文件产生x86可以用的库文件,今天就解决这个问题。
如何编译so文件的x86_64版本
下载源代码
首先需要用git下载mqtt模块的源代码,这里我们下载的是2.0.5版本的源代码,它可以和API9兼容:
git clone -b 2.0.5 --single-branch https://gitee.com/openharmony-tpc/ohos_mqtt.git
由于代码中引用了另外两个子模块,所以也需要下载:
git submodule update --init --recursive
代码下载后,可以看到D:\DevEcoStudioProjects\ohos_mqtt\ohos_Mqtt\src\main\cpp目录中包括NAPI相关的代码。OpenHarmony NAPI 提供了一套接口,使得 ArkTS/TS/JS 与 C/C++ 之间可以进行交互。通过 NAPI,可以实现例如网络通信、串口访问、多媒体解码、传感器数据收集等功能。
安装NDK
要编译NAPI相关的C语言代码就需要安装OpenHarmony NDK。如果以前在DevEco Studio中建立过Native C++工程,则DevEco Studio会自动安装NDK。如果没有安装过,也可以手工安装,选择File|Settings,在其中SDK部分选择Native。
代码编译
在Windows下打开PowerShell,进入C++语言所在目录,使用下面的命令调用CMake生成makefile(命令行中的具体路径取决于用户设置)。
D:\Huawei\SDK\OpenHarmony\9\native\build-tools\cmake\bin\cmake -G Ninja -B out -DCMAKE_TOOLCHAIN_FILE=D:\Huawei\SDK\OpenHarmony\9\native\build\cmake\ohos.toolchain.cmake -DCMAKE_MAKE_PROGRAM=D:\Huawei\SDK\OpenHarmony\9\native\build-tools\cmake\bin\ninja.exe -DCMAKE_BUILD_WITH_INSTALL_RPATH=true -DOHOS_ARCH=x86_64
命令行中的OHOS_ARCH
参数指定生成代码的操作系统的类型,其类型是armeabi-v7a
、x86_64
和arm64-v8a(缺省值)
。我们要使代码能够运行在x86的模拟器上,就需要设置该参数为x86_64。
执行过程如下:
-- The C compiler identification is Clang 12.0.1
-- The CXX compiler identification is Clang 12.0.1
-- Check for working C compiler: D:/Huawei/SDK/openharmony/9/native/llvm/bin/clang.exe
-- Check for working C compiler: D:/Huawei/SDK/openharmony/9/native/llvm/bin/clang.exe -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: D:/Huawei/SDK/openharmony/9/native/llvm/bin/clang++.exe
-- Check for working CXX compiler: D:/Huawei/SDK/openharmony/9/native/llvm/bin/clang++.exe -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- The ASM compiler identification is Clang
-- Found assembler: D:/Huawei/SDK/openharmony/9/native/llvm/bin/clang.exe
-- Configuring done
-- Generating done
-- Build files have been written to: D:/DevEcoStudioProjects/ohos_mqtt/ohos_Mqtt/src/main/cpp/out
正确生成makefile之后,可以执行如下命令进行编译:
D:\Huawei\SDK\OpenHarmony\9\native\build-tools\cmake\bin\cmake --build out
最后编译成功,我们就得到了x86_64平台下的libmqttasync.so文件。
安装MQTT软件包
在本文写作的时候,ohpm/mqtt最新的版本是2.14,针对的是API12。如果直接在Terminal中使用下面的命令安装的是最新版本。
ohpm install @ohos/mqtt
如果在工程中直接使用最新的这个版本会报告如下错误:
> hvigor ERROR: Failed :entry:default@MergeProfile...
> hvigor ERROR: The compatibleSdkVersion 9 cannot be smaller than version 12 declared in library [:ohos_Mqtt]
as the library might be using APIS not available in 9
所以最好的办法是使用老的版本,比如2.0.5-rc.0
ohpm install @ohos/mqtt@2.0.5-rc.0
使用2.06版本也可以,但是需要手工修改oh_modules/.ohpm/@ohos+mqtt@2.0.6/oh_modules/@ohos/mqtt/src/main/module.json文件中的minAPIVersion为9(默认是10)。
{
"app": {
"bundleName": "cn.openharmony.ohos_mqtt",
"debug": true,
"versionCode": 1000000,
"versionName": "2.0.6-rc.0",
"minAPIVersion": 9,
"targetAPIVersion": 10,
"apiReleaseType": "Beta2",
"compileSdkVersion": "4.0.9.6",
"compileSdkType": "OpenHarmony",
"bundleType": "app"
},
"module": {
"name": "ohos_Mqtt",
"type": "har",
"deviceTypes": [
"default",
"tablet"
],
"installationFree": false
}
}
避免MQTT软件包自动升级
上面的操作虽然可以导入老版本的MQTT包,但是当三方包发布新版本后,点击同步工程,会出现默认更新安装的三方包版本情况。为了避免这种情况,手工修改oh-package.json5,将其中@ohos/mqtt一行版本号前面的“^"符号删除掉,这样保证安装固定版本的三方包。
{
"name": "myapplication",
"version": "1.0.0",
"description": "Please describe the basic information.",
"main": "",
"author": "",
"license": "",
"dependencies": {
"@ohos/mqtt": "2.0.6"
},
"devDependencies": {
"@ohos/hypium": "1.0.6"
},
"dynamicDependencies": {}
}
设置libs
在DevEco Studio中,找到oh_modules/.ohpm/@ohos+mqtt@2.0.5/oh_modules/@ohos/mqtt/libs目录,在其下建立x86_64子目录,将libmqttasync.so和libc++_shared.so文件拷贝到其中。其中libc++_shared.so文件来自\Huawei\SDK\openharmony\9\native\llvm\lib\x86_64-linux-ohos\c++(具体路径取决于用户设置)。
客户端程序的编写
客户端程序的编写参考了参考文献中的第一个。
先建立MQTT.ets,内容如下:
import { MqttAsync, MqttClient, MqttPublishOptions, MqttResponse, MqttSubscribeOptions } from '@ohos/mqtt'
export class MQTT{
private serverUrl: string = 'tcp://bemfa.com:9501'
private clientId: string = 'xxxxxx'
private userName: string = ''
private password: string = ''
public mqttAsyncClient: MqttClient = MqttAsync.createMqtt({
url: this.serverUrl,
clientId: this.clientId,
persistenceType: 1,
})
private topic: string = "light002"
connectMqtt() {
this.mqttAsyncClient.connect({
userName: this.userName,
password: this.password,
}).then(() => {
this.mqttAsyncClient.isConnected()
.then((data: boolean) => {
console.log("连接状态: " + data)
});
}).catch(() => {
console.warn('连接失败')
})
}
subscribeMqtt() {
let subscribeOption: MqttSubscribeOptions = {
topic: this.topic,//主题名称
qos: 0 //消息的服务质量设置
}
this.mqttAsyncClient.subscribe(subscribeOption)
.then((data: MqttResponse) => {
console.log("订阅成功 " + JSON.stringify(data));
}).catch((err: MqttResponse) => {
console.log("订阅失败" + JSON.stringify(err));
})
}
messageArrived() {
this.mqttAsyncClient.messageArrived((err, data) => {
if (err) {
console.error("接收消息时发生错误:", err);
} else {
console.log("接收到的消息:",JSON.stringify(data));
}
});
}
publish(message:string) {
let publishOption: MqttPublishOptions = {
topic: this.topic, //主题名称
qos: 0, //消息的服务质量设置
payload: JSON.stringify(message),//发布的消息
};
this.mqttAsyncClient.publish(publishOption)
.then((data: MqttResponse) => {
console.log("推送成功" + JSON.stringify(data));
})
.catch((err: Error) => {
console.log("推送失败" + JSON.stringify(err));
});
}
disconnect() {
this.mqttAsyncClient.disconnect()
.then((data: MqttResponse) => {
console.log("断开成功:" + JSON.stringify(data));
})
.catch((err: MqttResponse) => {
console.log("断开失败:" + JSON.stringify(err));
})
}
}
export const mqtt = new MQTT();
程序中的设置是按照巴法云设置的, 巴法云不支持QoS2,所以将QoS改为0。
主程序的代码如下:
import promptAction from '@ohos.promptAction';
import { mqtt } from './MQTT';
@Entry
@Component
struct Index {
@State message: string = 'Hello World'
/**
* In low-code mode, do not add anything to the build function, as it will be
* overwritten by the content generated by the .visual file in the build phase.
*/
build() {
}
buttonClick()
{
mqtt.connectMqtt()
}
buttonPublish()
{
mqtt.publish("Hello!")
}
}
完整的程序可以从CSDN下载:在x86模拟器和鸿蒙API9如何使用MQTT模块ohos-mqtt的示例程序资源-CSDN文库https://download.csdn.net/download/bit_mike/90091745。
运行测试
接下来启动x86模拟器,然后在其上运行本工程即可。
先点击Connect按钮连接服务器,然后再点击Publish按钮就可以向服务器发布消息。
我们可以用Wireshark观测到整个通信过程:
结语
至此我们完成了最终的目标,这里面最核心的就是使用NDK编译了NAPI所使用库文件。整个过程虽然有点多,但是总体上看仍然是比较容易理解的。
参考文献
- HarmonyOS实现MQTT_鸿蒙mqtt库-CSDN博客
- docs/adapter_windows.md · OpenHarmony-SIG/tpc_c_cplusplus - Gitee.com