HarmonyOS ArkUI实战开发-引入三方库

804 篇文章 5 订阅
606 篇文章 11 订阅

笔者在第 4 小节里基于前 3 小结的知识点简单扩展了一个 md5() 方法并成功在 JS 代码里调起了 C++ 代码,本节笔者简单介绍一下引入三方库编译的知识点。

引入MD5源码

上一小节的 md5() 方法实现只是简单模拟,并没有真正实现 MD5 的计算,因此笔者从网上找了一个 MD5 计算的源码并引入工程,工程目录如下所示:

其中 md5.h 源码如下所示:

//
// Created on 2023/2/28.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".

#ifndef oh_0400_napi_md5_H
#define oh_0400_napi_md5_H

/* Parameters of MD5\. */
#define s11 7
#define s12 12
#define s13 17
#define s14 22

#define s21 5
#define s22 9
#define s23 14
#define s24 20

#define s31 4
#define s32 11
#define s33 16
#define s34 23

#define s41 6
#define s42 10
#define s43 15
#define s44 21

#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))

#define ROTATELEFT(num, n) (((num) << (n)) | ((num) >> (32-(n))))

#define FF(a, b, c, d, x, s, ac) { \
  (a) += F ((b), (c), (d)) + (x) + ac; \
  (a) = ROTATELEFT ((a), (s)); \
  (a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
  (a) += G ((b), (c), (d)) + (x) + ac; \
  (a) = ROTATELEFT ((a), (s)); \
  (a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
  (a) += H ((b), (c), (d)) + (x) + ac; \
  (a) = ROTATELEFT ((a), (s)); \
  (a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
  (a) += I ((b), (c), (d)) + (x) + ac; \
  (a) = ROTATELEFT ((a), (s)); \
  (a) += (b); \
}

#include <string>
#include <cstring>

using std::string;

/* Define of btye.*/
typedef unsigned char byte;
/* Define of byte. */
typedef unsigned int bit32;

class MD5 {
public:
    /* Construct a MD5 object with a string. */
    MD5(const string& message);

    /* Generate md5 digest. */
    const byte* getDigest();

    /* Convert digest to string value */
    string toStr();

private:
    /* Initialization the md5 object, processing another message block,
     * and updating the context.*/
    void init(const byte* input, size_t len);

    /* MD5 basic transformation. Transforms state based on block. */
    void transform(const byte block[64]);

    /* Encodes input (usigned long) into output (byte). */
    void encode(const bit32* input, byte* output, size_t length);

    /* Decodes input (byte) into output (usigned long). */
    void decode(const byte* input, bit32* output, size_t length);

private:
    /* Flag for mark whether calculate finished. */
    bool finished;

    /* state (ABCD). */
    bit32 state[4];

    /* number of bits, low-order word first. */
    bit32 count[2];

    /* input buffer. */
    byte buffer[64];

    /* message digest. */
    byte digest[16];

    /* padding for calculate. */
    static const byte PADDING[64];

    /* Hex numbers. */
    static const char HEX_NUMBERS[16];
};

#endif //oh_0400_napi_md5_H

md5.cpp 源码如下所示:

//
// Created on 2023/2/28.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".

#include "md5.h"
#include <string>

/* Define the static member of MD5\. */
const byte MD5::PADDING[64] = { 0x80 };
const char MD5::HEX_NUMBERS[16] = {
        '0', '1', '2', '3',
        '4', '5', '6', '7',
        '8', '9', 'a', 'b',
        'c', 'd', 'e', 'f'
};

MD5::MD5(const string& message) {
    finished = false;
    /* Reset number of bits. */
    count[0] = count[1] = 0;

    /* Initialization constants. */
    state[0] = 0x67452301;
    state[1] = 0xefcdab89;
    state[2] = 0x98badcfe;
    state[3] = 0x10325476;

    /* Initialization the object according to message. */
    init((const byte*)message.c_str(), message.length());
}

/**
 * @Generate md5 digest.
 *
 * @return the message-digest.
 *
 */
const byte* MD5::getDigest() {
    if (!finished) {
        finished = true;

        byte bits[8];
        bit32 oldState[4];
        bit32 oldCount[2];
        bit32 index, padLen;

        /* Save current state and count. */
        memcpy(oldState, state, 16);
        memcpy(oldCount, count, 8);

        /* Save number of bits */
        encode(count, bits, 8);

        /* Pad out to 56 mod 64\. */
        index = (bit32)((count[0] >> 3) & 0x3f);
        padLen = (index < 56) ? (56 - index) : (120 - index);
        init(PADDING, padLen);

        /* Append length (before padding) */
        init(bits, 8);

        /* Store state in digest */
        encode(state, digest, 16);

        /* Restore current state and count. */
        memcpy(state, oldState, 16);
        memcpy(count, oldCount, 8);
    }
    return digest;
}

/**
 * @Initialization the md5 object, processing another message block,
 * and updating the context.
 *
 * @param {input} the input message.
 *
 * @param {len} the number btye of message.
 *
 */
void MD5::init(const byte* input, size_t len) {

    bit32 i, index, partLen;

    finished = false;

    /* Compute number of bytes mod 64 */
    index = (bit32)((count[0] >> 3) & 0x3f);

    /* update number of bits */
    if ((count[0] += ((bit32)len << 3)) < ((bit32)len << 3)) {
        ++count[1];
    }
    count[1] += ((bit32)len >> 29);

    partLen = 64 - index;

    /* transform as many times as possible. */
    if (len >= partLen) {

        memcpy(&buffer[index], input, partLen);
        transform(buffer);

        for (i = partLen; i + 63 < len; i += 64) {
            transform(&input[i]);
        }
        index = 0;

    } else {
        i = 0;
    }

    /* Buffer remaining input */
    memcpy(&buffer[index], &input[i], len - i);
}

void MD5::transform(const byte block[64]) {

    bit32 a = state[0], b = state[1], c = state[2], d = state[3], x[16];

    decode(block, x, 64);

    /* Round 1 */
    FF (a, b, c, d, x[ 0], s11, 0xd76aa478);
    FF (d, a, b, c, x[ 1], s12, 0xe8c7b756);
    FF (c, d, a, b, x[ 2], s13, 0x242070db);
    FF (b, c, d, a, x[ 3], s14, 0xc1bdceee);
    FF (a, b, c, d, x[ 4], s11, 0xf57c0faf);
    FF (d, a, b, c, x[ 5], s12, 0x4787c62a);
    FF (c, d, a, b, x[ 6], s13, 0xa8304613);
    FF (b, c, d, a, x[ 7], s14, 0xfd469501);
    FF (a, b, c, d, x[ 8], s11, 0x698098d8);
    FF (d, a, b, c, x[ 9], s12, 0x8b44f7af);
    FF (c, d, a, b, x[10], s13, 0xffff5bb1);
    FF (b, c, d, a, x[11], s14, 0x895cd7be);
    FF (a, b, c, d, x[12], s11, 0x6b901122);
    FF (d, a, b, c, x[13], s12, 0xfd987193);
    FF (c, d, a, b, x[14], s13, 0xa679438e);
    FF (b, c, d, a, x[15], s14, 0x49b40821);

    /* Round 2 */
    GG (a, b, c, d, x[ 1], s21, 0xf61e2562);
    GG (d, a, b, c, x[ 6], s22, 0xc040b340);
    GG (c, d, a, b, x[11], s23, 0x265e5a51);
    GG (b, c, d, a, x[ 0], s24, 0xe9b6c7aa);
    GG (a, b, c, d, x[ 5], s21, 0xd62f105d);
    GG (d, a, b, c, x[10], s22,  0x2441453);
    GG (c, d, a, b, x[15], s23, 0xd8a1e681);
    GG (b, c, d, a, x[ 4], s24, 0xe7d3fbc8);
    GG (a, b, c, d, x[ 9], s21, 0x21e1cde6);
    GG (d, a, b, c, x[14], s22, 0xc33707d6);
    GG (c, d, a, b, x[ 3], s23, 0xf4d50d87);
    GG (b, c, d, a, x[ 8], s24, 0x455a14ed);
    GG (a, b, c, d, x[13], s21, 0xa9e3e905);
    GG (d, a, b, c, x[ 2], s22, 0xfcefa3f8);
    GG (c, d, a, b, x[ 7], s23, 0x676f02d9);
    GG (b, c, d, a, x[12], s24, 0x8d2a4c8a);

    /* Round 3 */
    HH (a, b, c, d, x[ 5], s31, 0xfffa3942);
    HH (d, a, b, c, x[ 8], s32, 0x8771f681);
    HH (c, d, a, b, x[11], s33, 0x6d9d6122);
    HH (b, c, d, a, x[14], s34, 0xfde5380c);
    HH (a, b, c, d, x[ 1], s31, 0xa4beea44);
    HH (d, a, b, c, x[ 4], s32, 0x4bdecfa9);
    HH (c, d, a, b, x[ 7], s33, 0xf6bb4b60);
    HH (b, c, d, a, x[10], s34, 0xbebfbc70);
    HH (a, b, c, d, x[13], s31, 0x289b7ec6);
    HH (d, a, b, c, x[ 0], s32, 0xeaa127fa);
    HH (c, d, a, b, x[ 3], s33, 0xd4ef3085);
    HH (b, c, d, a, x[ 6], s34,  0x4881d05);
    HH (a, b, c, d, x[ 9], s31, 0xd9d4d039);
    HH (d, a, b, c, x[12], s32, 0xe6db99e5);
    HH (c, d, a, b, x[15], s33, 0x1fa27cf8);
    HH (b, c, d, a, x[ 2], s34, 0xc4ac5665);

    /* Round 4 */
    II (a, b, c, d, x[ 0], s41, 0xf4292244);
    II (d, a, b, c, x[ 7], s42, 0x432aff97);
    II (c, d, a, b, x[14], s43, 0xab9423a7);
    II (b, c, d, a, x[ 5], s44, 0xfc93a039);
    II (a, b, c, d, x[12], s41, 0x655b59c3);
    II (d, a, b, c, x[ 3], s42, 0x8f0ccc92);
    II (c, d, a, b, x[10], s43, 0xffeff47d);
    II (b, c, d, a, x[ 1], s44, 0x85845dd1);
    II (a, b, c, d, x[ 8], s41, 0x6fa87e4f);
    II (d, a, b, c, x[15], s42, 0xfe2ce6e0);
    II (c, d, a, b, x[ 6], s43, 0xa3014314);
    II (b, c, d, a, x[13], s44, 0x4e0811a1);
    II (a, b, c, d, x[ 4], s41, 0xf7537e82);
    II (d, a, b, c, x[11], s42, 0xbd3af235);
    II (c, d, a, b, x[ 2], s43, 0x2ad7d2bb);
    II (b, c, d, a, x[ 9], s44, 0xeb86d391);

    state[0] += a;
    state[1] += b;
    state[2] += c;
    state[3] += d;
}

/**
* @Encodes input (unsigned long) into output (byte).
*
* @param {input} usigned long.
*
* @param {output} byte.
*
* @param {length} the length of input.
*
*/
void MD5::encode(const bit32* input, byte* output, size_t length) {

    for (size_t i = 0, j = 0; j < length; ++i, j += 4) {
        output[j]= (byte)(input[i] & 0xff);
        output[j + 1] = (byte)((input[i] >> 8) & 0xff);
        output[j + 2] = (byte)((input[i] >> 16) & 0xff);
        output[j + 3] = (byte)((input[i] >> 24) & 0xff);
    }
}

/**
 * @Decodes input (byte) into output (usigned long).
 *
 * @param {input} bytes.
 *
 * @param {output} unsigned long.
 *
 * @param {length} the length of input.
 *
 */
void MD5::decode(const byte* input, bit32* output, size_t length) {
    for (size_t i = 0, j = 0; j < length; ++i, j += 4) {
        output[i] = ((bit32)input[j]) | (((bit32)input[j + 1]) << 8) |
                    (((bit32)input[j + 2]) << 16) | (((bit32)input[j + 3]) << 24);
    }
}

/**
 * @Convert digest to string value.
 *
 * @return the hex string of digest.
 *
 */
string MD5::toStr() {
    const byte* digest_ = getDigest();
    string str;
    str.reserve(16 << 1);
    for (size_t i = 0; i < 16; ++i) {
        int t = digest_[i];
        int a = t / 16;
        int b = t % 16;
        str.append(1, HEX_NUMBERS[a]);
        str.append(1, HEX_NUMBERS[b]);
    }
    return str;
}

使用MD5算法

引入 MD5 算法后,就可以在 hello.cpp 里的 Md5() 方法内实现 MD5 算法了,使用流程如下:

  • 引入头文件

    引入头文件的目的是调用其提供的 MD5 计算方法,和 JS 里的 import 功能类似。

    #include "./md5/md5.h"
  • 使用md5算法

修改 hello.cpp 里的 Md5() 方法内容如下所示:

    static napi_value Md5(napi_env env, napi_callback_info info) {
        // 1、从info中取出JS传递过来的参数放入args
        size_t argc = 1;
        napi_value args[1] = { nullptr };
        if (napi_ok != napi_get_cb_info(env, info, &argc, args, nullptr, nullptr)) {
            napi_throw_error(env, "-1000", "napi_get_cb_info error");
            return nullptr;
        }

        // 2、获取参数的类型
        napi_valuetype stringType;
        if (napi_ok != napi_typeof(env, args[0], &stringType)) {
            napi_throw_error(env, "-1001", "napi_typeof error");
            return nullptr;
        }

        // 3、如果参数为null,这抛异常
        if (napi_null == stringType) {
            napi_throw_error(env, "-1002", "the param can't be null");
            return nullptr;
        }

        // 4、获取传递的string长度
        size_t length = 0;
        if (napi_ok != napi_get_value_string_utf8(env, args[0], nullptr, 0, &length)) {
            napi_throw_error(env, "-1003", "napi_get_value_string_utf8 error");
            return nullptr;
        }

        // 5、如果传递的是"",则抛异常
        if (length == 0) {
            napi_throw_error(env, "-1004", "the param length invalid");
            return nullptr;
        }

        // 6、读取传递的string参数放入buffer中
        char* buffer = new char[length + 1];
        if (napi_ok != napi_get_value_string_utf8(env, args[0], buffer, length + 1, &length)) {
            delete[] buffer;
            buffer = nullptr;
            napi_throw_error(env, "-1005", "napi_get_value_string_utf8 error");
            return nullptr;
        }

        // **********************************************************************
        // ********************************MD5加密********************************
        // 7、计算MD5加密操作
        std::string str = buffer;
        // MD5 加密计算
        str = MD5(str).toStr();
        // **********************************************************************
        // ********************************MD5加密********************************

        // 8、把C++数据转成napi_value并返回
        napi_value value = nullptr;
        const char* md5 = str.c_str();
        if (napi_ok != napi_create_string_utf8(env, md5, strlen(md5), &value)) {
            delete[] buffer;
            buffer = nullptr;
            napi_throw_error(env, "-1006", "napi_create_string_utf8 error");
            return nullptr;
        }

        // 9、资源清理
        delete[] buffer;
        buffer = nullptr;

        return value;
    }

主要看第 7 步:直接创建 MD5 后调用其 toStr() 方法即可生成加密后的字符串。

修改CMake文件

增加了 MD5 计算的源码,需要修改 CMakeLists.txt 文件,目的是把计算 MD5 的源文件打包进 so 中,修改后的代码如下所示:

# the minimum version of CMake.
cmake_minimum_required(VERSION 3.4.1)
project(oh_0400_napi)

set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})

include_directories(${NATIVERENDER_ROOT_PATH}
                    ${NATIVERENDER_ROOT_PATH}/include)

# 把 md5.cpp 源文件引入
add_library(entry SHARED hello.cpp ./md5/md5.cpp)

target_link_libraries(entry PUBLIC libace_napi.z.so)

测试MD5算法

根据 Md5() 方法的实现,限制条件是不允许数据 null 和 “”,如果输入则抛异常。因此可测试以下三种场景:正常参数,null 参数和 “” 参数,样例代码如下所示:

import testNapi from 'libentry.so'

@Entry @Component struct Index {

  @State message: string = 'Hello,OpenHarmony'

  build() {
    Column({space: 10}) {

      Text(this.message)
        .fontSize(20)

      Button("正常参数")
        .onClick(() => {
          this.message = testNapi.md5("Hello, OpenHarmony")
        })

      Button("null参数")
        .onClick(() => {
          this.message = testNapi.md5(null);
        })

      Button("\"\"参数")
        .onClick(() => {
          this.message = testNapi.md5("");
        })
    }
    .padding(10)
    .width('100%')
    .height("100%")
  }
}

点解 正常参数 按钮,输出结果和在线网站上计算的结果一致,非常棒(#.#),样例运行结果如下所示:

小结

本节笔者通过引入三方库的方式实现了 MD5 的计算,当前只是一个简单的计算,如果是一个非常复杂的耗时计算,就会阻塞主线程,因此需要实现异步方法,笔者将要在下节讲解一下异步的实现方式。

码牛课堂也为了积极培养鸿蒙生态人才,让大家都能学习到鸿蒙开发最新的技术,针对一些在职人员、0基础小白、应届生/计算机专业、鸿蒙爱好者等人群,整理了一套纯血版鸿蒙(HarmonyOS Next)全栈开发技术的学习路线。大家可以进行参考学习:https://qr21.cn/FV7h05

①全方位,更合理的学习路径
路线图包括ArkTS基础语法、鸿蒙应用APP开发、鸿蒙能力集APP开发、次开发多端部署开发、物联网开发等九大模块,六大实战项目贯穿始终,由浅入深,层层递进,深入理解鸿蒙开发原理!

②多层次,更多的鸿蒙原生应用
路线图将包含完全基于鸿蒙内核开发的应用,比如一次开发多端部署、自由流转、元服务、端云一体化等,多方位的学习内容让学生能够高效掌握鸿蒙开发,少走弯路,真正理解并应用鸿蒙的核心技术和理念。

③实战化,更贴合企业需求的技术点
学习路线图中的每一个技术点都能够紧贴企业需求,经过多次真实实践,每一个知识点、每一个项目,都是码牛课堂鸿蒙研发团队精心打磨和深度解析的成果,注重对学生的细致教学,每一步都确保学生能够真正理解和掌握。

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:https://qr21.cn/FV7h05

如何快速入门:

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

鸿蒙开发面试真题(含参考答案):https://qr21.cn/FV7h05

大厂鸿蒙面试题::https://qr18.cn/F781PH

鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH

1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值