使用 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链接

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Rindew的iOS技术分享

iOS地图找房(类似链家、安居客等地图找房)

2906
来自专栏zaking's

RFC2616-HTTP1.1-Header Field Definitions(头字段规定部分—单词注释版)

1422
来自专栏黑白安全

来做个Google Hack吗?

storemanager/contents/item.php?page_code=

5346
来自专栏bboysoul

linux下的彩蛋和各种有趣的命令

循环输出 for ((i=1;i<=30;i++));do linux_logo -f -L $i;sleep 0.1;done

1514
来自专栏技术小黑屋

WebView处理网页位置请求

随着移动设备的激增,LBS(Location Based Service)已然成为趋势,其最关键的还是获取设备的位置信息。native代码获取位置信息轻轻松松可...

1551
来自专栏浅探ARKit

ARKit中控制.dae动画的播放

4.用时间控制动画--CAAnimation 里的 timeOffset 控制开始时间 duration控制播放时间

7407
来自专栏Android开发经验

Volley从源码梳理主要工作流程简记

重点来了。 这里开启了一个缓存调度线程CacheDispatcher,一个网络请求调度线程NetworkDispatcher。

692
来自专栏JarvanMo的IT专栏

Android通过代码实现多语言切换

最近接手一个Android项目,需要实现对维吾尔族语的支持。虽然做了这么久的android开发,只做过多语言支持,但做应用内部多语言支持还是第一次,而且还是对维...

5472
来自专栏岑玉海

Hbase 学习(二)补充 自定义filter

本来这个内容是不单独讲的,但是因为上一个页面太大,导致Live Writer死机了,不能继续编辑了,所以就放弃了 这里要讲的是自定义filter,从Filt...

3455
来自专栏杂烩

分布式服务框架之Dubbo整合Spring项目(二)

1002

扫码关注云+社区

领取腾讯云代金券