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

加解密

介绍

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

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

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

效果预览

使用说明

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

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

下面是鸿蒙的完整学习路线 ,展示如下:

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

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

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

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

鸿蒙面经

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

相关推荐
SoraLuna1 小时前
「Mac畅玩鸿蒙与硬件28」UI互动应用篇5 - 滑动选择器实现
macos·ui·harmonyos
hikktn2 小时前
如何在 Rust 中实现内存安全:与 C/C++ 的对比分析
c语言·安全·rust
ClkLog-开源埋点用户分析2 小时前
ClkLog企业版(CDP)预售开启,更有鸿蒙SDK前来助力
华为·开源·开源软件·harmonyos
mg6683 小时前
鸿蒙系统的优势 开发 环境搭建 开发小示例
华为·harmonyos
模拟IC攻城狮3 小时前
华为海思招聘-芯片与器件设计工程师-模拟芯片方向- 机试题-真题套题题目——共8套(每套四十题)
嵌入式硬件·华为·硬件架构·芯片
lqj_本人3 小时前
鸿蒙next选择 Flutter 开发跨平台应用的原因
flutter·华为·harmonyos
lqj_本人3 小时前
使用 Flutter 绘制一个棋盘
harmonyos
TangKenny3 小时前
计算网络信号
java·算法·华为
23zhgjx-NanKon4 小时前
华为eNSP:QinQ
网络·安全·华为
23zhgjx-NanKon4 小时前
华为eNSP:mux-vlan
网络·安全·华为