Flutter 混合開發 - 03 百度地圖定位功能 ios 篇

本節目標

  • 建立 ios flutter 插件流程
  • 集成百度定位功能

視頻

https://www.bilibili.com/vide...php

<iframe src="//player.bilibili.com/player.html?bvid=BV1HT4y1L73i&page=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true" width="100%" height="400px"> </iframe>html

代碼

https://github.com/ducafecat/...android

百度平臺部分

設置 AK

https://lbsyun.baidu.com/apic...ios

  • 添加應用

  • 查看 Bundle Identifier

IOS 部分

自動部署 CocoaPods

  • 安裝工具
sudo gem install cocoapods
  • ios/flutter_baidu_plugin_ducafecat.podspec
...
  s.dependency 'Flutter'
  s.platform = :ios, '8.0'

  s.dependency 'BMKLocationKit'

  # Flutter.framework does not contain a i386 slice. Only x86_64 simulators are supported.
  s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' }
end
  • 安裝百度 sdk 包
pod install
  • 升級
pod repo update
  • pod search 沒法搜索到類庫的解決辦法(找不到類庫)
(1)執行pod setup

(2)刪除~/Library/Caches/CocoaPods目錄下的search_index.json文件

    pod setup成功後會生成~/Library/Caches/CocoaPods/search_index.json文件

    終端輸入rm ~/Library/Caches/CocoaPods/search_index.json

    刪除成功後再執行pod search

(3)執行pod search

Info.plist 定位受權

example/ios/Runner/Info.plistgit

<dict>
    <key>NSLocationWhenInUseUsageDescription</key>
    <string>須要定位</string>

消息通知 BdmapFlutterStreamManager

  • ios/Classes/BdmapFlutterStreamManager.h
//
//  Header.h
//  bdmap_location_flutter_plugin
//
//  Created by Wang,Shengzhan on 2020/2/4.
//


#import <Foundation/Foundation.h>
#import <Flutter/Flutter.h>

NS_ASSUME_NONNULL_BEGIN
@class BdmapFlutterStreamHandler;
@interface BdmapFlutterStreamManager : NSObject
+ (instancetype)sharedInstance ;
@property (nonatomic, strong) BdmapFlutterStreamHandler* streamHandler;

@end

@interface BdmapFlutterStreamHandler : NSObject<FlutterStreamHandler>
@property (nonatomic, strong) FlutterEventSink eventSink;

@end
NS_ASSUME_NONNULL_END
  • ios/Classes/BdmapFlutterStreamManager.m
//
//  BdmapFlutterStreamManager.m
//  bdmap_location_flutter_plugin
//
//  Created by Wang,Shengzhan on 2020/2/4.
//

#import "BdmapFlutterStreamManager.h"

@implementation BdmapFlutterStreamManager

+ (instancetype)sharedInstance {
    static dispatch_once_t onceToken;
    static BdmapFlutterStreamManager *manager = nil;
    dispatch_once(&onceToken, ^{
        manager = [[BdmapFlutterStreamManager alloc] init];
        BdmapFlutterStreamHandler * streamHandler = [[BdmapFlutterStreamHandler alloc] init];
        manager.streamHandler = streamHandler;
    });

    return manager;
}

@end


@implementation BdmapFlutterStreamHandler

- (FlutterError*)onListenWithArguments:(id)arguments eventSink:(FlutterEventSink)eventSink {
    self.eventSink = eventSink;
    return nil;
}

- (FlutterError*)onCancelWithArguments:(id)arguments {

    return nil;
}

@end

地圖接口業務 FlutterBaiduPluginDucafecatPlugin

  • ios/Classes/FlutterBaiduPluginDucafecatPlugin.h
#import <Flutter/Flutter.h>

@interface FlutterBaiduPluginDucafecatPlugin : NSObject<FlutterPlugin>
@end
  • ios/Classes/FlutterBaiduPluginDucafecatPlugin.m
#import "FlutterBaiduPluginDucafecatPlugin.h"
#import "BMKLocationkit/BMKLocationComponent.h"
#import "BdmapFlutterStreamManager.h"

@interface FlutterBaiduPluginDucafecatPlugin()<BMKLocationManagerDelegate>

@property (nonatomic,strong) BMKLocationManager *locManager;

@property (nonatomic, copy) FlutterResult flutterResult;

@end



@implementation FlutterBaiduPluginDucafecatPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
  // FlutterMethodChannel* channel = [FlutterMethodChannel
  //     methodChannelWithName:@"flutter_baidu_plugin_ducafecat"
  //           binaryMessenger:[registrar messenger]];
  // FlutterBaiduPluginDucafecatPlugin* instance = [[FlutterBaiduPluginDucafecatPlugin alloc] init];
  // [registrar addMethodCallDelegate:instance channel:channel];

    FlutterMethodChannel* channel = [FlutterMethodChannel
                                     methodChannelWithName:@"flutter_baidu_plugin_ducafecat"
                                     binaryMessenger:[registrar messenger]];

    FlutterBaiduPluginDucafecatPlugin* instance = [[FlutterBaiduPluginDucafecatPlugin alloc] init];

    [registrar addMethodCallDelegate:instance channel:channel];

    FlutterEventChannel *eventChanel = [FlutterEventChannel eventChannelWithName:@"flutter_baidu_plugin_ducafecat_stream" binaryMessenger:[registrar messenger]];

    [eventChanel setStreamHandler:[[BdmapFlutterStreamManager sharedInstance] streamHandler]];

}

// - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
//   if ([@"getPlatformVersion" isEqualToString:call.method]) {
//     result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]);
//   }
//   else if ([@"duAddOne" isEqualToString:call.method]) {
//       NSInteger val = 100;
//       val += [[call.arguments objectForKey:@"num"] intValue];
//       result([NSNumber numberWithLong:val]);
//   }
//   else {
//     result(FlutterMethodNotImplemented);
//   }
// }


- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {

    if ([@"getPlatformVersion" isEqualToString:call.method]) {

        result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]);

    } else if ([@"startLocation" isEqualToString:call.method]){ // 開始定位

//        NSLog((@"\n[bdmap_loc_flutter_plugin:%s]"), "startLocation...");
        [self startLocation:result];

    }else if ([@"stopLocation" isEqualToString:call.method]){ // 中止定位

//        NSLog((@"\n[bdmap_loc_flutter_plugin:%s]"), "stopLocation...");
        [self stopLocation];
        result(@YES);

    } else if ([@"updateOption" isEqualToString:call.method] ) { // 設置定位參數

        result(@([self updateOption:call.arguments]));

    } else if ([@"setApiKey" isEqualToString:call.method]){ // 設置ios端ak
//        NSLog((@"\n[bdmap_loc_flutter_plugin:%s]"), "setApiKey...");
        [[BMKLocationAuth sharedInstance] checkPermisionWithKey:call.arguments authDelegate:self];
        result(@YES);
    } else {

        result(FlutterMethodNotImplemented);
    }
}

/**
 獲取設置的指望定位精度
 */
-(double)getDesiredAccuracy:(NSString*)str{

    if([@"kCLLocationAccuracyBest" isEqualToString:str]) {
        return kCLLocationAccuracyBest;
    } else if ([@"kCLLocationAccuracyNearestTenMeters" isEqualToString:str]) {
        return kCLLocationAccuracyNearestTenMeters;
    } else if ([@"kCLLocationAccuracyHundredMeters" isEqualToString:str]) {
        return kCLLocationAccuracyHundredMeters;
    } else if ([@"kCLLocationAccuracyKilometer" isEqualToString:str]) {
        return kCLLocationAccuracyKilometer;
    } else {
        return kCLLocationAccuracyBest;
    }
}

/**
 獲取設置的經緯度座標系類型
 */
-(int)getCoordinateType:(NSString*)str{

    if([@"BMKLocationCoordinateTypeBMK09LL" isEqualToString:str]) {
        return BMKLocationCoordinateTypeBMK09LL;
    } else if ([@"BMKLocationCoordinateTypeBMK09MC" isEqualToString:str]) {
        return BMKLocationCoordinateTypeBMK09MC;
    } else if ([@"BMKLocationCoordinateTypeWGS84" isEqualToString:str]) {
        return BMKLocationCoordinateTypeWGS84;
    } else if ([@"BMKLocationCoordinateTypeGCJ02" isEqualToString:str]) {
        return BMKLocationCoordinateTypeGCJ02;
    } else {
        return BMKLocationCoordinateTypeGCJ02;
    }


}


/**
 獲取設置的應用位置類型
 */
-(int)getActivityType:(NSString*)str{

    if ([@"CLActivityTypeOther" isEqualToString:str]) {
        return CLActivityTypeOther;
    } else if ([@"CLActivityTypeAutomotiveNavigation" isEqualToString:str]) {
        return CLActivityTypeAutomotiveNavigation;
    } else if ([@"CLActivityTypeFitness" isEqualToString:str]) {
        return CLActivityTypeFitness;
    } else if ([@"CLActivityTypeOtherNavigation" isEqualToString:str]) {
        return CLActivityTypeOtherNavigation;
    } else {
        return CLActivityTypeAutomotiveNavigation;
    }


}

/**
 解析flutter端所設置的定位SDK參數
 */
-(BOOL)updateOption:(NSDictionary*)args {
    if(self.locManager) {

//        NSLog(@"定位參數配置:%@",args);

        self.locManager.isNeedNewVersionReGeocode = YES;

        // 設置指望定位精度
        if ([[args allKeys] containsObject:@"desiredAccuracy"]) {
          [self.locManager setDesiredAccuracy:[ self getDesiredAccuracy: args[@"desiredAccuracy"]]];
        }

        // 設置定位的最小更新距離
        if ([[args allKeys] containsObject:@"distanceFilter"]) {
            self.locManager.distanceFilter = [args[@"distanceFilter"] doubleValue];
//            NSLog(@"最小更新距離值:%f", [args[@"distanceFilter"] doubleValue]);
        }

        // 設置返回位置座標系類型
        if ([[args allKeys] containsObject:@"BMKLocationCoordinateType"]) {
            [self.locManager setCoordinateType:[ self getCoordinateType: args[@"desiredAccuracy"]]];
        }

        // 設置應用位置類型
        if ([[args allKeys] containsObject:@"activityType"]) {
            [self.locManager setActivityType:[ self getActivityType: args[@"desiredAccuracy"]]];
        }

        // 設置是否須要返回新版本rgc信息
        if ([[args allKeys] containsObject:@"isNeedNewVersionRgc"]) {
            if ((bool)args[@"desiredAccuracy"]) {
//                NSLog(@"須要返回新版本rgc信息");
                self.locManager.isNeedNewVersionReGeocode = YES;
            } else {
//                NSLog(@"不須要返回新版本rgc信息");
                self.locManager.isNeedNewVersionReGeocode = NO;
            }

        }

        // 指定定位是否會被系統自動暫停
        if ([[args allKeys] containsObject:@"pausesLocationUpdatesAutomatically"]) {
            if ((bool)args[@"pausesLocationUpdatesAutomatically"]) {
//                NSLog(@"設置定位被系統自動暫停");
                self.locManager.isNeedNewVersionReGeocode = YES;
            } else {
//                NSLog(@"設置定位不能被系統自動暫停");
                self.locManager.isNeedNewVersionReGeocode = NO;
            }

        }

        // 設置是否容許後臺定位
        if ([[args allKeys] containsObject:@"allowsBackgroundLocationUpdates"]) {
             if ((bool)args[@"allowsBackgroundLocationUpdates"]) {
//                  NSLog(@"設置容許後臺定位");
                  self.locManager.isNeedNewVersionReGeocode = YES;
             } else {
//                  NSLog(@"設置不容許後臺定位");
                  self.locManager.isNeedNewVersionReGeocode = NO;
                 self.locManager.distanceFilter = kCLDistanceFilterNone;
             }

        }

        // 設置定位超時時間
        if ([[args allKeys] containsObject:@"locationTimeout"]) {
            [self.locManager setLocationTimeout:[args[@"locationTimeout"] integerValue]];
            self.locManager.coordinateType = BMKLocationCoordinateTypeGCJ02;
        }

        // 設置逆地理超時時間
        if ([[args allKeys] containsObject:@"reGeocodeTimeout"]) {
            [self.locManager setReGeocodeTimeout:[args[@"reGeocodeTimeout"] integerValue]];
        }

        return YES;

    }
    return NO;
}
/**
 啓動定位
 */
- (void)startLocation:(FlutterResult)result
{
    self.flutterResult = result;
    [self.locManager startUpdatingLocation];
}

/**
 中止定位
 */
- (void)stopLocation
{
    self.flutterResult = nil;
    [self.locManager stopUpdatingLocation];
}

- (BMKLocationManager *)locManager {
    if (!_locManager) {
        _locManager = [[BMKLocationManager alloc] init];
        _locManager.locatingWithReGeocode = YES;
        _locManager.delegate = self;
    }
    return _locManager;
}

/**
 *  @brief 連續定位回調函數
 *  @param manager 定位 BMKLocationManager 類。
 *  @param location 定位結果。
 */
- (void)BMKLocationManager:(BMKLocationManager * _Nonnull)manager didUpdateLocation:(BMKLocation * _Nullable)location orError:(NSError * _Nullable)error

{
    if (error)
    {
//        NSLog(@"locError:{%ld - %@};", (long)error.code, error.localizedDescription);
    } if (location) { // 獲得定位信息,添加annotation
        NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithCapacity:1];

        if (location) {

            if (location.location.timestamp) {
                [dic setObject:[self getFormatTime:location.location.timestamp] forKey:@"locTime"]; // 定位時間
            }


            if (location.location.horizontalAccuracy) {
                [dic setObject:@(location.location.horizontalAccuracy) forKey:@"radius"]; // 定位精度
            }


            if (location.location.coordinate.latitude) {
                [dic setObject:@(location.location.coordinate.latitude) forKey:@"latitude"]; // 緯度
            }

            if (location.location.coordinate.longitude) {
                [dic setObject:@(location.location.coordinate.longitude) forKey:@"longitude"]; // 經度
            }

            if (location.location.altitude) {
//                NSLog(@"返回海拔高度信息");
                [dic setObject:@(location.location.altitude) forKey:@"altitude"];// 高度
            }


            if (location.rgcData) {
                [dic setObject:[location.rgcData country] forKey:@"country"]; // 國家
                [dic setObject:[location.rgcData province] forKey:@"province"]; // 省份
                [dic setObject:[location.rgcData city] forKey:@"city"]; // 城市
                if (location.rgcData.district) {
                    [dic setObject:[location.rgcData district] forKey:@"district"]; // 區縣
                }

                if (location.rgcData.street) {
                    [dic setObject:[location.rgcData street] forKey:@"street"]; // 街道
                }

                if (location.rgcData.description) {
                    // 地址信息
                    [dic setObject:[location.rgcData description] forKey:@"address"];
                }


                if (location.rgcData.poiList) {

                    NSString* poilist;

                    if (location.rgcData.poiList.count == 1) {

                        for (BMKLocationPoi * poi in location.rgcData.poiList) {
                            poilist = [[poi name] stringByAppendingFormat:@",%@,%@", [poi tags], [poi addr]];
                        }

                    } else {
                        for (int i = 0; i < location.rgcData.poiList.count - 1 ; i++) {
                            poilist = [poilist stringByAppendingFormat:@"%@,%@,%@|", location.rgcData.poiList[i].name,location.rgcData.poiList[i].tags,location.rgcData.poiList[i].addr];
                        }

                        poilist = [poilist stringByAppendingFormat:@"%@,%@,%@",
                                location.rgcData.poiList[location.rgcData.poiList.count-1].name,location.rgcData.poiList[location.rgcData.poiList.count-1].tags,location.rgcData.poiList[location.rgcData.poiList.count-1].addr];

                    }
                    [dic setObject: poilist forKey:@"poiList"]; // 周邊poi信息

                }
            }
        } else {
            [dic setObject: @1 forKey:@"errorCode"]; // 定位結果錯誤碼
            [dic setObject:@"location is null" forKey:@"errorInfo"]; // 定位錯誤信息
        }

        // 定位結果回調時間
        [dic setObject:[self getFormatTime:[NSDate date]] forKey:@"callbackTime"];

        [[BdmapFlutterStreamManager sharedInstance] streamHandler].eventSink(dic);
//        NSLog(@"x=%f,y=%f",location.location.coordinate.latitude,location.location.coordinate.longitude);
    }
}

/**
 格式化時間
 */
- (NSString *)getFormatTime:(NSDate*)date
{
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"];
    NSString *timeString = [formatter stringFromDate:date];
    return timeString;
}

@end

Flutter 部分

設置 AK

@override
  void initState() {
    super.initState();
    _requestPermission(); // 執行權限請求

    if (Platform.isIOS == true) {
      FlutterBaiduPluginDucafecat.setApiKeyForIOS(
          "dkYT07blcAj3drBbcN1eGFYqt16HP1pR");
    }
  }
其它代碼和 android 同接口 無影響

參考


© 貓哥github

https://ducafecat.techjson

https://ducafecat.gitee.ioswift

相關文章
相關標籤/搜索