init project

This commit is contained in:
Kuloud
2023-12-22 21:23:24 +08:00
commit 1fb3d91106
461 changed files with 58770 additions and 0 deletions

View File

@ -0,0 +1,68 @@
//
// AMapConvertUtil.h
// amap_map
//
// Created by lly on 2020/10/30.
//
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#import <Flutter/Flutter.h>
#import <MAMapKit/MAMapKit.h>
NS_ASSUME_NONNULL_BEGIN
@class MATouchPoi;
@interface AMapConvertUtil : NSObject
/// 经纬度坐标转字符串
/// @param coordinate 经纬度坐标
+ (NSString *)stringFromCoordinate:(CLLocationCoordinate2D)coordinate;
/// 颜色的色值解析色值必须为json中的number类型
/// @param numberColor 色值
+ (UIColor*)colorFromNumber:(NSNumber*)numberColor;
/// 将数组内含数字转换为point坐标默认数组第一个元素为x值第二个为y值
/// @param data 数组
+ (CGPoint)pointFromArray:(NSArray*)data;
/// 从数据中解析经纬度
/// @param array 经纬度数组对(默认第一个当做维度,第二个当做经度)
+ (CLLocationCoordinate2D)coordinateFromArray:(NSArray *)array;
/// 经纬度转json数组
/// @param coord 经纬度
+ (NSArray *)jsonFromCoordinate:(CLLocationCoordinate2D )coord;
/// 经纬度转json数组
/// @param coordinate 经纬度
+ (NSArray<NSNumber *> *)jsonArrayFromCoordinate:(CLLocationCoordinate2D)coordinate;
+ (UIImage*)imageFromRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar iconData:(NSArray*)iconData;
/// 检测图标相关的描述,是否修改过
/// @param previousIcon 之前的图标
/// @param currentIcon 当前新的图标
/// @return 修改了则返回yes否则返回NO
+ (BOOL)checkIconDescriptionChangedFrom:(NSArray *)previousIcon to:(NSArray *)currentIcon;
/// 经纬度坐标比较
/// @param coord1 坐标1
/// @param coord2 坐标2
+ (BOOL)isEqualWith:(CLLocationCoordinate2D)coord1 to:(CLLocationCoordinate2D)coord2;
/// TouchPOI转字典
/// @param poi 点击POI
+ (NSDictionary *)dictFromTouchPOI:(MATouchPoi *)poi;
/// 解析得到mapRect结构
/// @param array json数组[southwest,northeast],分别为西南、东北的坐标
+ (MAMapRect)mapRectFromArray:(NSArray *)array;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,215 @@
//
// AMapConvertUtil.m
// amap_map
//
// Created by lly on 2020/10/30.
//
#import "AMapConvertUtil.h"
@implementation AMapConvertUtil
///
/// @param coordinate
+ (NSString *)stringFromCoordinate:(CLLocationCoordinate2D)coordinate {
return [NSString stringWithFormat:@"{%.6f,%.6f}", coordinate.longitude, coordinate.latitude];
}
+ (UIColor*)colorFromNumber:(NSNumber*)numberColor {
if (numberColor == nil || [numberColor isKindOfClass:[NSNumber class]] == NO) {
return nil;
}
unsigned long value = [numberColor unsignedLongValue];
return [UIColor colorWithRed:((float)((value & 0xFF0000) >> 16)) / 255.0
green:((float)((value & 0xFF00) >> 8)) / 255.0
blue:((float)(value & 0xFF)) / 255.0
alpha:((float)((value & 0xFF000000) >> 24)) / 255.0];
}
+ (CGPoint)pointFromArray:(NSArray*)data {
NSAssert((data != nil && [data isKindOfClass:[NSArray class]] && data.count == 2), @"数组类型转point格式错误");
return CGPointMake([data[0] doubleValue],
[data[1] doubleValue]);
}
///
/// @param array
+ (CLLocationCoordinate2D)coordinateFromArray:(NSArray *)array {
CLLocationCoordinate2D location = kCLLocationCoordinate2DInvalid;
if (array.count == 2) {
double latitude = [array[0] doubleValue];
double longitude = [array[1] doubleValue];
if ([self checkValidLatitude:latitude longitude:longitude]) {
location = CLLocationCoordinate2DMake(latitude, longitude);
} else if ([self checkValidLatitude:longitude longitude:latitude]) {//
location = CLLocationCoordinate2DMake(longitude, latitude);
} else {
NSLog(@"经纬度参数异常,解析为无效经纬度");
}
} else {
NSLog(@"经纬度参数异常,解析为无效经纬度");
}
return location;
}
+ (NSArray *)jsonFromCoordinate:(CLLocationCoordinate2D )coord {
if (CLLocationCoordinate2DIsValid(coord)) {
return @[@(coord.latitude),@(coord.longitude)];
} else {
NSLog(@"经纬度无效,返回为空");
return @[];
}
}
///
/// @param latitude
/// @param longitude
+ (BOOL)checkValidLatitude:(double)latitude longitude:(double)longitude {
if (latitude > 90 || latitude < -90) {
return false;
}
if (longitude > 180 || longitude < -180) {
return false;
}
return true;
}
+ (NSArray<NSNumber *> *)jsonArrayFromCoordinate:(CLLocationCoordinate2D)coordinate {
if (CLLocationCoordinate2DIsValid(coordinate)) {
return @[ @(coordinate.latitude), @(coordinate.longitude) ];
} else {
return @[];
}
}
+ (UIImage*)scaleImage:(UIImage*)image param:(NSNumber*)scaleParam {
double scale = 1.0;
if ([scaleParam isKindOfClass:[NSNumber class]]) {
scale = scaleParam.doubleValue;
}
if (fabs(scale - 1) > 1e-3) {
return [UIImage imageWithCGImage:[image CGImage]
scale:(image.scale * scale)
orientation:(image.imageOrientation)];
}
return image;
}
+ (UIImage*)imageFromRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar iconData:(NSArray*)iconData {
UIImage* image;
if ([iconData.firstObject isEqualToString:@"defaultMarker"]) {
image = [UIImage imageNamed:[registrar lookupKeyForAsset:@"packages/amap_map/res/marker_default.png"]];//
CGFloat screenScale = [[UIScreen mainScreen] scale];
image = [self scaleImage:image param:[NSNumber numberWithFloat:screenScale]];
//
} else if ([iconData.firstObject isEqualToString:@"fromAsset"]) {
if (iconData.count == 2) {
image = [UIImage imageNamed:[registrar lookupKeyForAsset:iconData[1]]];
CGFloat screenScale = [[UIScreen mainScreen] scale];
image = [self scaleImage:image param:[NSNumber numberWithFloat:screenScale]];
}
} else if ([iconData.firstObject isEqualToString:@"fromAssetImage"]) {
if (iconData.count == 3) {
image = [UIImage imageNamed:[registrar lookupKeyForAsset:iconData[1]]];
NSNumber* scaleParam = iconData[2];
image = [self scaleImage:image param:scaleParam];
} else {
NSString* error =
[NSString stringWithFormat:@"'fromAssetImage' should have exactly 3 arguments. Got: %lu",
(unsigned long)iconData.count];
NSException* exception = [NSException exceptionWithName:@"InvalidBitmapDescriptor"
reason:error
userInfo:nil];
@throw exception;
}
} else if ([iconData[0] isEqualToString:@"fromBytes"]) {
if (iconData.count == 2) {
@try {
FlutterStandardTypedData* byteData = iconData[1];
CGFloat screenScale = [[UIScreen mainScreen] scale];
image = [UIImage imageWithData:[byteData data] scale:screenScale];
} @catch (NSException* exception) {
@throw [NSException exceptionWithName:@"InvalidByteDescriptor"
reason:@"Unable to interpret bytes as a valid image."
userInfo:nil];
}
} else {
NSString* error = [NSString
stringWithFormat:@"fromBytes should have exactly one argument, the bytes. Got: %lu",
(unsigned long)iconData.count];
NSException* exception = [NSException exceptionWithName:@"InvalidByteDescriptor"
reason:error
userInfo:nil];
@throw exception;
}
}
return image;
}
///
/// @param previousIcon
/// @param currentIcon
/// @return yesNO
+ (BOOL)checkIconDescriptionChangedFrom:(NSArray *)previousIcon to:(NSArray *)currentIcon {
if (previousIcon.count != currentIcon.count) {
return YES;
}
//
for (NSUInteger index = 0; index < previousIcon.count; index ++) {
if ([previousIcon[index] isKindOfClass:[NSString class]]) {
if ([previousIcon[index] isEqualToString:currentIcon[index]] == NO) {
return YES;
}
} else if ([previousIcon[index] isKindOfClass:[NSNumber class]]) {
if (fabs([previousIcon[index] doubleValue] - [currentIcon[index] doubleValue]) > 0.000001) {
return YES;
}
} else {//
return NO;
}
}
return NO;
}
+ (BOOL)isEqualWith:(CLLocationCoordinate2D)coord1 to:(CLLocationCoordinate2D)coord2 {
if (fabs(coord1.latitude - coord2.latitude) > 0.000001 || fabs(coord1.longitude - coord2.longitude) > 0.000001) {
return NO;
}
return YES;
}
+ (NSDictionary *)dictFromTouchPOI:(MATouchPoi *)poi {
if (poi == nil) {
return nil;
}
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:3];
if (poi.name) {
[dict setObject:poi.name forKey:@"name"];
}
if (CLLocationCoordinate2DIsValid(poi.coordinate)) {
[dict setObject:[AMapConvertUtil jsonArrayFromCoordinate:poi.coordinate] forKey:@"latLng"];
}
if (poi.uid) {
[dict setObject:poi.uid forKey:@"id"];
}
return [dict copy];
}
+ (MAMapRect)mapRectFromArray:(NSArray *)array {
NSAssert((array && [array isKindOfClass:[NSArray class]] && array.count == 2), @"解析mapRect的参数有误");
CLLocationCoordinate2D southwest = [AMapConvertUtil coordinateFromArray:array[0]];
CLLocationCoordinate2D northeast = [AMapConvertUtil coordinateFromArray:array[1]];
MAMapPoint mapNorthEastPoint = MAMapPointForCoordinate(northeast);
MAMapPoint mapSouthWestPoint = MAMapPointForCoordinate(southwest);
double width = fabs(mapNorthEastPoint.x - mapSouthWestPoint.x);
double height = fabs(mapNorthEastPoint.y - mapSouthWestPoint.y);
MAMapRect limitRect = MAMapRectMake(mapSouthWestPoint.x, mapNorthEastPoint.y, width, height);
return limitRect;
}
@end

View File

@ -0,0 +1,35 @@
//
// MAJsonUtils.h
// amap_map
//
// Created by shaobin on 2019/2/13.
// Copyright © 2019 Amap.com. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface AMapJsonUtils : NSObject
/**
model转为可序列化为json的对象。
@param model model对象:支持NSDictionary、NSArray、自定义类且支持嵌套(Dict、Array内包含自定义类示例或自定义类内包含Dict、Array) 注意如果自定义类或dict、array中包含非字符串、数字、布尔、null类型的属性其行为是undefined的
@return 返回NSArray或者NSDictionary对象如果失败返回nil。
*/
+ (id)jsonObjectFromModel:(id)model;
/**
dict转model
@param dict dict
@param modelClass model对应的Class
@return 返回modelClass实例
*/
+ (id)modelFromDict:(NSDictionary*)dict modelClass:(Class)modelClass;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,275 @@
//
// MAJsonUtils.m
// amap_map
//
// Created by shaobin on 2019/2/13.
// Copyright © 2019 Amap.com. All rights reserved.
//
#import "AMapJsonUtils.h"
#import <objc/runtime.h>
#import <objc/message.h>
#import <CoreLocation/CoreLocation.h>
#import "AMapConvertUtil.h"
@implementation AMapJsonUtils
+ (BOOL)isValidJsonValue:(id)value {
if([value isKindOfClass:NSString.class] ||
[value isKindOfClass:NSNumber.class] ||
value == [NSNull null]) {
return YES;
}
return NO;
}
+ (id)jsonValueFromObject:(id)obj {
if([self isValidJsonValue:obj]) {
return obj;
}
if(!obj) {
return [NSNull null];
}
//not exhausted
if([obj isKindOfClass:NSDate.class] ||
[obj isKindOfClass:NSData.class] ||
[obj isKindOfClass:NSValue.class]) {
NSString *retStr = [NSString stringWithFormat:@"%@", obj];
return retStr;
}
if([obj isKindOfClass:NSArray.class]) {
NSArray *oldArray = (NSArray*)obj;
NSMutableArray *retArray = [NSMutableArray arrayWithCapacity:[oldArray count]];
for(id item in oldArray) {
id jsonValue = [self jsonValueFromObject:item];
[retArray addObject:jsonValue];
}
return retArray;
}
if([obj isKindOfClass:NSDictionary.class]) {
NSDictionary *oldDict = (NSDictionary *)obj;
NSMutableDictionary *retDict = [NSMutableDictionary dictionaryWithCapacity:[oldDict count]];
for(id key in [oldDict allKeys]) {
id item = [oldDict objectForKey:key];
id jsonValue = [self jsonValueFromObject:item];
if(jsonValue) {
[retDict setObject:jsonValue forKey:key];
}
}
return retDict;
}
NSArray *propertyArray = [self allPropertiesOfClass:[obj class]];
NSMutableDictionary *returnDict = [NSMutableDictionary dictionaryWithCapacity:propertyArray.count];
for(NSString *property in propertyArray) {
id value = [obj valueForKey:property];
if(value) {
id jsonValue = [self jsonValueFromObject:value];
NSString *mappedName = property;
if(jsonValue) {
[returnDict setObject:jsonValue forKey:mappedName];
}
}
}
return returnDict;
}
+ (id)jsonObjectFromModel:(id)model {
id ret = [self jsonValueFromObject:model];
if(![NSJSONSerialization isValidJSONObject:ret]) {
return nil;
}
return ret;
}
+ (id)modelFromDict:(NSDictionary*)dict modelClass:(Class)modelClass {
if(![dict isKindOfClass:[NSDictionary class]]) {
NSLog(@"[AMap] the object must be of %@", [NSDictionary class]);
return nil;
}
if([modelClass isSubclassOfClass:[NSDictionary class]]) {
return [dict copy];
}
//clazz
NSArray *propertyArray = [self allPropertiesOfClass:modelClass];
NSMutableArray* missedProperties = [NSMutableArray array];
id ret = [[modelClass alloc] init];
//clazz
for (NSString *propertyName in propertyArray) {
NSString *keyName = propertyName;
id value = [dict objectForKey:keyName];
//'id''id''id_'
if(!value && [propertyName isEqualToString:@"id_"]) {
value = [dict objectForKey:@"id"];
}
if(!value) {
[missedProperties addObject:propertyName];
continue;
}
if(value == [NSNull null]) {
continue;
}
Class propertyClass = nil;
objc_property_t property = class_getProperty(modelClass, [propertyName UTF8String]);
NSString *propertyAttributes = [NSString stringWithCString:property_getAttributes(property) encoding:NSUTF8StringEncoding];
NSArray *splitPropertyAttributes = [propertyAttributes componentsSeparatedByString:@","];
if(splitPropertyAttributes.count > 0) {
NSString *encodeType = splitPropertyAttributes[0];
if([encodeType hasPrefix:@"T@"]) {
NSArray *splitEncodeType = [encodeType componentsSeparatedByString:@"\""];
NSString *className = nil;
if(splitEncodeType.count > 1) {
className = splitEncodeType[1];
}
if(className) {
propertyClass = NSClassFromString(className);
}
} else if ([encodeType isEqualToString:@"T{CLLocationCoordinate2D=dd}"]) {//
//
CLLocationCoordinate2D coordinate = [self coordinateFromModel:value];
//使msgSend
SEL sel = NSSelectorFromString([NSString stringWithFormat:@"set%@:",[propertyName capitalizedString]]);
((void (*)(id,SEL,CLLocationCoordinate2D))objc_msgSend)(ret,sel,coordinate);
continue;
} else if ([encodeType isEqualToString:@"T{CGPoint=dd}"]) {//CGPoint点
CGPoint point = [AMapConvertUtil pointFromArray:value];
//使用msgSend直接设置经纬度的属性
SEL sel = NSSelectorFromString([NSString stringWithFormat:@"set%@:",[propertyName capitalizedString]]);
((void (*)(id,SEL,CGPoint))objc_msgSend)(ret,sel,point);
continue;
}
}
//property
if(propertyClass) {
if([value isKindOfClass:propertyClass]) {
//array
if([propertyClass isSubclassOfClass:NSArray.class]) {
NSString *elementClassSel = [NSString stringWithFormat:@"%@ElementClass", propertyName];
SEL selector = NSSelectorFromString(elementClassSel);
if([[ret class] respondsToSelector:selector]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
Class elementCls = [[ret class] performSelector:selector];
#pragma clang diagnostic pop
NSArray *arr = (NSArray *)value;
NSMutableArray *mutArr = [NSMutableArray arrayWithCapacity:arr.count];
for(id item in arr) {
id newItem = [self modelFromDict:item modelClass:elementCls];
if(newItem) {
[mutArr addObject:newItem];
} else {
[mutArr addObject:item];
}
}
[ret setValue:mutArr forKey:propertyName];
} else {
[ret setValue:value forKey:propertyName];
}
} else {
[ret setValue:value forKey:propertyName];
}
} else if([value isKindOfClass:NSDictionary.class]){
NSDictionary *tempDic = value;
id model = [self modelFromDict:tempDic modelClass:propertyClass];
[ret setValue:model forKey:propertyName];
} else if ([value isKindOfClass:[NSNumber class]] && [NSStringFromClass(propertyClass) isEqualToString:@"UIColor"]) {
UIColor *color = [AMapConvertUtil colorFromNumber:value];
[ret setValue:color forKey:propertyName];
} else {
[ret setValue:value forKey:propertyName];
#ifdef DEBUG
Class valueClaz = [value class];
NSLog(@"\U0001F913\U0001F913 Warning1: property '%@' of %@ is %@, %@ is received", propertyName, modelClass, propertyClass, valueClaz);
#endif
}
} else { //end of if(propertyClaz) @"Ti" @"Tf"
if([self isValidJsonValue:value]){
[ret setValue:value forKey:propertyName];
} else {
#ifdef DEBUG
Class valueClaz = [value class];
NSLog(@"\U0001F913\U0001F913 Warning1: property '%@' of %@ is %@, %@ is received", propertyName, modelClass, propertyClass, valueClaz);
#endif
}
}
}
#ifdef DEBUG
if([missedProperties count] > 0) {
NSLog(@"\U0001F913\U0001F913 Warning2: %@ value missed: %@", modelClass, missedProperties);
}
#endif
NSString *postHookSel = [NSString stringWithFormat:@"postHookWith:"];
SEL sel = NSSelectorFromString(postHookSel);
if([ret respondsToSelector:sel]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[ret performSelector:sel withObject:dict];
#pragma clang diagnostic pop
}
return ret;
}
//array of propertyNames
+ (NSArray<NSString*> *)allPropertiesOfClass:(Class)cls {
Class clazz = cls;
NSMutableArray *mutArr = [[NSMutableArray alloc] init];
while(clazz != [NSObject class]) {
unsigned int count = 0;
objc_property_t* properties = class_copyPropertyList(clazz, &count);
for (int i = 0; i < count ; i++) {
objc_property_t prop = properties[i];
NSString *propertyName = [NSString stringWithCString:property_getName(prop) encoding:NSUTF8StringEncoding];
[mutArr addObject:propertyName];
}
if(properties) {
free(properties);
}
clazz = class_getSuperclass(clazz);
}
return mutArr;
}
//model
+ (CLLocationCoordinate2D)coordinateFromModel:(id)model {
CLLocationCoordinate2D location = kCLLocationCoordinate2DInvalid;
if ([model isKindOfClass:[NSArray class]]) {
return [AMapConvertUtil coordinateFromArray:model];
} else if ([model isKindOfClass:[NSString class]]) {//
NSString *coordStr = model;
NSArray *array = [coordStr componentsSeparatedByString:@","];
array = [[array reverseObjectEnumerator] allObjects];//
return [AMapConvertUtil coordinateFromArray:array];
} else if ([model isKindOfClass:[NSDictionary class]]) {
NSDictionary *dict = model;
NSNumber *latitudeNum = [dict objectForKey:@"latitude"];
NSNumber *longitudeNum = [dict objectForKey:@"longitude"];
if (latitudeNum && longitudeNum) {
location = CLLocationCoordinate2DMake([latitudeNum doubleValue], [longitudeNum doubleValue]);
} else {
NSLog(@"经纬度参数异常,解析为无效经纬度");
}
}
return location;
}
@end

View File

@ -0,0 +1,27 @@
//
// AMapMethodCallDispatcher.h
// amap_map
//
// Created by lly on 2020/11/16.
//
#import <Foundation/Foundation.h>
#import <Flutter/Flutter.h>
NS_ASSUME_NONNULL_BEGIN
/// methodCall的分发器该对象以Category的形式设置给FlutterMethodChannel作为FlutterMethodCallHandler
/// 再根据call.method来分发处理对应的处理block
@interface AMapMethodCallDispatcher : NSObject
- (void)onMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result;
- (void)addMethodName:(NSString *)methodName withHandler:(FlutterMethodCallHandler)handler;
- (void)removeHandlerWithMethodName:(NSString *)methodName;
- (void)clearAllHandler;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,61 @@
//
// AMapMethodCallDispatcher.m
// amap_map
//
// Created by lly on 2020/11/16.
//
#import "AMapMethodCallDispatcher.h"
@interface AMapMethodCallDispatcher ()
@property (nonatomic, strong) NSRecursiveLock *dictLock;
@property (nonatomic, strong) NSMutableDictionary *callDict;
@end
@implementation AMapMethodCallDispatcher
- (instancetype)init {
self = [super init];
if (self) {
self.dictLock = [[NSRecursiveLock alloc] init];
self.callDict = [[NSMutableDictionary alloc] init];
}
return self;
}
- (void)onMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
[self.dictLock lock];
FlutterMethodCallHandler handle = [self.callDict objectForKey:call.method];
[self.dictLock unlock];
if (handle) {
handle(call,result);
} else {
NSLog(@"call method:%@ handler is null",call.method);
result(nil);
}
}
- (void)addMethodName:(NSString *)methodName withHandler:(FlutterMethodCallHandler)handler {
NSAssert((methodName.length > 0 && handler != nil), @"添加methodCall回调处理参数异常");
[self.dictLock lock];
[self.callDict setObject:handler forKey:methodName];
[self.dictLock unlock];
}
- (void)removeHandlerWithMethodName:(NSString *)methodName {
NSAssert(methodName.length > 0, @"移除methodCall时参数异常");
[self.dictLock lock];
[self.callDict removeObjectForKey:methodName];
[self.dictLock unlock];
}
- (void)clearAllHandler {
[self.dictLock lock];
[self.callDict removeAllObjects];
[self.dictLock unlock];
}
@end