使用 Unity 来实现 iOS 原生弹框

原帖地址

目标
本文的主要的目标是帮助你使用 Unity 创建 iOS 原生弹框。

你会得到的最终效果如下图




你想要遵循 iOS 的标准来显示弹框吗?

你想要移除额外的图形来减小你构建应用的大小吗?

你想要从 Unity 中显示原生的弹框来提高用户体验吗?

如果你有这些疑虑,那么现在你来对地方了。在这篇博客中,我将使用 Unity 创建 iOS 原生弹框。

第一步 介绍

弹框是一种小的遮挡或者提示用户做一些操作的警告信息。

在这儿,我们将创建3种类型的弹框

类型 行为
消息 弹框 单一行为
确认 弹框 两种行为
评价我们 弹框 三种行为

现在让我们创建一些简单的弹窗吧!

第二步 在 Unity 中设置场景

创建新的 Unity 工程,然后保存场景到你的资源文件夹中。

为三个弹框创建三个按钮

第三步 创建脚本然后分配所有按钮的引用

创建一个脚本然后给它命名。我命名为 PopupView.cs ,现在让我们在代码中添加一个按钮点击的监听事件。

为每一个按钮创建一个方法并且在按钮点击事件添加引用。从 iOS 的对话行为中返回一个枚举存储消息的状态。

public enum MessageState
{
    OK,
    YES,
    NO,
    RATED,
    REMIND,
    DECLINED,
    CLOSED
}   

#region PUBLIC_VARIABLES

//在你想要评价的应用创建一个变量来保持 appID
public string appleId = "925623445";
#endregion

#region BUTTON_EVENT_LISTENER

// 会话按钮点击事件
public void OnDialogPopUp() {
    NativeDialog dialog = new NativeDialog("TheAppGuruz", "Do you wants to know about TheAppGuruz");
    dialog.SetUrlString("http://theappguruz.com/");
    dialog.init();
}

// 评价按钮点击事件
public void OnRatePopUp()
{
    NativeRateUS ratePopUp = new NativeRateUS("Like this game?", "Please rate to support future updates!");
    ratePopUp.SetAppleId(appleId);
    ratePopUp.InitRateUS();
}

// 消息按钮点击事件
public void OnMessagePopUp()
{
    NativeMessage msg = new NativeMessage("TheAppGuruz", "Welcome To TheAppGuruz");
}
#endregion

现在让我们为原生的弹框行为注册委托事件监听者。

#region UNITY_DEFAULT_CALLBACKS

void OnEnable()
{
    // 注册所有的委托事件监听者
    IOSRateUsPopUp.onRateUSPopupComplete += OnRateUSPopupComplete;
    IOSDialog.onDialogPopupComplete += OnDialogPopupComplete;
    IOSMessage.onMessagePopupComplete += OnMessagePopupComplete;
}

void OnDisable()
{
    // 注销所有的委托事件监听者
    IOSRateUsPopUp.onRateUSPopupComplete -= OnRateUSPopupComplete;
    IOSDialog.onDialogPopupComplete -= OnDialogPopupComplete;
    IOSMessage.onMessagePopupComplete -= OnMessagePopupComplete;
}

#endregion

#region DELEGATE_EVENT_LISTENER

// 当点击评价弹框的按钮时会输出不同的状态
void OnRateUSPopupComplete(MessageState state)
{
    switch (state)
    {
        case MessageState.RATED:
        Debug.Log("Rate Button pressed");
        break;
        case MessageState.REMIND:
        Debug.Log("Remind Button pressed");
        break;
        case MessageState.DECLINED:
        Debug.Log("Declined Button pressed");
        break;
    }
}

// 当点击会话弹框的按钮时会输出不同的状态
void OnDialogPopupComplete(MessageState state)
{
    switch (state)
    {
        case MessageState.YES:
        Debug.Log("Yes button pressed");
        break;
        case MessageState.NO:
        Debug.Log("No button pressed");
        break;
    }
}

// 当点击消息弹框的按钮时会输出不同的状态
void OnMessagePopupComplete(MessageState state)
{
    Debug.Log("Ok button Clicked");
}
#endregion

第四步 创建脚本和 Objective-c 代码的相互作用

现在,创建一个脚本命名为 IOSNative.cs 来直接和 iOS 代码(Objective-c)进行交互。


#define DEBUG_MODE

using UnityEngine;
using System.Collections;

#if (UNITY_IPHONE && !UNITY_EDITOR) || DEBUG_MODE
using System.Runtime.InteropServices;
#endif

public class IOSNative
{
    #if (UNITY_IPHONE && !UNITY_EDITOR) || DEBUG_MODE
    [DllImport("__Internal")]
    private static extern void _TAG_ShowRateUsPopUp(string title, string message, string rate, string remind, string declined);

    [DllImport("__Internal")]
    private static extern void _TAG_ShowDialog(string title, string message, string yes, string no);

    [DllImport("__Internal")]
    private static extern void _TAG_ShowMessage(string title, string message, string ok);

    [DllImport("__Internal")]
    private static extern void _TAG_RedirectToAppStoreRatingPage(string appId);

    [DllImport("__Internal")]
    private static extern void _TAG_RedirectToWebPage(string urlString);

    [DllImport("__Internal")]
    private static extern void _TAG_DismissCurrentAlert();

    #endif

public static void showRateUsPopUP(string title, string message, string rate, string remind, string declined)
{
    #if (UNITY_IPHONE && !UNITY_EDITOR) || DEBUG_MODE
    _TAG_ShowRateUsPopUp(title, message, rate, remind, declined);
    #endif
}

public static void showDialog(string title, string message, string yes, string no)
{
    #if (UNITY_IPHONE && !UNITY_EDITOR) || DEBUG_MODE
    _TAG_ShowDialog(title, message, yes, no);
    #endif
}

public static void showMessage(string title, string message, string ok)
{
    #if (UNITY_IPHONE && !UNITY_EDITOR) || DEBUG_MODE
    _TAG_ShowMessage(title, message, ok);
    #endif
}

public static void RedirectToAppStoreRatingPage(string appleId)
{
    #if (UNITY_IPHONE && !UNITY_EDITOR) || DEBUG_MODE
    _TAG_RedirectToAppStoreRatingPage(appleId);
    #endif
}

public static void RedirectToWebPage(string urlString)
{
    #if (UNITY_IPHONE && !UNITY_EDITOR) || DEBUG_MODE
    _TAG_RedirectToWebPage(urlString);
    #endif
}

public static void DismissCurrentAlert()
{
    #if (UNITY_IPHONE && !UNITY_EDITOR) || DEBUG_MODE
    _TAG_DismissCurrentAlert();
    #endif
}
}

第五步 为不同的弹框创建脚本

正如我上面所提到的,我们将创建三种类型的弹框,让我们创建脚本来创建不同的弹框。

消息弹框

A) 创建 NativeMessage.cs 脚本为简单的消息弹框做一些基本设置。

public class NativeMessage
{
#region PUBLIC_FUNCTIONS

public NativeMessage(string title, string message)
{
init(title, message, "Ok");
}

public NativeMessage(string title, string message, string ok)
{
init(title, message, ok);
}

private void init(string title, string message, string ok)
{
#if UNITY_IPHONE
IOSMessage.Create(title, message, ok);
#endif
}
#endregion
}

B) 为简单消息弹框创建 IOSMessage.cs 脚本

public class IOSMessage : MonoBehaviour
{           
#region DELEGATE
public delegate void OnMessagePopupComplete(MessageState state);
public static event OnMessagePopupComplete onMessagePopupComplete;

    #endregion

    #region DELEGATE_CALLS

    private void RaiseOnMessagePopupComplete(MessageState state)
    {
        if (onMessagePopupComplete != null)
            onMessagePopupComplete(state);
    }

    #endregion

    #region PUBLIC_VARIABLES

    public string title;
    public string message;
    public string ok;

    #endregion

    #region PUBLIC_FUNCTIONS

    public static IOSMessage Create(string title, string message)
    {
        return Create(title, message, "Ok");
    }

    public static IOSMessage Create(string title, string message, string ok)
    {
        IOSMessage dialog;
        dialog = new GameObject("IOSMessagePopUp").AddComponent<IOSMessage>();
        dialog.title = title;
        dialog.message = message;
        dialog.ok = ok;
        
        dialog.init();
        return dialog;
    }

    public void init()
    {
        IOSNative.showMessage(title, message, ok);
    }

    #endregion

    #region IOS_EVENT_LISTENER

    public void OnPopUpCallBack(string buttonIndex)
    {
        RaiseOnMessagePopupComplete(MessageState.OK);
        Destroy(gameObject);
    }

    #endregion
}

确认弹框

A) 创建 NativeDialog.cs 脚本为会话的消息弹框做一些基本设置。

public class NativeDialog
{
    #region PUBLIC_VARIABLES
    string title;
    string message;
    string yesButton;
    string noButton;
    public string urlString;
    #endregion

    #region PUBLIC_FUNCTIONS
    public NativeDialog(string title, string message)
    {
        this.title = title;
        this.message = message;
        this.yesButton = "Yes";
        this.noButton = "No";
    }

    public NativeDialog(string title, string message, string yesButtonText, string noButtonText)
    {
        this.title = title;
        this.message = message;
        this.yesButton = yesButtonText;
        this.noButton = noButtonText;
    }

    public void SetUrlString(string urlString)
    {
        this.urlString = urlString;
    }

    public void init()
    {
        #if UNITY_IPHONE
        IOSDialog dialog = IOSDialog.Create(title, message, yesButton, noButton);
        dialog.urlString = urlString;
        #endif
    }
    #endregion
}

B) 为会话消息弹框创建 IOSDialog.cs 脚本

public class IOSDialog : MonoBehaviour
{
    #region DELEGATE
    public delegate void OnDialogPopupComplete(MessageState state);
    public static event OnDialogPopupComplete onDialogPopupComplete;
    #endregion

    #region DELEGATE_CALLS
    private void RaiseOnOnDialogPopupComplete(MessageState state)
    {
        if (onDialogPopupComplete != null)
            onDialogPopupComplete(state);
    }
    #endregion

    #region PUBLIC_VARIABLES
    public string title;
    public string message;
    public string yes;
    public string no;
    public string urlString;
    #endregion

    #region PUBLIC_FUNCTIONS
    // Constructor
    public static IOSDialog Create(string title, string message)
    {
        return Create(title, message, "Yes", "No");
    }

    public static IOSDialog Create(string title, string message, string yes, string no)
    {
        IOSDialog dialog;
        dialog = new GameObject("IOSDialogPopUp").AddComponent<IOSDialog>();
        dialog.title = title;
        dialog.message = message;
        dialog.yes = yes;
        dialog.no = no;
        dialog.init();
        return dialog;
    }

    public void init()
    {
        IOSNative.showDialog(title, message, yes, no);
    }
    #endregion

    #region IOS_EVENT_LISTENER
    public void OnDialogPopUpCallBack(string buttonIndex)
    {
        int index = System.Convert.ToInt16(buttonIndex);
        switch (index)
        {
            case 0: 
                IOSNative.RedirectToWebPage(urlString);
                RaiseOnOnDialogPopupComplete(MessageState.YES);
                break;
            case 1: 
                RaiseOnOnDialogPopupComplete(MessageState.NO);
                break;
        }
        Destroy(gameObject);
    }
    #endregion
}

评价我们弹框

A) 创建 NativeRateUS.cs 脚本为评价我们的弹框做一些基本设置。

public class NativeRateUS
{
   #region PUBLIC_VARIABLES
    public string title;
    public string message;
    public string yes;
    public string later;
    public string no;
    public string appleId;
    #endregion

    #region PUBLIC_FUNCTIONS
    // Constructor
    public NativeRateUS(string title, string message)
    {
        this.title = title;
        this.message = message;
        this.yes = "Rate app";
        this.later = "Later";
        this.no = "No, thanks";
    }

    // Constructor
    public NativeRateUS(string title, string message, string yes, string later, string no)
    {
        this.title = title;
        this.message = message;
        this.yes = yes;
        this.later = later;
        this.no = no;
    }
    // Set AppID to rate app
    public void SetAppleId(string _appleId)
    {
        appleId = _appleId;
    }
    
    // Initialize rate popup
    public void InitRateUS()
    {
        #if UNITY_IPHONE
        IOSRateUsPopUp rate = IOSRateUsPopUp.Create(title, message, yes, later, no);
        rate.appleId = appleId;
        #endif
    }
    #endregion
}

B) 为评价我们弹框创建 IOSRateUsPopUp.cs 脚本

public class IOSRateUsPopUp : MonoBehaviour
{
    #region DELEGATE
    public delegate void OnRateUSPopupComplete(MessageState state);
    public static event OnRateUSPopupComplete onRateUSPopupComplete;
    #endregion

    #region DELEGATE_CALLS
    private void RaiseOnOnRateUSPopupComplete(MessageState state)
    {
        if (onRateUSPopupComplete != null)
            onRateUSPopupComplete(state);
    }

    #endregion

    #region PUBLIC_VARIABLES
    public string title;
    public string message;
    public string rate;
    public string remind;
    public string declined;
    public string appleId;
    #endregion

    #region PUBLIC_FUNCTIONS
    public static IOSRateUsPopUp Create()
    {
        return Create("Like the Game?", "Rate US");
    }

    public static IOSRateUsPopUp Create(string title, string message)
    {
        return Create(title, message, "Rate Now", "Ask me later", "No, thanks");
    }

    public static IOSRateUsPopUp Create(string title, string message, string rate, string remind, string declined)
    {
        IOSRateUsPopUp popup = new GameObject("IOSRateUsPopUp").AddComponent<IOSRateUsPopUp>();
        popup.title = title;
        popup.message = message;
        popup.rate = rate;
        popup.remind = remind;
        popup.declined = declined;
        popup.init();
        return popup;
    }

    public void init()
    {
        IOSNative.showRateUsPopUP(title, message, rate, remind, declined);
    }
    #endregion

    #region IOS_EVENT_LISTENER
    public void OnRatePopUpCallBack(string buttonIndex)
    {
        int index = System.Convert.ToInt16(buttonIndex);
        switch (index)
        {
            case 0: 
                IOSNative.RedirectToAppStoreRatingPage(appleId);
                RaiseOnOnRateUSPopupComplete(MessageState.RATED);
                break;
            case 1:
                RaiseOnOnRateUSPopupComplete(MessageState.REMIND);
                break;
            case 2:
                RaiseOnOnRateUSPopupComplete(MessageState.DECLINED);
                break;
        }
        Destroy(gameObject);
    }
    #endregion
}

注意
在这些类中(每个弹框的 B 部分),我们创建了游戏物体并且我们使用游戏物体的名字来获得事件的回调。我们将在下一个部分(Objective-C 文件 UnitySendMessage())使用这些名字。

第六步 设置 iOS 文件

你完成了基本的代码!现在,让我们用 Objective-C 编码来创建弹框

这样做,创建新的 xcode 工程来创建 Objective-C 文件。如果你不了解 xcdoe 并不知道怎样使用 xcode 来创建工程,那么请看这里 使用 xcode 创建基本的工程

不要担心现在的代码,你只需要在你的文件中拷贝然后粘贴。如果你在创建工程和文件时面临着任何问题,那么你可以从博客的底部下载源代码。只要你下载完了工程,你就可以拷贝所有的 iOS 文件到你的 unity 工程的 Plugins 文件夹中

回到 xcode,创建新的 Objective-C 文件命名为 DataConvertor 来转换数据。

DataConverter.h

#import <Foundation/Foundation.h>
@interface DataConvertor : NSObject
+ (NSString*) charToNSString: (char*)value;
+ (const char *) NSIntToChar: (NSInteger) value;
+ (const char *) NSStringToChar: (NSString *) value;
@end

DataConverter.m

#import "DataConvertor.h"
@implementation DataConvertor
+(NSString *) charToNSString:(char *)value {
    if (value != NULL) {
        return [NSString stringWithUTF8String: value];
    } else {
        return [NSString stringWithUTF8String: ""];
    }
}

+(const char *)NSIntToChar:(NSInteger)value {
    NSString *tmp = [NSString stringWithFormat:@"%ld", (long)value];
    return [tmp UTF8String];
}

+ (const char *)NSStringToChar:(NSString *)value {
    return [value UTF8String];
}
@end

创建另一个文件命名为 IOSNativePopUpsManager 来从 unity 脚本中调用,并且显示弹框。

IOSNativePopUpsManager.h

#import <Foundation/Foundation.h>
#import "DataConvertor.h"
@interface IOSNativePopUpsManager : NSObject
+ (void) unregisterAllertView;
@end

IOSNativePopUpsManager.m

#import "IOSNativePopUpsManager.h"
@implementation IOSNativePopUpsManager
static UIAlertController* _currentAllert = nil;
+ (void) unregisterAllertView {
    if(_currentAllert != nil) {
        _currentAllert = nil;
    }
}

+(void) dismissCurrentAlert {
    if(_currentAllert != nil) {
        [_currentAllert dismissViewControllerAnimated:NO completion:nil];
        _currentAllert = nil;
    }
}

+(void) showRateUsPopUp: (NSString *) title message: (NSString*) msg b1: (NSString*) b1 b2: (NSString*) b2 b3: (NSString*) b3 {

    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:msg preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *rateAction = [UIAlertAction actionWithTitle:b1 style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
    [IOSNativePopUpsManager unregisterAllertView];
    UnitySendMessage("IOSRateUsPopUp", "OnRatePopUpCallBack", [DataConvertor NSIntToChar:0]);
    }];

    UIAlertAction *laterAction = [UIAlertAction actionWithTitle:b2 style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
    [IOSNativePopUpsManager unregisterAllertView];
    UnitySendMessage("IOSRateUsPopUp", "OnRatePopUpCallBack", [DataConvertor NSIntToChar:1]);
    }];

    UIAlertAction *declineAction = [UIAlertAction actionWithTitle:b3 style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
    [IOSNativePopUpsManager unregisterAllertView];
    UnitySendMessage("IOSRateUsPopUp", "OnRatePopUpCallBack", [DataConvertor NSIntToChar:2]);
    }];

    [alertController addAction:rateAction];
    [alertController addAction:laterAction];
    [alertController addAction:declineAction];
    [[[[UIApplication sharedApplication] keyWindow] rootViewController] presentViewController:alertController animated:YES completion:nil];
    _currentAllert = alertController;
}

+ (void) showDialog: (NSString *) title message: (NSString*) msg yesTitle:(NSString*) b1 noTitle: (NSString*) b2{

    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:msg preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *yesAction = [UIAlertAction actionWithTitle:b1 style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
    [IOSNativePopUpsManager unregisterAllertView];
    UnitySendMessage("IOSDialogPopUp", "OnDialogPopUpCallBack", [DataConvertor NSIntToChar:0]);
    }];

    UIAlertAction *noAction = [UIAlertAction actionWithTitle:b2 style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
    [IOSNativePopUpsManager unregisterAllertView];
    UnitySendMessage("IOSDialogPopUp", "OnDialogPopUpCallBack", [DataConvertor NSIntToChar:1]);
    }];

    [alertController addAction:yesAction];
    [alertController addAction:noAction];
    [[[[UIApplication sharedApplication] keyWindow] rootViewController] presentViewController:alertController animated:YES completion:nil];
    _currentAllert = alertController;
}

+(void)showMessage: (NSString *) title message: (NSString*) msg okTitle:(NSString*) b1 {
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:msg preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *okAction = [UIAlertAction actionWithTitle:b1 style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
    [IOSNativePopUpsManager unregisterAllertView];
    UnitySendMessage("IOSMessagePopUp", "OnPopUpCallBack", [DataConvertor NSIntToChar:0]);
    }];

    [alertController addAction:okAction];
    [[[[UIApplication sharedApplication] keyWindow] rootViewController] presentViewController:alertController animated:YES completion:nil];
    _currentAllert = alertController;
}

extern "C" {
    // Unity Call
    void _TAG_ShowRateUsPopUp(char* title, char* message, char* b1, char* b2, char* b3) {
        [IOSNativePopUpsManager showRateUsPopUp:[DataConvertor charToNSString:title] message:[DataConvertor charToNSString:message] b1:[DataConvertor charToNSString:b1] b2:[DataConvertor charToNSString:b2] b3:[DataConvertor charToNSString:b3]];
    }
    void _TAG_ShowDialog(char* title, char* message, char* yes, char* no) {
        [IOSNativePopUpsManager showDialog:[DataConvertor charToNSString:title] message:[DataConvertor charToNSString:message] yesTitle:[DataConvertor charToNSString:yes] noTitle:[DataConvertor charToNSString:no]];
    }
    void _TAG_ShowMessage(char* title, char* message, char* ok) {
        [IOSNativePopUpsManager showMessage:[DataConvertor charToNSString:title] message:[DataConvertor charToNSString:message] okTitle:[DataConvertor charToNSString:ok]];
    }
    void _TAG_DismissCurrentAlert() {
        [IOSNativePopUpsManager dismissCurrentAlert];
    }
}
@end

注意
在这个类中,我们使用 UnitySendMessage() 向 unity 发送一条消息,然后我们使用游戏物体的名字作为参数。必须和创建的游戏物体,特别是弹框类相匹配。

现在创建一个新的文件命名为 IOSNativeUtility 来重定向控制从应用程序到评价页面或者任何其他网页。

IOSNativeUtility.h

#import <Foundation/Foundation.h>
#import "DataConvertor.h"
#if UNITY_VERSION < 450
#include "iPhone_View.h"
#endif

@interface IOSNativeUtility : NSObject
@property (strong) UIActivityIndicatorView *spinner;
+ (id) sharedInstance;
- (void) redirectToRatigPage: (NSString *) appId;
@end

IOSNativeUtility.m

#import "IOSNativeUtility.h"
@implementation IOSNativeUtility
static IOSNativeUtility *_sharedInstance;
static NSString* templateReviewURLIOS7 = @"itms-apps://itunes.apple.com/app/idAPP_ID";
NSString *templateReviewURL = @"itms-apps://ax.itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?type=Purple+Software&id=APP_ID";

+ (id)sharedInstance {
    if (_sharedInstance == nil) {
        _sharedInstance = [[self alloc] init];
    }
    return _sharedInstance;
}

-(void) redirectToRatigPage:(NSString *)appId {
    #if TARGET_IPHONE_SIMULATOR
        NSLog(@"APPIRATER NOTE: iTunes App Store is not supported on the iOS simulator. Unable to open App Store page.");
    #else
    NSString *reviewURL;
    NSArray *vComp = [[UIDevice currentDevice].systemVersion componentsSeparatedByString:@"."];
    if ([[vComp objectAtIndex:0] intValue] >= 7) {
        reviewURL = [templateReviewURLIOS7 stringByReplacingOccurrencesOfString:@"APP_ID" withString:[NSString stringWithFormat:@"%@", appId]];
    } else {
        reviewURL = [templateReviewURL stringByReplacingOccurrencesOfString:@"APP_ID" withString:[NSString stringWithFormat:@"%@", appId]];
    }
    NSLog(@"redirecting to iTunes page, IOS version: %i", [[vComp objectAtIndex:0] intValue]);
    NSLog(@"redirect URL: %@", reviewURL);
    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:reviewURL]];
    #endif
}

-(void) openWebPage:(NSString *)urlString{
    #if TARGET_IPHONE_SIMULATOR
        NSLog(@"APPIRATER NOTE: iTunes App Store is not supported on the iOS simulator. Unable to open App Store page.");
    #else
        NSURL *url = [ [ NSURL alloc ] initWithString:urlString];
        [[UIApplication sharedApplication] openURL:url];
    #endif
}

extern "C" {
    void _TAG_RedirectToAppStoreRatingPage(char* appId) {
        [[IOSNativeUtility sharedInstance] redirectToRatigPage: [DataConvertor charToNSString:appId ]];
    }
    void _TAG_RedirectToWebPage(char* urlString){
        [[IOSNativeUtility sharedInstance] openWebPage:[DataConvertor charToNSString:urlString]];
    }
}
@end

现在,从 xcode 工程目录中把所有的 Objective-C 文件拷贝到 unity 工程的 Plugins 目录中。

如果你在创建 xcode 工程或 Objective-C 文件时面临着任何问题,那么你可以从博客的底部下载源代码。只要你下载完了工程,你就可以拷贝所有的 Objective-C 文件到你的 unity 工程的 Plugins/iOS 文件夹中

我希望这篇博客对你是有帮助的。如果你对 iOS 原生弹框有任何问题或疑惑,那么请自由地在评论区发表评论。我一定会尽快回复你。有一个游戏开发的想法么?你还在等什么?现在就联系我们吧,不久你就会看到你的想法实现了。

下载完整代码
CSDN链接

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,482评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,377评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,762评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,273评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,289评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,046评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,351评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,988评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,476评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,948评论 2 324
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,064评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,712评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,261评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,264评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,486评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,511评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,802评论 2 345

推荐阅读更多精彩内容