iOS AMap IPC Link Kit 最后更新时间: 2026年08月27日
一、概述
AMap IPC Link Kit 提供了与高德地图应用进行进程间通信的能力,主要包含两个核心组件: - AMapAuthorizationManager: 负责高德应用认证 - AMapLinkManager: 负责IPC连接管理和数据传输
二、基础配置
2.1 导入头文件
#import "AMapLinkManager.h"
#import "AMapAuthorizationManager.h"2.2 配置URL Scheme
在合作方工程的 Info.plist 中配置回调URL Scheme:
授权后高德APP返回合作方APP,否则无法返回获取授权结果
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>AMapAuth</string>
<key>CFBundleURLSchemes</key>
<array>
<string>amapuri2f3df76603c218a5f2198c77f956</string>
</array>
</dict>
</array>
判断是否安装高德APP,否则判断始终返回NO
<key>LSApplicationQueriesSchemes</key>
<array>
<string>amapuri</string>
</array>
三、认证管理 (AMapAuthorizationManager)
3.1 初始化配置
授权时依赖APIKey进行认证,需在更早时机调用基础库设置APIKey,举例如下
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
self.window = [[UIWindow alloc] initWithWindowScene:(UIWindowScene *)scene];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:[[ViewController alloc] init]];
self.window.rootViewController = nav;
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
[[[NSBundle mainBundle] infoDictionary] setValue:@"com.autonavi.DevDemoNavi" forKey:@"CFBundleIdentifier"];
[[AMapServices sharedServices] setEnableHTTPS:NO];
[[AMapServices sharedServices] setApiKey:(NSString *)APIKey];
[AMapPrivacyUtility handlePrivacyAgreeStatusWithWindow:self.window];
}3.2 安装状态检查
// 检查是否安装高德APP
BOOL isInstalled = [[AMapAuthorizationManager sharedInstance] isInstallAMapApp];
// 跳转应用商店下载高德APP
[[AMapAuthorizationManager sharedInstance] turnToAppStore];3.3 启动认证流程
- (void)startAuthentication {
__weak typeof(self) weakSelf = self;
[[AMapAuthorizationManager sharedInstance] startAuthenticationWithCallback:^(BOOL success, NSError * _Nonnull error) {
}];
}3.4 处理认证回调
AppDelegate 方式
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
return [[业务Manager sharedInstance] handleURL:url];
}SceneDelegate 方式
- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts {
UIOpenURLContext *urlContext = URLContexts.allObjects.firstObject;
if (urlContext) {
[[业务Manager sharedInstance] handleURL:urlContext.URL];
}
}业务Manager处理URL
- (BOOL)handleUrl:(NSURL *)url
{
BOOL authResult = [[AMapAuthorizationManager sharedInstance] handleURL:url];
if (authResult) {
[[NSUserDefaults standardUserDefaults] setBool:authResult forKey:@"AMapAuthorization_Authored"];
[self createConnect];
}
return YES;
}四、连接管理 (AMapLinkManager)
4.1 初始化linkSDK&建联
connect之前务必先授权成功、再调用initWithConnectConfig,否则linkClient不会初始化,示例如下
- (void)createConnect
{
BOOL isAuthed = [[NSUserDefaults standardUserDefaults] boolForKey:@"AMapAuthorization_Authored"];
if (!isAuthed) {
// 需在业务场景内调用startAuthenticationWithCallback处理授权
return;
}
if ([[AMapLinkManager sharedInstance] isConnected]) {
return;
}
AMapLinkConnectConfig *config = [AMapLinkConnectConfig new];
config.autoReconnect = YES;
config.maxReconnectAttempts = 50;
config.reconnectDelay = 2;
[[AMapLinkManager sharedInstance] initWithConnectConfig:config];
[[AMapLinkManager sharedInstance] connect];
}4.2 监听连接状态
@property (nonatomic, strong) NSString *reachabilityObserverID;
- (void)setupConnectionObserver {
__weak typeof(self) weakSelf = self;
self.reachabilityObserverID = [[AMapLinkManager sharedInstance] addReachablityChanged:^(BOOL isReachablity) {
dispatch_async(dispatch_get_main_queue(), ^{
if (isReachablity) {
NSLog(@"连接已建立");
[weakSelf onConnectionEstablished];
} else {
NSLog(@"连接已断开");
[weakSelf onConnectionLost];
}
});
}];
}
- (void)removeConnectionObserver {
if (self.reachabilityObserverID) {
[[AMapLinkManager sharedInstance] removeReachablityObserver:self.reachabilityObserverID];
self.reachabilityObserverID = nil;
}
}
4.3 监听错误
@property (nonatomic, strong) NSString *errorObserverID;
- (void)setupErrorObserver {
self.errorObserverID = [[AMapLinkManager sharedInstance] addErrorOccurred:^(NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"连接错误: %@", error.localizedDescription);
});
}];
}
- (void)removeErrorObserver {
if (self.errorObserverID) {
[[AMapLinkManager sharedInstance] removeErrorObserver:self.errorObserverID];
self.errorObserverID = nil;
}
}4.4 监听打车数据变化
高德测试安装包,登录后进入打车页面,起终点定位在北京,比如 起点在高德总部,终点也改成高德附近,立即打车。
可测打车发起订单、进入行程、结束等链路。(测试环境订单到打车测试平台,有测试人员在测时可能会被接单,无人接单时 可重新打车试试)
[[AMapLinkManager sharedInstance] addTaxiInfoChanged:^(AMapTaxiInfo * _Nonnull taxiInfo) {
NSString *msg = [NSString stringWithFormat:@"addTaxiInfoChanged:%@", taxiInfo];
callBack(msg);
}];4.5 检查连接状态
BOOL isConnected = [[AMapLinkManager sharedInstance] isConnected];4.6 断开连接
- (void)disconnect {
[[AMapLinkManager sharedInstance] disconnect];
}五、数据传输
5.1 发送数据
- (void)sendDataToClient:(NSDictionary *)data {
if (!data || ![NSJSONSerialization isValidJSONObject:data]) {
return;
}
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:data
options:NSJSONWritingSortedKeys
error:&error];
if (error) {
NSLog(@"JSON序列化失败: %@", error.localizedDescription);
return;
}
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
if (jsonString) {
[[AMapLinkManager sharedInstance] sendDataToClient:jsonString];
}
}5.2 常用命令示例
// 开始导航
- (void)startNavigation {
NSDictionary *command = @{
@"cmd": @(5),
@"requestId": @(12345)
};
[self sendDataToClient:command];
}
// 添加途经点
- (void)addViaPoint {
NSDictionary *command = @{
@"cmd": @(3),
@"data": @{
@"lon": @116.397455,
@"lat": @39.909187,
@"name": @"天安门",
@"poiid": @"B000A60DA1",
@"entranceList": @[
@{
@"lon": @116.397604,
@"lat": @39.907697
}
]
},
@"requestId": @(12346)
};
[self sendDataToClient:command];
}
// 更改目的地
- (void)changeDestination {
NSDictionary *command = @{
@"cmd": @(4),
@"data": @{
@"lon": @116.397455,
@"lat": @39.909187,
@"name": @"天安门",
@"poiid": @"B000A60DA1",
@"entranceList": @[
@{
@"lon": @116.397604,
@"lat": @39.907697
}
]
},
@"requestId": @(12347)
};
[self sendDataToClient:command];
}
// 更改播报设置
- (void)changeBroadcastSettings {
NSDictionary *command = @{
@"cmd": @(6),
@"data": @{
@"value": @(1) // 0:静音, 1:简洁, 2:详细, 6:极简, 7:智能
},
@"requestId": @(12348)
};
[self sendDataToClient:command];
}
5.3 获取出行方式
在 AMapLinkManager.h内,如下接口
// 当前Link投屏的导航类型 0、-1为-无效值 1-驾车 2-骑行(自行车) 3-步行 4-骑行(电动车)
- (int)getCurrentTravelTool;5.4 获取终点目的地
高德app投屏获取目的地poi,需要调用如下监听
self.naviTypeDataCallback = ^(AMapNaviTypeData * _Nonnull naviTypeData) {
NSString *msg = [NSString stringWithFormat:@"😊AMapLinkManagerDemo addNaviTypeDataListener:%@", naviTypeData];
[AMapIPCLinkLogger logFormat:@"addNaviTypeDataListener: %ld, %@", naviTypeData.type, naviTypeData];
if (callBack) {
callBack(msg);
}
};
[[AMapNaviClientManager shareInstance] addNaviTypeDataListener:self.naviTypeDataCallback];在监听到type==2时,取resultObj字段,获取到的数据为AMapNaviRouteGroup对象,对象内有endPoi对象 可以拿到后进行缓存
@interface AMapNaviTypeData : NSObject
/**
* 导航数据对象
* 如果路线类型,路线信息数据结构 AMapNaviRouteGroup
* id类型用于后续扩展
*/
@property (nonatomic, strong) id _Nullable resultObj;
/**
* 数据类型
*/
@property (nonatomic, assign) AMapNaviDataType type;
/**
* 数据来源
*/
@property (nonatomic, assign) AMapNaviDataSource source;
@end六、完整集成示例
//
// AMapLinkClientViewController.m
// AMapNaviKit
//
// Created by lihui.qlh on 2025/3/25.
// Copyright © 2025 Amap. All rights reserved.
//
#import "AMapLinkClientViewController.h"
#import "NavBarView.h"
#import "EventActionView.h"
#import <MALLMKit/AMapLinkManager.h>
#import <MALLMKit/AMapAuthorizationManager.h>
#import <MALLMKit/AMapLinkConnectConfig.h>
#import "AMapLinkClientObserverManager.h"
@interface AMapLinkClientViewController ()
@property(nonatomic, assign) BOOL isAuthored;
@property(nonatomic, strong) UITextView *receivedTextView;
@property(nonatomic, strong) NavBarView *navBarView;
@property(nonatomic, strong) EventActionView *eventActionView;
@property(nonatomic, strong) AMapLinkConnectConfig *connectConfig;
@end
@implementation AMapLinkClientViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view setBackgroundColor:[UIColor whiteColor]];
[self initUI];
[self tryLink];
__weak typeof(self) weakSelf = self;
[[AMapLinkClientObserverManager sharedInstance] addObserver:^(NSString * _Nonnull msg) {
[weakSelf apptendMessage:msg];
[weakSelf updateInfo];
}];
}
- (void)handleBackButtonClick
{
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)tryLink
{
[self createConnect];
}
- (BOOL)handleUrl:(NSURL *)url
{
BOOL authResult = [[AMapAuthorizationManager sharedInstance] handleURL:url];
if (authResult) {
[[NSUserDefaults standardUserDefaults] setBool:authResult forKey:@"AMapAuthorization_Authored"];
[self createConnect];
}
return YES;
}
#pragma EventActionViewDelegate
- (void)createConnect
{
BOOL isAuthed = [[NSUserDefaults standardUserDefaults] boolForKey:@"AMapAuthorization_Authored"];
if (!isAuthed) {
// 需在业务场景内调用startAuthenticationWithCallback处理授权
return;
}
if ([[AMapLinkManager sharedInstance] isConnected]) {
return;
}
AMapLinkConnectConfig *config = [AMapLinkConnectConfig new];
config.autoReconnect = YES;
config.maxReconnectAttempts = 50;
config.reconnectDelay = 2;
self.connectConfig = config;
[[AMapLinkManager sharedInstance] initWithConnectConfig:config];
[[AMapLinkManager sharedInstance] connect];
}
- (void)disconnect
{
[[AMapLinkManager sharedInstance] disconnect];
}
- (void)sendData:(NSDictionary *)data {
if (!data || ![NSJSONSerialization isValidJSONObject:data]) {
return;
}
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:data
options:NSJSONWritingSortedKeys
error:&error];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
if (jsonString) {
[self apptendMessage:[NSString stringWithFormat:@"writeData: %@",jsonString]];
[[AMapLinkManager sharedInstance] sendDataToClient:jsonString]; // 使用tag 200标识二进制数据
}
}
- (void)openAmap
{
__weak typeof(self) weakSelf = self;
[[AMapAuthorizationManager sharedInstance] startAuthenticationWithCallback:^(BOOL success, NSError * _Nonnull error) {
[weakSelf updateInfo];
}];
}
#pragma UIView
- (void)apptendMessage:(id)message
{
if ([message isKindOfClass:[NSObject class]]) {
self.receivedTextView.text = [NSString stringWithFormat:@"%@\n----------------------------\n%@",self.receivedTextView.text,message];
}
}
- (void)updateInfo
{
BOOL isConnected = [[AMapLinkManager sharedInstance] isConnected];
BOOL isAuthed = self.isAuthored || [[NSUserDefaults standardUserDefaults] boolForKey:@"AMapAuthorization_Authored"];
[self.eventActionView updateInfo:@{
@"isConnected": @(isConnected),
@"isAuthored": @(isAuthed)
}];
}
- (void)sendData
{
[self sendData:@{
@"text": @"你好呀"
}];
}
- (void)startNavi
{
NSDictionary *dict = @{
@"cmd": @(5),
@"requestId": @2222225
};
[self sendData:dict];
}
- (void)changeRideBroadcast
{
NSArray *rideValues = @[@"0", @"1"];
NSUInteger randomIndex = arc4random_uniform((uint32_t)rideValues.count);
NSString *randomValue = rideValues[randomIndex];
[self sendData:@{
@"cmd": @(6),
@"data": @{
@"value": randomValue, // 骑行 @"0", @"1"
},
@"requestId": @2222226
}];
}
- (void)changeCarBroadcast
{
NSArray *carValues = @[@(0), @(1), @(2), @(6), @(7)];
NSUInteger randomIndex = arc4random_uniform((uint32_t)carValues.count);
NSNumber *randomValue = carValues[randomIndex];
[self sendData:@{
@"cmd": @(6),
@"data": @{
@"value": randomValue, // 驾车 @(0),@(1),@(2),@(6),@(7) 静音、简洁、详细、极简、智能
},
@"requestId": @2222227
}];
}
- (void)changeDestination
{
NSDictionary *dict = @{
@"cmd": @(4),
@"data": @{
@"lon": @116.397455,
@"lat": @39.909187,
@"name": @"天安门",
@"poiid": @"B000A60DA1",
@"entranceList": @[
@{
@"lon": @116.397604,
@"lat": @39.907697
}
]
},
@"requestId": @2222224
};
[self sendData:dict];
}
- (void)addViaPoint
{
NSDictionary *dict = @{
@"cmd": @(3),
@"data": @{
@"lon": @116.397455,
@"lat": @39.909187,
@"name": @"天安门",
@"poiid": @"B000A60DA1",
@"entranceList": @[
@{
@"lon": @116.397604,
@"lat": @39.907697
}
]
},
@"requestId": @2222223
};
[self sendData:dict];
}
- (void)clearLog
{
self.receivedTextView.text = [NSString stringWithFormat:@"日志已清除"];
}
- (void)copyLog
{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"复制日志"
message:@"确认要复制日志内容到剪贴板吗?"
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消"
style:UIAlertActionStyleCancel
handler:nil];
UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:@"确认"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) {
[UIPasteboard generalPasteboard].string = self.receivedTextView.text;
[self apptendMessage:@"日志内容已复制到剪贴板"];
}];
[alertController addAction:cancelAction];
[alertController addAction:confirmAction];
[self presentViewController:alertController animated:YES completion:nil];
}
#pragma UIView
// 初始化UI
- (void)initUI {
NSInteger screenWidth = self.view.bounds.size.width;
NSInteger screenHeight = self.view.bounds.size.height;
CGFloat statusBarHeight = 20;
if (@available(iOS 11.0, *)) {
UIWindow *window = UIApplication.sharedApplication.windows.firstObject;
statusBarHeight = window.safeAreaInsets.top;
}
CGFloat navBarHeight = statusBarHeight + 44;
NavBarView *navBarView = [[NavBarView alloc] initWithFrame:CGRectMake(0, 0, screenWidth, navBarHeight)];
[navBarView setTitle:@"AMap IPC Link Demo"];
[self.view addSubview:navBarView];
EventActionView *eventActionView = [[EventActionView alloc] initWithOriginX:0 originY:navBarView.bounds.size.height width:screenWidth];
eventActionView.delegate = self;
[self.view addSubview:eventActionView];
self.eventActionView = eventActionView;
// 创建"接收数据"的容器UITextView(放在Label下方)
NSInteger eventActionViewBottom = eventActionView.bounds.size.height + navBarView.bounds.size.height + 10;
UITextView *receivedTextView = [[UITextView alloc] initWithFrame:CGRectMake(20, eventActionViewBottom, screenWidth-40, screenHeight- eventActionViewBottom-48)];
receivedTextView.text = @"日志回显..."; // 初始文本
receivedTextView.textColor = [UIColor blackColor];
receivedTextView.font = [UIFont systemFontOfSize:14];
receivedTextView.backgroundColor = [UIColor whiteColor];
receivedTextView.textAlignment = NSTextAlignmentLeft;
receivedTextView.editable = NO; // 设置为不可编辑
receivedTextView.scrollEnabled = YES; // 允许滚动(内容过长时)
receivedTextView.translatesAutoresizingMaskIntoConstraints = NO;
receivedTextView.layer.borderColor = [UIColor lightGrayColor].CGColor;
receivedTextView.layer.borderWidth = 0.5;
[self.view addSubview:receivedTextView];
self.receivedTextView = receivedTextView;
}
@end七、注意事项
- API Key配置: 必须在应用启动时尽早配置API Key
- URL Scheme: 确保正确配置回调URL Scheme
- 认证流程: 首次使用需要完成认证流程
- 连接管理: 建议在适当的时机建立和断开连接
- 观察者管理: 记得在适当时机移除观察者,避免内存泄漏
- 线程安全: 回调可能在子线程,UI更新需要切换到主线程
八、常见问题
Q: 认证失败怎么办?
A: 检查API Key是否正确,URL Scheme是否配置正确,确保已安装高德地图APP
Q: 连接失败怎么办?
A: 可以开启自动服务器探测功能,或者检查网络连接状态
Q: 如何处理数据接收?
A: 需要额外实现数据接收的观察者模式,具体实现可参考AMapNaviClientManager
