如何做一个跨平台的游戏App?
iOS和安卓系统上的应用程序,根据提供的内容不同,按照开发方式和用户体验不同,可区分为app和游戏;
首先从开发方式不同来说明,app开发一般是用操作系统官方提供的开发套件来做对应的开发;
这里的开发套件就系统不同可做以下区别:
iOS: Xcode, Objective-C
android: AndroidStudio, Java/Kotlin
游戏的开发方式就很多了,不过最终一步一般都是生成对应IDE的项目工程,然后在对应的项目工程上进行配置设置,签名配置等步骤,最后完成打包.ipa和.apk的打包; 在最后一步前开发方式就根据项目需求以及其他因素考量,可采取不同的开发方案了; 之前有幸在做iOS的SDK开发,对接了上百款游戏,也算对游戏的开发环境有所了解了。
2D游戏一般用: Cocos2dx, Cordova,Corona,Contruct2等,当然也可以用Unity来开发2D游戏;
3D游戏一般用: Unity为主流;
最后从用户体验不同来说明,
app在前几年时间里,界面一般要根据不同系统来做开发,市面上看到的很多app的iOS版本和安卓版本有一些UI是长的不一样的, 这里就导致用户体验不一致的问题,如果领导需要,可采取混合网页的方式,但是同时会带来体验不流畅的问题,这就要看沟通了,最终采取哪种方式了。
一般情况下,市面上的应用程序要么是app要么是游戏类型,但是碰到一些需求,需要吸取app和游戏的特性,融合在一起,丰富应用程序的功能和体验,这时候我们开发的应用程序,我通常称它为游戏app.
前段时间参与过一个项目,功能和体验就是这样的一个应用程序,我把用到的基本技术抽出来,整理代码出来一个小demo, 其它类似的游戏混合app都可以借鉴此思路进行开发; 这个小demo的效果如下所示:
iOS Android
demo说明:
演示场景最后一个画面是Unity的游戏场景,倒数第二个界面是React-Native界面,其它页面是原生界面;
相关开发环境说明:
Unity2018.3.11f1
AndroidStudio3.3.2 (gradle插件版本3.2.0,gradle版本4.10.1,buildToolsVersion 29.0.0-rc1)
ReactNative0.59.5
XCode10.2.1
demo效果参考步骤如下:
一. 创建ReactNative工程
参考文档https://facebook.github.io/react-native/docs/getting-started,逐步实现RN功能,下面截图就是我demo工程里创建的一个测试登录界面:
二.Unity导出原生项目
这步网上有很多教程,参考就可以了,基本没什么特别需要注意的地方,主要是一些打包配置设置问题,在我demo工程里,由于我引入了ReactNative功能,我需要把导出的xcode工程和as工程放到指定的文件夹层次,我把导出的原生项目工程截图所示如下:
使用的Unity版本在iOS和安卓打包的时候,有一些区别;
iOS端: 打包生成Xcode工程,可以选择replace或者append, 建议用append方式,这样每次打包不影响原生工程的东西。
安卓端: 打包生成AS工程,会直接替换老的文件,建议用github Desktop进行代码文件管理,不然原生工程修改的相关配置一不小心就被覆盖了。
下面说一下Unity每次修改打包成Xcode工程和AS工程的时候,会改变哪些代码和哪些文件? 此类混合项目要清楚,不然在功能协作的时候,很容易发生混乱,代码相互覆盖等问题!
开发场景一: 每次修改Unity里的.scene里的场景数据,打包出来Xcode工程,截图所示文件夹内的代码文件会发生大幅度的修改
iOS
android
开发场景二: 脚本代码发生修改后,打包出来的文件,截图所示红框部分文件每次新打包都会改变,黄框部分文件是脚本代码发生修改后,打包出来发生修改的文件
iOS android
测试发现Unity打包出Xcode工程以及Unity里功能变更,打包出来的Xcode工程,涉及到文件和项目配置众多,之前网上看到的很多文章大都是把Unity打包出来的新文件和配置,手动在原生项目里进行修改和文件引用众 多工作,我个人操作很麻烦,也有很多问题,每次Unity端功能发生更新,代码和文件更新到原生项目就有点麻烦了,我这边的操作步骤是在Unity端打包出来的Xcode工程上进行原生模块功能添加,原生模块功能以动态 库.framework形式引入,彼此松耦合!
三.原生项目框架引入
这一步按照ReactNative官方文档https://facebook.github.io/react-native/docs/integration-with-existing-apps来就可以了,这里需要注意;
我在iOS端使用CocoaPods (建议最好用CocoaPods集成方式,跟之前的项目工程形成松耦合)方式的时候,有一些第三方React-Native库没有CocoaPods集成方式,这时候就需要查看源码来手动link和项目配置了,或者换第三方库,再或者自己写,自己写的话,可按照官方指引https://facebook.github.io/react-native/docs/native-modules-setup来;
下面分享一段我项目中使用的Podfile文件
# Uncomment the next line to define a global platform for your project # platform :ios, '9.0' target 'Unity-iPhone' do # Comment the next line if you don't want to use dynamic frameworks use_frameworks! # Pods for Unity-iPhone # 'node_modules'目录一般位于根目录中 # 但是如果你的结构不同,那你就要根据实际路径修改下面的`:path` pod 'React', :path => '../node_modules/react-native', :subspecs => [ 'Core', 'CxxBridge', # 如果RN版本 >= 0.47则加入此行 'DevSupport', # 如果RN版本 >= 0.43,则需要加入此行才能开启开发者菜单 'RCTText', 'RCTNetwork', 'RCTWebSocket', # 调试功能需要此模块 'RCTAnimation', # FlatList和原生动画功能需要此模块 # 在这里继续添加你所需要的其他RN模块 'RCTImage', ] # 如果你的RN版本 >= 0.42.0,则加入下面这行 pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga' # 如果RN版本 >= 0.45则加入下面三个第三方编译依赖 pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec' pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec' pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec' # # CodePush plugin dependency # pod 'CodePush', :path => '../node_modules/react-native-code-push' # pod 'react-native-blur', :path => '../node_modules/react-native-blur' # pod 'react-native-fetch-blob',:path => '../node_modules/react-native-fetch-blob' # pod 'react-native-fast-image',:path => '../node_modules/react-native-fast-image' # pod 'react-native-orientation',:path => '../node_modules/react-native-orientation' # pod 'RNFS', :path => '../node_modules/react-native-fs' # pod 'RNSVG',:path => '../node_modules/react-native-svg' target 'Unity-iPhone Tests' do inherit! :search_paths # Pods for testing # pod 'react-native-blur', :path => '../node_modules/react-native-blur' end end
四. 功能整合
这里要以iOS和android两端做对应处理,区别有点大,由于iOS和安卓端都是我一个人弄,而我本身是iOS出身,对iOS端会更熟悉些,安卓端处理可能会不太专业,但也算初步实现了。
以iOS端为例:
前面的步骤可以算ReactNative功能跟Unity功能初步集成到一起了,接下来就要再加入iOS原生功能,最后再把ReactNative功能,Unity功能串接到一起了!
1. 加入iOS原生功能
demo里我是加入了两个导航页面,我是直接在Unity导出的Xcode工程上加入的,因为Unity导出Xcode工程是可以增量更新的,后续Unity测功能更新,重新打包也不会影响我旧有Xcode工程的代码。
2.引入ReactNative功能
在第一步里,我们已经创建好ReactNative项目,也创建了一个登录测试页面,在这一步里我们需要导航到这个页面,这个页面我们需要用一个原生视图控制器来承载,然后就是原生功能的简单导航了
-(UIViewController*) getRNDisplayVC { if(!self.rnVC) { NSURL* jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; jsCodeLocation=[[NSBundle mainBundle] URLForResource:@"/bundle/index" withExtension:@"jsbundle"]; RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation moduleName:@"myApp" initialProperties:nil launchOptions:self.launchOptions]; rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; UIViewController *rootViewController = [UIViewController new]; rootViewController.view = rootView; self.rnVC=rootViewController; } return self.rnVC; }
代码里我使用的是已经打包好的.jsbundle文件,下面给出打包命令,在ReactNative文件夹下创建bundle文件夹,然后在ReactNative项目根文件夹里打开终端命令,输入下面代码
react-native bundle --entry-file index.js --platform ios --dev false --bundle-output ./bundle/index.jsbundle --assets-dest ./bundle
最后把bundle文件夹引入到项目工程里,使用视图控制器的导航相关代码,就已经完成原生页面向ReactNative页面导航了,而ReactNative页面向原生页面导航,实质就是ReactNative访问原生模块的问题了,参考官方指引 https://facebook.github.io/react-native/docs/native-modules-ios#content
3.Unity跟原生互调或者Unity跟ReactNative互调
本质就是Unity跟原生的通信了,网上文章很多,这里就不阐述了。
demo的开发思路初步是这样,其中有一些步骤还不算完美,有做类似此类项目的同学,可以一起讨论!