安卓JNI精細化講解,讓你徹底瞭解JNI(一):環境搭建與HelloWord

来源:https://www.cnblogs.com/qixingchao/archive/2019/11/22/11911764.html
-Advertisement-
Play Games

目錄 "1、基礎概念" "├──1.1、JNI" "├──1.2、NDK" "├──1.3、CMake與ndk build" "2、環境搭建" "3、Native C++ 項目(HelloWord案例)" "├── 3.1、項目創建(java、kotlin)" "├── 3.2、CMake的應用(詳 ...


目錄
1、基礎概念
├──1.1、JNI
├──1.2、NDK
├──1.3、CMake與ndk-build
2、環境搭建
3、Native C++ 項目(HelloWord案例)
├── 3.1、項目創建(java、kotlin)
├── 3.2、CMake的應用(詳細講解)
├── 3.3、ndk-build的應用(詳細講解)

1、基礎概念

1.1、JNI

JNI(Java Native Interface)Java本地介面,使得Java與C/C++具有交互能力

1.2、NDK

NDK(Native Development Kit) 本地開發工具包,允許使用原生語言(C和C++)來實現應用程式的部分功能

Android NDK開發的主要作用:

1、特定場景下,提升應用性能;
2、代碼保護,增加反編譯難度;
3、生成庫文件,庫可重覆使用,也便於平臺、項目間移植;

1.3、CMake與ndk-build

當我們基於NDK開發出native功能後,通常需要編譯成庫文件,給Android項目使用。
目前,有兩種主流的編譯方式:__CMake__與ndk-build

__CMake__與__ndk-build__是兩種不同的編譯工具(與Android代碼和C/C++代碼無關)

CMake

CMake是Androidstudio2.2之後引入的跨平臺編譯工具(特點:簡單易用,2.2之後是預設的NDK編譯工具)

如何配置:
   1、創建CMakeLists.txt文件,配置CMake必要參數;
   2、使用gradle配置CMakeLists.txt以及native相關參數;

如何編譯庫文件:
   1、Android Studio執行Build即可;

ndk-build

ndk-build是NDK中包含的腳本工具(可在NDK目錄下找到該工具,為了方便使用,通常配置NDK的環境變數)

如何配置:
   1、創建Android.mk文件,配置ndk-build必要參數;
   2、可選創建application.mk文件,配置ndk-build參數 (該文件的配置項可使用gradle的配置替代);
   3、使用gradle配置Android.mk以及native相關參數;

2、如何編譯庫文件(兩種方式):
   1、Android Studio執行Build即可(執行了:Android.mk + gradle配置);
   2、也可在Terminal、Mac終端、cmd終端中通過ndk-build命令直接構建庫文件(執行了:Android.mk)

2、環境搭建

JNI安裝
JNI 是JDK里的內容,電腦上正確安裝並配置JDK即可 (JDK1.1之後就正式支持了);

NDK安裝
可從官網自行下載、解壓到本地,也可基於AndroidStudio下載解壓到預設目錄;

編譯工具安裝
cmake 可基於AndroidStudio下載安裝;
ndk-build 是NDK里的腳本工具,NDK安裝好即可使用ndk-build;

當前演示,使用的Android Studio版本如下(當前最新版):

啟動Android Studio --> 打開SDK Manager --> SDK Tools,如下圖所示:

我們選擇NDK、CMake、LLDB(調試Native時才會使用),選擇Apply進行安裝,等安裝成功後,NDK開發所依賴的環境也就都齊全了。

3、Native C++ 項目(HelloWord案例)

3.1、項目創建(java / kotlin)

新建項目,選擇 Native C++,如下圖:

新創建的項目,預設已包含完整的native 示例代碼、cmake配置 ,如下圖:

這樣,我們就可以自己定義Java native方法,併在cpp目錄中寫native實現了,很方便。

但是,當我們寫完native的實現代碼,希望運行APP,查看JNI的交互效果,此時,就需要使用編譯工具了,咱們還是先看一下Android Studio預設的Native編譯方式吧:CMake

3.2、CMake的應用

在CMake編譯之前,咱們應該先做哪些準備工作?

1、NDK環境是否配置正確?
-- 如果未配置正確是無法進行C/C++開發的,更不用說CMake編譯了

2、C/C++功能是否實現? 
-- 此次演示主要使用系統預設創建的native-lib.cpp文件,關於具體如何實現:後續文章再詳細講解

3、CMakeLists.txt是否創建並正確配置? 
-- 該文件是CMake工具編譯的基礎,未配置或配置項錯誤,均會影響編譯結果

4、gradle是否正確配置?
-- gradle配置也是CMake工具編譯的基礎,未配置或配置項錯誤,均會影響編譯結果

除此之外,咱們還應該學習CMake的哪些重要知識?

1、CMake工具編譯生成的庫文件預設在什麼位置?apk中庫文件又是在什麼位置?
2、CMake工具如何指定編譯生成的庫文件位置?
3、CMake工具如何指定生成不同CPU平臺對應的庫文件?

帶著這些問題,咱們開始CMake之旅吧:

3.2.1、NDK環境檢查

編譯前,建議先檢查下工程的NDK配置情況(不然容易報一些亂七八糟的錯誤):
File --> Project Structure --> SDK Location,如下圖(我本地的Android Studio預設沒有給配置NDK路徑,那麼,需要自己手動指定一下):

3.2.2、C/C++功能實現

因為本節主講CMake編譯工具,代碼就不單獨寫了,咱們直接使用工程預設生成的native-liv.cpp,簡單調整一下native實現方法的代碼吧(修改返迴文本信息):

因Native C++工程預設已配置好了CMakeLists.txt和gradle,所以咱們可直接運行工程看效果,如下圖:

JNI交互效果我們已經看到了,說明CMake編譯成功了。那麼,這究竟是怎麼做到的呢?咱們接著分析一下吧:

3.2.3、CMake生成的庫文件與apk中的庫文件

安卓工程編譯時,會執行CMake編譯,在 工程/app/build/.../cmake/ 中會產生對應的so文件,如下圖:

繼續編譯安卓工程,會根據build中的內容,生成我們的*.apk安裝包文件。我們找到、反編譯apk安裝包文件,查找so庫文件。原來在apk安裝包中,so庫都被存放在lib目錄中,如下圖:

3.2.4、CMake是如何編譯生成so庫的呢?

在前面介紹CMake定義時,提到了CMake是基於CMakeLists.txt文件和gradle配置實現編譯Native類的。那麼,咱們先來看一下CMakeLists.txt文件吧:

#cmake最低版本要求
cmake_minimum_required(VERSION 3.4.1)

#添加庫
add_library(
        # 庫名
        native-lib

        # 類型:
        # SHARED 是指動態庫,對應的是.so文件
        # STATIC 是指靜態庫,對應的是.a文件
        # 其他類型:略
        SHARED

        # native類路徑
        native-lib.cpp)

# 查找依賴庫
find_library( 
        # 依賴庫別名
        log-lib

        # 希望加到本地的NDK庫名稱,log指NDK的日誌庫
        log)


# 鏈接庫,建立關係( 此處就是指把log-lib 鏈接給 native-lib使用 )
target_link_libraries( 
        # 目標庫名稱(native-lib 是咱們要生成的so庫)
        native-lib

        # 要鏈接的庫(log-lib 是上面查找的log庫)
        ${log-lib})

實際上,CMakeList.txt可配置的內容遠不止這些,如:so輸出目錄,生成規則等等,有需要的同學可查下官網。

接著,咱們再看一下app的gradle又是如何配置CMake的呢?

apply plugin: 'com.android.application'

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.1"
    defaultConfig {
        applicationId "com.qxc.testnativec"
        minSdkVersion 21
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        //定義cmake預設配置屬性
        externalNativeBuild {
            cmake {
                cppFlags ""
            }
        }
    }
    
    //定義cmake對應的CMakeList.txt路徑(重要)
    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}

實際上,gradle可配置的cmake內容也遠不止這些,如:abi、cppFlags、arguments等,有需要的同學可查下官網。

3.2.5、如何指定庫文件的輸出目錄?

如果希望將so庫生成到特定目錄,並讓項目直接使用該目錄下的so,應該如何配置呢?
比較簡單:需要在CMakeList.txt中配置庫的輸出路徑信息,即:

CMAKE_LIBRARY_OUTPUT_DIRECTORY

# cmake最低版本要求
cmake_minimum_required(VERSION 3.4.1)

# 配置庫生成路徑
# CMAKE_CURRENT_SOURCE_DIR是指 cmake庫的源路徑,通常是build/.../cmake/
# /../jniLibs/是指與CMakeList.txt所在目錄的同級目錄:jniLibs (如果沒有會新建)
# ANDROID_ABI 生成庫文件時,採用gradle配置的ABI策略(即:生成哪些平臺對應的庫文件)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI})

# 添加庫
add_library( # 庫名
        native-lib

        # 類型:
        # SHARED 是指動態庫,對應的是.so文件
        # STATIC 是指靜態庫,對應的是.a文件
        # 其他類型:略
        SHARED

        # native類路徑
        native-lib.cpp)

# 查找依賴庫
find_library(
        # 依賴庫別名
        log-lib

        # 希望加到本地的NDK庫名稱,log指NDK的日誌庫
        log)


# 鏈接庫,建立關係( 此處就是指把log-lib 鏈接給native-lib使用 )
target_link_libraries(
        # 目標庫名稱(native-lib就是咱們要生成的so庫)
        native-lib

        # 要鏈接的庫(上面查找的log庫)
        ${log-lib})

還需要在gradle中配置 jniLibs.srcDirs 屬性(即:指定了lib庫目錄):

sourceSets {
        main {
            jniLibs.srcDirs = ['jniLibs']//指定lib庫目錄
        }
    }

接著,重新build就會在cpp相同目錄級別位置生成jniLibs目錄,so庫也在其中了:

註意事項:
1、配置了CMAKE_CURRENT_SOURCE_DIR,並非表示編譯時直接將so生成在該目錄中,實際編譯時,so文件仍然是
先生成在build/.../cmake/中,然後再拷貝到目標目錄中的

2、如果只配置了CMAKE_CURRENT_SOURCE_DIR,並未在gradle中配置 jniLibs.srcDirs,也會有問題,如下:
More than one file was found with OS independent path 'lib/arm64-v8a/libnative-lib.so'

此問題是指:在編譯生成apk時,發現了多個so目錄,android studio不知道使用哪一個了,所以需要咱們
告訴android studio當前工程使用的是jniLibs目錄,而非build/.../cmake/目錄
3.2.5、如何生成指定CPU平臺對應的庫文件呢?

我們可以在cmake中設置abiFilters,也可在ndk中設置abiFilters,效果是一樣的:

defaultConfig {
        applicationId "com.qxc.testnativec"
        minSdkVersion 21
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                cppFlags ""
                abiFilters "arm64-v8a"
            }
        }
    }
defaultConfig {
        applicationId "com.qxc.testnativec"
        minSdkVersion 21
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                cppFlags ""
            }
        }
        ndk {
            abiFilters "arm64-v8a"
        }
    }

按照新的配置,我們重新運行工程,如下圖:

再反編譯看下工程,果然只有arm64-v8a的so庫了,不過庫文件在apk中仍然是放在lib目錄,而非jniLibs(其實也很好理解,jniLibs只是我們本地的目錄,便於我們管理庫文件,真正生成apk時,仍然會按照lib目錄放置庫文件),如下圖:

至此,CMake的主要技術點都講完了,接下來咱們看下NDK-Build吧~

3.3、ndk-build的應用

在ndk-build編譯之前,咱們又應該先做哪些準備工作?

1、ndk-build環境變數是否正確配置?
-- 如果未配置,是無法在cmd、Mac終端、Terminal中使用ndk-build命令的(會報錯:找不到命令)

2、NDK環境是否配置正確?
-- 如果未配置正確是無法進行C/C++開發的,更不用說ndk-build編譯了

3、C/C++功能是否實現?
-- 此次演示主要使用系統預設創建的native-lib.cpp文件,關於具體如何實現:後續文章再詳細講解
-- 註意:為了與CMake區分,咱們新建一個“jni”目錄存放C/C++文件、配置文件吧

4、Android.mk是否創建並正確配置? 
-- 該文件是ndk-build工具編譯的基礎,未配置或配置項錯誤,均會影響編譯結果

5、gradle是否正確配置?(可選項,如果通過cmd、Mac終端、Terminal執行ndk-build,可忽略)
-- gradle配置也是ndk-build工具編譯的基礎,未配置或配置項錯誤,均會影響編譯結果

6、Application.mk是否創建並正確配置?(可選項,一般配ABI、版本,這些項均可在gradle中配置)
-- 該文件也是ndk-build工具編譯的基礎,未配置或配置項錯誤,均會影響編譯結果

除此之外,咱們還應該學習ndk-build的哪些重要知識?

1、ndk-build工具如何指定編譯生成的庫文件位置?
2、ndk-build工具如何指定生成不同CPU平臺對應的庫文件?

帶著這些問題,咱們繼續ndk-build之旅吧:

3.3.1、環境變數配置

介紹NDK-Build定義時,提到了其實它是NDK的腳本工具。那麼,咱們還是先進NDK目錄找一下吧,ndk-build工具的位置如下圖:

如果我們希望任意情況下都能便捷的使用這種腳本工具,通常做法是配置其環境變數,否則我們在cmd、Mac終端、Terminal中執行 ndk-build 命令時,會報錯:“未找到命令”

配置NDK的環境變數,也很簡單,以Mac電腦舉例(如果是Windows電腦,網上也有很多關於配置環境變數的文章,如果有需要可自行查下):

1、打開命令終端,輸入命令: open -e .bash_profile,打開bash_profile配置文件

2、寫入如下內容(NDK_HOME指向 ndk-build 所在路徑):
export NDK_HOME=/Users/xc/SDK/android-sdk-macosx/ndk/20.1.5948944
export PATH=$PATH:$NDK_HOME

3、生效.bash_profile配置
source .bash_profile

當我們在cmd、Mac終端、Terminal中執行 ndk-build 命令時,如果出現下圖所示內容,則代表配置成功了:

3.3.2、C/C++功能實現

咱們使用比較常用的一種ndk-build方式吧:ndk-build + Android.mk + gradle配置

項目中新建jni目錄,拷貝一份CMake的代碼實現吧:

1、新建jni目錄
2、拷貝cpp/native-lib.cpp 至 jni目錄下
3、重命名為haha.cpp (與CMake區分)
4、調整一下native實現方法的文本(與CMake運行效果區分)
5、新建Android.mk文件

接著,編寫Android.mk文件內容:

#表示Android.mk所在目錄
LOCAL_PATH := $(call my-dir)

#CLEAR_VARS變數指向特殊 GNU Makefile,用於清除部分LOCAL_變數
include $(CLEAR_VARS)

#模塊名稱
LOCAL_MODULE    := haha
#構建系統用於生成模塊的源文件列表
LOCAL_SRC_FILES := haha.cpp

#BUILD_SHARED_LIBRARY 表示.so動態庫
#BUILD_STATIC_LIBRARY 表示.a靜態庫
include $(BUILD_SHARED_LIBRARY)

配置gradle:

apply plugin: 'com.android.application'
android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.aaa.testnative"
        minSdkVersion 16
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

        //定義ndkBuild預設配置屬性
        externalNativeBuild {
            ndkBuild {
                cppFlags ""
            }
        }
    }
   
    //定義ndkBuild對應的Android.mk路徑(重要)
    externalNativeBuild {
        ndkBuild{
            path "src/main/jni/Android.mk"
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

現在,native代碼、ndk-build配置都完成了,咱們運行看一下效果吧,如下圖:

3.3.4、如何指定庫文件的輸出目錄?

通常,可在Android.mk文件中配置NDK_APP_DST_DIR
指定源目錄與輸出目錄(與CMake類似)

#表示Android.mk所在目錄
LOCAL_PATH := $(call my-dir)

#設置庫文件的輸入目錄
#輸出目錄 ../jniLibs/
#源目錄 $(TARGET_ARCH_ABI)
NDK_APP_DST_DIR=../jniLibs/$(TARGET_ARCH_ABI)

#CLEAR_VARS變數指向特殊 GNU Makefile,用於清除部分LOCAL_變數
include $(CLEAR_VARS)

#模塊名稱
LOCAL_MODULE    := haha
#構建系統用於生成模塊的源文件列表
LOCAL_SRC_FILES := haha.cpp

#BUILD_SHARED_LIBRARY 表示.so動態庫
#BUILD_STATIC_LIBRARY 表示.a靜態庫
include $(BUILD_SHARED_LIBRARY)
3.3.5、如何生成指定CPU平臺對應的庫文件呢?

可在gradle中配置abiFilters(與Cmake類似)

externalNativeBuild {
            ndkBuild {
                cppFlags ""
                abiFilters "arm64-v8a"
            }
        }
externalNativeBuild {
            ndkBuild {
                cppFlags ""
            }
        }
  ndk {
            abiFilters "arm64-v8a"
        }
3.3.6、如何在Terminal中直接通過ndk-build命令構建庫文件呢?

除了執行AndroidStudio的build命令,基於gradle配置 + Android.mk編譯生成庫文件,我們還可以在cmd、Mac 終端、Terminal中直接通過ndk-build命令構建庫文件,此處以Terminal為例進行演示吧:

先進入包含Android.mk文件的jni目錄(Android Studio中可直接選中jni目錄並拖拽到Terminal中,會自動跳轉到該目錄),再執行ndk-build命令,如下圖:

同樣,編譯也成功了,如下圖:

因是直接在Terminal中執行了ndk-build命令,所以只會根據Android.mk進行編譯(不包含gradle配置內容,也就不會執行abiFilters過濾),生成了所有預設CPU平臺的so庫文件。

ndk-build命令其實也可以配上一些參數使用,此處就不再詳解了。日常開發時,還是建議選擇CMake作為Native編譯工具,因為是安卓主推的,而且更簡單一些。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 對比結論 1. 性能上: 性能上都很出色,具體到細節,由於Redis只使用單核,而Memcached可以使用多核,所以平均每一個核上Redis在存儲小數據時比Memcached性能更高。而在100k以上的數據中,Memcached性能要高於Redis,雖然Redis最近也在存儲大數據的性能上進行優化 ...
  • select * from table1 t where (select count(*) from table1 where column1=t.column1 AND column2=t.column2 and column3=t.column3)>1 ...
  • USE [SPECIAL_BLD]GO SET ANSI_NULLS ONGO SET QUOTED_IDENTIFIER ONGO CREATE FUNCTION [dbo].[get_upper] ( @num numeric(18,5))RETURNS VARCHAR(500)ASBEGIN ...
  • 一、Atlas是什麼? 在當今大數據的應用越來越廣泛的情況下,數據治理一直是企業面臨的巨大問題。 大部分公司只是單純的對數據進行了處理,而數據的血緣,分類等等卻很難實現,市場上也急需要一個專註於數據治理的技術框架,這時Atlas應運而生。 Atlas官網地址: "https://atlas.apac ...
  • 看如下一條sql語句: # table T (id int, name varchar(20)) delete from T where id = 10; MySQL在執行的過程中,是如何加鎖呢? 在看下麵這條語句: select * from T where id = 10; 那這條語句呢?其實這 ...
  • 在MySQL中經常出現未按照理想情況使用索引的情況,今天記錄一種Order by語句的使用導致未按預期使用索引的情況。 1. 問題現象 1.1 SQL語句: SELECT DISTINCT p.* FROM tb_name p WHERE 1=1 AND p.createDate >= '2019- ...
  • [20191122]oracel SQL parsing function qcplgte.txt--//昨天看了鏈接:https://nenadnoveljic.com/blog/memory-leak-parsing/ =>Memory Leak During Parsingqcplgteqcp ...
  • 目錄 "用法解析" "├── 1、JNI函數" "│ ├── 1.1、extern "C"" "│ ├── 1.2、JNIEXPORT、JNICALL" "│ ├── 1.3、函數名" "│ ├── 1.4、JNIEnv" "│ ├── 1.5、jobject" "├── 2、Java、JNI、C/ ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...