Unity-IOS-微信支付

時間:2018.6

Unity版本:5.6.2

平臺:Unity+iOS

微信SDK版本:2018.6月 1.8.2版本

適用人群:unity 開發(fā),oc基礎(chǔ)較弱

食用前提:請確保已經(jīng)清楚官方的整個支付流程。以及unity與ios的基礎(chǔ)交互。

官方支付流程鏈接:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_3

寫作原因:目前百度上能搜索到的資料看來看去就那幾個人的資料,有的雖然看似也能跑通,但是要么是講解很不清楚,要么是版本老,而且很多情況沒將清楚,讓新人特別是沒有oc基礎(chǔ)的新人非常難受。雖然是這么說,但是我也是收益與上述這種不太清楚的攻略才艱難的完成了支付模塊。這也是寫這篇文章的原因。

支付情況:1.整個模塊都在客戶端完成的。也就是官方流程圖中統(tǒng)一下單也在客戶端完成的。個人是不建議這樣做的,因為很不安全,其次客戶端代碼也會稍微復雜點,再加上如果unity開發(fā)人員不懂oc,幾乎不能調(diào)試錯誤。百度能查到的一些有源碼的很多都是整個一起的。

2.客戶端二次簽名的,上述情況已經(jīng)包含著一種了,因為像服務(wù)器請求已經(jīng)在客戶端了,二次簽名當然也在客戶端。還有一種是服務(wù)器端返回了客戶端需要的參數(shù),客戶端再次簽名,然后調(diào)用支付接口api的,這種要注意的是,客戶端的簽名方法一定要和服務(wù)器端相同,否則就會出現(xiàn)簽名錯誤的提示。(跳轉(zhuǎn)到app后,跳轉(zhuǎn)到微信,只有一個錯誤提示,點擊確定會再回到原程序內(nèi))

3.服務(wù)器端進行二次簽名,客戶端只需要傳參數(shù)的,這種是最簡單的,不過這種需要后臺的配合,讓服務(wù)器調(diào)用統(tǒng)一下單api后,再返回客戶端需要參數(shù)前,再進行一次簽名,這樣客戶端就只需要很簡單的傳參數(shù)就可以。

本文主要作為引導,以及分享一些本人遇到的問題上的解決。

正式開始:

1.確保你的unity工程發(fā)布成Xcode后可以在真機跑通。

2.如果是情況1的話,你需要知道所有微信相關(guān)的參數(shù)。例如:appid ,商戶id,商戶迷鑰等。

3.如果是情況3的話,你需要知道appid。其他參數(shù)讓后臺發(fā)送即可。

4.把微信sdk放入到,unity/plugins/ios/下

5.在unity工程中的playerSetting-otherSetting-Supported URL schemes中加入微信支付appid。

6.編寫unity調(diào)用iOS的代碼:

[DllImport("__Internal")]

    private static extern void _startUp(string appid, string partnerid, string prepayid, string noncster,string time,string sign);

ps:這句的代碼意思是有一個_startUp函數(shù)是外部函數(shù),他需要這些參數(shù)。_statUp即是要在Xcode中實現(xiàn)的調(diào)用微信sdk的方法。

7.寫一個回調(diào)函數(shù) payCallBack(string info),記下這個腳本所掛載的物體,iOS端再調(diào)用了微信支付后需要將參數(shù)傳遞給unity端,用來方便后續(xù)的邏輯處理。

到此。unity 端的工作就完成了。

8:配置

我們可以發(fā)布xcode代碼了,unity發(fā)布xcode時有兩個選項,一個是append 還有一個replace 一個是增量一個是替換,因為微信支付在xcode端還有很多參數(shù)和屬性要陪著,多數(shù)情況下,unity發(fā)布的工程,不會一次就ok。如果每次都要重新配置那些屬性和引用的框架,怕不是要瘋。所以建議,再后續(xù)的發(fā)布時選擇append。這樣,添加好的框架和所需要填寫的linker就不需要每次配置。

發(fā)布到xcode后,要按照官方的教程進行配置。

這里不偷懶,也再寫一下。[圖片上傳失敗...(image-18bb14-1528966115678)]
步驟名對應(yīng)官方教程,不清楚的,還可以到官方再次確認。

3]微信開放平臺新增了微信模塊用戶統(tǒng)計功能,便于開發(fā)者統(tǒng)計微信功能模塊的用戶使用和活躍情況。開發(fā)者需要在工程中鏈接上:SystemConfiguration.framework, libz.dylib, libsqlite3.0.dylib, libc++.dylib, Security.framework, CoreTelephony.framework, CFNetwork.framework。


pic1.jpg

4.在你的工程文件中選擇Build Setting,在"Other Linker Flags"中加入"-Objc -all_load",在Search Paths中添加 libWeChatSDK.a ,WXApi.h,WXApiObject.h,文件所在位置(如下圖所示)。


pic2.jpg

Ps:官方寫的是兩個-Objc 與 -all_load,但我在使用中如果兩個都加的話,編譯時會爆linker error -v錯誤,刪掉 -all_load就好了,查了百度可能是引用添加重復導致的。

5,在Xcode中,選擇你的工程設(shè)置項,選中“TARGETS”一欄,在“info”標簽欄的“URL type“添加“URL scheme”為你所注冊的應(yīng)用程序id(如下圖所示)。

pic3.jpg

6. 在Xcode中,選擇你的工程設(shè)置項,選中“TARGETS”一欄,在“info”標簽欄的“LSApplicationQueriesSchemes“添加weixin(如下圖所示)。

pic4.jpg

Ps:5,6提到的TARGETS 就是我們發(fā)布到Xcode中的Info.plist文件。

9,引用頭文件

在UnityAppController.h 添加wxapi的回掉 如下圖

pic5.jpg

10.在 UnityAppController.mm 中完成,首先找到文件中 didFinishLaunchingWithOptions 函數(shù)的位置,加入

[WXApi registerApp:@"wxa72a15850b99c773"];

代碼。

這里寫你自己的app ID,千萬別忘了改。

11.添加支付成功后的回掉方法,以及兩個官方要求的方法。

//iOS9 之后使用這個回調(diào)方法。

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString *,id> *)options

{

    if ([url.host isEqualToString:@"pay"]) {

        return [WXApi handleOpenURL:url delegate:self];

    }

    return YES;

}

#pragma mark - 微信支付的代理方法

- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url

{

    return  [WXApi handleOpenURL:url delegate:self];

}

-(void)onResp:(BaseResp*)resp

{

    if ([resp isKindOfClass:[PayResp class]]){

        PayResp *response = (PayResp*)resp;

        switch(response.errCode){

            case WXSuccess:

                //服務(wù)器端查詢支付通知或查詢API返回的結(jié)果再提示成功

                NSLog(@"\n\n\n\n\n支付成功\n\n\n\n\n\n");

                UnitySendMessage("AppManager", "OnGetPayResponse","0");

                //發(fā)送通知給帶有微信支付功能的視圖控制器,告訴他支付成功了,請求后臺訂單狀態(tài),如果后臺返回的訂單也是成功的狀態(tài),那么可以進行下一步操作

                [[NSNotificationCenter defaultCenter] postNotificationName:@"WeiXinPaysucceed" object:nil userInfo:nil];

                break;

            default:

                /*

                 resp.errCode = 2 用戶取消支付

                 resp.errCode = -1 錯誤

                 */

                NSLog(@"支付失敗,retcode=%d ---- %@",resp.errCode,resp.errStr);

                break;

        }

    }

}//微信支付成功的回調(diào)方法(回調(diào)函數(shù))

Ps:UnitySendMessage("AppManager", "OnGetPayResponse","0");

這個就是ios 給unity 傳值的方法。一個參數(shù)為接受方法的物體名,第二個是物體所掛載腳本的函數(shù)名,第三個是參數(shù)。

注意。這3個方法都要寫在

@implementation UnityAppController

@end

實現(xiàn)內(nèi)。

11,編寫支付方法_startUp

針對文章開始分的三種情況,這里分別給出代碼。但是我本人只驗證過情況二和情況三。沒有驗證過情況一,不過應(yīng)該也沒有問題。

情況一:(直接搬運的下面鏈接博文的代碼,需要修改的較多,不過也是很容易改的)

void wxpaytest(char* orderN,char* orderP) 

{ 

payRequsestHandler *handle = [[payRequsestHandler alloc]init];

if ( [handle  init:APP_id mch_id:MCH_id]) {

    NSLog(@"初始化成功");

}

//設(shè)置商戶密鑰

[handle setKey:PARTNER_id];

//提交預(yù)支付,獲得prepape_id

NSString *order_name = [[NSString alloc] initWithUTF8String:orderN];   //訂單標題

NSString *order_price = [[NSString alloc] initWithUTF8String:orderP];//測試價格 分為單位

NSString *nocify_URL = nocify_url;    //回調(diào)借口

NSString *noncestr  = [NSString stringWithFormat:@"%d", rand()]; //隨機串

NSString *orderno   = [NSString stringWithFormat:@"%ld",time(0)];

NSMutableDictionary *params = [@{@"appid":APP_id,

                                 @"mch_id":MCH_id,

                                 @"device_info":[[[UIDevice currentDevice] identifierForVendor] UUIDString],

                                 @"nonce_str":noncestr,

                                 @"trade_type":@"APP",

                                 @"body":order_name,

                                 @"notify_url":nocify_URL,

                                 @"out_trade_no":orderno,//商戶訂單號:這個必須用后臺的訂單號

                                 @"spbill_create_ip":@"8.8.8.8",

                                 @"total_fee":order_price}mutableCopy];

//提交預(yù)支付兩次簽名得到預(yù)支付訂單的id(每次的請求得到的預(yù)支付訂單id都不同)

NSString *prepate_id = [handle sendPrepay:params];

//提交預(yù)訂單成功

if (prepate_id != nil) {

    PayReq *request = [[PayReq alloc]init];

    //商家id

    request.partnerId = MCH_id;

    //訂單id

    request.prepayId = prepate_id;

    //擴展字段(官方文檔:暫時填寫固定值)

    request.package = @"Sign=WXPay";

    //隨機字符串

    request.nonceStr = noncestr;

    //時間戳

    request.timeStamp = (UInt32)[[NSDate date] timeIntervalSince1970];

    //sign參數(shù)(很經(jīng)常出現(xiàn)的問題:就是調(diào)起支付到微信那邊只出現(xiàn)一個確定按鈕,單擊確認按鈕直接返回到app,出現(xiàn)這個問題100%是sign參數(shù)的問題)

    /*

     參數(shù)依次是: appid_key、partnerid_key、prepayid_key、固定值Sign=WXPay、預(yù)支付的隨機數(shù)(跟上面得到預(yù)支付訂單的隨機數(shù)要一致)、支付時間(秒)

     */

    //request.sign = [selfClass createMD5SingForPay:APP_id partnerid:MCH_id prepayid:prepate_id package:@"Sign=WXPay" noncestr:noncestr timestamp:(UInt32)[[NSDate date] timeIntervalSince1970]];

    NSMutableDictionary *signParams = [NSMutableDictionary dictionary];

    [signParams setObject:APP_id forKey:@"appid"];

    [signParams setObject:noncestr forKey:@"noncestr"];

    [signParams setObject:@"Sign=WXPay" forKey:@"package"];

    [signParams setObject:MCH_id forKey:@"partnerid"];

    [signParams setObject:prepate_id forKey:@"prepayid"];

    [signParams setObject:[NSString stringWithFormat:@"%u",(unsigned int)(UInt32)[[NSDate date] timeIntervalSince1970]] forKey:@"timestamp"];

    NSMutableString *contentString  =[NSMutableString string];

    NSArray *keys = [signParams allKeys];

    //按字母順序排序

    NSArray *sortedArray = [keys sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {

        return [obj1 compare:obj2 options:NSNumericSearch];

    }];

    //拼接字符串

    for (NSString *categoryId in sortedArray) {

        if (   ![[signParams objectForKey:categoryId] isEqualToString:@""]

            && ![[signParams objectForKey:categoryId] isEqualToString:@"sign"]

            && ![[signParams objectForKey:categoryId] isEqualToString:@"key"]

            )

        {

            [contentString appendFormat:@"%@=%@&", categoryId, [signParams objectForKey:categoryId]];

        }

    }

    //添加商戶密鑰key字段

    [contentString appendFormat:@"key=%@",PARTNER_id];

    // NSString *resul = [self md5:contentString];

    const char *cStr = [contentString UTF8String];

    unsigned char result[16]= "0123456789abcdef";

    CC_MD5(cStr, (CC_LONG)strlen(cStr), result);

    //這里的x是小寫則產(chǎn)生的md5也是小寫,x是大寫則md5是大寫,這里只能用大寫,微信的大小寫驗證很逗

    NSString *resul = [NSString stringWithFormat:

                       @"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",

                       result[0], result[1], result[2], result[3],

                       result[4], result[5], result[6], result[7],

                       result[8], result[9], result[10], result[11],

                       result[12], result[13], result[14], result[15]

                       ];

    request.sign = resul;

    //帶起微信支付

    if ([WXApi sendReq:request]) {

   }else{

        //未安裝微信客戶端

                    [[[UIAlertView alloc]initWithTitle:@"測試demo" message:@"您還未安裝微信客戶端,請前往Appstore下載或者選擇其他支付方式!" delegate:nil cancelButtonTitle:@"知道了" otherButtonTitles:nil, nil]show];

    }

    //接受成功的通知

    [[NSNotificationCenter defaultCenter]addObserver:nil selector:@selector(succeed) name:WEIXINPAYSUCCESSED object:nil];

    NSLog(@"wanc");

}

情況2:

extern "C" void _startUp(char* appid,char* partnerid,char *prepayid,char *noncster,char *time,char *sign,char *messageName)

{      

        PayReq *request = [[PayReq alloc]init];

        request.openID =[NSString stringWithUTF8String:appid];

        //商家id

        request.partnerId = [NSString stringWithUTF8String:partnerid];

        //訂單id

        request.prepayId = [NSString stringWithUTF8String:prepayid];

        //擴展字段(官方文檔:暫時填寫固定值)

        request.package = @"Sign=WXPay";

        //隨機字符串

        request.nonceStr = [NSString stringWithUTF8String:noncster];

        //時間戳

        //request.timeStamp = (UInt32)[[NSDate date] timeIntervalSince1970];

        NSMutableString *stampmp =[[NSString stringWithUTF8String:time] mutableCopy];

    request.timeStamp = stampmp.intValue;

        //NSLog(@"時間戳=%@",(UInt32)[[NSDate date] timeIntervalSince1970]);

        //sign參數(shù)(很經(jīng)常出現(xiàn)的問題:就是調(diào)起支付到微信那邊只出現(xiàn)一個確定按鈕,單擊確認按鈕直接返回到app,出現(xiàn)這個問題100%是sign參數(shù)的問題)

        /*

         參數(shù)依次是: appid_key、partnerid_key、prepayid_key、固定值Sign=WXPay、預(yù)支付的隨機數(shù)(跟上面得到預(yù)支付訂單的隨機數(shù)要一致)、支付時間(秒)

         */

        //request.sign = [selfClass createMD5SingForPay:APP_id partnerid:MCH_id prepayid:prepate_id package:@"Sign=WXPay" noncestr:noncestr timestamp:(UInt32)[[NSDate date] timeIntervalSince1970]];

        NSMutableDictionary *signParams = [NSMutableDictionary dictionary];

        [signParams setObject:[NSString stringWithUTF8String:appid] forKey:@"appid"];

        [signParams setObject:[NSString stringWithUTF8String:noncster] forKey:@"noncestr"];

        [signParams setObject:@"Sign=WXPay" forKey:@"package"];

        [signParams setObject:[NSString stringWithUTF8String:partnerid] forKey:@"partnerid"];

        [signParams setObject:[NSString stringWithUTF8String:prepayid] forKey:@"prepayid"];

        //[signParams setObject:[NSString stringWithFormat:@"%u",(unsigned int)(UInt32)[[NSDate date] timeIntervalSince1970]] forKey:@"timestamp"];

        [signParams setObject:[NSString stringWithFormat:@"%u",stampmp.intValue] forKey:@"timestamp"];

    NSMutableString *contentString  =[NSMutableString string];

        NSArray *keys = [signParams allKeys];

        //按字母順序排序

        NSArray *sortedArray = [keys sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {

            return [obj1 compare:obj2 options:NSNumericSearch];

        }];

        //拼接字符串

        for (NSString *categoryId in sortedArray) {

            if (   ![[signParams objectForKey:categoryId] isEqualToString:@""]

                && ![[signParams objectForKey:categoryId] isEqualToString:@"sign"]

                && ![[signParams objectForKey:categoryId] isEqualToString:@"key"]

                )

            {

                [contentString appendFormat:@"%@=%@&", categoryId, [signParams objectForKey:categoryId]];

            }

        }

        //添加商戶密鑰key字段

        [contentString appendFormat:@"key=%@“,@“XXXXXXXXXXXXX”];

        // NSString *resul = [self md5:contentString];

        const char *cStr = [contentString UTF8String];

        //unsigned char result[16]= "0123456789abcdef";

    unsigned char result[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};

    CC_MD5(cStr, (CC_LONG)strlen(cStr), result);

        //這里的x是小寫則產(chǎn)生的md5也是小寫,x是大寫則md5是大寫,這里只能用大寫,微信的大小寫驗證很逗

        NSString *resul = [NSString stringWithFormat:

                           @"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",

                           result[0], result[1], result[2], result[3],

                           result[4], result[5], result[6], result[7],

                           result[8], result[9], result[10], result[11],

                           result[12], result[13], result[14], result[15]

                           ];

        request.sign = resul;

        //帶起微信支付

        if ([WXApi sendReq:request]) {

        }else{

            //未安裝微信客戶端

            [[[UIAlertView alloc]initWithTitle:@"測試demo" message:@"您還未安裝微信客戶端,請前往Appstore下載或者選擇其他支付方式!" delegate:nil cancelButtonTitle:@"知道了" otherButtonTitles:nil, nil]show];

        }

    }

情況3:

extern "C" void _startUp(char* appid,char* partnerid,char *prepayid,char *noncster,char *time,char *sign,char *messageName)

{    

        PayReq *request = [[PayReq alloc]init];

        request.openID =[NSString stringWithUTF8String:appid];

        //商家id

        request.partnerId = [NSString stringWithUTF8String:partnerid];

        //訂單id

        request.prepayId = [NSString stringWithUTF8String:prepayid];

        //擴展字段(官方文檔:暫時填寫固定值)

        request.package = @"Sign=WXPay";

        //隨機字符串

        request.nonceStr = [NSString stringWithUTF8String:noncster];

        //時間戳

        //request.timeStamp = (UInt32)[[NSDate date] timeIntervalSince1970];

        NSMutableString *stampmp =[[NSString stringWithUTF8String:time] mutableCopy];

    request.timeStamp = stampmp.intValue;

    request.sign =[NSString stringWithUTF8String:sign];

        //帶起微信支付

        if ([WXApi sendReq:request]) {

        }else{

            //未安裝微信客戶端

            [[[UIAlertView alloc]initWithTitle:@"測試demo" message:@"您還未安裝微信客戶端,請前往Appstore下載或者選擇其他支付方式!" delegate:nil cancelButtonTitle:@"知道了" otherButtonTitles:nil, nil]show];    

        }    

    }

最后,本人不是ios開發(fā),所以可能會再某些地方描述錯誤。而且我相信如果你對oc也不是很了解的話。在目前我這一定是最新最詳細的教程了。如果有錯誤,或者幫助了你,千萬不要吝嗇評論噢。

最最后,還是要感謝下面兩個博客的作者。

推薦博文:

官方接入流程:https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=1417694084&token=&lang=zh_CN

情況一接入流程:https://blog.csdn.net/qq_24189773/article/details/78360099

Ps: 他文章的一些代碼需要根據(jù)自己的情況來改。

情況三接入流程:

https://fengyu.name/article/449

ps:寫的很清楚明白。[圖片上傳失敗...(image-5eddc9-1528966603827)]

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容