Unity游戏嵌入iOS应用(融合为一个应用) v2.0

一 游戏嵌入APP
1.1 开发工具版本
1.1.1 iOS 开发工具版本Xcode Version 14.2(14C18)
请添加图片描述
1.1.2 iOS项目开发语言为Swift5
在这里插入图片描述
1.1.3 Unity开发工具版本 2022.3.8f1c1
在这里插入图片描述
1.2 iOS项目和Unity项目结合

1.2.1 iOS新建一个Swift语言的项目
在这里插入图片描述
在这里插入图片描述

在新建的iOS工程里,新建文件夹Unity_Framework_Project,后续Unity导出的工程放到这个文件夹里

在这里插入图片描述
1.2.2 Unity项目里,切到iOS平台
在这里插入图片描述

Unity将程序包导出,放入iOS工程里的文件夹Unity_Framework_Project。

在这里插入图片描述

在这里插入图片描述

导出的文件

在这里插入图片描述
1.2.3 把游戏工程导入iOS工程

在这里插入图片描述
在这里插入图片描述
1.2.4 在Xcode做如下设置
在这里插入图片描述
1.2.5 加入Unity和iOS可以相互传值的共通代码
unity项目里新建两个文件,加入
在这里插入图片描述

iOSUtilUnity3dBridge.h

#import <Foundation/Foundation.h>
//调用录音权限需要引入的包
#import <AVFoundation/AVFoundation.h>
@interface iOSUtilUnity3dBridge : NSObject
#ifdef __cplusplus
extern "C"{
#endif
const char* UnitySendMessageToiOS(const char *str);
NSString* iOSGetMessage();
void iOSGetMessageChangeColor();
const char* getMicroRight();
#ifdef __cplusplus
}
#endif
@end
iOSUtilUnity3dBridge.m

#import <Foundation/Foundation.h>
#import "iOSUtilUnity3dBridge.h"
#ifdef __cplusplus
extern "C"
{
#endif
    
    NSString *returnString;
    //NSString转char*
    char* _MakeStringCopy(const char* str) {
        if(str == NULL){return NULL;}
        char* res = (char*)malloc(strlen(str)+1);
        strcpy(res, str);
        return res;
    }
    
    const char* UnitySendMessageToiOS(const char *str)
    {
        NSString *string1 = [[NSString alloc] initWithUTF8String:str];
        NSString *string2 = [NSString stringWithFormat:@"%@", string1];
        returnString = string2;
        return _MakeStringCopy([string2 UTF8String]);
    }


    NSString* iOSGetMessage()
    {
        return returnString;
    }
    
    /// 通知ios关闭遮挡游戏的画面关闭
    void iOSGetMessageChangeColor()
    {
        NSLog(@"iOSGetMessageChangeColor");
        //oc层发出通知,swift层会在需要的地方接收到通知做对应的逻辑处理。
        [[NSNotificationCenter defaultCenter] postNotificationName:@"iOSGetMessageChangeColor" object:nil];
    }


    //获取录音权限状态
    //约定返回游戏,1代表授权。0代表未授权
    const char* getMicroRight()
    {
        AVAuthorizationStatus microPhoneStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
            switch (microPhoneStatus) {
                case AVAuthorizationStatusDenied:
                case AVAuthorizationStatusRestricted:
                {
                    // 被拒绝
                    NSString *string = [NSString stringWithFormat:@"%s", "0"];
                    return _MakeStringCopy([string UTF8String]);
                }
                    break;
                case AVAuthorizationStatusNotDetermined:
                {
                    // 没弹窗
                    NSString *string = [NSString stringWithFormat:@"%s", "0"];
                    return _MakeStringCopy([string UTF8String]);
                }
                    break;
                case AVAuthorizationStatusAuthorized:
                {
                    // 有授权
                    NSString *string = [NSString stringWithFormat:@"%s", "1"];
                    return _MakeStringCopy([string UTF8String]);
                }
                    break;


                default:
                    break;
            }
        
        NSString *string = [NSString stringWithFormat:@"%s", "0"];
        return _MakeStringCopy([string UTF8String]);
    }
  
#ifdef __cplusplus
}
#endif

Unity导出的iOS项目,如下图需要调整iOSUtilUnity3dBridge.h的位置

在这里插入图片描述

添加如下代码
在这里插入图片描述

#import "iOSUtilUnity3dBridge.h"

在这里插入图片描述

- (NSString *)myiOSGetMessage;

在这里插入图片描述

- (NSString *)myiOSGetMessage
{
    return iOSGetMessage();
}

1.2.6 添加2个类,控制Unity游戏在APP新画面里的显示
在这里插入图片描述
在这里插入图片描述

UnityFrameworkWrapper.swift

import Foundation
import UnityFramework


protocol UnityFrameworkDeallocator {
    func exitUnity()
}


class UnityFrameworkWrapper: NSObject, UnityFrameworkListener {
    
    static let shared = UnityFrameworkWrapper()
    
    // MARK: - Properties
    var framework: UnityFramework
    var delegate: UnityFrameworkDeallocator?
    
    // MARK: - init
    override init() {
        self.framework = UnityFramework.getInstance()
        super.init()
        //下面的BundleId是unity的ios工程里framework的target里的BundleId,这个要和里面的包名一致。
        framework.setDataBundleId("com.unity3d.framework")
        framework.register(self)
        //这句不加,程序运行不起来
        framework.runEmbedded(withArgc:  CommandLine.argc, argv: CommandLine.unsafeArgv, appLaunchOpts: nil)
    }


    // MARK: - NativeCallsProtocol
    func showHostMainWindow(_ color: String!) {
        delegate?.exitUnity()
    }
    
    //unity的CSharp代码里调用Application.unload后会触发下面的方法
    func unityDidUnload(_ notification: Notification!) {
        print("Unity发送的信息,iOS接收的信息 = \(String(describing: framework.myiOSGetMessage()))")
        //点击Unity的Application.unload方法会进入到这个方法
        framework.unregisterFrameworkListener(self)
        //调用UnityViewController里的exitUnity方法
        delegate?.exitUnity()
    }
    
    func showUnityView() {
        //iOS向Unity发送信息
        framework.sendMessageToGO(withName: "Main Camera", functionName: "IOSToUnity", message: "iOSToUnityStart")
        //显示unity画面
        framework.showUnityWindow()
    }


}

UnityViewController.swift

import UIKit


class UnityViewController: UIViewController, UnityFrameworkDeallocator {


    var unityInstance:UnityFrameworkWrapper? = nil
    
    override func viewDidLoad() {
        super.viewDidLoad()
        startUnity()
    }
    
    //加载游戏画面
    func startUnity() {
        unityInstance = UnityFrameworkWrapper.init()
        unityInstance?.delegate = self
        unityInstance?.showUnityView()
    }
    
    //退出游戏画面
    func exitUnity() {
        let appDelegate = UIApplication.shared.delegate as? AppDelegate
        //不加下面的代码,从游戏回到APP画面会卡主
        if let window = appDelegate?.window {
            window.makeKeyAndVisible()
        }
        //退回上一级画面
        self.dismiss(animated: false, completion: nil)
    }


}

1.2.7 新建一个文件夹存放生成的UnityFramework

2

编译生成UnityFramework

在这里插入图片描述

找到它

在这里插入图片描述
在这里插入图片描述

添加进iOS工程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.2.8 删除系统的Main,自己新建一个启动的ViewController

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        window = UIWindow(frame:UIScreen.main.bounds)
        window?.backgroundColor = .white
        window?.rootViewController = ViewController()
        window?.makeKeyAndVisible()
        return true
    }
}

在这里插入图片描述
在这里插入图片描述

1.2.9 新建的ViewController代码包含有显示游戏画面和传参的代码

在这里插入图片描述

import UIKit
class ViewController: UIViewController, UnityFrameworkDeallocator {
    var unityInstance:UnityFrameworkWrapper? = nil
    let buttonChangeGame = UIButton(frame: CGRect(x: 250, y: 250, width: 100, height: 100))
    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = .white
        let buttonGoToGameNewPage = UIButton(frame: CGRect(x: 50, y: 100, width: 150, height: 100))
        buttonGoToGameNewPage.backgroundColor = .gray
        buttonGoToGameNewPage.setTitle("新页面显示游戏", for: .normal)
        view.addSubview(buttonGoToGameNewPage)
        buttonGoToGameNewPage.addTarget(self, action: #selector(buttonGoToGameNewPageClick), for: UIControl.Event.touchUpInside)
        let buttonGoToGame = UIButton(frame: CGRect(x: 50, y: 250, width: 150, height: 100))
        buttonGoToGame.backgroundColor = .gray
        buttonGoToGame.setTitle("当前页显示游戏", for: .normal)
        view.addSubview(buttonGoToGame)
        buttonGoToGame.addTarget(self, action: #selector(buttonGoToGameClick), for: UIControl.Event.touchUpInside)
        //获得游戏的通知,改变颜色
        NotificationCenter.default.addObserver(self, selector: #selector(ChangeColor), name:Notification.Name("iOSGetMessageChangeColor") , object: nil) 
    }
    @objc func ChangeColor() {
        self.view.backgroundColor = .systemYellow
    }
    @objc func buttonGoToGameNewPageClick() {
        //新画面显示
        let unityViewController = UnityViewController()
        unityViewController.modalPresentationStyle = UIModalPresentationStyle.fullScreen
        self.present(unityViewController, animated: false)
        self.unityInstance?.framework.appController().rootView.alpha = 1.0;
        buttonChangeGame.alpha = 0.0
    }
    @objc func buttonGoToGameClick() {
        //当前画面显示
        unityInstance = UnityFrameworkWrapper.init()
        unityInstance?.delegate = self
        self.unityInstance?.framework.appController().rootView.frame = CGRect(x: 0, y: 500, width: 400, height: 200)
        self.unityInstance?.framework.appController().rootView.alpha = 1.0
        self.unityInstance?.framework.sendMessageToGO(withName: "Main Camera", functionName: "IOSToUnity", message: "ios_to_unity")
        //在游戏的window上加载一个APP的按钮,按钮可以点击。
        buttonChangeGame.backgroundColor = .gray
        buttonChangeGame.setTitle("游戏变色", for: .normal)
        unityInstance?.framework.appController().window.addSubview(buttonChangeGame)
        buttonChangeGame.addTarget(self, action: #selector(buttonChangeGameClick), for: UIControl.Event.touchUpInside)
        buttonChangeGame.alpha = 1.0
    }
    @objc func buttonChangeGameClick() {
        self.unityInstance?.framework.sendMessageToGO(withName: "Main Camera", functionName: "IOSToUnity", message: "unity_change_color")
        print("buttonChangeGameClick")
    }
    //退出游戏画面
    func exitUnity() {
        let appDelegate = UIApplication.shared.delegate as? AppDelegate
        //不加下面的代码,从游戏回到APP画面会卡主
        if let window = appDelegate?.window {
            window.makeKeyAndVisible()
        }
        self.unityInstance?.framework.appController().rootView.alpha = 0.0;
    }
}

1.2.10 项目APP是竖屏,做的一些设置
在这里插入图片描述

二 APP传参给游戏(APP运行中和APP结束时)

2.1 iOS结束,启动Unity时传参
在这里插入图片描述

        let unityViewController = UnityViewController()
        unityViewController.modalPresentationStyle = UIModalPresentationStyle.fullScreen
        self.present(unityViewController, animated: false)
        self.unityInstance?.framework.appController().rootView.alpha = 1.0;
        buttonChangeGame.alpha = 0.0

2

在这里插入图片描述

framework.sendMessageToGO(withName: "Main Camera", functionName: "IOSToUnity", message: "iOSToUnityStart")

Main Camera 是Unity接收的对象
IOSToUnity 是挂载在Main Camera脚本里的方法
iOSToUnityStart 是传给Unity的具体字符
在这里插入图片描述
在这里插入图片描述

    public void IOSToUnity(string str)
    {
        Debug.Log("Unity接收IOS信息" + str);
    }

2.2 iOS运行中向Unity传参

在这里插入图片描述

self.unityInstance?.framework.sendMessageToGO(withName: "Main Camera", functionName: "IOSToUnity", message: "unity_change_color")

Main Camera 是Unity接收的对象
IOSToUnity 是挂载在Main Camera脚本里的方法
unity_change_color 是传给Unity的具体字符
2
在这里插入图片描述
获得iOS传给的字符unity_change_color,改变Unity的背景色

    public void IOSToUnity(string str)
    {
        Debug.Log("Unity接收IOS信息" + str);
        if (str == "unity_change_color")
            camera.backgroundColor = new Color(0 / 255, 255 / 255, 255 / 255);
    }

三 游戏传参给APP(游戏运行中和游戏结束时)

3.1 Unity结束,启动iOS时传参
Unity:

在这里插入图片描述

//Unity发送信息给iOS
UnitySendMessageToiOS("unity_to_ios");
//unity程序关闭
Application.Unload();

iOS:

Unity里调用Application.Unload();方法。在iOS里有一个接收的方法
在这里插入图片描述

    func unityDidUnload(_ notification: Notification!) {
        print("Unity发送的信息,iOS接收的信息 = \(String(describing: framework.myiOSGetMessage()))")
        //点击Unity的Application.unload方法会进入到这个方法
        framework.unregisterFrameworkListener(self)
        //调用UnityViewController里的exitUnity方法
        delegate?.exitUnity()
    }

myiOSGetMessage方法是前面添加Unity和iOS共通里处理好的方法(具体参考1.2.5 加入代码做到Unity和iOS相互传值的共通代码)。

3.2 Unity运行中向iOS传参
Unity:
在这里插入图片描述
//Unity发送信息给iOS
iOSGetMessageChangeColor();

iOS:
在这里插入图片描述

//获得游戏的通知,改变APP颜色
NotificationCenter.default.addObserver(self, selector: #selector(ChangeColor), name:Notification.Name("iOSGetMessageChangeColor") , object: nil)

@objc func ChangeColor() {
    self.view.backgroundColor = .systemYellow
}

iOSGetMessageChangeColor方法是前面添加Unity和iOS共通里处理好的方法(具体参考1.2.5 加入代码做到Unity和iOS相互传值的共通代码)。

四 游戏获取APP的权限(以录音权限为例说明)
4.1 游戏申请录音权限,会弹窗让用户选择是否赋权限给APP
在这里插入图片描述
在这里插入图片描述

    /// <summary>
    /// 申请录音权限(录音1秒)
    /// </summary>
    void RequestRecordRight()
    {
        Microphone.Start(null, false, 1, 1);
        Microphone.End(null);
        Debug.Log("申请权限");
    }

4.2 游戏调用iOS的API确认是否获取了录音权限
Unity:
在这里插入图片描述
在这里插入图片描述

    // 调用此方法,iOS端对应方法可以接收到,返回值通过iOS的方法返回给Unity
    private static extern string getMicroRight();

在这里插入图片描述

/// <summary>
    /// 检测录音权限,需要游戏向APP申请,APP获取是否有权限后,再返回给游戏
    /// </summary>
    /// <returns></returns>
    public IEnumerator CheckiOSRecordRight()
    {
        Debug.Log("getMicroRight() = " + getMicroRight());
        yield return new WaitForSeconds(0.5f);
#if UNITY_IOS
        //录音权限未开启,提醒用户,并且不能玩游戏。
        if (getMicroRight() == "0")
        {
            Debug.Log("录音权限未授权,请在设置画面开启录音权限");
        }
        else
        {
            Debug.Log("具有录音权限,实现相关功能");
        }
#endif
    }

iOS:

getMicroRight方法是写在iOSUtilUnity3dBridge.h和iOSUtilUnity3dBridge.m里
在这里插入图片描述
在这里插入图片描述

//获取录音权限状态
    //约定返回游戏,1代表授权。0代表未授权
    const char* getMicroRight()
    {
        AVAuthorizationStatus microPhoneStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
            switch (microPhoneStatus) {
                case AVAuthorizationStatusDenied:
                case AVAuthorizationStatusRestricted:
                {
                    // 被拒绝
                    NSString *string = [NSString stringWithFormat:@"%s", "0"];
                    return _MakeStringCopy([string UTF8String]);
                }
                    break;
                case AVAuthorizationStatusNotDetermined:
                {
                    // 没弹窗
                    NSString *string = [NSString stringWithFormat:@"%s", "0"];
                    return _MakeStringCopy([string UTF8String]);
                }
                    break;
                case AVAuthorizationStatusAuthorized:
                {
                    // 有授权
                    NSString *string = [NSString stringWithFormat:@"%s", "1"];
                    return _MakeStringCopy([string UTF8String]);
                }
                    break;
                default:
                    break;
            }
        
        NSString *string = [NSString stringWithFormat:@"%s", "0"];
        return _MakeStringCopy([string UTF8String]);
    }

在iOS端获取到权限会及时返回到Unity,Unity拿到是否获取到录音权限后,再处理相关逻辑。
在这里插入图片描述
五 运行效果
请添加图片描述

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值