不管是游戏还是普通APP,经常会有用定位功能,这里我以Cocos2d-X为例基于百度地图SDK实现定位功能,其他APP其实也是类似方式。

申请百度地图AK

https://lbsyun.baidu.com/ 进入百度地图开放平台,注册并且创建应用,创建成功后可以获取到AK,不同的平台需要多次申请

IOS平台

导入百度SDK相关框架,并且在项目的 Info.plist 添加定位权限申请,具体可以参考百度SDK文档https://lbsyun.baidu.com/index.php?title=ios-locsdk/guide/create-project/manual-create

在AppController.h 文件中,添加百度定位相关的 Delegate,并且加上一些相关的成员变量,请忽略代码中的微信API:

#import <UIKit/UIKit.h>
#import "WXApi.h"
#import <BaiduMapAPI_Base/BMKBaseComponent.h>
#import <BaiduMapAPI_Base/BMKMapManager.h>
#import <BaiduMapAPI_Location/BMKLocationService.h>
#import <BaiduMapAPI_Search/BMKGeocodeSearch.h>

@class RootViewController;

@interface AppController : NSObject <UIApplicationDelegate,WXApiDelegate, BMKLocationServiceDelegate ,BMKGeoCodeSearchDelegate> {
    UIWindow *window;
    BMKMapManager* _mapManager;
    BMKLocationService* _locService;
    BMKGeoCodeSearch *_geocodesearch;
}

@property(nonatomic, readonly) RootViewController* viewController;

@end

在 AppController.mm中的didFinishLaunchingWithOptions中初始化百度地图服务

    //百度地图
    _mapManager = [[BMKMapManager alloc] init];
    BOOL ret = [_mapManager start:@BD_APPKEY generalDelegate:nil];
    _geocodesearch = [[BMKGeoCodeSearch alloc] init];
    _geocodesearch.delegate = self;
    if (!ret) {
        NSLog(@"manager start failed!");
    }
    _locService = [[BMKLocationService alloc] init];//初始化BMKLocationService
    _locService.delegate = self;
    [_locService startUserLocationService];//启动LocationService
//实现相关delegate 处理位置信息更新
//处理方向变更信息
- (void)didUpdateUserHeading:(BMKUserLocation *)userLocation {
    NSLog(@"heading is %@", userLocation.heading);
}

//处理位置坐标更新
- (void)didUpdateBMKUserLocation:(BMKUserLocation *)userLocation {
    NSLog(@"didUpdateUserLocation lat %f,long %f", userLocation.location.coordinate.latitude, userLocation.location.coordinate.longitude);
    BMKReverseGeoCodeOption *reverseGeocodeSearchOption = [[BMKReverseGeoCodeOption alloc] init];
    reverseGeocodeSearchOption.reverseGeoPoint = userLocation.location.coordinate;
    BOOL flag = [_geocodesearch reverseGeoCode:reverseGeocodeSearchOption];
    if (flag) {
        NSLog(@"反geo检索发送成功");
        [_locService stopUserLocationService];
        onLocationInfo(userLocation.location.coordinate.longitude, userLocation.location.coordinate.latitude);
    } else {
        NSLog(@"反geo检索发送失败");
    }
    [reverseGeocodeSearchOption release];
}

//定位结果
- (void)onGetReverseGeoCodeResult:(BMKGeoCodeSearch *)searcher result:(BMKReverseGeoCodeResult *)result errorCode:(BMKSearchErrorCode)error {
    NSLog(@"address:%@----%@", result.addressDetail, result.address);
    if (result != nil) {
        onAddressInfo([result.address cStringUsingEncoding:NSUTF8StringEncoding]);
    } else {
        //NSString *msg = @"定位失败!";
    }
}

//定位失败
- (void)didFailToLocateUserWithError:(NSError *)error {
    NSLog(@"error:%@", error);
    //NSString *msg = @"定位失败!";
}

通过自定义的onLocationInfo函数,和onAddressInfo 两个静态函数将具体的经纬度与物理地址,赋值给Cocos2d-X逻辑里的定位相关对象,方便后续IOS与ANDROID统一处理。

ANDROID平台

第一步同样是导入百度SDK相关的各种包和申请权限,具体如何导出与申请那些权限查看百度SDK文档https://lbsyun.baidu.com/index.php?title=android-locsdk/guide/create-project/eclipse

准备工作搞定后,AppActivity中添加定位代码,在onCreate中初始化百度地图服务

	mLocationClient = new LocationClient(getApplicationContext());// 声明LocationClient类
	initLocation();
	mLocationClient.registerLocationListener(myListener);
	mLocationClient.start();
/**
	 * 初始化定位配置
	 */
	private void initLocation() {
		LocationClientOption option = new LocationClientOption();
		option.setLocationMode(LocationMode.Hight_Accuracy);
		option.setCoorType("bd09ll");
		option.setScanSpan(0);
		// 可选,默认0,即仅定位一次,设置发起定位请求的间隔需要大于等于1000ms才是有效的
		option.setIsNeedAddress(true);
		// 可选,设置是否需要地址信息,默认不需要
		option.setOpenGps(true);
		// 可选,默认false,设置是否使用gps
		option.setLocationNotify(true);
		// 可选,默认false,设置是否当GPS有效时按照1S/1次频率输出GPS结果
		option.setIsNeedLocationDescribe(true);
		// 可选,默认false,设置是否需要位置语义化结果,可以在BDLocation.getLocationDescribe里得到,结果类似于“在北京天安门附近”
		option.setIsNeedLocationPoiList(true);
		// 可选,默认false,设置是否需要POI结果,可以在BDLocation.getPoiList里得到
		option.setIgnoreKillProcess(false);
		// 可选,默认true,定位SDK内部是一个SERVICE,并放到了独立进程,设置是否在stop的时候杀死这个进程,默认不杀死
		option.SetIgnoreCacheException(false);
		// 可选,默认false,设置是否收集CRASH信息,默认收集
		option.setEnableSimulateGps(false);
		// 可选,默认false,设置是否需要过滤GPS仿真结果,默认需要
		mLocationClient.setLocOption(option);
	}
	/**
	 * 定位
	 */
	public BDLocationListener myListener = new BDLocationListener() {

		@Override
		public void onReceiveLocation(final BDLocation location) {
			boolean isOk = false;
			// 获取定位结果
			StringBuffer sb = new StringBuffer(256);
			sb.append("time : ");
			sb.append(location.getTime()); // 获取定位时间
			sb.append("\nerror code : ");
			sb.append(location.getLocType()); // 获取类型类型
			sb.append("\nlatitude : ");
			sb.append(location.getLatitude()); // 获取纬度信息
			sb.append("\nlontitude : ");
			sb.append(location.getLongitude()); // 获取经度信息
			sb.append("\nradius : ");
			sb.append(location.getRadius()); // 获取定位精准度
			if (location.getLocType() == BDLocation.TypeGpsLocation) {// GPS定位结果
				isOk = true;
				sb.append("gps定位成功");
				address = location.getAddrStr(); // 地址
			} else if (location.getLocType() == BDLocation.TypeNetWorkLocation) {// 网络定位结果
				isOk = true;
				sb.append("网络定位成功");
				address = location.getAddrStr(); // 地址
			} else if (location.getLocType() == BDLocation.TypeOffLineLocation) {
				address = "离线定位失败"; // 地址
			} else if (location.getLocType() == BDLocation.TypeServerError) {
				address = "服务端网络定位失败"; // 地址
			} else if (location.getLocType() == BDLocation.TypeNetWorkException) {
				address = "网络不同导致定位失败,请检查网络是否通畅";
			} else if (location.getLocType() == BDLocation.TypeCriteriaException) {
				address = "无法获取有效定位依据导致定位失败";
			}
			sb.append(address);
			Log.i("BaiduLocationApiDem", sb.toString());
			mLocationClient.stop();
			if(isOk){
				JniHelper.onAddressInfo(location.getLatitude(), location.getLongitude(), address);
			}
		}
		
		@Override
		public void onConnectHotSpotMessage(String arg0, int arg1) {

		}
	};

到这里已经拿到了定位信息了,通过JniHelper.onAddressInfo方法将定位结果通过JNI方式传递到Cocos2d-X的C++代码层,方式也很简单JAVA层定义个Native方法

public static native void onAddressInfo(double latitude, double longitude, String address);	

C++层定一个对应的JNI函数


#if ((CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID))
#include <jni.h>
#include "platform/android/jni/JniHelper.h" 
#include <android/log.h>
extern "C"{    
	void Java_net_yw365_jni_JniHelper_onAddressInfo(JNIEnv *env,jdouble latitude, jdouble longitude, jstring address)
	{
        GetJni()->m_Latitude = latitude;
        GetJni()->m_Longitude =longitude;
        GetJni()->m_Address = cocos2d::StringUtils::getStringUTFCharsJNI(env,address);
	}
};
#endif

这样就将IOS与ANDROID平台的定位结果全部放到 m_Latitude,m_Longitude,m_Address三个变量中,后续业务逻辑与平台无关了。

打赏
Cocos2d-X基于百度SDK实现定位功能(IOS、Android双平台)
Tagged on:     

发表评论