iOS中,将C、C++、Objective-C代码,以及实现面向iOS编译的库作为本地插件使用。
以制作一个获取地理位置的本地插件为例。
创建名为 “LocationPlugin.mm” 的文件,放在Assets/Plugins/iOS文件夹下,代码如下:
// LocationPlugin.mm
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
@interface LocationPlugin : NSObject<CLLocationManagerDelegate>
// 采用CLLocationManagerDelegate协议
{
CLLocationManager *locationManager;
NSString *callbackTarget;
bool isReverseGeocoding; // 是否处于反地理编码处理
}
+ (LocationPlugin *)sharedInstance;
@end
// LocationPlugin类定义
@implementation LocationPlugin
// 单例
static LocationPlugin *sharedInstance = nil;
+ (id)sharedInstance
{
@synchronized(self)
{
if(sharedInstance == nil)
{
sharedInstance = [[self alloc] init];
}
}
return sharedInstance;
}
// 开始获取位置信息
- (BOOL)startUpdatingLocation:(NSString *)newCallbackTarget
{
// 缓存回调
callbackTarget = newCallbackTarget;
if(locationManager == nil)
{
locationManager = [[CLLocationManager alloc] init];
}
// 确认位置信息服务是否有效且被许可
BOOL isEnabledAndAuthorized = NO;
if([CLLocationManager locationServicesEnabled])
{
CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
if(status == kCLAuthorizationStatusAuthorizedAlways ||
status == kCLAuthorizationStatusAuthorizedWhenInUse)
{
isEnabledAndAuthorized = YES;
}
}
if(!isEnabledAndAuthorized)
{
// 位置信息服务无效且未被许可时,请求用户授权
[locationManager requestWhenInUseAuthorization];
return NO;
}
// 开始获取位置信息
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
return YES;
}
// 停止获取位置信息
- (void)stopUpdatingLocation
{
if(locationManager != nil)
{
[locationManager stopUpdatingLocation];
}
}
#pragma mark - CLLocationManagerDelegate协议的方法实现
// 更新位置信息时调用
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
if(isReverseGeocoding)
{
return;
}
// 基于获取的位置信息进行反地理编码以获取地址
isReverseGeocoding = YES;
CLLocation *location = [locations lastObject];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:location
completionHandler:^(NSArray *placemarks, NSError *error) {
isReverseGeocoding = NO;
// 从CLPlacemark对象的FormattedAddressLines中获取地址的字符串
NSString *addressString = @"";
if(placemarks.count >= 1)
{
CLPlacemark *placemark = [placemarks firstObject];
NSArray *addressLines =
[placemark addressDictionary][@"FormattedAddressLines"];
addressString = [addressLines componentsJoinedByString:@" "];
}
// 创建作为参数传递的字符串
NSString *parameter = [NSString stringWithFormat:@"%f\t%f\t%f\t%f\t%@",
location.coordinate.latitude,
location.coordinate.longitude,
location.speed, location.horizontalAccuracy,
addressString];
// 使用UnitySendMessage方法调用Unity的OnUpdateLocation方法
UnitySendMessage([callbackTarget cStringUsingEncoding:NSUTF8StringEncoding],
"OnUpdateLocation",
[parameter cStringUsingEncoding:NSUTF8StringEncoding]);
}];
}
// 其他必须的方法
- (void)locationManager:(CLLocationManager *)manager
didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region {}
- (void)locationManagerDidPauseLocationUpdates:(CLLocationManager *)manager {}
- (void)locationManagerDidResumeLocationUpdates:(CLLocationManager *)manager {}
@end
#pragma mark - 接口
// 为回避C++命名粉碎,以C linkage进行声明
extern "C" {
// 用于调用开始获取位置信息方法的接口
BOOL _startUpdatingLocation(const char *callbackTarget)
{
LocationPlugin *instance = [LocationPlugin sharedInstance];
@synchronized(instance)
{
return [instance startUpdatingLocation:
[NSString stringWithUTF8String:callbackTarget]];
}
}
// 用于调用停止获取位置信息方法的接口
void _stopUpdatingLocation()
{
LocationPlugin *instance = [LocationPlugin sharedInstance];
@synchronized(instance)
{
[instance stopUpdatingLocation];
}
}
}
注意选中LocationPlugin.mm脚本后,可以在Inspector面板中选择platforms for plugin,要选择iOS
接下来是从Unity方的脚本实现调用本地插件接口
创建名为 “LocationPluginInterface.cs” 的文件,代码如下
using UnityEngine;
using System.Runtime.InteropServices;
public class LocationPluginInterface
{
#if UNITY_IOS
// 访问本地插件接口的声明
[DllImport ("__Internal")]
private static extern bool _startUpdatingLocation(string callbackTarget);
[DllImport ("__Internal")]
private static extern void _stopUpdatingLocation();
#endif
// 开始获取位置信息
public static bool StartUpdatingLocation(string callbackTarget)
{
#if !UNITY_EDITOR
return _startUpdatingLocation(callbackTarget);
#else
return false;
#endif
}
// 停止获取位置信息
public static void StopUpdatingLocation()
{
#if !UNITY_EDITOR
_stopUpdatingLocation();
#endif
}
}
接下来是测试,测试脚本LocationExample.cs,代码如下(含有一些ui逻辑,根据实际需求进行设计),注意LocationExample.cs要挂到场景中的某个物体上,并且物体的名字要读一无二,因为本地插件回调是通过名字来找对应的物体的)
// LocationExample.cs
using UnityEngine;
using UnityEngine.UI;
public class LocationExample : MonoBehaviour
{
[SerializeField] private Text addressLabel; // 地址
[SerializeField] private Text latitudeLabel; // 维度
[SerializeField] private Text longitudeLabel; // 经度
[SerializeField] private Text speedLabel; // 移动速度
[SerializeField] private Text accuracyLabel; // 精度
// 是否正在获取位置信息
private bool IsUpdatingLocation { get; set; }
void Awake()
{
IsUpdatingLocation = false;
UpdateUpdateLocationButton();
}
private void UpdateUpdateLocationButton()
{
Animator animator = GetComponent<Animator>();
if(animator != null)
{
animator.SetTrigger(IsUpdatingLocation? "Started": "Stopped");
}
}
// 按下开始/停止获取位置信息按钮
public void OnPressUpdateLocationButton()
{
IsUpdatingLocation = !IsUpdatingLocation;
if(IsUpdatingLocation)
{
// 开始获取位置信息
if(!LocationPluginInterface.StartUpdatingLocation(this.name))
{
IsUpdatingLocation = false;
return;
}
}
else
{
// 停止获取位置信息
LocationPluginInterface.StopUpdatingLocation();
}
UpdateUpdateLocationButton();
}
// 位置信息更新时,从本地插件中回调过来
public void OnUpdateLocation(string parameter)
{
// 取出参数
string[] components = parameter.Split(new char[] {'\t'}, 5);
float latitude = float.Parse(components[0]);
float longitude = float.Parse(components[1]);
float speed = float.Parse(components[2]);
float accuracy = float.Parse(components[3]);
string address = components[4];
addressLabel.text = address;
latitudeLabel.text = string.Format("{0:0}° {1:0}′",
Mathf.Floor(latitude), (latitude - Mathf.Floor(latitude)) * 60);
longitudeLabel.text = string.Format("{0:0}° {1:0}′",
Mathf.Floor(longitude), (longitude - Mathf.Floor(longitude)) * 60);
speedLabel.text = string.Format("{0:0.0} m/s", (speed >= 0.0f)? speed: 0.0f);
accuracyLabel.text = string.Format("{0} m", accuracy);
}
}
原文地址:https://linxinfa.blog.csdn.net
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。