鸿蒙系统开发【加解密】安全

加解密

介绍

本示例使用cryptoFramework接口的Cipher对象相关方法实现了字符串加解密算法,包括RSA加密算法与AES加密算法。

RSA加密算法:RSA公开密钥密码体制是一种使用不同的加密密钥与解密密钥,由已知加密密钥推导出解密密钥在计算上是不可行的密码体制。

AES加密算法:AES密码学中的高级加密标准,又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。

效果预览

1

使用说明

1.点击主页面的加密按钮,在加密界面中点击Encryption Algorithm下拉选择加密算法,在输入框中输入待加密的内容,点击加密 按钮,下方文本框中显示加密后内容。

2.点击重置按钮,清除文本框中内容。

3.点击主页面的解密按钮,在解密界面中点击Decrypt Algorithm下拉选择解密算法,在输入框中输入待解密的内容,点击解密 按钮,下方文本框中显示解密后内容。

4.点击重置按钮,清除文本框中内容。

具体实现

  • 本示例分成加密与解密两个模块

    • 加密模块

      • 使用到rsaEncrypt(RSA算法加密)与aesEncrypt(AES算法加密)两种加密方法进行加密操作。
      • 源码:[Encrypt.ets]
/*
 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { promptAction } from '@kit.ArkUI';
import { CipherModel } from '../model/CipherModel';
import Logger from '../model/Logger';

const TAG: string = '[Encrypt]';

@Component
export struct Encrypt {
  @State info: string = '';
  @State message: string = '';
  @State algorithmType: string = 'Encrypt Algorithm';
  private cipherModel: CipherModel = new CipherModel();

  build() {
    Stack({ alignContent: Alignment.Center }) {
      Column() {
        Select([{ value: 'RSA' },
          { value: 'AES' }])
          .id('encryptAlgorithm')
          .margin(4)
          .selected(0)
          .value(this.algorithmType)
          .font({ size: 20, weight: 300, family: 'serif', style: FontStyle.Normal })
          .optionFont({ size: 16, weight: 280, family: 'serif', style: FontStyle.Normal })
          .selectedOptionFont({ size: 16, weight: 280, family: 'serif', style: FontStyle.Normal })
          .onSelect((index: number, value: string) => {
            this.algorithmType = value;
            Logger.info(TAG, `Select: ${index} value: ${value}`);
          })

        TextArea()
          .margin(4)
          .width('60%')
          .id('encryptInput')
          .onChange((value: string) => {
            this.message = value;
          })

        Row() {
          Button($r('app.string.encrypt'))
            .margin(10)
            .fontSize(20)
            .width('30%')
            .height('6%')
            .id('encryptionBtn')
            .onClick(() => {
              if (this.message === '') {
                promptAction.showToast({
                  message: 'This message is null.'
                })
              } else {
                if (this.algorithmType === 'RSA') {
                  this.cipherModel.rsaEncrypt(this.message, (result: string) => {
                    Logger.info(TAG, `this result = ${JSON.stringify(result)}`);
                    this.info = `Encryption result is :  ${result}`;
                  })
                } else {
                  this.cipherModel.aesEncrypt(this.message, (result: string) => {
                    Logger.info(TAG, `this result = ${JSON.stringify(result)}`);
                    this.info = `Encryption result is :  ${result}`;
                  })
                }
              }
            })

          Button($r('app.string.reset'))
            .margin(10)
            .fontSize(20)
            .width('30%')
            .height('6%')
            .id('encryptionResetBtn')
            .onClick(() => {
              this.info = '';
            })
        }
        .margin(10)

        Text(this.info)
          .id('encryptionInfo')
          .fontSize(18)
          .width('85%')
          .height('25%')
          .border({ width: 2, color: Color.Black })
          .margin(10)
          .copyOption(CopyOptions.InApp)
      }
    }
    .width('100%')
    .height('100%')
  }
}
  • 源码[CipherModel.ts]
/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { cryptoFramework } from "@kit.CryptoArchitectureKit";
import { buffer, util } from '@kit.ArkTS';
import Logger from './Logger';
import { BusinessError } from '@kit.BasicServicesKit';

const TAG: string = '[CipherModel]'
const AES_ENCRYPT_KEY: string = '5QXzAbJj0TJN9OQNvxFhhw==';
const RSA_ENCRYPT_KEY: string =
  'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALXJZEloyLbBB6UbUQzUtM3WGTkcd4dn4HgCxL5wHcdICoLbv6EiUjcaQq8c906hqv6/J7Bv9Owj59XMauKweJUCAwEAAQ==';
const RSA_DECRYPT_KEY: string =
  'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAtclkSWjItsEHpRtRDNS0zdYZORx3h2fgeALEvnAdx0gKgtu/oSJSNxpCrxz3TqGq/r8nsG/07CPn1cxq4rB4lQIDAQABAkA3boG2IM2TbKj4H6xHTVUUrwRh9dw83eAEuFNl/qoV6c4zRUAx+efZ29rDz6CVWuAhxaVBDUOmOHvyxOL8m8IBAiEA3EcTP1jngtiJ8lffvIVbehM6p7437+9UScKMXZSy/PkCIQDTRFj00GbAW9oKqEWTrUCWNxNFCSR82Mlw1sZvQh5LfQIgBApBrh3BUUMLdKhr8Bc6EEkeAEma2Qm4sAmjbWv2xHECIF81ux1BWj0wZ9hLs2d1Odk4ot+G2kHFdSr8L9tuIbcFAiEA2rEXmzyQTxZM1N4QDkaLJiCwSfMTYu48DxfUcevbfhA=';
const RSA512_PRIMES_2: string = 'RSA512|PRIMES_2';
const RSA512_PKCS1: string = 'RSA512|PKCS1';
const AES128: string = 'AES128';
const AES128_PKCS7: string = 'AES128|PKCS7';

export class CipherModel {
  stringToUint8Array(str) {
    return new Uint8Array(buffer.from(str, 'utf-8').buffer);
  }

  uint8ArrayToString(array: Uint8Array) {
    let out: string = '';
    let index: number = 0;
    let len: number = array.length;
    while (index < len) {
      let character = array[index++];
      switch (character >> 4) {
        case 0:
        case 1:
        case 2:
        case 3:
        case 4:
        case 5:
        case 6:
        case 7:
          out += String.fromCharCode(character);
          break;
        case 12:
        case 13:
          out += String.fromCharCode(((character & 0x1F) << 6) | (array[index++] & 0x3F));
          break;
        case 14:
          out += String.fromCharCode(((character & 0x0F) << 12) | ((array[index++] & 0x3F) << 6) |
            ((array[index++] & 0x3F) << 0));
          break;
        default:
          break;
      }
    }
    return out;
  }

  rsaEncrypt(message: string, callback) {
    let rsaGenerator = cryptoFramework.createAsyKeyGenerator(RSA512_PRIMES_2);
    let cipher = cryptoFramework.createCipher(RSA512_PKCS1);
    let that = new util.Base64Helper();
    let pubKey = that.decodeSync(RSA_ENCRYPT_KEY);
    let pubKeyBlob: cryptoFramework.DataBlob = { data: pubKey };
    rsaGenerator.convertKey(pubKeyBlob, null, (err, keyPair) => {
      if (err) {
        Logger.error("convertKey: error." + (err as BusinessError).code);
        return;
      }
      cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, keyPair.pubKey, null, (err, data) => {
        let input: cryptoFramework.DataBlob = { data: this.stringToUint8Array(message) };
        cipher.doFinal(input, (err, data) => {
          Logger.info(TAG, "EncryptOutPut is " + data.data);
          let result = that.encodeToStringSync(data.data)
          Logger.info(TAG, "result is " + result);
          callback(result)
        })
      })
    })
  }

  rsaDecrypt(message: string, callback) {
    let rsaGenerator = cryptoFramework.createAsyKeyGenerator(RSA512_PRIMES_2);
    let cipher = cryptoFramework.createCipher(RSA512_PKCS1);
    let that = new util.Base64Helper();
    let priKey = that.decodeSync(RSA_DECRYPT_KEY);
    let priKeyBlob: cryptoFramework.DataBlob = { data: priKey };
    rsaGenerator.convertKey(null, priKeyBlob, (err, keyPair) => {
      if (err) {
        Logger.error(TAG, "convertKey: error." + (err as BusinessError).code);
        return;
      }
      cipher.init(cryptoFramework.CryptoMode.DECRYPT_MODE, keyPair.priKey, null, (err, data) => {
        try {
          let newMessage = that.decodeSync(message);
          let input: cryptoFramework.DataBlob = { data: newMessage };
          cipher.doFinal(input, (err, data) => {
            if (err) {
              Logger.error(TAG, "cipher doFinal." + (err as BusinessError).code);
              return;
            }
            Logger.info(TAG, "DecryptOutPut is " + data.data);
            let result = this.uint8ArrayToString(data.data);
            Logger.info(TAG, "result is " + result);
            callback(result)
          })
        } catch (err) {
          Logger.info(TAG, "cipher init error: " + (err as BusinessError).code);
          return err;
        }
      })
    })
  }

  aesEncrypt(message: string, callback) {
    let aesGenerator = cryptoFramework.createSymKeyGenerator(AES128);
    let cipher = cryptoFramework.createCipher(AES128_PKCS7);
    let that = new util.Base64Helper();
    let pubKey = that.decodeSync(AES_ENCRYPT_KEY);
    let pubKeyBlob: cryptoFramework.DataBlob = { data: pubKey };
    aesGenerator.convertKey(pubKeyBlob, (err, symKey) => {
      if (err) {
        console.error("convertKey: error." + (err as BusinessError).code);
        return;
      }
      cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, symKey, null, (err, data) => {
        let input: cryptoFramework.DataBlob = { data: this.stringToUint8Array(message) };
        cipher.doFinal(input, (err, data) => {
          Logger.info(TAG, "EncryptOutPut is " + data.data);
          let result = that.encodeToStringSync(data.data)
          Logger.info(TAG, "result is " + result);
          callback(result)
        })
      })
    })
  }

  aesDecrypt(message: string, callback) {
    let aesGenerator = cryptoFramework.createSymKeyGenerator(AES128);
    let cipher = cryptoFramework.createCipher(AES128_PKCS7);
    let that = new util.Base64Helper();
    let pubKey = that.decodeSync(AES_ENCRYPT_KEY);
    let pubKeyBlob: cryptoFramework.DataBlob = { data: pubKey };
    aesGenerator.convertKey(pubKeyBlob, (err, symKey) => {
      if (err) {
        console.error("convertKey: error." + (err as BusinessError).code);
        return;
      }
      cipher.init(cryptoFramework.CryptoMode.DECRYPT_MODE, symKey, null, (err, data) => {
        try {
          let newMessage = that.decodeSync(message);
          let input: cryptoFramework.DataBlob = { data: newMessage };
          cipher.doFinal(input, (err, data) => {
            if (err) {
              Logger.error(TAG, "cipher doFinal." + (err as BusinessError).code);
              return;
            }
            Logger.info(TAG, "DecryptOutPut is " + data?.data);
            let result = this.uint8ArrayToString(data?.data)
            Logger.info(TAG, "result is " + result);
            callback(result)
          })
        } catch (err) {
          Logger.info(TAG, "cipher init error: " + (err as BusinessError).code);
          return err;
        }
      })
    })
  }
}
  • 接口参考:@ohos.security.cryptoFramework,@ohos.promptAction,@ohos.router

  • 解密模块

  • 使用到rsaDecrypt(RSA算法解密)与aesDecrypt(AES算法解密)两种解密方法进行解密操作。

  • 源码:[Decrypt.ets]

/*
 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { promptAction } from '@kit.ArkUI';
import { CipherModel } from '../model/CipherModel';
import Logger from '../model/Logger';

const TAG: string = '[Decrypt]';

@Component
export struct Decrypt {
  @State info: string = '';
  @State message: string = '';
  @State algorithmType: string = 'Decrypt Algorithm';
  private cipherModel: CipherModel = new CipherModel();

  build() {
    Stack({ alignContent: Alignment.Center }) {
      Column() {
        Select([{ value: 'RSA' },
          { value: 'AES' }])
          .id('decryptAlgorithm')
          .margin(4)
          .selected(0)
          .value(this.algorithmType)
          .font({ size: 20, weight: 300, family: 'serif', style: FontStyle.Normal })
          .selectedOptionFont({ size: 16, weight: 280, family: 'serif', style: FontStyle.Normal })
          .optionFont({ size: 16, weight: 280, family: 'serif', style: FontStyle.Normal })
          .onSelect((index: number, value: string) => {
            this.algorithmType = value;
            Logger.info(TAG, `Select: ${index} value: ${value}`);
          })

        TextArea()
          .id('decryptInput')
          .margin(6)
          .width('60%')
          .onChange((value: string) => {
            this.message = value;
          })

        Row() {
          Button($r('app.string.decrypt'))
            .fontSize(20)
            .margin(10)
            .width('30%')
            .height('6%')
            .id('decryptBtn')
            .onClick(() => {
              if (this.message === '') {
                promptAction.showToast({
                  message: 'This message is null.'
                })
              } else {
                if (this.algorithmType === 'RSA') {
                  this.cipherModel.rsaDecrypt(this.message, (result: string) => {
                    Logger.info(TAG, `this result = ${JSON.stringify(result)}`);
                    this.info = `Decrypt result is :  ${result}`;
                  })
                } else {
                  this.cipherModel.aesDecrypt(this.message, (result: string) => {
                    Logger.info(TAG, `this result = ${JSON.stringify(result)}`);
                    this.info = `Decrypt result is :  ${result}`;
                  })
                }
              }
            })

          Button($r('app.string.reset'))
            .fontSize(20)
            .margin(10)
            .width('30%')
            .height('6%')
            .id('decryptResetBtn')
            .onClick(() => {
              this.info = '';
            })
        }
        .margin(10)

        Text(this.info)
          .id('decryptInfo')
          .fontSize(18)
          .width('85%')
          .height('25%')
          .border({ width: 2, color: Color.Black })
          .margin(10)
      }
    }
    .width('100%')
    .height('100%')
  }
}

源码[CipherModel.ts]

/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { cryptoFramework } from "@kit.CryptoArchitectureKit";
import { buffer, util } from '@kit.ArkTS';
import Logger from './Logger';
import { BusinessError } from '@kit.BasicServicesKit';

const TAG: string = '[CipherModel]'
const AES_ENCRYPT_KEY: string = '5QXzAbJj0TJN9OQNvxFhhw==';
const RSA_ENCRYPT_KEY: string =
  'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALXJZEloyLbBB6UbUQzUtM3WGTkcd4dn4HgCxL5wHcdICoLbv6EiUjcaQq8c906hqv6/J7Bv9Owj59XMauKweJUCAwEAAQ==';
const RSA_DECRYPT_KEY: string =
  'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAtclkSWjItsEHpRtRDNS0zdYZORx3h2fgeALEvnAdx0gKgtu/oSJSNxpCrxz3TqGq/r8nsG/07CPn1cxq4rB4lQIDAQABAkA3boG2IM2TbKj4H6xHTVUUrwRh9dw83eAEuFNl/qoV6c4zRUAx+efZ29rDz6CVWuAhxaVBDUOmOHvyxOL8m8IBAiEA3EcTP1jngtiJ8lffvIVbehM6p7437+9UScKMXZSy/PkCIQDTRFj00GbAW9oKqEWTrUCWNxNFCSR82Mlw1sZvQh5LfQIgBApBrh3BUUMLdKhr8Bc6EEkeAEma2Qm4sAmjbWv2xHECIF81ux1BWj0wZ9hLs2d1Odk4ot+G2kHFdSr8L9tuIbcFAiEA2rEXmzyQTxZM1N4QDkaLJiCwSfMTYu48DxfUcevbfhA=';
const RSA512_PRIMES_2: string = 'RSA512|PRIMES_2';
const RSA512_PKCS1: string = 'RSA512|PKCS1';
const AES128: string = 'AES128';
const AES128_PKCS7: string = 'AES128|PKCS7';

export class CipherModel {
  stringToUint8Array(str) {
    return new Uint8Array(buffer.from(str, 'utf-8').buffer);
  }

  uint8ArrayToString(array: Uint8Array) {
    let out: string = '';
    let index: number = 0;
    let len: number = array.length;
    while (index < len) {
      let character = array[index++];
      switch (character >> 4) {
        case 0:
        case 1:
        case 2:
        case 3:
        case 4:
        case 5:
        case 6:
        case 7:
          out += String.fromCharCode(character);
          break;
        case 12:
        case 13:
          out += String.fromCharCode(((character & 0x1F) << 6) | (array[index++] & 0x3F));
          break;
        case 14:
          out += String.fromCharCode(((character & 0x0F) << 12) | ((array[index++] & 0x3F) << 6) |
            ((array[index++] & 0x3F) << 0));
          break;
        default:
          break;
      }
    }
    return out;
  }

  rsaEncrypt(message: string, callback) {
    let rsaGenerator = cryptoFramework.createAsyKeyGenerator(RSA512_PRIMES_2);
    let cipher = cryptoFramework.createCipher(RSA512_PKCS1);
    let that = new util.Base64Helper();
    let pubKey = that.decodeSync(RSA_ENCRYPT_KEY);
    let pubKeyBlob: cryptoFramework.DataBlob = { data: pubKey };
    rsaGenerator.convertKey(pubKeyBlob, null, (err, keyPair) => {
      if (err) {
        Logger.error("convertKey: error." + (err as BusinessError).code);
        return;
      }
      cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, keyPair.pubKey, null, (err, data) => {
        let input: cryptoFramework.DataBlob = { data: this.stringToUint8Array(message) };
        cipher.doFinal(input, (err, data) => {
          Logger.info(TAG, "EncryptOutPut is " + data.data);
          let result = that.encodeToStringSync(data.data)
          Logger.info(TAG, "result is " + result);
          callback(result)
        })
      })
    })
  }

  rsaDecrypt(message: string, callback) {
    let rsaGenerator = cryptoFramework.createAsyKeyGenerator(RSA512_PRIMES_2);
    let cipher = cryptoFramework.createCipher(RSA512_PKCS1);
    let that = new util.Base64Helper();
    let priKey = that.decodeSync(RSA_DECRYPT_KEY);
    let priKeyBlob: cryptoFramework.DataBlob = { data: priKey };
    rsaGenerator.convertKey(null, priKeyBlob, (err, keyPair) => {
      if (err) {
        Logger.error(TAG, "convertKey: error." + (err as BusinessError).code);
        return;
      }
      cipher.init(cryptoFramework.CryptoMode.DECRYPT_MODE, keyPair.priKey, null, (err, data) => {
        try {
          let newMessage = that.decodeSync(message);
          let input: cryptoFramework.DataBlob = { data: newMessage };
          cipher.doFinal(input, (err, data) => {
            if (err) {
              Logger.error(TAG, "cipher doFinal." + (err as BusinessError).code);
              return;
            }
            Logger.info(TAG, "DecryptOutPut is " + data.data);
            let result = this.uint8ArrayToString(data.data);
            Logger.info(TAG, "result is " + result);
            callback(result)
          })
        } catch (err) {
          Logger.info(TAG, "cipher init error: " + (err as BusinessError).code);
          return err;
        }
      })
    })
  }

  aesEncrypt(message: string, callback) {
    let aesGenerator = cryptoFramework.createSymKeyGenerator(AES128);
    let cipher = cryptoFramework.createCipher(AES128_PKCS7);
    let that = new util.Base64Helper();
    let pubKey = that.decodeSync(AES_ENCRYPT_KEY);
    let pubKeyBlob: cryptoFramework.DataBlob = { data: pubKey };
    aesGenerator.convertKey(pubKeyBlob, (err, symKey) => {
      if (err) {
        console.error("convertKey: error." + (err as BusinessError).code);
        return;
      }
      cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, symKey, null, (err, data) => {
        let input: cryptoFramework.DataBlob = { data: this.stringToUint8Array(message) };
        cipher.doFinal(input, (err, data) => {
          Logger.info(TAG, "EncryptOutPut is " + data.data);
          let result = that.encodeToStringSync(data.data)
          Logger.info(TAG, "result is " + result);
          callback(result)
        })
      })
    })
  }

  aesDecrypt(message: string, callback) {
    let aesGenerator = cryptoFramework.createSymKeyGenerator(AES128);
    let cipher = cryptoFramework.createCipher(AES128_PKCS7);
    let that = new util.Base64Helper();
    let pubKey = that.decodeSync(AES_ENCRYPT_KEY);
    let pubKeyBlob: cryptoFramework.DataBlob = { data: pubKey };
    aesGenerator.convertKey(pubKeyBlob, (err, symKey) => {
      if (err) {
        console.error("convertKey: error." + (err as BusinessError).code);
        return;
      }
      cipher.init(cryptoFramework.CryptoMode.DECRYPT_MODE, symKey, null, (err, data) => {
        try {
          let newMessage = that.decodeSync(message);
          let input: cryptoFramework.DataBlob = { data: newMessage };
          cipher.doFinal(input, (err, data) => {
            if (err) {
              Logger.error(TAG, "cipher doFinal." + (err as BusinessError).code);
              return;
            }
            Logger.info(TAG, "DecryptOutPut is " + data?.data);
            let result = this.uint8ArrayToString(data?.data)
            Logger.info(TAG, "result is " + result);
            callback(result)
          })
        } catch (err) {
          Logger.info(TAG, "cipher init error: " + (err as BusinessError).code);
          return err;
        }
      })
    })
  }
}
  • 接口参考:@ohos.security.cryptoFramework,@ohos.promptAction,@ohos.router

以上就是本篇文章所带来的鸿蒙开发中一小部分技术讲解;想要学习完整的鸿蒙全栈技术。可以在结尾找我可全部拿到!
下面是鸿蒙的完整学习路线,展示如下:
1

除此之外,根据这个学习鸿蒙全栈学习路线,也附带一整套完整的学习【文档+视频】,内容包含如下

内容包含了:(ArkTS、ArkUI、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、鸿蒙南向开发、鸿蒙项目实战)等技术知识点。帮助大家在学习鸿蒙路上快速成长!

鸿蒙【北向应用开发+南向系统层开发】文档

鸿蒙【基础+实战项目】视频

鸿蒙面经

在这里插入图片描述

为了避免大家在学习过程中产生更多的时间成本,对比我把以上内容全部放在了↓↓↓想要的可以自拿喔!谢谢大家观看!

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值