需求
對外提供一個SDK
,功能是拉起微信小程序。
分析
實現原理:在將要開發的
SDK
中,封裝微信的SDK
,通過微信SDK
,從而達到拉起微信小程序的目的以前項目中,接入過微信
SDK
,是1.8.4
版本的,使用了其中的分享圖片到朋友圈的功能,比較順利,是通過CocoaPod
實現的,比較省心。隨著
iOS13
的發布,現在的微信SDK
升級到了1.8.6.1
,增加了通用鏈接功能。并且通用鏈接是必選項,初始化函數增加了參數,否則就失敗。
[WXApi registerApp:APP_ID universalLink:UNIVERSAL_LINK];
嘗試過繞開這個通用鏈接,比如用百度的網址占位,這個函數一直返回NO
。說實話,通用鏈接真的很麻煩,看看微信給的介紹文章,說了一大堆,還沒把問題說清楚。并且通用鏈接只是一個用
Safari
瀏覽器來打開app
,比較雞肋。說是增加安全性,這里也用不到。這里只是簡單拉起微信小程序就可以了,不需要回傳信息。
關于openSDK1.8.6的更新說明提供了一個雞肋功能,導致以前的版本不能用,也不考慮兼容性,微信的
SDK
做得真的很差。折騰了好幾天,最終還是決定用相對簡單易用的1.8.4
,避開繁瑣而沒用的通用鏈接。網上說
iOS
的SDK
一般都是靜態庫,比如微信提供的SDK
就是.a
形式的靜態庫。我也試著封裝了一下,發現使用起來很麻煩。比如我們提供的靜態庫叫my.a
,用戶使用的時候,要把my.a
和對應的頭文件my.h
導入工程。由于my.a
用到了微信的libWeChatSDK.a
,所以用戶也要把libWeChatSDK.a
和配套的頭文件導入工程。另外,libWeChatSDK.a
還用到了很多系統庫,微信文檔不準確,自己查了好久的百度才link
成功。這部分工作,用戶也要重復一遍,想想都麻煩。
既然這樣,封裝一層
my.a
又有什么意義,直接使用libWeChatSDK.a
不就行了?
- 封裝成動態
framework
的話,至少使用libWeChatSDK.a
時遇到的麻煩事只要做一遍就好了,這樣才有封裝的意義。
結論:使用動態framework
封裝WeChatSDK1.8.4
實現拉起微信小程序的功能
開發動態framework
Setp1: 創建framework
工程
以framework
的名字為工程名字,Xcode
的菜單路徑為File->New->Project...
,在彈出菜單中,類型選擇framework
工程創建完成后,會自動生成一個和framework
同名的h
文件,這個文件是必須的,不能刪除。
Setp2: 修改輸出文件
- 默認情況下,只有與
framework
同名的h
文件才能輸出。如果項目不大,有這么一個輸出文件就夠了。但是,只有一個h
文件不是很方便,可以用一個繼承自NSObject
的類代替,名字和framework
同名。在頭文件中定義輸出函數。
- 外部可以使用的文件在
Build Phases -> Headers
標簽下,從Project
部分移動到Public
部分
Step3:導入微信SDK
這里選用的是
WeChatSDK1.8.4
,以前從微信開發者平臺下的,這個版本不需要通用鏈接,比較方便。現在網上能下的版本是WeChatSDK1.8.6.1
,要求通用鏈接,用起來很麻煩,并且向前不兼容,效果很差,拋棄不用。微信
SDK
是靜態的.a
文件,將整個文件夾通過Xcode
菜單File->Add files to ...
就可以了。新建一個以
NSObject
為基類的自定義類,這里是KJTWeiXin
,通過調用微信SDK
的相關函數,完成拉起微信小程序的功能。在輸出文件,這里是
KJTUrlSdk.m
,調用剛才的實現,完成的功能實現的導出工作。
Step4:創建調試Target
-
framework
是不能直接使用的,需要一個調用者APP
。這里采用Target
的方式(菜單路徑File->New->Target...
),名字,在framework
名字后面加-Sample
后綴,(這里是),類型就選最簡單的單頁面工程。
- 建立項目依賴。使用者,(這里是KJTUrlSdk-Sample),依賴framework,(這里是KJTUrlSdk)。
合并framework
生成的framework
要么是真機的,要么是模擬器的,很不方便。用命令行也比較煩,用腳本的方式比較好。
-
Build Phase中的New Run Script Phase
可以添加自動運行的腳本
- 腳本內容如下:
if [ "${ACTION}" = "build" ]
then
INSTALL_DIR=${SRCROOT}/Products/${PROJECT_NAME}.framework
DEVICE_DIR=${BUILD_ROOT}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework
SIMULATOR_DIR=${BUILD_ROOT}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework
if [ -d "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi
mkdir -p "${INSTALL_DIR}"
cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/"
#ditto "${DEVICE_DIR}/Headers" "${INSTALL_DIR}/Headers"
lipo -create "${DEVICE_DIR}/${PROJECT_NAME}" "${SIMULATOR_DIR}/${PROJECT_NAME}" -output "${INSTALL_DIR}/${PROJECT_NAME}"
open "${DEVICE_DIR}"
open "${SRCROOT}/Products"
fi
- 每次運行都會生成一遍,模擬器和真機至少運行一次之后,在工程根目錄下的
Product
文件夾下就是合并過的framework
,真機和模擬都能用。
Step5: Demo工程
創建一個獨立的工程,使用自己開發的
framework
。這個工程要和前面的開發工程完全獨立。名字可以加-Demo
后綴,(這里是KJRUrlSdk-Demo
)通過菜單Flie->Add files to ... 將合并過的framework添加進來。
注意:如果要提交蘋果市場,只能用真機版本的framework,否則會出錯。
- 在General標簽下,將framework的載入格式改為Embed&Sign,否則會奔潰。
如果不改,崩潰信息一般如下:
dyld: Library not loaded: @rpath/KJTUrlSdk.framework/KJTUrlSdk
Referenced from: /var/mobile/Containers/Bundle/Application/CFEEFAD2-1BF3-4D29-967B-42CAAB7C4811/KJTUrlSdk-Demo.app/KJTUrlSdk-Demo
Reason: image not found
最后的樣子:經過以上各步驟,最后的文件結構樣子大致如下
微信SDK依賴系統庫
- 微信
WeChatSDK1.8.4
依賴如下系統庫
如果不添加這些系統庫,會出現鏈接錯誤,并且這些問題,微信的開發文檔并沒有完全說清楚。只能百度,一個個試過去,比較麻煩。
導入微信支付報錯解決使用動態
framework
包含一個靜態.a的好處是上面那些依賴可以在framework
內部處理掉,最終使用者,這里是KJTUrlSdk-Demo
,就不需要再考慮這些麻煩事了。
注冊函數導致崩潰。
- 由于是MTA庫中的剪貼板和其他程序競爭,導致崩潰。只要不打開MTA就好了。
WXApi registerApp:@"xxx" enableMTA:NO];
[__NSArrayM enqueue:]: unrecognized selector sent to instance
- WeChatSDK1.8.5之后的版本解決了這個問題。
檢查微信是否安裝函數不可用
這是因為微信SDK使用[[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"weixin://"]]
方式來檢查是否安裝微信。iOS9
之后,要在Plist中加白名單才可以用。不然這個函數始終返回NO
應用BundleID信息校驗不通過
- 如果使用者
APP
的bundle ID
,(這里是KJTUrlSdk-Demo
和KJTUrlSdk-Sample
),和微信后臺配置的bundle ID
不一致,就會彈這個信息框,小程序跳轉也有異常。但是,微信API函數執行還是成功的。
framework的版本號
-
framework
工程創建的時候,會自動給出兩個關于版本的全局變量,一個是double
型的,一個是char
數組
- 這兩個變量對應的是
Target->General
下的Build
,并不是通常理解的Version
-
double
型的數字只能顯示兩位,比如設置1.2.3.4
,顯示1.200000
;字符型的能顯示全,不過會加上很多前綴。比如Build
配置為1.2.3.4
,通過NSLog
輸出:
NSLog(@"數字版本號:%f", KJTUrlSdkVersionNumber); // 數字版本號:1.200000
NSLog(@"字符數組版本號:%s", KJTUrlSdkVersionString); // 字符數組版本號:@(#)PROGRAM:KJTUrlSdk PROJECT:KJTUrlSdk-1.2.3.4
- 參考文章:iOS Framework-版本號指定
如何生成Release模式的framework?
一般的
scheme
,都是Run
的時候Debug,Archive
的時候Release
。這個設定對于可執行文件是可行的,但是對于framework
就不合適了。因為framework
無法單獨執行,沒法Archive
可以將
framework
的Run
改為Release
。就算這樣,用斷點調試,也是可以停住的,不影響調試效果。可以這樣說,Debug
模式對于framework
來說是沒有意義的,統一使用Release
就好了。