之前调用iOS的SDK代码都是将Unity导出XCode工程,再将iOS代码拷贝到XCode工程目录下,手动在CompileSources中添加。但在接入MSDK和米大师,嫌大厂的麻烦,自己写了一套自动配置Xcode工程的代码。感觉略微了解XCode的配置。
在后续的对接中,大厂需要收集运营商和网络情况(Wifi/2G/3G/4G)这些数据,就尝试写个iOS的插件,减少手动操作的麻烦和出错概率。
经过网上一番搜索和自己动手测试后,得出结论:只需要将.h和.m文件拷入到Plugins/iOS目录下,后续在XCode中就不需要管了,如下图:
调用也跟之前接入SDK类似,先写个DllImport,然后就可以直接调用了,代码:
public class MobileUtility
{
private static AndroidJavaObject m_apiInstance;
private static AndroidJavaObject m_currentActivity;
private static AndroidJavaObject m_assetManager;
[DllImport("__Internal")]
private static extern string iGetMobileCarrier();
[DllImport("__Internal")]
private static extern string iGetNetworkType();
[DllImport("__Internal")]
private static extern string iGetIDFA();
[DllImport("__Internal")]
private static extern float iGetNotchScreenSize();
/// <summary>
/// 获取安卓工具类实例
/// </summary>
/// <returns></returns>
private static AndroidJavaObject GetApiInstance()
{
#if UNITY_ANDROID && !UNITY_EDITOR
if (null == m_apiInstance)
{
var apiClass = new AndroidJavaClass("com.zp.utility.api");
m_apiInstance = apiClass.CallStatic<AndroidJavaObject>("instance");
}
#endif
return m_apiInstance;
}
/// <summary>
/// 获取当前Activity
/// </summary>
/// <returns></returns>
private static AndroidJavaObject GetCurrentActivity()
{
#if UNITY_ANDROID && !UNITY_EDITOR
if (null == m_currentActivity)
m_currentActivity = new AndroidJavaClass("com.unity3d.player.UnityPlayer").GetStatic<AndroidJavaObject>("currentActivity");
#endif
return m_currentActivity;
}
/// <summary>
/// 获取安卓的AssetManager,用于读取Unity中StreamingAsset中的文件
/// </summary>
/// <returns></returns>
private static AndroidJavaObject GetAssetManager()
{
#if UNITY_ANDROID && !UNITY_EDITOR
if (null == m_assetManager)
{
var currentActivity = GetCurrentActivity();
if(currentActivity != null)
m_assetManager = currentActivity.Call<AndroidJavaObject>("getAssets");
}
#endif
return m_assetManager;
}
/// <summary>
/// 获取手机imei
/// </summary>
/// <returns></returns>
public static string GetIMEIOrIDFA()
{
string result = "";
#if UNITY_ANDROID && !UNITY_EDITOR
var currentActivity = GetCurrentActivity();
AndroidJavaClass contextClass = new AndroidJavaClass("android.content.Context");
string TELEPHONY_SERVICE = contextClass.GetStatic<string>("TELEPHONY_SERVICE");
AndroidJavaObject telephonyService = currentActivity.Call<AndroidJavaObject>("getSystemService", TELEPHONY_SERVICE);
var imei = telephonyService.Call<string>("getDeviceId");
result = imei;
#elif UNITY_IOS && !UNITY_EDITOR
result = iGetIDFA();
#endif
return result;
}
/// <summary>
/// 运营商
/// </summary>
/// <returns></returns>
public static string GetMobileCarrier()
{
string mobileCarrier = "";
#if UNITY_ANDROID && !UNITY_EDITOR
var currentActivity = GetCurrentActivity();
var apiInstance = GetApiInstance();
if (currentActivity != null && apiInstance != null)
mobileCarrier = apiInstance.Call<string>("GetMobileCarrier", currentActivity);
#elif UNITY_IOS && !UNITY_EDITOR
mobileCarrier = iGetMobileCarrier();
#endif
return mobileCarrier;
}
/// <summary>
/// WIFI 2G 3G 4G
/// </summary>
/// <returns></returns>
public static string GetNetworkType()
{
string networkType = "";
#if UNITY_ANDROID && !UNITY_EDITOR
var currentActivity = GetCurrentActivity();
var apiInstance = GetApiInstance();
if (currentActivity != null && apiInstance != null)
networkType = apiInstance.Call<string>("GetNetworkType", currentActivity);
#elif UNITY_IOS && !UNITY_EDITOR
networkType = iGetNetworkType();
#endif
return networkType;
}
/// <summary>
/// 获取刘海屏宽度
/// </summary>
/// <returns></returns>
public static float GetNotchScreenSize()
{
float result = 0.0f;
#if UNITY_ANDROID && !UNITY_EDITOR
#elif UNITY_IOS && !UNITY_EDITOR
result = iGetNotchScreenSize();
#endif
return result;
}
/// <summary>
/// 移动机型
/// </summary>
/// <returns></returns>
public static string GetMobileName()
{
return SystemInfo.deviceModel;
}
}
iOS代码:
//
// Utility.m
// Unity-iPhone
//
// Created by 张平 on 2019/2/15.
//
#import <Foundation/Foundation.h>
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
#import <CoreTelephony/CTCarrier.h>
#import <AdSupport/AdSupport.h>
#import <UIKit/UIKit.h>
#import "Reachability.h"
char* iGetMobileCarrier()
{
//获取本机运营商名称
CTTelephonyNetworkInfo *info = [[CTTelephonyNetworkInfo alloc] init];
CTCarrier *carrier = [info subscriberCellularProvider];
//当前手机所属运营商名称
NSString *mobile;
//先判断有没有SIM卡,如果没有则不获取本机运营商
if (!carrier.isoCountryCode) {
NSLog(@"没有SIM卡");
mobile = @"无运营商";
}else{
mobile = [carrier carrierName];
}
const char* output = [mobile UTF8String];
// 是里如果直接返回_output是会报错的,因为它是是const,不能被返回。
char* result = (char*)malloc(strlen(output)+1);
strcpy(result, output);
return result;
}
char* iGetNetworkType()
{
NSString *netconnType = @"";
Reachability *reach = [Reachability reachabilityWithHostName:@"www.apple.com"];
switch ([reach currentReachabilityStatus]) {
case NotReachable:// 没有网络
{
netconnType = @"no network";
}
break;
case ReachableViaWiFi:// Wifi
{
netconnType = @"Wifi";
}
break;
case ReachableViaWWAN:// 手机自带网络
{
// 获取手机网络类型
CTTelephonyNetworkInfo *info = [[CTTelephonyNetworkInfo alloc] init];
NSString *currentStatus = info.currentRadioAccessTechnology;
if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyGPRS"]) {
netconnType = @"GPRS";
}else if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyEdge"]) {
netconnType = @"2.75G EDGE";
}else if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyWCDMA"]){
netconnType = @"3G";
}else if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyHSDPA"]){
netconnType = @"3.5G HSDPA";
}else if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyHSUPA"]){
netconnType = @"3.5G HSUPA";
}else if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyCDMA1x"]){
netconnType = @"2G";
}else if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyCDMAEVDORev0"]){
netconnType = @"3G";
}else if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyCDMAEVDORevA"]){
netconnType = @"3G";
}else if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyCDMAEVDORevB"]){
netconnType = @"3G";
}else if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyeHRPD"]){
netconnType = @"HRPD";
}else if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyLTE"]){
netconnType = @"4G";
}
}
break;
default:
break;
}
const char* output = [netconnType UTF8String];
// 是里如果直接返回_output是会报错的,因为它是是const,不能被返回。
char* result = (char*)malloc(strlen(output)+1);
strcpy(result, output);
return result;
}
char* iGetIDFA()
{
NSString *idfa = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
const char* output = [idfa UTF8String];
// 是里如果直接返回_output是会报错的,因为它是是const,不能被返回。
char* result = (char*)malloc(strlen(output)+1);
strcpy(result, output);
return result;
}
float iGetNotchScreenSize()
{
//iOS 11 以下的默认不存在刘海儿(没有谁iphone X 刷回ios 10 系统吧。哈哈)
if (__IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_11_0) {
return 0.0f;
}
/* iPhone8 Plus UIEdgeInsets: {20, 0, 0, 0}
* iPhone8 UIEdgeInsets: {20, 0, 0, 0}
* iPhone XR UIEdgeInsets: {44, 0, 34, 0}
* iPhone XS UIEdgeInsets: {44, 0, 34, 0}
* iPhone XS Max UIEdgeInsets: {44, 0, 34, 0}
*/
//ios 11 以上提供专门方法获取刘海儿高度
UIEdgeInsets safeAreaInsets = UIApplication.sharedApplication.windows.firstObject.safeAreaInsets;
CGFloat bottomSpace = 0;
switch (UIApplication.sharedApplication.statusBarOrientation) {
case UIInterfaceOrientationPortrait:{
bottomSpace = safeAreaInsets.top;
}break;
case UIInterfaceOrientationLandscapeLeft:{
bottomSpace = safeAreaInsets.left;
}break;
case UIInterfaceOrientationLandscapeRight:{
bottomSpace = safeAreaInsets.right;
} break;
case UIInterfaceOrientationPortraitUpsideDown:{
bottomSpace = safeAreaInsets.bottom;
}break;
default:
bottomSpace = safeAreaInsets.bottom;
break;
}
return (float)bottomSpace;
}