【前言】
以下只是简要介绍,详细的内容需要自己去看链接
【Objective-C基础知识】
.h .m .mm .cpp文件区别
.h是头文件扩展名。头文件包含类,类型,函数和常数的声明,这里的定义一般是Public的
.m是实现文件扩展名。其包含源代码,用于.h文件中的实现,一般是private的。这是C++中的类似。
.mm类似.m,除了可以包含Objective-C代码外,还可以包含C、C++代码
.cpp只能包含C++代码
一般在unity中会使用.h和.mm文件
include和import
两者都可以用于导入需要的源代码的头文件,include与C++中的类似,Import在此基础上会确保相同的文件只会被包含一次,类似Java的import,推荐使用import
""和<>
和C++类型,“”用于导入自定义的文件,<>用于导入系统文件
+和-
+类似C#的静态方法,-类似C#的实例方法
语法基础
Swift和OC
Swift是2014年苹果推出的新语言,相对于OC有很多优势,会逐步取代OC。作为Unity程序,Swift比OC可读性更好,在调用iOS原生功能时,如果用OC不好实现,可以考虑用Swift来写,这时需要了解OC如何调用Swift
【C#与OC的调用】
C#不可以直接调用OC,但可以通过DllImport来调用C,让C调用OC
OC调用C
第一种方式是单独的C头文件,C实现文件
//test.h
#ifndef test_h
#define test_h
#include <stdio.h>
#endif /* test_h */
int Add();
//test.c
#include "test.h"
int Add(int a,int b)
{
return a+b
}
然后创建OC的头文件,实现文件
//TestOc.h
#import <Foundation/Foundation.h>
@interface TestOC : NSObject
- (int)ocCallC:(int)a with:(int)b;
@end
//TestOC.m
#import "TestOC.h"
#include "test.h" //要include C的头文件
@implementation TestOC
- (void)ocCallC:(int)a with:(int)b
{
int result = add(a,b);//可以直接按照C语言的函数调用语法来调用函数
return result;
}
@end
第二种方式是直接在.mm文件中写C函数
//TestOC.mm
#import "TestOC.h"
int Add(int a,int b)
{
return a+b
}
@implementation TestOC
- (int)ocCallC:(int)a with:(int)b
{
int result = add(a,b);//可以直接按照C语言的函数调用语法来调用函数
return result;
}
@end
我们一般不会用第一种方式,还要写C的头文件和实现文件比较麻烦,一般都用第二种方式。
C调用OC
函数调用主要是找到函数的地址,C函数调用直接通过函数名(参数)找到函数指针,直接执行函数地址。OC等面向对象的语言需要通过找到类的地址,然后再找到函数地址。因此,C调用OC函数时,可以直接在C函数中按照OC写法即可。这同样有两种方式,我们直接用第二种方式。
//TestOC.mm
#import "TestOC.h"
int Add(int a,int b)
{
return a+b
}
@implementation TestOC
+ (void)CCalloc:(int)a with:(int)b
{
return a + b;
}
int CAdd(int a,int b)
{
return [TestOC CCalloc:a with:b];
}
@end
extern "C"
extern "C"会指示编译器这部分代码按C语言的方式进行编译,extern表示该代码可以被跨模块使用,编译器在编译时会跨模块寻找而不是在Include的文件中寻找,将找到的函数链接。这样用C#的P/Invoke功能可以调用.mm文件中的函数。代码如下:
//.mm文件中
#if defined(__cplusplus)
extern "C"
{
#endif
void SDKInit()//按照C的写法
{
NSLog(@"hello world!");//按照OC的写法
}
//写其他各种代码
void SDKClose()
{
}
#if defined(__cplusplus)
}
#endif
//C#代码调用
[DllImport("__Internal")]
private static extern void SDKInit();
C调用C#
和Android一样,用UnitySendMessage将消息传递会C#
【Xcode工程基本概念】
workspace、project、target、scheme
- target是工程中 最小可编译单元,其包含编译时所需要的全部信息,每个target可以被编译成链接库、可执行单元或资源包,类似Android中的library。每次构建应用时,必须指定一个target。target之间可以相互依赖,共享代码和资源,但只有一个能处于Active状态。
- project就是一个xcode工程,其包含了所有的代码文件、资源文件、framework、基本信息、编译配置等。project是管理资源的容器,其中可以有多个target,其也有基本信息和编译配置,可以用于target,如果target有自己的编译配置等,会覆盖project的。一般情况下工程里只有一个project,双击后缀名为
.xcodeproj
的文件即可打开该 project 了。unity xcode project属于一般情况。 - workspace是对project的进一步分类,其可以对多个project进行管理,因为会存在一个project引用(依赖)另一个project的情况。
- scheme是编译任务,其定义了编译 target 时使用的配置选项,执行的任务,环境参数等,有预设的六种:Build, Run, Test, Profile, Analyze, Archive
framework
framework类似库,由二进制文件、头文件、资源文件、其他信息等组成。iOS中framework分为系统级别的dynamic framework和用户级别的static framework、embedded framework
.app .xarchive 和 .ipa的区别
.xarchive是对target进行分析、编译和打包后生成的归档文件的文件格式,其中包含了已经编译好的、打包好的二进制代码、资源文件、配置文件等。具体来说是:BCSymbolMaps、dSYMs(解析崩溃堆栈的符号表)、Products(包含表示生成的.app包)、info.plist等。
.ipa(iOS App Store Package)是一个zip压缩包,从应用商店下载就是这个文件,其包含了运行 App 所必需的的签名、二进制包、资源等内容。
.app是程序运行包,其中包括二进制的可执行文件、运行所需要的资源文件、配置文件,签名文件和privisioning file。
.app 文件是在应用程序开发阶段生成的文件,通常用于在模拟器上测试应用程序或在开发阶段进行本地部署
Info.plist
属性列表文件(information property list file)提供应用在运行期的配置,是一个XML文件,类似AndroidManifest.xml,xcode工程会自动创建一个Info.plist,并且提供许多合适的Keys以及其对应的默认的values,例如权限配置等。
【Unity Xcode工程结构】
根据需要在Unity中设置Bundle Identifier等,每个Unity Xcode工程都有如下的结构和targets
- Unity-iPhone:这个target包括MainApp文件夹和应用程序表示数据,例如启动屏幕、.xib文件、图标、数据和/Info.plist文件,其依赖于UnityFrameWork target。(Project的名字也是Unity-iPhone)
-
UnityFramework: 这个target包括Classes、UnityFramework和Libraries文件夹,以及相关的框架,Xcode使用它来构建UnityFramework.framework文件
-
GameAssembly:这个target是将C#代码编译为C++代码的容器,Xcode使用Unity在每个生成的Xcode项目中包含的IL2CPP工具实现编译,生成的结果包括:包含项目的所有托管代码并被编译成C++代码的库libGameAssembly.a、包含 IL2CPP 运行时代码以支持项目的托管代码的静态库il2cpp.a。
-
MainApp文件夹:包含程序入口代码文件和可能的资源文件等。
-
Classes文件夹:包含用于集成 Unity Runtime 和 Objective-C 的代码。Unity 将应用程序的入口点存储在此文件夹内的 main.mm 和 UnityAppController.mm/h 文件中。如果你的任何插件包含 AppController.h,你可以改为包含 UnityAppController.h。如果 Plugins/iOS文件夹包含 AppController.mm/h,可以对它们进行合并和重命名。这个文件夹的代码基本不会变化。
-
Data文件夹:包含应用程序的序列化资源以及 .NET 程序集(.dll 或 .dat 文件),其形式为完整代码或元数据(取决于代码剥离设置)。machine.config 文件可以设置各种 .NET 服务(例如安全性和 WebRequest)。Xcode 在每次构建时都会刷新此文件夹的内容。
-
Libraries文件夹:Libraries 文件夹包含用于 IL2CPP 的 libil2cpp.a。libiPhone-lib.a 文件是 Unity Runtime 静态库,RegisterMonoModules.cpp将 Unity 原生代码与 .NET 绑定。Xcode 在每次构建时都会刷新此文件夹的内容。你可以不用做任何修改。Unity工程中的Plugins文件夹里的文件位于该文件夹内。
-
图形文件:图标和启动画面(.png 文件)位于 Unity-iPhone 文件夹中的资源目录中。Unity 自动管理这些文件。启动屏幕、它们的 XML 接口构建器(.xib 文件)和 Storyboard 文件存储在项目的根文件夹中。
-
FrameWorks文件夹:包含使用的iOS系统framework和第三方framework
【iOS的生命周期】
UIApplication
每一个 iOS app 都会有一个UIApplication的实例,当一个app启动的时候,系统会调用 UIApplicationMain 函数,该函数会创建一个单例UIApplication对象和一个UIApplicationDelegate对象,UIApplication类中会持有一个UIApplicationDelegate,会通知其运行时的一些重要事件,例如app启动、内存过低、状态改变等,我们一般会写一个类继承UIApplicationDelegate来接收通知,自定义处理事件。
iOS是继承C语言的,入口也是main函数,一般在Xcode工程中是固定写好的,不用修改。
#import "AppDelegate.h"
int main(int argc, char * argv[])
{
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
APP的五种状态
Not running(未运行状态):app未启动或者被终止(无论是被系统还是用户)。
Inactive(不活跃状态):app在前台运行但未接收事件。app只在转换到不同状态时会短暂地保持此状态。进入此状态后,app会很快进入后台(Background)或活动(Active)状态。(打电话时或者下拉通知栏时app会进入此状态)
Active(活动状态):app在前台运行并且正在接收事件。处于前台的app通常状态就是Active。
Background(后台状态):app在屏幕上不可见但是正在执行代码,这是后台状态。当用户退出应用后(应该是按home键),系统会将app在挂起(suspend)前短暂地移动到后台(Background)状态。
Suspended(挂起状态):应用程序在内存中,但不执行代码。系统会挂起在后台(Background)状态的应用程序。系统可能会为了腾出内存空间,将app清除出内存。
(类似进程的五种状态:创建状态、就绪状态、运行状态、阻塞状态、终止状态)
状态转换时的调用
//启动程序是最先调用的函数
-(BOOL) application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
return YES;
}
//在app显示给用户之前,最后的初始化操作。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
return YES;
}
/*通知APP将要变成前台程序,这里可以重启被暂停的任务,如果此程序在后台进入可以选择更新用户界面。
*/
- (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
/**
* 通知 APP 将进入前台,
*这里可以撤销一些在为后台运行而做的改变。
**/
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
/**通知APP将要离开前台,(依次进行inActive -》background-》-Suspended)。如果有电话接入、SMS消息、是用户退出、或者想后台切换都会调用此函数。
*应该使用这个方法暂停正在执行的任务,取消定时器、取消图形渲染回调,暂停游戏等操作。
*/
- (void)applicationWillResignActive:(UIApplication *)application {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
/**
*通知APP将要进入后台状态,随时可能被挂起。
*应该使用这个方法:释放分享的资源,存储用户数据、取消定时器、保存APP的状态消息以用于恢复。
*如果APP支持后台运行,当用户退回时,调用此方法而不调用applicationWillTerminate。
**/
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
/**
*通知 APP 将要终止,如果程序被挂起将不调用。
*保存数据
**/
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
UIView和UIWindow
iOS应用程序通过UIView和UIWindow在屏幕上展现图形内容。UIWindow 继承于UIView,但是一个特殊的UIView,其是所有其他UIView的根视图,管理协调应用程序的显示。一般应用程序只有一个UIWindow对象,即使有多个UIWindow对象,也只有一个UIWindow可以接受到用户的触屏事件。Unity会自己渲染画面,不会用iOS的UIView,但作为iOS上的应用程序,还是会用到UIWindow。