iOS Unity 集成 微信SDK 支付寶SDK Unity生成Xcode項(xiàng)目自動(dòng)配置

前言:

在Unity里面能走到這一步的,多半前面已經(jīng)經(jīng)歷了iOS 和Unity傳值交互的痛苦歷程脾拆。有了前面的代碼經(jīng)驗(yàn)苦银,這次要做的事情,就是在交互基礎(chǔ)之上铛绰,了解如何自動(dòng)配置Unity生成Xcode項(xiàng)目诈茧,使得每次打包即可真機(jī)調(diào)試而不必每次都要去修改簽名證書(shū),添加framework累死個(gè)人捂掰。

傳值系列

iOS Unity 交互(系列一)Unity調(diào)用iOS函數(shù) Unity給iOS傳值
iOS Unity 交互(系列二)iOS調(diào)用Unity函數(shù) iOS給Unity傳值
iOS Unity 交互(系列三)iOS Unity互傳參數(shù)與完整示例代碼
iOS Unity 交互(系列四)Unity調(diào)用iOS SDK

本次實(shí)驗(yàn)的環(huán)境:

1敢会、蘋果電腦安裝:Xcode(Version 13.2.1 (13C100)),Unity(Version 2020.3.25f1c1 Personal)这嚣,VSCode(這個(gè)隨意吧)

2鸥昏、蘋果手機(jī)真機(jī),用于調(diào)試疤苹。

實(shí)現(xiàn)場(chǎng)景

Unity集成支付寶和微信SDK互广。
讓Unity生成Xcode項(xiàng)目,并且在生成Xcode項(xiàng)目的時(shí)候卧土,腳本自動(dòng)配置Xcode項(xiàng)目所需要的 framework,info.plist像樊,代碼簽名尤莺,證書(shū),等等生棍。
生成項(xiàng)目之后即可調(diào)用支付寶和微信SDK進(jìn)行付款操作颤霎。

備注

操作太多了,仔細(xì)寫要寫上大半天涂滴。這里就直接貼圖講解細(xì)節(jié)和一些注意的點(diǎn)友酱。

工程的初始化配置

1.png

關(guān)于支付寶SDK

原始的支付寶SDK是同時(shí)支持真機(jī)架構(gòu)和模擬器架構(gòu)的。如果直接導(dǎo)入原始支付寶SDK到Unity項(xiàng)目里柔纵,生成的Xcode項(xiàng)目在運(yùn)行的時(shí)候會(huì)報(bào)錯(cuò)缔杉,會(huì)給你搞出什么 arm64 architecture 之類的錯(cuò)誤。所以我們需要把支付寶SDK里面的模擬器架構(gòu)剔除搁料。微信SDK則不需要或详。
在命令行里運(yùn)行以下代碼:

//1 切換到外層的文件夾,查看架構(gòu)
cd /Users/zhaoxin/Desktop/Ali_iOS_SDK
lipo -info AlipaySDK.framework/AlipaySDK

//2 切換到 cd /Users/zhaoxin/Desktop/Ali_iOS_SDK/AlipaySDK.framework 剔除模擬器
lipo -remove i386 AlipaySDK -o AlipaySDK
lipo -remove x86_64 AlipaySDK -o AlipaySDK
2.png

關(guān)于生成Xcode項(xiàng)目

Unity現(xiàn)在已經(jīng)可以在面板上直接配置項(xiàng)目的某些參數(shù),以前好像是要寫腳本代碼去改的郭计。
在Unity里面依次尋找:File → Build Settings → Player Settings霸琴,如下圖:

3.png

我的示例代碼文件目錄結(jié)構(gòu)

4.png

圖片中的示例代碼:

C# 腳本代碼 AliWxPayDemo

using System.Runtime.InteropServices;
using UnityEngine;

public class AliWxPayDemo : MonoBehaviour
{

    //定義函數(shù) 支付寶支付
    [DllImport("__Internal")]
    private static extern void IOSAliPay(string objectName, string payOrder, string scheme);

    //注冊(cè)微信
    [DllImport("__Internal")]
    private static extern void IOSRegistWxApi(string objectName, string WXAppKey, string WXAppUniversalLink);
    //定義函數(shù) 微信支付
    [DllImport("__Internal")]
    private static extern void IOSWxPay(string openID, string partnerId, string prepayId, string nonceStr, string timeStamp, string package, string sign);

    void Start() { }

    void Update() { }

    void OnGUI()
    {
        if (GUI.Button(new Rect(150, 400, 700, 150), "點(diǎn)擊使用支付寶"))
        {
            string alipay = "這個(gè)支付字符串來(lái)自于后端,在傳參的時(shí)候換成你自己的支付字符串";
            alipay = "service=mobile.securitypay.pay&partner=608896586645411740&_input_charset=utf-8&notify_url=http%7A%6F%6Fopen.jike%6Fcallback%6Falipay&out_trade_no=60664894135456448&subject=%88%B1%E5%8A%A8-%E8%AF%BE%E7%A8%8B%E9%A6%84%E7%BA%A6-606601665448&body=%E7%88%B1%E5%8A%A8-%E8%AF%BE%E8%8B%E9%A6%84%E7%BA%A6-60660166506448&payment_type=1&total_fee=0.01&seller_id=6088045411740&it_b_pay=70m&sign_type=RSA&sign=AYHT%6F0tyV8oG7Fs8s6YlqpnZb4nW74nmDkWCVOLRpB5aoPzOuiCp%6BSCvyXrtC6Q9IaxFXU79432y9hka9v87L880uPgPCqHaOC1kWBm%6FSGuIRM4WRukI7VdZWlF7TuXB%6BM1ZgJKFfd486132SDLliY4B4ZkDRZgetE%7D";
            IOSAliPay("PayObject", alipay, iOSPayConfig.Ali_Pay_Schema);
        }

        if (GUI.Button(new Rect(150, 800, 700, 150), "點(diǎn)擊使用微信"))
        {
            //先注冊(cè)微信
            IOSRegistWxApi("PayObject", iOSPayConfig.WXAppKey, iOSPayConfig.WXAppUniversalLink);
            //然后調(diào)用微信支付
            IOSWxPay("wx765vb987v5123d70", "1666707801", "wx661178461614106f6b7d46c6c0b640000", "8d66017766a641fab68d86a79054071", "164717894656", "Sign=WXPay", "B561D744E816D7DD015C0D76DCE99D4");
        }
    }

    //來(lái)自O(shè)C的函數(shù) 支付寶支付結(jié)果回調(diào)
    public void IOS_Ali_Pay_Result(string dictionaryString)
    {
        Debug.Log("C# 收到 支付寶 回調(diào):" + dictionaryString);
    }

    //來(lái)自O(shè)C的函數(shù) 微信支付結(jié)果回調(diào)
    public void IOS_Wx_Pay_Result(string dictionaryString)
    {
        Debug.Log("C# 收到 微信 回調(diào):" + dictionaryString);
    }
}

C# 腳本代碼 BuildCallback

using UnityEngine;
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEditor.Callbacks;
using UnityEditor.iOS.Xcode;
using System.IO;
using UnityEditor.XCodeEditor;
using System;

public class BuildCallback : IPreprocessBuildWithReport, IPostprocessBuildWithReport
{
    int IOrderedCallback.callbackOrder { get { return 0; } }

    System.DateTime startTime;

    //打包前事件
    void IPreprocessBuildWithReport.OnPreprocessBuild(BuildReport report)
    {
        startTime = System.DateTime.Now;
        Debug.Log("開(kāi)始打包 : " + startTime);
    }

    //打包后事件
    void IPostprocessBuildWithReport.OnPostprocessBuild(BuildReport report)
    {
        System.TimeSpan buildTimeSpan = System.DateTime.Now - startTime;
        Debug.Log("打包成功,耗時(shí) : " + buildTimeSpan);
    }

    //回調(diào)  打包后處理
    [PostProcessBuild(1)]
    public static void OnPostProcessBuild(BuildTarget target, string pathToBuiltProject)
    {
        if (target != BuildTarget.iOS)
        {
            return;
        }

        var projPath = pathToBuiltProject + "/Unity-iPhone.xcodeproj/project.pbxproj";
        var proj = new PBXProject();
        proj.ReadFromFile(projPath);
        //var targetGUID = proj.TargetGuidByName("Unity-iPhone");
        //var targetGUID = proj.GetUnityMainTargetGuid();
        var targetGUID = proj.GetUnityFrameworkTargetGuid();
        proj.AddBuildProperty(targetGUID, "OTHER_LDFLAGS", "-ObjC -all_load"); //微信開(kāi)發(fā)文檔要求在 Other Link Flags 里面添加 "-ObjC -all_load" 但是實(shí)際驗(yàn)證發(fā)現(xiàn)生成的Xcode項(xiàng)目這句比并沒(méi)有添加上,然而不影響使用
        //proj.SetBuildProperty(targetGUID, "ENABLE_BITCODE", "NO");

        // 添加系統(tǒng)庫(kù)
        // 這里是支付寶需要用到系統(tǒng)庫(kù),如果不引入系統(tǒng)庫(kù), Unity生成Xcode項(xiàng)目運(yùn)行必定報(bào)錯(cuò),各種缺
        /*
         * 舉例: 如果沒(méi)有引入 WebKit.framework 就會(huì)報(bào)如下錯(cuò)誤:
         ld: warning: arm64 function not 4-byte aligned: _unwind_tester from /Users/zhaoxin/Desktop/支付寶微信合并Demo/ios_generate_proj/Libraries/libiPhone-lib.a(unwind_test_arm64.o)
         Undefined symbols for architecture arm64:
         "_OBJC_METACLASS_$_WKWebView", referenced from:
         _OBJC_METACLASS_$_MQPWebView in AlipaySDK
         */
        proj.AddFrameworkToProject(targetGUID, "libz.tbd", false);
        proj.AddFrameworkToProject(targetGUID, "libc++.tbd", false);
        proj.AddFrameworkToProject(targetGUID, "CoreText.framework", false);
        proj.AddFrameworkToProject(targetGUID, "CoreTelephony.framework", false);
        proj.AddFrameworkToProject(targetGUID, "CoreMotion.framework", false);
        proj.AddFrameworkToProject(targetGUID, "CoreGraphics.framework", false);
        proj.AddFrameworkToProject(targetGUID, "QuartzCore.framework", false);
        proj.AddFrameworkToProject(targetGUID, "UIKit.framework", false);
        proj.AddFrameworkToProject(targetGUID, "Foundation.framework", false);
        proj.AddFrameworkToProject(targetGUID, "CFNetwork.framework", false);
        proj.AddFrameworkToProject(targetGUID, "SystemConfiguration.framework", false);
        proj.AddFrameworkToProject(targetGUID, "WebKit.framework", false);
        // 這里是微信需要使用到的系統(tǒng)庫(kù)
        proj.AddFrameworkToProject(targetGUID, "CoreGraphics.framework", false);
        proj.AddFrameworkToProject(targetGUID, "WebKit.framework", false);
        proj.AddFrameworkToProject(targetGUID, "Security.framework", false);
        //proj.AddFrameworkToProject(targetGUID, "VideoToolbox.framework", false);
        //proj.AddFrameworkToProject(targetGUID, "StoreKit.framework", false);
        //proj.AddFrameworkToProject(targetGUID, "Security.framework", false);
        //proj.AddFrameworkToProject(targetGUID, "ReplayKit.framework", false);
        //proj.AddFrameworkToProject(targetGUID, "Photos.framework", false);
        //proj.AddFrameworkToProject(targetGUID, "MultipeerConnectivity.framework", false);
        //proj.AddFrameworkToProject(targetGUID, "MobileCoreServices.framework", false);
        //proj.AddFrameworkToProject(targetGUID, "MetalPerformanceShaders.framework", false);
        //proj.AddFrameworkToProject(targetGUID, "MediaToolbox.framework", false);
        //proj.AddFrameworkToProject(targetGUID, "MediaPlayer.framework", false);
        //proj.AddFrameworkToProject(targetGUID, "libresolv.9.tbd", false);
        //proj.AddFrameworkToProject(targetGUID, "libiconv.tbd", false);
        //proj.AddFrameworkToProject(targetGUID, "libcompression.tbd", false);
        //proj.AddFrameworkToProject(targetGUID, "libc++abi.tbd", false);
        //proj.AddFrameworkToProject(targetGUID, "JavaScriptCore.framework", false);
        //proj.AddFrameworkToProject(targetGUID, "GLKit.framework", false);
        //proj.AddFrameworkToProject(targetGUID, "AVFoundation.framework", false);
        //proj.AddFrameworkToProject(targetGUID, "AudioToolbox.framework", false);
        //proj.AddFrameworkToProject(targetGUID, "AssetsLibrary.framework", false);
        //proj.AddFrameworkToProject(targetGUID, "Accelerate.framework", false);
        //proj.AddFrameworkToProject(targetGUID, "AuthenticationServices.framework", false);
        //proj.AddFrameworkToProject(targetGUID, "libil2cpp.a", false);
        //proj.AddFrameworkToProject(targetGUID, "libiPhone-lib.a", false);
        //proj.AddFrameworkToProject(targetGUID, "AuthenticationServices.framework", false);
        //proj.AddFrameworkToProject(targetGUID, "AVKit.framework", false);
        //proj.AddFrameworkToProject(targetGUID, "CoreMedia.framework", false);
        //proj.AddFrameworkToProject(targetGUID, "CoreVideo.framework", false);
        //proj.AddFrameworkToProject(targetGUID, "OpenAL.framework", false);
        //proj.AddFrameworkToProject(targetGUID, "OpenGLES.framework", false);
        //proj.AddFrameworkToProject(targetGUID, "libiconv.2.dylib", false);
        //proj.AddFrameworkToProject(targetGUID, "LightGameSDK.framework", false);
        //proj.AddFrameworkToProject(targetGUID, "Metal.framework", false);
        //proj.AddFrameworkToProject(targetGUID, "libresolv.9.tbd", false);
        //proj.AddFrameworkToProject(targetGUID, "CoreLocation.framework", false);
        //proj.AddFrameworkToProject(targetGUID, "ImageIO.framework", false);
        //proj.AddFrameworkToProject(targetGUID, "AdSupport.framework", false);

        proj.WriteToFile(projPath);

        var plistPath = Path.Combine(pathToBuiltProject, "Info.plist");
        var plist = new PlistDocument();
        plist.ReadFromFile(plistPath);
        PlistElementDict rootDict = plist.root;
        plist.root.SetString("NSPhotoLibraryAddUsageDescription", "需要相冊(cè)權(quán)限");
        plist.root.SetString("NSPhotoLibraryUsageDescription", "需要相冊(cè)權(quán)限");
        plist.root.SetString("NSCalendarsUsageDescription", "需要日歷權(quán)限");
        plist.root.SetString("NSMicrophoneUsageDescription", "錄制屏幕需要麥克風(fēng)權(quán)限");
        plist.root.SetString("NSCameraUsageDescription", "需要相機(jī)權(quán)限");
        plist.root.SetString("NSLocationWhenInUseUsageDescription", "需要定位權(quán)限");

        // plist 里面 允許 http 請(qǐng)求
        if (rootDict.values.ContainsKey("NSAppTransportSecurity"))
        { rootDict.values.Remove("NSAppTransportSecurity");}
        PlistElementDict urlDict = rootDict.CreateDict("NSAppTransportSecurity");
        urlDict.SetBoolean("NSAllowsArbitraryLoads", true);


        //添加各種白名單
        PlistElementArray queriesSchemes = rootDict.CreateArray("LSApplicationQueriesSchemes");
        //queriesSchemes.AddString("douyinsharesdk");
        //queriesSchemes.AddString("douyinopensdk");
        //queriesSchemes.AddString("snssdk1128");
        //queriesSchemes.AddString("toutiaoopensdk");
        //queriesSchemes.AddString("wechat");  //微信白名單
        queriesSchemes.AddString("weixinULAPI"); //微信白名單
        queriesSchemes.AddString("weixin");  //微信白名單

        //配置urlSchemes(數(shù)組里面有字典昭伸,字典里面有子數(shù)組)
        PlistElementArray urlTypes = plist.root.CreateArray("CFBundleURLTypes");
        PlistElementDict itemDict;
        //添加支付寶的 URL Scheme
        itemDict = urlTypes.AddDict();
        itemDict.SetString("CFBundleTypeRole", "Editor");
        itemDict.SetString("CFBundleURLName", "AliPay");
        PlistElementArray zhifubaoSchemesArray = itemDict.CreateArray("CFBundleURLSchemes");
        zhifubaoSchemesArray.AddString(iOSPayConfig.Ali_Pay_Schema);

        //添加微信的 URL Scheme
        itemDict = urlTypes.AddDict();
        itemDict.SetString("CFBundleTypeRole", "Editor");
        itemDict.SetString("CFBundleURLName", "weixin");
        PlistElementArray weixinSchemes = itemDict.CreateArray("CFBundleURLSchemes");
        weixinSchemes.AddString(iOSPayConfig.WXAppKey);

        //添加第2個(gè)
        //itemDict = urlTypes.AddDict();
        //itemDict.SetString("CFBundleTypeRole", "Editor");
        //PlistElementArray schemesArray2 = itemDict.CreateArray("CFBundleURLSchemes");
        //schemesArray2.AddString("xxxx");
        //添加第3個(gè)
        //itemDict = urlTypes.AddDict();
        //itemDict.SetString("CFBundleTypeRole", "Editor");
        //itemDict.SetString("CFBundleURLName", "xxxx");
        //PlistElementArray schemesArray3 = itemDict.CreateArray("CFBundleURLSchemes");
        //schemesArray3.AddString("xxxx");

        File.WriteAllText(plistPath, plist.WriteToString());
        plist.WriteToFile(plistPath);


        //編輯 Capability  在我這個(gè)版本,即使不添加 AssociatedDomains 也沒(méi)有關(guān)系, 因?yàn)槲⑿挪蛔?- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity 這個(gè)方法
        //在高版本原生iOS App中,需要在 AssociatedDomains 里面配置微信的 UniversalLink 用于接收微信的回調(diào)
        AddCapability(proj, pathToBuiltProject);

        //編輯代碼文件 得到xcode工程的路徑
        string path = Path.GetFullPath(pathToBuiltProject);
        EditorCode(path);

        UnityEngine.Debug.Log("Xcode 后續(xù)處理完成");
    }

    //編輯Xcode代碼文件
    private static void EditorCode(string filePath)
    {
        //讀取UnityAppController.mm文件
        XClass UnityAppController = new XClass(filePath + "/Classes/UnityAppController.mm");

        //在Xcode工程入口處導(dǎo)入類 iOSPayHelper.h, 這個(gè)代碼文件集成了 支付寶和微信支付的入口
        UnityAppController.WriteBelow("#import \"UnityAppController.h\"", "#import \"iOSPayHelper.h\"");

        //支付寶
        //在Xcode工程入口函數(shù) openurl 里添加處理支付回調(diào)拉起UnityApp的處理
        UnityAppController.WriteBelow("AppController_SendNotificationWithArg(kUnityOnOpenURL, notifData);", "    [[iOSPayHelper shared] handleAliPayURL:url];");

        //微信
        //注冊(cè)微信, 一定是要在 - (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions 這里面注冊(cè)微信, 如果只是從你寫的 .mm 文件里面,使用支付的時(shí)候才去注冊(cè), 驗(yàn)證結(jié)果也是生效的, 為了防止后續(xù)因?yàn)榘姹揪壒蕦?dǎo)致失效, 下面這兩行寫在 App啟動(dòng)入口的函數(shù)保留使用
        //string code = "    [WXApi registerApp:" + "@\"" + iOSPayConfig.WXAppKey + "\" " + "universalLink:" + "@\"" + iOSPayConfig.WXAppUniversalLink + "\"" + "];";
        //UnityAppController.WriteBelow("[KeyboardDelegate Initialize];", code);
        //在AppDelegate里面添加匿名分類,添加一個(gè)協(xié)議
        UnityAppController.WriteBefore("@implementation UnityAppController", "@interface UnityAppController()<WXApiDelegate>\n@end");
        //注意,在這3個(gè)函數(shù)里面, 最好都要添加微信處理的回調(diào)處理, 自己創(chuàng)建空白的項(xiàng)目然后使用微信支付 和 從Unity生成出來(lái)的項(xiàng)目使用微信支付, 微信的回調(diào)走的不是同一個(gè) Application 里面的回調(diào)函數(shù).
        //在這3個(gè)地方都添加回調(diào)處理,可以最大范圍涵蓋微信可能走的系統(tǒng)回調(diào)函數(shù), 也是因?yàn)檫@個(gè), 花了大量時(shí)間去驗(yàn)證.
        UnityAppController.WriteBefore("NSURL* url = userActivity.webpageURL;", "  [WXApi handleOpenUniversalLink:userActivity delegate:self];");
        UnityAppController.WriteBefore("- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity", "- (BOOL)application:(UIApplication*)application handleOpenURL: (NSURL*)url {return [WXApi handleOpenURL: url delegate:self];}");
        UnityAppController.WriteBelow("AppController_SendNotificationWithArg(kUnityOnOpenURL, notifData);", "[WXApi handleOpenURL: url delegate:self];");
        //添加微信的代理函數(shù)
        UnityAppController.WriteBefore("- (BOOL)application:(UIApplication*)application willFinishLaunchingWithOptions:(NSDictionary*)launchOptions", "- (void)onResp:(BaseResp *)resp {\n    [[iOSPayHelper shared] handleWxPayResp:resp];\n}");
    }

    //添加 Capability
    private static void AddCapability(PBXProject project, string pathToBuiltProject)
    {
        //string target = project.TargetGuidByName(PBXProject.GetUnityTargetName());
        var target = project.GetUnityFrameworkTargetGuid();

        // Add BackgroundModes And Need to modify info.plist
        //project.AddCapability(target, PBXCapabilityType.BackgroundModes);
        //project.AddCapability(target, PBXCapabilityType.InAppPurchase);
        //project.AddCapability(target, PBXCapabilityType.AssociatedDomains);

        // Need Create entitlements
        string relativeEntitlementFilePath = "Unity-iPhone/Unity-iPhone.entitlements";
        string absoluteEntitlementFilePath = pathToBuiltProject + "/" + relativeEntitlementFilePath;

        PlistDocument tempEntitlements = new PlistDocument();

        //添加鑰匙串
        //string key_KeychainSharing = "keychain-access-groups";
        //var arr = (tempEntitlements.root[key_KeychainSharing] = new PlistElementArray()) as PlistElementArray;
        //arr.values.Add(new PlistElementString("$(AppIdentifierPrefix)com.tencent.xxxx"));
        //arr.values.Add(new PlistElementString("$(AppIdentifierPrefix)com.tencent.wsj.keystoregroup"));

        //添加推送
        //string key_PushNotifications = "aps-environment";
        //tempEntitlements.root[key_PushNotifications] = new PlistElementString("development");

        //添加關(guān)聯(lián)網(wǎng)址
        string key_Associated = "com.apple.developer.associated-domains";
        var arr_Ass = (tempEntitlements.root[key_Associated] = new PlistElementArray()) as PlistElementArray;
        arr_Ass.values.Add(new PlistElementString(iOSPayConfig.WXAssociatedDomains));
        arr_Ass.values.Add(new PlistElementString(""));

        project.AddCapability(target, PBXCapabilityType.AssociatedDomains, relativeEntitlementFilePath);
        //project.AddCapability(target, PBXCapabilityType.PushNotifications, relativeEntitlementFilePath);
        //project.AddCapability(target, PBXCapabilityType.KeychainSharing, relativeEntitlementFilePath);

        string projPath = PBXProject.GetPBXProjectPath(pathToBuiltProject);
        File.WriteAllText(projPath, project.WriteToString());
        tempEntitlements.WriteToFile(absoluteEntitlementFilePath);

        ModifyEntitlementFile(absoluteEntitlementFilePath);
    }

    private static void ModifyEntitlementFile(string absoluteEntitlementFilePath)
    {
        if (!File.Exists(absoluteEntitlementFilePath)) return;

        try
        {
            StreamReader reader = new StreamReader(absoluteEntitlementFilePath);
            var content = reader.ReadToEnd().Trim();
            reader.Close();

            var needFindString = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
            var changeString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "\n" + "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">";
            Debug.Log("Before: " + content);
            content = content.Replace(needFindString, changeString);
            Debug.Log("After: " + content);
            StreamWriter writer = new StreamWriter(new FileStream(absoluteEntitlementFilePath, FileMode.Create));
            writer.WriteLine(content);
            writer.Flush();
            writer.Close();
        }
        catch (Exception e)
        {
            Debug.Log("ModifyEntitlementFile - 失敗了伙計(jì) Failed: " + e.Message);
        }
    }

}

C# 腳本代碼 XClass

using UnityEngine;
using System.IO;

namespace UnityEditor.XCodeEditor
{
    public partial class XClass : System.IDisposable
    {
        private string filePath;

        public XClass(string fPath)
        {
            filePath = fPath;
            if (!System.IO.File.Exists(filePath))
            {
                Debug.LogError(filePath + "路徑下文件不存在");
                return;
            }
        }

        public void WriteBelow(string below, string text)
        {
            StreamReader streamReader = new StreamReader(filePath);
            string text_all = streamReader.ReadToEnd();
            streamReader.Close();

            int beginIndex = text_all.IndexOf(below);
            if (beginIndex == -1)
            {
                Debug.LogError(filePath + "中沒(méi)有找到標(biāo)志" + below);
                return;
            }

            int endIndex = text_all.LastIndexOf("\n", beginIndex + below.Length);

            text_all = text_all.Substring(0, endIndex) + "\n" + text + "\n" + text_all.Substring(endIndex);

            StreamWriter streamWriter = new StreamWriter(filePath);
            streamWriter.Write(text_all);
            streamWriter.Close();
        }

        public void WriteBefore(string before, string text)
        {
            StreamReader streamReader = new StreamReader(filePath);
            string text_all = streamReader.ReadToEnd();
            streamReader.Close();

            int beginIndex = text_all.IndexOf(before);  //找開(kāi)始的索引
            if (beginIndex == -1)
            {
                Debug.LogError(filePath + "中沒(méi)有找到標(biāo)志" + before);
                return;
            }

            text_all = text_all.Substring(0, beginIndex) + text + "\n\n" + text_all.Substring(beginIndex);

            StreamWriter streamWriter = new StreamWriter(filePath);
            streamWriter.Write(text_all);
            streamWriter.Close();
        }

        public void Replace(string below, string newText)
        {
            StreamReader streamReader = new StreamReader(filePath);
            string text_all = streamReader.ReadToEnd();
            streamReader.Close();

            int beginIndex = text_all.IndexOf(below);
            if (beginIndex == -1)
            {
                Debug.LogError(filePath + "中沒(méi)有找到標(biāo)致" + below);
                return;
            }

            text_all = text_all.Replace(below, newText);
            StreamWriter streamWriter = new StreamWriter(filePath);
            streamWriter.Write(text_all);
            streamWriter.Close();

        }

        public void Dispose()
        {

        }
    }
}

C# 腳本代碼 iOSPayConfig

// 支付SDK使用到的常量定義類
// 注意,這個(gè)類放到 Assets 目錄下面
public static class iOSPayConfig
{
    //支付寶使用到的 Schema
    //1 用在支付方法里,作為參數(shù)
    //2 在Unity工程導(dǎo)出Xcode工程后,寫如到 info.plist 當(dāng)中作為支付寶拉起Unity App的接口. (這部分功能已經(jīng)寫入到腳本自動(dòng)添加)
    public static string Ali_Pay_Schema = "支付寶給你的Schema";


    //微信使用到的 Key
    //1 在Unity工程導(dǎo)出Xcode工程后,寫如到 info.plist 當(dāng)中作為支付寶拉起Unity App的接口. (這部分功能已經(jīng)寫入到腳本自動(dòng)添加)
    public static string WXAppKey = "微信給你的AppKey";
    //2 在Unity工程導(dǎo)出Xcode工程后,寫如到 info.plist 當(dāng)中作為支付寶拉起Unity App的接口. (這部分功能已經(jīng)寫入到腳本自動(dòng)添加)
    public static string WXAppUniversalLink = "微信給你的UniversalLink";
    //3 微信 Associated Domains 鏈接
    public static string WXAssociatedDomains = "微信給你的 Associated url 去微信開(kāi)放平臺(tái)弄"; //這個(gè)需要在微信開(kāi)放平臺(tái)去配置,把微信給的鏈接寫到項(xiàng)目里,這里是直接改代碼文件硬寫.

}

iOS 代碼 iOSPayHelper.h

//
//  iOSPayHelper.h
//  UnityFramework
//
//  Created by 童年的大灰狼 on 2020/5/13.
//

#import <Foundation/Foundation.h>
#import <AlipaySDK/AlipaySDK.h>
#import "WXApi.h"

@interface iOSPayHelper : NSObject

///單例對(duì)象
+ (instancetype)shared;

///處理支付回調(diào)URL
- (void)handleAliPayURL:(NSURL *)url;
///支付寶支付
- (void)AliPayOrder:(NSString *)orderStr;
///支付寶 掛載的Unity對(duì)象
@property (nonatomic, strong) NSString *gameobject_Ali;
///支付寶使用的 Schema
@property (nonatomic, strong) NSString *ali_schemeStr;

///處理微信支付的回調(diào)
- (void)handleWxPayResp:(BaseResp *)resp;
///微信 掛載的Unity對(duì)象
@property (nonatomic, strong) NSString *gameobject_Wx;

@end

iOS 代碼 iOSPayHelper.mm

//
//  iOSPayHelper.m
//  UnityFramework
//
//  Created by 童年的大灰狼 on 2020/5/13.
//

#import "iOSPayHelper.h"

@interface iOSPayHelper()

@end

@implementation iOSPayHelper

static iOSPayHelper *_sharedInstance = nil;

static dispatch_once_t onceToken;

+ (instancetype)shared {
    dispatch_once(&onceToken, ^{
        _sharedInstance = [[iOSPayHelper alloc] init];
    });
    return _sharedInstance;
}

- (instancetype)init {
    self = [super init];
    if (self) {
    }
    return self;
}


- (void)AliPayOrder:(NSString *)orderStr {
    [[AlipaySDK defaultService] payOrder:orderStr fromScheme:self.ali_schemeStr callback:^(NSDictionary *resultDic) {
        NSLog(@"?????? %s", __func__);
        [self executeCompleteBlock:resultDic];
    }];
}

- (void)handleAliPayURL:(NSURL *)url {
    if ([url.scheme isEqualToString:self.ali_schemeStr]) {
        [[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) {
            NSLog(@"?????? %s", __func__);
            [self executeCompleteBlock:resultDic];
        }];
    }
}

- (void)executeCompleteBlock:(NSDictionary *)resultDic {
    //    返回碼    含義
    //    9000    訂單支付成功
    //    8000    正在處理中梧乘,支付結(jié)果未知(有可能已經(jīng)支付成功),請(qǐng)查詢商戶訂單列表中訂單的支付狀態(tài)
    //    4000    訂單支付失敗
    //    5000    重復(fù)請(qǐng)求
    //    6001    用戶中途取消
    //    6002    網(wǎng)絡(luò)連接出錯(cuò)
    //    6004    支付結(jié)果未知(有可能已經(jīng)支付成功)庐杨,請(qǐng)查詢商戶訂單列表中訂單的支付狀態(tài)
    //    其它    其它支付錯(cuò)誤
    
    NSInteger resultCode = [resultDic[@"resultStatus"] integerValue];
    NSString *msg = nil;
    if (resultCode ==  9000) {
        msg = @"訂單支付成功";
    } else if (resultCode ==  8000) {
        msg = @"支付結(jié)果未知选调,請(qǐng)查詢商戶訂單列表中訂單的支付狀態(tài)";
    } else if (resultCode ==  5000) {
        msg = @"重復(fù)請(qǐng)求";
    } else if (resultCode ==  6001) {
        msg = @"用戶中途取消";
    } else if (resultCode ==  6002) {
        msg = @"網(wǎng)絡(luò)連接出錯(cuò)";
    } else if (resultCode ==  6004) {
        msg = @"支付結(jié)果未知嗡善,請(qǐng)查詢商戶訂單列表中訂單的支付狀態(tài)";
    } else {
        msg = @"訂單支付失敗";
    }
    
    NSMutableDictionary *tempdic = [NSMutableDictionary dictionaryWithDictionary:resultDic];
    [tempdic setObject:msg forKey:@"iOS_Add_Msg"];
    
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:tempdic options:NSJSONWritingPrettyPrinted error:nil];
    NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    NSLog(@"?????? iOS 收到支付寶回調(diào)結(jié)果: resultDic = %@",resultDic);
    UnitySendMessage([self.gameobject_Ali UTF8String], "IOS_Ali_Pay_Result", [jsonString UTF8String]);
}



///注冊(cè)微信支付
- (void)registerApp:(NSString *)WXAppKey universalLink:(NSString *)WXAppUniversalLink {
    [WXApi registerApp:WXAppKey universalLink:WXAppUniversalLink];
}

///微信支付
- (void)WxPayReq:(PayReq *)req {
    //調(diào)起微信支付,包裝參數(shù)
    [WXApi sendReq:req completion:^(BOOL success) {}];
}

///處理微信支付的回調(diào)
- (void)handleWxPayResp:(BaseResp *)resp {
    
    if ([resp isKindOfClass:[PayResp class]]) {
        //微信支付回調(diào)中errCode值列表:
        //名稱   描述        解決方案
        //0     成功        展示成功頁(yè)面
        //-1    錯(cuò)誤        可能的原因:簽名錯(cuò)誤、未注冊(cè)APPID学歧、項(xiàng)目設(shè)置APPID不正確罩引、注冊(cè)的APPID與設(shè)置的不匹配、其他異常等枝笨。
        //-2    用戶取消     無(wú)需處理袁铐。發(fā)生場(chǎng)景:用戶不支付了,點(diǎn)擊取消横浑,返回APP剔桨。
        NSString *msg = @"";
        if (resp.errCode == WXSuccess) {
            msg = @"支付成功";
        } else if(resp.errCode == WXErrCodeUserCancel) {
            msg = @"用戶取消";
        } else {
            msg = @"支付失敗";
        }
        NSMutableDictionary *tempdic = [NSMutableDictionary dictionary];
        [tempdic setObject:msg forKey:@"iOS_Add_Msg"];
        [tempdic setObject:@(resp.errCode) forKey:@"errCode"];
        if (resp.errStr) {
            [tempdic setObject:resp.errStr forKey:@"errStr"];
        }
        [tempdic setObject:@(resp.type) forKey:@"type"];
        
        NSData *jsonData = [NSJSONSerialization dataWithJSONObject:tempdic options:NSJSONWritingPrettyPrinted error:nil];
        NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
        NSLog(@"?????? iOS 收到微信回調(diào)結(jié)果: tempdic = %@", tempdic);
        UnitySendMessage([self.gameobject_Wx UTF8String], "IOS_Wx_Pay_Result", [jsonString UTF8String]);
    } else {
        NSLog(@"?????? iOS 收到微信支付回調(diào)對(duì)象錯(cuò)誤! 這不是支付完成的類實(shí)例對(duì)象");
    }
}

@end


#ifdef __cplusplus
extern "C" {
#endif

///支付寶
extern void IOSAliPay(const char *objName, const char *payOrder, const char *scheme) {
    NSString *o = [NSString stringWithUTF8String:objName];
    NSString *p = [NSString stringWithUTF8String:payOrder];
    NSString *s = [NSString stringWithUTF8String:scheme];
    [iOSPayHelper shared].gameobject_Ali = o;
    [iOSPayHelper shared].ali_schemeStr = s;
    [[iOSPayHelper shared] AliPayOrder:p];
}


///需要注冊(cè)微信
extern void IOSRegistWxApi(const char *objName, const char *WXAppKey, const char *WXAppUniversalLink) {
    NSString *o = [NSString stringWithUTF8String:objName];
    [iOSPayHelper shared].gameobject_Wx = o;
    NSString *k = [NSString stringWithUTF8String:WXAppKey];
    NSString *l = [NSString stringWithUTF8String:WXAppUniversalLink];
    [[iOSPayHelper shared] registerApp:k universalLink:l];
}

///微信
extern void IOSWxPay(const char *openID, const char *partnerId, const char *prepayId, const char *nonceStr, const char *timeStamp, const char *package, const char *sign) {
    //調(diào)起微信支付,包裝參數(shù)
    PayReq *req      = [[PayReq alloc] init];
    req.openID       = [NSString stringWithUTF8String:openID];
    req.partnerId    = [NSString stringWithUTF8String:partnerId];
    req.prepayId     = [NSString stringWithUTF8String:prepayId];
    req.nonceStr     = [NSString stringWithUTF8String:nonceStr];
    req.timeStamp    = (UInt32)[[NSString stringWithUTF8String:timeStamp] longLongValue];
    req.package      = [NSString stringWithUTF8String:package];
    req.sign         = [NSString stringWithUTF8String:sign];
    [[iOSPayHelper shared] WxPayReq:req];
}

#ifdef __cplusplus
}
#endif

結(jié)語(yǔ)

感謝以下iOS/Unity玩家的文章:

Unity打包iOS,Xcode自動(dòng)打包framework

Unity 自動(dòng)打包 Part1—配置Xcode工程

Unity 配置Xcode工程--添加Capability

[Unity]配置Xcode工程(2)--添加Capability

Unity3D研究院之IOS全自動(dòng)編輯framework徙融、plist洒缀、oc代碼(六十七)

Unity編譯到Xcode自動(dòng)添加文件及代碼修改

Unity導(dǎo)出XCode工程的時(shí)候自動(dòng)修改工程設(shè)置添加依賴

Unity 打包IOS(自動(dòng)化構(gòu)建)

Unity配置Xcode腳本

Unity配置Xcode腳本

IOS自動(dòng)化打包,自動(dòng)導(dǎo)入并修改文件

Unity3d Android IOS 自動(dòng)設(shè)置 簽名和輸出 路徑

Unity 打包IOS(自動(dòng)化構(gòu)建)

[Unity]騰訊SDK踩坑之路(2)--配置Xcode工程(MSDK和米大師配置代碼沖突)

使用PostProcessBuild設(shè)定Unity產(chǎn)生的Xcode Project

Unity iOS Xcode 自動(dòng)化一些記錄

Unity成功導(dǎo)出Xcode工程后自動(dòng)修改一些設(shè)置

報(bào)錯(cuò)指引

iOS 微信支付SDK -canOpenURL: failed for URL: "weixinULAPI://"

微信支付無(wú)法回調(diào)函數(shù),iOS端微信支付成功失敗無(wú)法收到不執(zhí)行回調(diào)微信回調(diào)函數(shù)的原因...

Undefined symbols for architecture arm64解決方案

Undefined symbols for architecture arm64:問(wèn)題解決方法

解決Undefined symbols for architecture arm64問(wèn)題

iOS 支付寶SDK接入詳解

iOS framework分離與合并 刪除SDK中的i386欺冀,x86_86架構(gòu)

iOS開(kāi)發(fā) 刪除framework里支持模擬器的架構(gòu)

微信開(kāi)放平臺(tái)

微信開(kāi)放平臺(tái) iOS Demo下載頁(yè)面

微信開(kāi)放平臺(tái) iOS SDK接入官方文檔

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末树绩,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子隐轩,更是在濱河造成了極大的恐慌饺饭,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,590評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件职车,死亡現(xiàn)場(chǎng)離奇詭異瘫俊,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)悴灵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門扛芽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人积瞒,你說(shuō)我怎么就攤上這事川尖。” “怎么了赡鲜?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,301評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵空厌,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我银酬,道長(zhǎng)嘲更,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,078評(píng)論 1 300
  • 正文 為了忘掉前任揩瞪,我火速辦了婚禮赋朦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己宠哄,他們只是感情好壹将,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著毛嫉,像睡著了一般诽俯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上承粤,一...
    開(kāi)封第一講書(shū)人閱讀 52,682評(píng)論 1 312
  • 那天暴区,我揣著相機(jī)與錄音,去河邊找鬼辛臊。 笑死仙粱,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的彻舰。 我是一名探鬼主播伐割,決...
    沈念sama閱讀 41,155評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼刃唤!你這毒婦竟也來(lái)了隔心?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 40,098評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤透揣,失蹤者是張志新(化名)和其女友劉穎济炎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體辐真,經(jīng)...
    沈念sama閱讀 46,638評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評(píng)論 3 342
  • 正文 我和宋清朗相戀三年崖堤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了侍咱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,852評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡密幔,死狀恐怖楔脯,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情胯甩,我是刑警寧澤昧廷,帶...
    沈念sama閱讀 36,520評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站偎箫,受9級(jí)特大地震影響木柬,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜淹办,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧州弟,春花似錦、人聲如沸谤牡。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,674評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)翅萤。三九已至,卻和暖如春腊满,著一層夾襖步出監(jiān)牢的瞬間套么,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,788評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工糜烹, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留违诗,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,279評(píng)論 3 379
  • 正文 我出身青樓疮蹦,卻偏偏與公主長(zhǎng)得像诸迟,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子愕乎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容