Compare commits

..

57 Commits

Author SHA1 Message Date
Sean 6299dbbbd9 Merge branch 'phiz_2.42.7.12' of https://git-dev.xyue.zip:8443/phiz/mop-flutter-sdk into phiz_2.42.7.12 2023-12-06 15:23:24 +08:00
Sean 497546886f xj 2023-12-06 15:23:21 +08:00
Stewen f829c4b90b phizMethodChannel 2023-12-06 15:11:57 +08:00
Stewen ed4df837c8 finAppletExt 2023-12-06 14:56:29 +08:00
Stewen 23061dfc8e 修改pod 2023-12-06 14:55:13 +08:00
Stewen 5f907e9b4f Merge branch 'phiz_2.42.7.12' of https://git-dev.xyue.zip:8443/phiz/mop-flutter-sdk into phiz_2.42.7.11
# Conflicts:
#	ios/Classes/Api/MOPAppletDelegate.m
2023-12-06 14:53:47 +08:00
Stewen 8274fe3aaf 冲突 2023-12-06 14:39:55 +08:00
Stewen b09e60067c 小修改 2023-12-06 14:38:50 +08:00
Stewen 2aa8cf9b15 最新凡泰版本 2023-12-06 13:57:15 +08:00
Sean 1b566ef884 线程xj 2023-11-20 13:56:58 +08:00
Stewen 8574fc53c0 恢复 2023-10-19 14:16:15 +08:00
Stewen cedb23eec5 蓝牙2.42.2 2023-10-19 14:09:04 +08:00
Sean 31f68432f9 xj 2023-10-18 15:08:53 +08:00
Sean 08a5a23fde test 2023-10-18 14:52:28 +08:00
Sean 4999057d25 getCustomMenus 2023-10-18 14:00:38 +08:00
Stewen 5b29167042 Merge branch 'phiz_2.42.1' of https://git-dev.xyue.zip:8443/phiz/mop-flutter-sdk into phiz_2.42.1.1
# Conflicts:
#	ios/mop.podspec
2023-10-16 10:53:34 +08:00
Stewen b7b59390c9 纯finclip 2.42.1代码 2023-10-16 10:51:24 +08:00
Stewen 275ca3d4a1 fix error 2023-09-26 19:56:20 +08:00
Stewen efcabfe7c8 add shareToMoment 2023-09-26 19:46:56 +08:00
Stewen c291d64199 不写版本号试试 2023-09-26 18:10:57 +08:00
Stewen ebc5edcbf5 恢复2.41.13 2023-09-26 17:28:46 +08:00
Stewen 892035a0c8 蓝牙弄2.41.5 2023-09-26 17:21:31 +08:00
Stewen c9c7f00cb4 解决冲突 2023-09-26 15:38:06 +08:00
Stewen 5606f294e5 Merge branch 'phiz_2.41.5.10' of https://git-dev.xyue.zip:8443/phiz/mop-flutter-sdk into phiz_2.41.13.1
# Conflicts:
#	ios/Classes/Api/MOP_initialize.m
#	ios/mop.podspec
#	ios/mop.podspec.tpl
2023-09-26 15:37:08 +08:00
Stewen 52e29a405e 加入iOS蓝牙SDK 2023-09-26 14:15:08 +08:00
Stewen ac757dbfb5 注释FATClipBoardComponent 2023-09-23 15:54:53 +08:00
Stewen 2da5b8ead3 注释FinAppletClipBoard 2023-09-23 15:43:58 +08:00
Stewen 7a95d27791 注释FinAppletClipBoard 2023-09-23 15:43:02 +08:00
Stewen 685ff6ff1b 改下 2023-09-23 15:41:50 +08:00
Stewen 8e85abcb15 移除FinAppletClipBoard 2023-09-23 15:11:24 +08:00
Stewen b3c70cd5f2 .11 2023-09-23 15:04:46 +08:00
Stewen a5de8826c8 FinAppletClipBoard 2023-09-23 14:58:11 +08:00
Stewen 9c4c772c70 版本号要一致 2023-09-23 14:46:49 +08:00
Stewen fa41022f41 调整格式 2023-09-23 14:41:54 +08:00
Stewen 03eedd4991 Merge branch 'phiz_2.41.5.9' of https://git-dev.xyue.zip:8443/phiz/mop-flutter-sdk into phiz_2.41.13.1
# Conflicts:
#	ios/mop.podspec
2023-09-23 14:37:59 +08:00
Stewen 70f910a76c 纯凡泰2.41.13版本 2023-09-23 14:35:26 +08:00
Stewen 40e6eeda59 log 2023-09-18 10:48:49 +08:00
Stewen 99d074d023 set googleMapApi timeout 2023-08-23 17:33:29 +08:00
Stewen c030e31a5a 去掉小程序支付测试 2023-08-23 15:51:39 +08:00
Stewen 0ac5a988dc sync 2023-08-22 18:02:39 +08:00
stewen 98168c167e fix map sdk 2023-08-14 18:51:27 +08:00
stewen f2077784db add log 2023-08-14 11:55:29 +08:00
stewen 2ed4c891c5 试下修改menus 2023-08-14 09:24:21 +08:00
stewen f9ee987c5a 添加加载中 2023-08-12 15:44:12 +08:00
stewen 2b3bd6a226 debug 2023-08-12 15:25:17 +08:00
stewen 957f14dde5 获取按钮改成同步 2023-08-08 16:08:21 +08:00
stewen 6749f2fc82 fix countrycode 2023-08-04 17:56:51 +08:00
stewen a6bd02e789 fix error 2023-08-04 17:33:45 +08:00
stewen 366f8ab9ac fix error 2023-08-04 17:30:34 +08:00
stewen 58a8e5b804 ios同步方法更改 2023-08-04 17:25:36 +08:00
stewen 9951bebc56 config googlemapkey 2023-08-03 14:33:57 +08:00
stewen 8ef8d78b2a 提交测试 2023-08-03 10:54:49 +08:00
jayce b800cb3786 import FinAppletExt 2023-08-02 19:59:34 +08:00
jayce f097d86cd1 clipdata 2023-08-02 19:41:51 +08:00
jayce 195b2d11a9 add google map 2023-08-02 19:36:40 +08:00
simpleman1984@126.com 4df164b35f sync method and clipdata 2023-08-02 17:48:03 +08:00
simpleman1984@126.com 4cfdbafcbf sync method and clipdata 2023-08-02 17:31:33 +08:00
141 changed files with 9895 additions and 74 deletions

View File

@ -91,6 +91,6 @@ kapt {
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.finogeeks.lib:finapplet:2.41.11'
implementation 'com.finogeeks.mop:plugins:2.41.11'
implementation 'com.finogeeks.lib:finapplet:2.42.7'
implementation 'com.finogeeks.mop:plugins:2.42.7'
}

View File

@ -133,6 +133,7 @@ public class InitSDKModule extends BaseApi {
configBuilder.setSchemes(schemes);
}
configBuilder.setDebugMode((Boolean) configMap.get("debug"));
configBuilder.setEnableLog((Boolean) configMap.get("debug"));
Integer maxRunningApplet = (Integer) configMap.get("maxRunningApplet");
if (maxRunningApplet != null) {
configBuilder.setMaxRunningApplet(maxRunningApplet);
@ -194,11 +195,23 @@ public class InitSDKModule extends BaseApi {
if (appletText != null) {
configBuilder.setAppletText(appletText);
}
Integer languageInteger = (Integer) configMap.get("language");
if (languageInteger == 1) {
configBuilder.setLocale(Locale.ENGLISH);
Object localeLanguage = configMap.get("localeLanguage");
if (localeLanguage != null) {
String language = (String) localeLanguage;
if (language.contains("_")) {
String[] locales = language.split("_");
configBuilder.setLocale(new Locale(locales[0], locales[1]));
} else {
configBuilder.setLocale(new Locale(language));
}
} else {
configBuilder.setLocale(Locale.SIMPLIFIED_CHINESE);
Integer languageInteger = (Integer) configMap.get("language");
if (languageInteger == 1) {
configBuilder.setLocale(Locale.ENGLISH);
} else {
configBuilder.setLocale(Locale.SIMPLIFIED_CHINESE);
}
}
// uiConfig

View File

@ -2,7 +2,7 @@ package com.finogeeks.mop.api.mop;
import android.content.Context;
import com.finogeeks.finochat.sdkcore.client.FinoChatSDKCoreClient;
import com.finogeeks.finclip.sdkcore.manager.FinClipSDKCoreManager;
import com.finogeeks.lib.applet.client.FinAppClient;
import com.finogeeks.lib.applet.db.entity.FinApplet;
import com.finogeeks.mop.api.BaseApi;
@ -25,7 +25,7 @@ public class SmSignModule extends BaseApi {
@Override
public void invoke(String event, Map param, ICallback callback) {
String text = (String) param.get("plainText");
String result = FinoChatSDKCoreClient.getInstance().finoLicenseService().messageDigest(text);
String result = new FinClipSDKCoreManager.Builder().build().messageDigestBySM(text);
Map<String, Object> res = new HashMap<>();
res.put("data", result);
callback.onSuccess(res);

68
bundle.sh 100755
View File

@ -0,0 +1,68 @@
export LANG=en_US.UTF-8
export FASTLANE_DISABLE_COLORS=1
export version="$1"
export iosVersion="$2"
export androidVersion="$3"
#version=`git describe --abbrev=0 --tags | tr -d '\\n' | tr -d '\\t'`
echo "当前版本号:${version}"
echo "依赖的iOS${iosVersion}"
echo "依赖的Android:${androidVersion}"
#git reset --hard
#git checkout ${version}
# pubspec.yaml
cp -r pubspec.tpl.yaml pubspec.yaml
sed -i "" "s/__mop_flutter_sdk_version__/${version}/g" pubspec.yaml
# iOS podspec
if [ -n "$iosVersion" ]
then
echo "更新mop.podspec====>"
cp -r ios/mop.podspec.tpl ios/mop.podspec
sed -i "" "s/__finapplet_version__/${iosVersion}/g" ios/mop.podspec
fi
# android gradle
if [ -n "$androidVersion" ]
then
echo "更新build.gradle====>"
cp -r android/build.gradle.tpl android/build.gradle
sed -i "" "s/__finapplet_version__/${androidVersion}/g" android/build.gradle
fi
cat pubspec.yaml
git remote add ssh-origin ssh://git@gitlab.finogeeks.club:2233/finclipsdk/finclip-flutter-sdk.git
git add .
git commit -m "release: version:$version"
git tag -d ${version}
git push ssh-origin --delete tag ${version}
git tag -a ${version} -m 'FinClip-Flutter-SDK发版'
git push ssh-origin HEAD:refs/heads/master --tags -f
#export http_proxy=http://127.0.0.1:1087
#export https_proxy=http://127.0.0.1:1087
flutter packages pub publish --dry-run --server=https://pub.dartlang.org
flutter packages pub publish --server=https://pub.dartlang.org --force
#unset http_proxy
#unset https_proxy
git remote add github ssh://git@github.com/finogeeks/mop-flutter-sdk.git
#git push github HEAD:refs/heads/master --tags
git push github HEAD:refs/heads/master

View File

@ -83,9 +83,26 @@ class _MyAppState extends State<MyApp> {
Mop.instance.registerExtensionApi('getUserProfile', getUserProfile);
Mop.instance.registerExtensionApi('pushNativePage', pushNativePage);
if (!mounted) return;
}
Future<Map<String, dynamic>> pushNativePage(dynamic params) async {
print(params);
Map<String, dynamic> result = {
"userInfo":{
"nickName" : "haley",
"avatarUrl" : "https://www.finclip.com",
"gender" : 1,
"country" : "China",
"province" : "Guangdong",
"city" : "shenzhen",
}
};
return Future.value(result);
}
Future<Map<String, dynamic>> getUserProfile(dynamic params) async {
Map<String, dynamic> result = {
"userInfo":{
@ -262,6 +279,12 @@ class MyAppletHandler extends AppletHandler {
return Future.value(result);
}
// @override
// Future<Map<String, dynamic>> getUserInfo() {
// // TODO: implement getUserInfo
// throw UnimplementedError();
// }
@override
Future<void> onCustomMenuClick(String appId, String path, String menuId, String appInfo) {
// TODO: implement onCustomMenuClick

View File

@ -47,42 +47,59 @@
- (NSDictionary *)getUserInfoWithAppletInfo:(FATAppletInfo *)appletInfo {
NSLog(@"getUserInfoWithAppletInfo");
__block NSDictionary *userInfo;
CFRunLoopRef runLoop = CFRunLoopGetCurrent();
FlutterMethodChannel *channel = [[MopPlugin instance] methodChannel];
[channel invokeMethod:@"extensionApi:getUserInfo" arguments:nil result:^(id _Nullable result) {
CFRunLoopStop(CFRunLoopGetMain());
userInfo = result;
CFRunLoopStop(runLoop);
}];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
CFRunLoopStop(runLoop);
});
CFRunLoopRun();
return userInfo;
}
- (BOOL)appletInfo:(FATAppletInfo *)appletInfo didClickMoreBtnAtPath:(NSString *)path {
NSLog(@"appletInfo:didClickMoreBtnAtPath");
__block BOOL flag;
CFRunLoopRef runLoop = CFRunLoopGetCurrent();
FlutterMethodChannel *channel = [[MopPlugin instance] methodChannel];
NSLog(@"appletInfo:didClickMoreBtnAtPath,appId=%@,path=%@,channel=%@",appletInfo.appId,path,channel);
[channel invokeMethod:@"extensionApi:customCapsuleMoreButtonClick" arguments:@{@"appId": appletInfo.appId} result:^(id _Nullable result) {
CFRunLoopStop(CFRunLoopGetMain());
if ([result isKindOfClass:[NSNumber class]]) {
flag = [result boolValue];
}
CFRunLoopStop(runLoop);
}];
CFRunLoopRun();
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
CFRunLoopStop(runLoop);
});
CFRunLoopRun();
return flag;
}
- (NSArray<id<FATAppletMenuProtocol>> *)customMenusInApplet:(FATAppletInfo *)appletInfo atPath:(NSString *)path {
NSLog(@"customMenusInApplet");
NSLog(@"customMenusInApplet:%@,appletInfo=%@",path,appletInfo);
__block NSArray *list;
CFRunLoopRef runLoop = CFRunLoopGetCurrent();
FlutterMethodChannel *channel = [[MopPlugin instance] methodChannel];
[channel invokeMethod:@"extensionApi:getCustomMenus" arguments:@{@"appId": appletInfo.appId} result:^(id _Nullable result) {
CFRunLoopStop(CFRunLoopGetMain());
if ([result isKindOfClass:[NSArray class]]) {
list = result;
NSLog(@"customMenusInApplet2222:list=%@",list);
}
CFRunLoopStop(runLoop);
}];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
CFRunLoopStop(runLoop);
});
CFRunLoopRun();
NSLog(@"customMenusInApplet:%@,list=%@",path,list);
NSMutableArray *models = [NSMutableArray array];
for (NSDictionary<NSString *, NSString *> *data in list) {
MopCustomMenuModel *model = [[MopCustomMenuModel alloc] init];
@ -108,11 +125,13 @@
}
[models addObject:model];
}
return models;
}
- (void)clickCustomItemMenuWithInfo:(NSDictionary *)contentInfo inApplet:(FATAppletInfo *)appletInfo completion:(void (^)(FATExtensionCode code, NSDictionary *result))completion {
NSLog(@"HJH1,clickCustomItemMenuWithInfo");
NSError *parseError = nil;
NSMutableDictionary *shareDic = [[NSMutableDictionary alloc] initWithDictionary:[self dictionaryRepresentation:appletInfo]];
[shareDic setValue:@{@"desc" : shareDic[@"originalInfo"][@"customData"][@"detailDescription"]} forKey:@"params"];
@ -120,19 +139,20 @@
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:shareDic options:NSJSONWritingPrettyPrinted error:&parseError];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSDictionary *arguments = @{
@"appId": contentInfo[@"appId"],
@"path": contentInfo[@"path"],
@"menuId": contentInfo[@"menuId"],
@"appInfo": jsonString
@"appId": contentInfo[@"appId"],
@"path": contentInfo[@"path"],
@"menuId": contentInfo[@"menuId"],
@"appInfo": jsonString
};
FlutterMethodChannel *channel = [[MopPlugin instance] methodChannel];
[channel invokeMethod:@"extensionApi:onCustomMenuClick" arguments:arguments result:^(id _Nullable result) {
}];
if ([@"Desktop" isEqualToString:contentInfo[@"menuId"]]) {
[self addToDesktopItemClick:appletInfo path:contentInfo[@"path"]];
}
NSLog(@"HJH2,clickCustomItemMenuWithInfo");
}
- (NSDictionary *)dictionaryRepresentation:(FATAppletInfo *)object {
@ -157,7 +177,7 @@
NSDictionary *params = @{@"appId":appletId};
FlutterMethodChannel *channel = [[MopPlugin instance] methodChannel];
[channel invokeMethod:@"extensionApi:appletDidOpen" arguments:params result:^(id _Nullable result) {
}];
}
@ -176,9 +196,9 @@ static NSString *scheme = @"fatae55433be2f62915";//App对应的scheme
[url appendFormat:@"?iconpath=%@", appInfo.appAvatar];
[url appendFormat:@"&apptitle=%@", appInfo.appTitle.fat_encodeString];
[url appendFormat:@"&linkhref=%@", herf];
NSLog(@"跳转到中间页面:%@", url);
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]];
}
@ -202,7 +222,7 @@ static NSString *scheme = @"fatae55433be2f62915";//App对应的scheme
NSString *album = [MOPTools fat_currentLanguageIsEn] ? @"Album" : @"从相册选择";
UIAlertAction *chooseAlbumAction = [UIAlertAction actionWithTitle:album style:UIAlertActionStyleDefault handler:^(UIAlertAction *_Nonnull action) {
NSDictionary *params = @{@"name":@"chooseAvatarAlbum"};
FlutterMethodChannel *channel = [[MopPlugin instance] methodChannel];
[channel invokeMethod:@"extensionApi:chooseAvatarAlbum" arguments:params result:^(id _Nullable result) {
!bindChooseAvatar?: bindChooseAvatar(result);
@ -211,7 +231,7 @@ static NSString *scheme = @"fatae55433be2f62915";//App对应的scheme
NSString *camera = [MOPTools fat_currentLanguageIsEn] ? @"Camera" : @"拍照";
UIAlertAction *photoAction = [UIAlertAction actionWithTitle:camera style:UIAlertActionStyleDefault handler:^(UIAlertAction *_Nonnull action) {
NSDictionary *params = @{@"name":@"chooseAvatarPhoto"};
FlutterMethodChannel *channel = [[MopPlugin instance] methodChannel];
[channel invokeMethod:@"extensionApi:chooseAvatarPhoto" arguments:params result:^(id _Nullable result) {
!bindChooseAvatar?: bindChooseAvatar(result);

View File

@ -23,6 +23,22 @@
return _instance;
}
- (BOOL)getUserInfoWithAppletInfo:(FATAppletInfo *)appletInfo bindGetUserInfo:(void (^)(NSDictionary *result))bindGetUserInfo
{
FlutterMethodChannel *channel = [[MopPlugin instance] methodChannel];
NSLog(@"getUserInfoWithAppletInfo:%@", channel);
[channel invokeMethod:@"extensionApi:getUserInfo" arguments:nil result:^(id _Nullable result) {
NSDictionary *userInfo;
if (![result isKindOfClass:[NSDictionary class]]) {
userInfo = @{@"errMsg":@"getUserInfo:fail return value format invalid"};
} else {
userInfo = result;
}
bindGetUserInfo(userInfo);
}];
return YES;
}
- (BOOL)getUserProfileWithAppletInfo:(FATAppletInfo *)appletInfo
bindGetUserProfile:(void (^)(NSDictionary *result))bindGetUserProfile
{

View File

@ -69,8 +69,8 @@
} else {
config.language = FATPreferredLanguageSimplifiedChinese;
}
config.customLanguagePath = self.config[@"customLanguagePath"];
NSError* error = nil;
FATUIConfig *uiconfig = [[FATUIConfig alloc]init];
if (_uiConfig) {

View File

@ -15,15 +15,13 @@
{
NSLog(@"MOP_registerExtensionApi");
FlutterMethodChannel *channel = [[MopPlugin instance] methodChannel];
[[FATClient sharedClient] registerExtensionApi:self.name handle:^(id param, FATExtensionApiCallback callback) {
NSLog(@"invoke ExtensionApi:");
NSLog(@"%@",self.name);
NSLog(@"%@",param);
NSString* api = [@"extensionApi:" stringByAppendingString:self.name];
NSString *name = self.name;
[[FATClient sharedClient] registerExtensionApi:name handler:^(FATAppletInfo *appletInfo, id param, FATExtensionApiCallback callback) {
NSLog(@"channel:%@---invoke ExtensionApi:%@, param:%@", channel, name, param);
NSString *api = [@"extensionApi:" stringByAppendingString:name];
[channel invokeMethod:api arguments:param result:^(id _Nullable result) {
NSLog(@"extensionApi reslut:%@",result);
NSLog(@"extensionApi [%@] reslut:%@", name, result);
// flutter
// BOOL isFlutterError = [result isKindOfClass:[FlutterError class]] || result == FlutterMethodNotImplemented;
BOOL isValid = [result isKindOfClass:[NSDictionary class]];
if (!isValid) {
NSLog(@"extensionApi reslut is not NSDictionary");
@ -34,7 +32,7 @@
BOOL hasError = [[result allKeys] containsObject:@"errMsg"];
if (hasError) {
NSString *errMsg = result[@"errMsg"];
NSString *errPrefix = [NSString stringWithFormat:@"%@:fail", self.name];
NSString *errPrefix = [NSString stringWithFormat:@"%@:fail", name];
BOOL isFail = [errMsg hasPrefix:errPrefix];
if (isFail) {
NSLog(@"extensionApi reslut:fail");

View File

@ -0,0 +1,46 @@
//
// FATClient+ext.h
// Pods
//
// Created by on 2021/11/15.
//
#ifndef FATClient_ext_h
#define FATClient_ext_h
#import <FinApplet/FinApplet.h>
@interface FATClient (FATAppletExt)
///
/// @param authType 0: 1: 2: 3:
/// @param appletId id
/// @param complete status: 0 1: 2: sdk
- (void)fat_requestAppletAuthorize:(FATAuthorizationType)authType appletId:(NSString *)appletId complete:(void (^)(NSInteger status))complete;
/// sdkAPIsdksdk APIapi
/// @param extApiName API
/// @param handler
- (BOOL)registerInnerExtensionApi:(NSString *)extApiName handler:(void (^)(FATAppletInfo *appletInfo, id param, FATExtensionApiCallback callback))handler;
/**
sdkAPIsdksdk APIapi
@param syncExtApiName api
@param handler
@return
*/
- (BOOL)registerInnerSyncExtensionApi:(NSString *)syncExtApiName handler:(NSDictionary *(^)(FATAppletInfo *appletInfo, id param))handler;
/**
HTML apisdkapi
@param webApiName api
@param handler
*/
- (BOOL)fat_registerInnerWebApi:(NSString *)webApiName handler:(void (^)(FATAppletInfo *appletInfo, id param, FATExtensionApiCallback callback))handler;
@end
#endif /* FATClient_ext_h */

View File

@ -0,0 +1,28 @@
//
// FATExtClient.h
// FinAppletExtension
//
// Created by Haley on 2020/8/11.
// Copyright © 2020 finogeeks. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface FATExtClient : NSObject
+ (instancetype)sharedClient;
///
+ (NSString *)SDKVersion;
- (void)fat_prepareExtensionApis;
- (void)registerGoogleMapService:(NSString*)apiKey placesKey:(NSString*)placeKey;
/// webView
/// @param frame frame
/// @param URL URL
/// @param appletId ID
- (UIView *)webViewWithFrame:(CGRect)frame URL:(NSURL *)URL appletId:(NSString *)appletId;
@end

View File

@ -0,0 +1,92 @@
//
// FATExtClient.m
// FinAppletExtension
//
// Created by Haley on 2020/8/11.
// Copyright © 2020 finogeeks. All rights reserved.
//
#import "FATExtClient.h"
#import "FATExtBaseApi.h"
#import "FATWebView.h"
#import <FinApplet/FinApplet.h>
#import "FATExtPrivateConstant.h"
#import "FATExtMapManager.h"
#import "FATMapViewDelegate.h"
#import "FATClient+ext.h"
static FATExtClient *instance = nil;
@implementation FATExtClient
+ (instancetype)sharedClient {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[FATExtClient alloc] init];
});
return instance;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [super allocWithZone:zone];
});
return instance;
}
+ (NSString *)SDKVersion
{
return FATExtVersionString;
}
///
/// @param mapClass UIViewFATMapViewDelegate
- (BOOL)fat_registerMapClass:(Class)mapClass {
if (![mapClass isSubclassOfClass:UIView.class]) {
return NO;
}
if (![mapClass conformsToProtocol:@protocol(FATMapViewDelegate)]) {
return NO;
}
[FATExtMapManager shareInstance].mapClass = mapClass;
return YES;
}
- (void)registerGoogleMapService:(NSString*)apiKey placesKey:(NSString*)placeKey{
//[GMSServices provideAPIKey: apiKey];
[FATExtMapManager shareInstance].googleMapApiKey = apiKey;
if(placeKey == nil || [placeKey length] == 0){
[FATExtMapManager shareInstance].placesApiKey = apiKey;
}else{
[FATExtMapManager shareInstance].placesApiKey = placeKey;
}
}
- (void)fat_prepareExtensionApis {
}
- (void)registerExtensionBLEApi {
//SDK
}
- (UIView *)webViewWithFrame:(CGRect)frame URL:(NSURL *)URL appletId:(NSString *)appletId {
if (![FATClient sharedClient].inited) {
NSLog(@"appKey invalid");
return nil;
}
if (!URL || ![URL isKindOfClass:[NSURL class]]) {
NSLog(@"URL invalid");
return nil;
}
FATWebView *webView = [[FATWebView alloc] initWithFrame:frame URL:URL appletId:appletId];
return webView;
}
@end

View File

@ -0,0 +1,34 @@
//
// UIView+FATExtFrame.h
// FinAppletBDMap
//
// Created by 耀 on 2021/12/12.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIView (FATExtFrame)
@property (nonatomic, assign) CGFloat x;
@property (nonatomic, assign) CGFloat y;
@property (nonatomic, assign) CGFloat centerX;
@property (nonatomic, assign) CGFloat centerY;
@property (nonatomic, assign) CGFloat width;
@property (nonatomic, assign) CGFloat height;
@property (nonatomic, assign) CGSize size;
@property (nonatomic, assign) CGPoint origin;
@property (nonatomic, assign) CGFloat top;
@property (nonatomic, assign) CGFloat bottom;
@property (nonatomic, assign) CGFloat left;
@property (nonatomic, assign) CGFloat right;
//selfView
- (BOOL)intersectWithView:(UIView *)view;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,131 @@
//
// UIView+FATExtFrame.m
// FinAppletBDMap
//
// Created by 耀 on 2021/12/12.
//
#import "UIView+FATExtFrame.h"
@implementation UIView (FATExtFrame)
- (void)setX:(CGFloat)x {
CGRect frame = self.frame;
frame.origin.x = x;
self.frame = frame;
}
- (CGFloat)x {
return self.frame.origin.x;
}
- (void)setY:(CGFloat)y {
CGRect frame = self.frame;
frame.origin.y = y;
self.frame = frame;
}
- (CGFloat)y {
return self.frame.origin.y;
}
- (void)setCenterX:(CGFloat)centerX {
CGPoint center = self.center;
center.x = centerX;
self.center = center;
}
- (CGFloat)centerX {
return self.center.x;
}
- (void)setCenterY:(CGFloat)centerY {
CGPoint center = self.center;
center.y = centerY;
self.center = center;
}
- (CGFloat)centerY {
return self.center.y;
}
- (void)setWidth:(CGFloat)width {
CGRect frame = self.frame;
frame.size.width = width;
self.frame = frame;
}
- (CGFloat)width {
return self.frame.size.width;
}
- (void)setHeight:(CGFloat)height {
CGRect frame = self.frame;
frame.size.height = height;
self.frame = frame;
}
- (CGFloat)height {
return self.frame.size.height;
}
- (void)setSize:(CGSize)size {
CGRect frame = self.frame;
frame.size = size;
self.frame = frame;
}
- (CGSize)size {
return self.frame.size;
}
- (CGPoint)origin {
return self.frame.origin;
}
- (void)setOrigin:(CGPoint)origin {
CGRect frame = self.frame;
frame.origin = origin;
self.frame = frame;
}
- (void)setTop:(CGFloat)t {
self.frame = CGRectMake(self.left, t, self.width, self.height);
}
- (CGFloat)top {
return self.frame.origin.y;
}
- (void)setBottom:(CGFloat)b {
self.frame = CGRectMake(self.left, b - self.height, self.width, self.height);
}
- (CGFloat)bottom {
return self.frame.origin.y + self.frame.size.height;
}
- (void)setLeft:(CGFloat)l {
self.frame = CGRectMake(l, self.top, self.width, self.height);
}
- (CGFloat)left {
return self.frame.origin.x;
}
- (void)setRight:(CGFloat)r {
self.frame = CGRectMake(r - self.width, self.top, self.width, self.height);
}
- (CGFloat)right {
return self.frame.origin.x + self.frame.size.width;
}
//selfView nilwindow
- (BOOL)intersectWithView:(UIView *)view {
if (view == nil) view = [UIApplication sharedApplication].keyWindow;
CGRect rect1 = [self convertRect:self.bounds toView:nil];
CGRect rect2 = [view convertRect:view.bounds toView:nil];
return CGRectIntersectsRect(rect1, rect2);
}
@end

View File

@ -0,0 +1,21 @@
//
// FATExtConstant.h
// FinAppletExt
//
// Created by Haley on 2021/9/6.
//
#ifndef FATExtPrivateConstant_h
#define FATExtPrivateConstant_h
static NSString *kExtSendToCoreEventNotification = @"kExtSendToCoreEventNotification";
static NSString *FATExtVersionString = @"2.41.3";
typedef NS_ENUM(NSUInteger, FATExtEventType) {
FATExtEventTypeService, // service
FATExtEventTypePage, // page
FATExtEventTypeView, // view
};
#endif /* FATExtPrivateConstant_h */

View File

@ -0,0 +1,36 @@
//
// FATExtAVManager.h
// FinAppletExt
//
// Created by Haley on 2020/8/14.
// Copyright © 2020 finogeeks. All rights reserved.
//
#import <Foundation/Foundation.h>
typedef void (^FATExtAVSuccess)(NSString *filePath);
typedef void (^FATExtAVFail)(NSString *failMsg);
@interface FATExtAVManager : NSObject
+ (instancetype)sharedManager;
/**
@param success
@param fail
*/
- (void)startRecordWithSuccess:(FATExtAVSuccess)success fail:(FATExtAVFail)fail;
/**
*/
- (void)stopRecord;
/**
*/
- (void)checkRecordState;
@end

View File

@ -0,0 +1,195 @@
//
// FATExtAVManager.m
// FinAppletExt
//
// Created by Haley on 2020/8/14.
// Copyright © 2020 finogeeks. All rights reserved.
//
#import "FATExtAVManager.h"
#import "FATExtFileManager.h"
#import <AVFoundation/AVFoundation.h>
#import <CommonCrypto/CommonDigest.h>
#import <FinApplet/FinApplet.h>
@interface FATExtAVManager () <AVAudioRecorderDelegate>
@property (nonatomic, strong) AVAudioRecorder *recorder;
@property (nonatomic, copy) FATExtAVSuccess recordSuccess;
@property (nonatomic, copy) FATExtAVFail recordFail;
@end
@implementation FATExtAVManager
+ (instancetype)sharedManager {
static id _sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedInstance = [[FATExtAVManager alloc] init];
[_sharedInstance add_notifications];
});
return _sharedInstance;
}
- (void)add_notifications {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appletPageDisappear:) name:kFATPageDidDisappearNotification object:nil];
}
- (void)appletPageDisappear:(NSNotification *)notification
{
if (self.recorder) {
[self.recorder pause];
if (self.recordFail) {
self.recordFail(@"fail");
}
[self.recorder deleteRecording];
self.recorder = nil;
//
UIViewController *vc = [[UIApplication sharedApplication] fat_topViewController];
UINavigationController<FATCapsuleViewProtocol> *nav = (UINavigationController<FATCapsuleViewProtocol> *)vc.navigationController;
if ([nav respondsToSelector:@selector(controlCapsuleStateButton:state:animate:)]) {
[nav controlCapsuleStateButton:YES state:FATCapsuleButtonStateMicroPhone animate:NO];
}
}
}
/**
@param success
@param fail
*/
- (void)startRecordWithSuccess:(FATExtAVSuccess)success fail:(FATExtAVFail)fail {
if ([self.recorder isRecording]) {
fail(@"正在录音中...");
return;
}
self.recordSuccess = success;
self.recordFail = fail;
self.recorder = [self createAudioRecord];
[self.recorder prepareToRecord];
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:NULL];
[audioSession setActive:YES error:NULL];
[self.recorder recordForDuration:60];
//
UIViewController *vc = [[UIApplication sharedApplication] fat_topViewController];
UINavigationController<FATCapsuleViewProtocol> *nav = (UINavigationController<FATCapsuleViewProtocol> *)vc.navigationController;
if ([nav respondsToSelector:@selector(controlCapsuleStateButton:state:animate:)]) {
[nav controlCapsuleStateButton:NO state:FATCapsuleButtonStateMicroPhone animate:YES];
}
}
/**
*/
- (void)stopRecord {
if (self.recorder) {
[self.recorder stop];
self.recorder = nil;
//
UIViewController *vc = [[UIApplication sharedApplication] fat_topViewController];
UINavigationController<FATCapsuleViewProtocol> *nav = (UINavigationController<FATCapsuleViewProtocol> *)vc.navigationController;
if ([nav respondsToSelector:@selector(controlCapsuleStateButton:state:animate:)]) {
[nav controlCapsuleStateButton:YES state:FATCapsuleButtonStateMicroPhone animate:NO];
}
}
}
- (void)checkRecordState {
if ([self.recorder isRecording]) {
//
UIViewController *vc = [[UIApplication sharedApplication] fat_topViewController];
UINavigationController<FATCapsuleViewProtocol> *nav = (UINavigationController<FATCapsuleViewProtocol> *)vc.navigationController;
if ([nav respondsToSelector:@selector(controlCapsuleStateButton:state:animate:)]) {
[nav controlCapsuleStateButton:NO state:FATCapsuleButtonStateMicroPhone animate:YES];
}
}
}
#pragma mark - private method
- (AVAudioRecorder *)createAudioRecord {
// 使 1200KB
NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:kAudioFormatMPEG4AAC], AVFormatIDKey,
[NSNumber numberWithFloat:16000.0], AVSampleRateKey,
[NSNumber numberWithInt:1], AVNumberOfChannelsKey,
nil];
// 使md5
NSString *currentDt = [NSString stringWithFormat:@"%f", [[NSDate date] timeIntervalSince1970]];
NSData *data = [currentDt dataUsingEncoding:NSUTF8StringEncoding];
NSString *nameMD5 = [self fat_md5WithBytes:(char *)[data bytes] length:data.length];
NSString *fileName = [NSString stringWithFormat:@"tmp_%@.m4a", nameMD5];
NSString *filePath = [[self tmpDir] stringByAppendingPathComponent:fileName];
AVAudioRecorder *recorder = [[AVAudioRecorder alloc] initWithURL:[NSURL fileURLWithPath:filePath] settings:settings error:nil];
recorder.delegate = self;
return recorder;
}
- (NSString *)tmpDir {
FATAppletInfo *appInfo = [[FATClient sharedClient] currentApplet];
NSString *cacheDir = [FATExtFileManager appTempDirPath:appInfo.appId];
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL flag = YES;
if (![fileManager fileExistsAtPath:cacheDir isDirectory:&flag]) {
[fileManager createDirectoryAtPath:cacheDir withIntermediateDirectories:YES attributes:nil error:nil];
}
return cacheDir;
}
- (NSString *)fat_md5WithBytes:(char *)bytes length:(NSUInteger)length {
unsigned char result[16];
CC_MD5(bytes, (CC_LONG)length, result);
return [NSString stringWithFormat:
@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
result[0], result[1], result[2], result[3],
result[4], result[5], result[6], result[7],
result[8], result[9], result[10], result[11],
result[12], result[13], result[14], result[15]];
}
#pragma mark - AVAudioRecord Delegate
- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag {
NSString *filePath = recorder.url.lastPathComponent;
if (flag) {
if (self.recordSuccess) {
self.recordSuccess([@"finfile://" stringByAppendingString:filePath]);
}
} else {
[recorder deleteRecording];
if (self.recordFail) {
self.recordFail(@"fail");
}
}
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:NULL];
[audioSession setActive:YES error:NULL];
self.recorder = nil;
self.recordSuccess = nil;
self.recordFail = nil;
//
UIViewController *vc = [[UIApplication sharedApplication] fat_topViewController];
UINavigationController<FATCapsuleViewProtocol> *nav = (UINavigationController<FATCapsuleViewProtocol> *)vc.navigationController;
if ([nav respondsToSelector:@selector(controlCapsuleStateButton:state:animate:)]) {
[nav controlCapsuleStateButton:YES state:FATCapsuleButtonStateMicroPhone animate:NO];
}
}
@end

View File

@ -0,0 +1,30 @@
//
// FATExtFileManager.h
// FinAppletExt
//
// Created by Haley on 2020/8/17.
// Copyright © 2020 finogeeks. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface FATExtFileManager : NSObject
/**
@return
*/
+ (NSString *)projectRootAppsDirPath;
/**
*/
+ (NSString *)appRootDirPath:(NSString *)appId;
/**
*/
+ (NSString *)appTempDirPath:(NSString *)appId;
@end

View File

@ -0,0 +1,60 @@
//
// FATExtFileManager.m
// FinAppletExt
//
// Created by Haley on 2020/8/17.
// Copyright © 2020 finogeeks. All rights reserved.
//
#import "FATExtFileManager.h"
#import "FATExtUtil.h"
#import <FinApplet/FinApplet.h>
static NSString *FATEXT_PROJECT_ROOT = @"FinChatRoot";
static NSString *FATEXT_PROJECT_ROOT_App = @"app";
static NSString *FATEXT_PROJECT_ROOT_Framework = @"framework";
@implementation FATExtFileManager
+ (NSString *)projectRootDirPath {
NSString *rootPath;
if ([FATExtUtil currentProductIdentificationIsEmpty]) {
rootPath = [NSTemporaryDirectory() stringByAppendingPathComponent:FATEXT_PROJECT_ROOT];
} else {
rootPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[FATExtUtil currentProductIdentification]];
}
return rootPath;
}
+ (NSString *)projectRootAppsDirPath {
NSString *rootPath = [[FATExtFileManager projectRootDirPath] stringByAppendingFormat:@"/%@", FATEXT_PROJECT_ROOT_App];
return rootPath;
}
/**
@return
*/
+ (NSString *)appRootDirPath:(NSString *)appId {
NSString *rootPath = [FATExtFileManager projectRootAppsDirPath];
NSString *appDirPath = [rootPath stringByAppendingPathComponent:appId];
return appDirPath;
}
/**
@return NSString *
*/
+ (NSString *)appTempDirPath:(NSString *)appId {
NSString *currtUserId = [FATExtUtil currentUserId];
NSString *tempFileCachePath = [[FATExtFileManager appRootDirPath:appId] stringByAppendingPathComponent:[currtUserId fat_md5String]];
tempFileCachePath = [tempFileCachePath stringByAppendingPathComponent:@"Temp"];
return tempFileCachePath;
}
@end

View File

@ -0,0 +1,17 @@
//
// FATExtLocationManager.h
// FinAppletExt
//
// Created by beetle_92 on 2022/8/19.
// Copyright © 2022 finogeeks. All rights reserved.
//
#import <CoreLocation/CoreLocation.h>
NS_ASSUME_NONNULL_BEGIN
@interface FATExtLocationManager : CLLocationManager
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,47 @@
//
// FATExtLocationManager.m
// FinAppletExt
//
// Created by beetle_92 on 2022/8/19.
// Copyright © 2022 finogeeks. All rights reserved.
//
#import "FATExtLocationManager.h"
#import "FATExtAVManager.h"
#import "FATExtRecordManager.h"
#import "FATExt_LocationUpdateManager.h"
#import <FinApplet/FinApplet.h>
@implementation FATExtLocationManager
- (void)startUpdatingLocation {
[super startUpdatingLocation];
if ([self.delegate isKindOfClass:NSClassFromString(@"FATMapView")]) {
return;
}
//
UIViewController *vc = [[UIApplication sharedApplication] fat_topViewController];
UINavigationController<FATCapsuleViewProtocol> *nav = (UINavigationController<FATCapsuleViewProtocol> *)vc.navigationController;
if ([nav respondsToSelector:@selector(controlCapsuleStateButton:state:animate:)]) {
[nav controlCapsuleStateButton:NO state:FATCapsuleButtonStateLocation animate:YES];
}
}
- (void)stopUpdatingLocation {
[super stopUpdatingLocation];
//
UIViewController *vc = [[UIApplication sharedApplication] fat_topViewController];
UINavigationController<FATCapsuleViewProtocol> *nav = (UINavigationController<FATCapsuleViewProtocol> *)vc.navigationController;
if ([nav respondsToSelector:@selector(controlCapsuleStateButton:state:animate:)]) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[nav controlCapsuleStateButton:YES state:FATCapsuleButtonStateLocation animate:NO];
[[FATExtAVManager sharedManager] checkRecordState];
[[FATExtRecordManager shareManager] checkRecordState];
[[FATExt_LocationUpdateManager sharedManager] checkLocationState];
});
}
}
@end

View File

@ -0,0 +1,25 @@
//
// FATExtMapManager.h
// FinAppletExt
//
// Created by 耀 on 2021/11/18.
//
#import <Foundation/Foundation.h>
#import "FATExtPrivateConstant.h"
NS_ASSUME_NONNULL_BEGIN
@interface FATExtMapManager : NSObject
@property (nonatomic, copy) NSString *pageId;
@property (nonatomic, strong) Class mapClass;
@property (nonatomic, strong) NSString *googleMapApiKey;
@property (nonatomic, strong) NSString *placesApiKey;
+ (instancetype)shareInstance;
@property (nonatomic, strong) NSMutableDictionary *dataDic;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,44 @@
//
// FATExtMapManager.m
// FinAppletExt
//
// Created by 耀 on 2021/11/18.
//
#import "FATExtMapManager.h"
#import <FinApplet/FinApplet.h>
#import "FATMapViewDelegate.h"
#import "FATMapView.h"
static FATExtMapManager *instance = nil;
@implementation FATExtMapManager
+ (instancetype)shareInstance {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[FATExtMapManager alloc] init];
});
return instance;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [super allocWithZone:zone];
});
return instance;
}
- (instancetype)init {
self = [super init];
if (self) {
_dataDic = [[NSMutableDictionary alloc] init];
self.mapClass = FATMapView.class;
}
return self;
}
@end

View File

@ -0,0 +1,30 @@
//
// FATRecordManager.h
// FinAppletExt
//
// Created by Haley on 2021/1/21.
// Copyright © 2021 finogeeks. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface FATExtRecordManager : NSObject
+ (instancetype)shareManager;
#pragma mark - new api
- (BOOL)startRecordWithData:(NSDictionary *)data appletId:(NSString *)appletId eventBlock:(void (^)(NSInteger eventType,NSString *eventName, NSDictionary *paramDic,NSDictionary *extDic))eventBlock;
- (BOOL)pauseRecordWithData:(NSDictionary *)data appletId:(NSString *)appletId;
- (BOOL)resumeRecordWithData:(NSDictionary *)data appletId:(NSString *)appletId;
- (BOOL)stopRecordWithData:(NSDictionary *)data appletId:(NSString *)appletId;
- (BOOL)checkRecordWithMethod:(NSString *)method data:(NSDictionary *)data appletId:(NSString *)appletId;
- (void)sendRecordFrameBufferWithData:(NSDictionary *)data appletId:(NSString *)appletId;
- (void)checkRecordState;
@end

View File

@ -0,0 +1,362 @@
//
// FATRecordManager.m
// FinAppletExt
//
// Created by Haley on 2021/1/21.
// Copyright © 2021 finogeeks. All rights reserved.
//
#import "FATExtRecordManager.h"
#import "FATExtRecorder.h"
#import "FATExtUtil.h"
#import <FinApplet/FinApplet.h>
static FATExtRecordManager *instance = nil;
@interface FATExtRecordManager () <FATExtRecorderDelegate>
@property (nonatomic, strong) NSMutableDictionary *recordDictionary;
@property (nonatomic, strong) NSMutableDictionary *recorderDict;
@end
@implementation FATExtRecordManager
+ (instancetype)shareManager {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[FATExtRecordManager alloc] init];
instance.recordDictionary = [[NSMutableDictionary alloc] init];
instance.recorderDict = [[NSMutableDictionary alloc] init];
});
return instance;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [super allocWithZone:zone];
});
return instance;
}
- (instancetype)init {
self = [super init];
if (self) {
[self p_addNotifications];
}
return self;
}
#pragma mark - private methods
- (void)p_addNotifications {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil];
}
- (void)_clearAudioSession {
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:NULL];
[audioSession setActive:YES error:NULL];
}
#pragma mark - notification handler
- (void)applicationDidEnterBackground:(NSNotification *)notice {
[self.recorderDict enumerateKeysAndObjectsUsingBlock:^(NSString *key, FATExtRecorder *recorder, BOOL * _Nonnull stop) {
if (!recorder.isPausing) {
[self pauseRecordWithData:nil appletId:key];
}
}];
}
#pragma mark - new api
- (BOOL)startRecordWithData:(NSDictionary *)data appletId:(NSString *)appletId eventBlock:(void (^)(NSInteger eventType,NSString *eventName, NSDictionary *paramDic,NSDictionary *extDic))eventBlock {
FATExtRecorder *record = [[FATExtRecorder alloc] init];
record.delegate = self;
record.eventCallBack = eventBlock;
BOOL started = [record startRecordWithDict:data appId:appletId];
if (started) {
[self.recorderDict setObject:record forKey:appletId];
NSDictionary *params = @{@"method" : @"onStart"};
if (eventBlock) {
eventBlock(0,@"onRecorderManager",params,nil);
}
//
UIViewController *vc = [[UIApplication sharedApplication] fat_topViewController];
UINavigationController<FATCapsuleViewProtocol> *nav = (UINavigationController<FATCapsuleViewProtocol> *)vc.navigationController;
if ([nav respondsToSelector:@selector(controlCapsuleStateButton:state:animate:)]) {
[nav controlCapsuleStateButton:NO state:FATCapsuleButtonStateMicroPhone animate:YES];
}
return YES;
}
return NO;
}
- (BOOL)pauseRecordWithData:(NSDictionary *)data appletId:(NSString *)appletId {
FATExtRecorder *record = [self.recorderDict objectForKey:appletId];
if (!record) {
return NO;
}
BOOL result = [record pauseRecord];
if (result) {
if (record.eventCallBack) {
NSDictionary *params = @{@"method" : @"onPause"};
record.eventCallBack(0, @"onRecorderManager", params,nil);
}
//
UIViewController *vc = [[UIApplication sharedApplication] fat_topViewController];
UINavigationController<FATCapsuleViewProtocol> *nav = (UINavigationController<FATCapsuleViewProtocol> *)vc.navigationController;
if ([nav respondsToSelector:@selector(controlCapsuleStateButton:state:animate:)]) {
[nav controlCapsuleStateButton:YES state:FATCapsuleButtonStateMicroPhone animate:NO];
}
return YES;
}
return NO;
}
- (BOOL)resumeRecordWithData:(NSDictionary *)data appletId:(NSString *)appletId {
FATExtRecorder *record = [self.recorderDict objectForKey:appletId];
BOOL result = [record resumeRecord];
if (result) {
if (record.eventCallBack) {
NSDictionary *params = @{@"method" : @"onResume"};
record.eventCallBack(0, @"onRecorderManager", params,nil);
}
//
UIViewController *vc = [[UIApplication sharedApplication] fat_topViewController];
UINavigationController<FATCapsuleViewProtocol> *nav = (UINavigationController<FATCapsuleViewProtocol> *)vc.navigationController;
if ([nav respondsToSelector:@selector(controlCapsuleStateButton:state:animate:)]) {
[nav controlCapsuleStateButton:NO state:FATCapsuleButtonStateMicroPhone animate:YES];
}
return YES;
}
return NO;
}
- (BOOL)stopRecordWithData:(NSDictionary *)data appletId:(NSString *)appletId {
FATExtRecorder *record = [self.recorderDict objectForKey:appletId];
[record stopRecord];
//
UIViewController *vc = [[UIApplication sharedApplication] fat_topViewController];
UINavigationController<FATCapsuleViewProtocol> *nav = (UINavigationController<FATCapsuleViewProtocol> *)vc.navigationController;
if ([nav respondsToSelector:@selector(controlCapsuleStateButton:state:animate:)]) {
[nav controlCapsuleStateButton:YES state:FATCapsuleButtonStateMicroPhone animate:NO];
}
return YES;
}
- (BOOL)checkRecordWithMethod:(NSString *)method data:(NSDictionary *)data appletId:(NSString *)appletId {
FATExtRecorder *recorder = [self.recorderDict objectForKey:appletId];
if ([method isEqualToString:@"start"]) { //
if (recorder.isRecording || recorder.isPausing) {
NSDictionary *params = @{
@"method" : @"onError",
@"data" : @{@"errMsg" : @"is recording or paused"},
};
if (recorder.eventCallBack) {
recorder.eventCallBack(0, @"onRecorderManager", params,nil);
}
return NO;
}
} else if ([method isEqualToString:@"pause"]) { //
if (![recorder isRecording]) {
NSDictionary *params = @{
@"method" : @"onError",
@"data" : @{@"errMsg" : @"not recording"},
};
if (recorder.eventCallBack) {
recorder.eventCallBack(0, @"onRecorderManager", params,nil);
}
return NO;
}
} else if ([method isEqualToString:@"resume"]) { //
if (!recorder.isPausing) {
NSDictionary *params = @{
@"method" : @"onError",
@"data" : @{@"errMsg" : @"not paused"},
};
if (recorder.eventCallBack) {
recorder.eventCallBack(0, @"onRecorderManager", params,nil);
}
return NO;
}
} else if ([method isEqualToString:@"stop"]) { //
if (!recorder.isStarted) {
NSDictionary *params = @{
@"method" : @"onError",
@"data" : @{@"errMsg" : @"recorder not start"},
};
if (recorder.eventCallBack) {
recorder.eventCallBack(0, @"onRecorderManager", params,nil);
}
return NO;
}
}
return YES;
}
- (void)sendRecordFrameBufferWithData:(NSDictionary *)data appletId:(NSString *)appletId {
FATExtRecorder *recorder = [self.recorderDict objectForKey:appletId];
recorder.frameState = FATFrameStatePrepareToSend;
if (recorder.frameInfoArray.count == 0) {
recorder.waitToSendBuffer = YES;
return;
}
[self sendFrameDataWithRecorder:recorder withFrameBufferData:nil];
}
- (void)sendFrameDataWithRecorder:(FATExtRecorder *)recorder withFrameBufferData:(NSData *)data {
// 0.
recorder.waitToSendBuffer = NO;
recorder.frameState = FATFrameStateAlreadyWillSend;
// 1.bufferjscore
NSDictionary *dict = [recorder.frameInfoArray firstObject];
if (!dict) {
return;
}
// NSNumber *frameIndex = dict[@"frameIndex"];
NSString *frameBufferKey = dict[@"frameBufferKey"];
NSString *frameBufferPath = dict[@"frameBufferPath"];
NSNumber *isLastFrame = dict[@"isLastFrame"];
NSData *frameData;
if (data) {
frameData = data;
} else {
frameData = [NSData dataWithContentsOfFile:frameBufferPath options:0 error:nil];
}
Byte *bytes = (Byte *)frameData.bytes;
NSMutableArray *arrayM = [NSMutableArray array];
for (int i = 0; i < frameData.length; i++) {
int number = (int)bytes[i];
[arrayM addObject:@(number)];
}
NSDictionary *params = @{
@"method" : @"onFrameRecorded",
@"data" : @{
@"isLastFrame": isLastFrame,
@"buffer_id": frameBufferKey
}
};
NSDictionary *extDic = @{@"jsContextKey":frameBufferKey,@"jsContextValue":arrayM};
[recorder.frameInfoArray removeObject:dict];
if (recorder.eventCallBack) {
recorder.eventCallBack(0, @"onRecorderManager", params,extDic);
}
// [[FATExtCoreEventManager shareInstance] sendToServiceWithAppId:[[FATClient sharedClient] currentApplet].appId eventName:@"onRecorderManager" paramDict:params];
// 2.
recorder.frameState = FATFrameStateAlreadySent;
}
- (void)checkRecordState {
FATAppletInfo *appInfo = [[FATClient sharedClient] currentApplet];
if (!appInfo.appId) {
return;
}
FATExtRecorder *recorder = [self.recorderDict objectForKey:appInfo.appId];
if ([recorder isRecording]) {
//
UIViewController *vc = [[UIApplication sharedApplication] fat_topViewController];
UINavigationController<FATCapsuleViewProtocol> *nav = (UINavigationController<FATCapsuleViewProtocol> *)vc.navigationController;
if ([nav respondsToSelector:@selector(controlCapsuleStateButton:state:animate:)]) {
[nav controlCapsuleStateButton:NO state:FATCapsuleButtonStateMicroPhone animate:YES];
}
}
}
#pragma mark - FATExtRecorderDelegate
- (void)extRecorder:(FATExtRecorder *)recorder
onFrameData:(NSData *)frameData
frameIndex:(NSInteger)frameIndex
isLastFrame:(BOOL)isLastFrame {
NSString *frameBufferKey = [recorder.recordFilePath lastPathComponent];
frameBufferKey = [frameBufferKey stringByDeletingPathExtension];
frameBufferKey = [frameBufferKey stringByAppendingFormat:@"_%ld", (long)frameIndex];
NSString *frameFileName = [frameBufferKey stringByAppendingPathExtension:recorder.recordFilePath.pathExtension];
NSString *frameBufferPath = [[recorder.recordFilePath stringByDeletingLastPathComponent] stringByAppendingPathComponent:frameFileName];
NSDictionary *infoDict = @{@"frameIndex": @(frameIndex),
@"isLastFrame": @(isLastFrame),
@"frameBufferKey": frameBufferKey,
@"frameBufferPath": frameBufferPath
};
if ([NSThread isMainThread]) {
[recorder.frameInfoArray addObject:infoDict];
if (recorder.frameState == FATFrameStatePrepareToSend || recorder.waitToSendBuffer) {
//
[self sendFrameDataWithRecorder:recorder withFrameBufferData:frameData];
}
} else {
dispatch_async(dispatch_get_main_queue(), ^{
[recorder.frameInfoArray addObject:infoDict];
if (recorder.frameState == FATFrameStatePrepareToSend || recorder.waitToSendBuffer) {
//
[self sendFrameDataWithRecorder:recorder withFrameBufferData:frameData];
}
});
}
}
- (void)extRecorder:(FATExtRecorder *)recorder onError:(NSError *)error {
NSString *msg = error.localizedDescription ? : @"fail";
NSDictionary *params = @{
@"method" : @"onError",
@"data" : @{@"errMsg" : msg},
};
if (recorder.eventCallBack) {
recorder.eventCallBack(0, @"onRecorderManager", params,nil);
}
}
- (void)extRecorderDidCompletion:(FATExtRecorder *)recorder {
NSString *filePath = recorder.recordFilePath;
NSURL *fileURL = [NSURL fileURLWithPath:filePath];
float duration = [FATExtUtil durtaionWithFileURL:fileURL];
long long fileSize = [FATExtUtil fileSizeWithFileURL:fileURL];
NSString *tempFilePath = [@"finfile://" stringByAppendingString:filePath.lastPathComponent];
NSMutableDictionary *result = [NSMutableDictionary dictionary];
[result setValue:tempFilePath forKey:@"tempFilePath"];
[result setValue:@(duration) forKey:@"duration"];
[result setValue:@(fileSize) forKey:@"fileSize"];
NSDictionary *params = @{
@"method" : @"onStop",
@"data" : result,
};
[self.recorderDict removeObjectForKey:recorder.recorderId];
[self _clearAudioSession];
if (recorder.eventCallBack) {
recorder.eventCallBack(0, @"onRecorderManager", params,nil);
}
}
- (void)extRecorderBeginInterruption:(FATExtRecorder *)recorder {
NSDictionary *params = @{@"method" : @"onInterruptionBegin"};
if (recorder.eventCallBack) {
recorder.eventCallBack(0, @"onRecorderManager", params,nil);
}
//
[self pauseRecordWithData:nil appletId:recorder.recorderId];
}
- (void)extRecorderEndInterruption:(FATExtRecorder *)recorder withOptions:(NSUInteger)flags {
NSDictionary *params = @{@"method" : @"onInterruptionEnd"};
if (recorder.eventCallBack) {
recorder.eventCallBack(0, @"onRecorderManager", params,nil);
}
}
@end

View File

@ -0,0 +1,84 @@
//
// FATMapViewDelegate.h
// FinAppletExt
//
// Created by on 2021/11/24.
// Copyright © 2021 finogeeks. All rights reserved.
//
#ifndef FATMapViewDelegate_h
#define FATMapViewDelegate_h
#import <UIKit/UIKit.h>
@protocol FATMapViewDelegate <NSObject>
@required
/// Subscribepage
/// eventName
/// resultDic
@property (nonatomic, copy) void(^eventCallBack)(NSString *eventName, NSDictionary *paramDic);
- (instancetype)initWithParam:(NSDictionary *)param mapPageId:(NSString *)pageId;
- (void)updateWithParam:(NSDictionary *)param;
///
- (NSDictionary *)fat_getCenter;
///
- (double)fat_getScale;
///
/// @param data
- (NSString *)fat_moveToLocation:(NSDictionary *)data;
///
/// @param data
- (void)fat_includePoints:(NSDictionary *)data;
///
- (NSDictionary *)fat_mapgetRegion;
///
- (NSDictionary *)fat_fromScreenLocation;
///
/// @param data
- (CGPoint)fat_toScreenLocation:(NSDictionary *)data;
///// app
- (void)fat_openMapApp:(NSDictionary *)data;
///
- (void)fat_addMarkers:(NSDictionary *)data;
///
- (void)fat_removeMarkers:(NSDictionary *)data;
///
- (BOOL)fat_translateMarker:(NSDictionary *)data;
/// 沿 marker
- (BOOL)fat_moveAlong:(NSDictionary *)data;
@optional
/// (0.25~0.75)[0.5, 0.5]
- (void)mapSetCenterOffset:(NSDictionary *)data;
- (void)fat_setLocMarkerIcon:(NSDictionary *)data;
/// sdknil
- (NSDictionary *)fat_getRotate;
///
- (NSDictionary *)fat_getskew;
/// customCallout
- (void)updateNativeMapMarkers:(NSDictionary *)param;
@end
#endif /* FATMapViewDelegate_h */

View File

@ -0,0 +1,15 @@
//
// FATExtHelper.h
// FinAppletExt
//
// Created by Haley on 2020/8/19.
// Copyright © 2020 finogeeks. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface FATExtHelper : NSObject
+ (UIImage *)fat_ext_imageFromBundleWithName:(NSString *)imageName;
@end

View File

@ -0,0 +1,21 @@
//
// FATExtHelper.m
// FinAppletExt
//
// Created by Haley on 2020/8/19.
// Copyright © 2020 finogeeks. All rights reserved.
//
#import "FATExtHelper.h"
@implementation FATExtHelper
+ (UIImage *)fat_ext_imageFromBundleWithName:(NSString *)imageName {
NSString *bundleResourcePath = [NSBundle bundleForClass:[FATExtHelper class]].resourcePath;
NSString *assetPath = [bundleResourcePath stringByAppendingPathComponent:@"FinAppletExt.bundle"];
NSBundle *assetBundle = [NSBundle bundleWithPath:assetPath];
NSString *path = [[assetBundle bundlePath] stringByAppendingPathComponent:[NSString stringWithFormat:@"/%@", imageName]];
return [UIImage imageWithContentsOfFile:path];
}
@end

View File

@ -0,0 +1,53 @@
//
// FATExtUtil.h
// FinAppletExt
//
// Created by Haley on 2021/1/25.
// Copyright © 2021 finogeeks. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
#import <CoreLocation/CoreLocation.h>
@interface FATExtUtil : NSObject
+ (NSString *)tmpDirWithAppletId:(NSString *)appletId;
+ (NSString *)fat_md5WithBytes:(char *)bytes length:(NSUInteger)length;
+ (NSString *)jsonStringFromDict:(NSDictionary *)dict;
+ (NSString *)jsonStringFromArray:(NSArray *)array;
+ (NSString *)signFromDict:(NSDictionary *)dict;
+ (NSString *)realPathForFINFile:(NSString *)finfile appId:(NSString *)appId;
///
/// @param fileURL urlAVURLAsset .caf .aac .wav .mp3
+ (float)durtaionWithFileURL:(NSURL *)fileURL;
///
/// @param fileURL url
+ (long long)fileSizeWithFileURL:(NSURL *)fileURL;
/// userId
+ (NSString *)currentUserId;
/**
*/
+ (BOOL)currentProductIdentificationIsEmpty;
/**
*/
+ (NSString *)currentProductIdentification;
+ (NSString *)getAppName;
+ (void)getNearbyPlacesByCategory:(NSString *)category coordinates:(CLLocationCoordinate2D)coordinates radius:(NSInteger)radius token:(NSString *)token completion:(void (^)(NSDictionary *))completion;
+ (NSArray *)convertPlaceDictToArray:(NSDictionary*)dict;
@end

View File

@ -0,0 +1,268 @@
//
// FATExtUtil.m
// FinAppletExt
//
// Created by Haley on 2021/1/25.
// Copyright © 2021 finogeeks. All rights reserved.
//
#import "FATExtUtil.h"
#import "FATExtFileManager.h"
#import "FATExtMapManager.h"
#import "fincore.h"
#import "FATMapPlace.h"
#import <FinApplet/FinApplet.h>
#import <CommonCrypto/CommonDigest.h>
#define FAT_EXT_FILE_SCHEMA @"finfile://"
@implementation FATExtUtil
+ (NSString *)tmpDirWithAppletId:(NSString *)appletId {
if (!appletId) {
return nil;
}
NSString *cacheDir = [FATExtFileManager appTempDirPath:appletId];
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL flag = YES;
if (![fileManager fileExistsAtPath:cacheDir isDirectory:&flag]) {
[fileManager createDirectoryAtPath:cacheDir withIntermediateDirectories:YES attributes:nil error:nil];
}
return cacheDir;
}
+ (NSString *)fat_md5WithBytes:(char *)bytes length:(NSUInteger)length {
unsigned char result[16];
CC_MD5(bytes, (CC_LONG)length, result);
return [NSString stringWithFormat:
@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
result[0], result[1], result[2], result[3],
result[4], result[5], result[6], result[7],
result[8], result[9], result[10], result[11],
result[12], result[13], result[14], result[15]];
}
+ (NSString *)jsonStringFromDict:(NSDictionary *)dict {
if (!dict || ![dict isKindOfClass:[NSDictionary class]]) {
return nil;
}
NSData *data = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:nil];
if (!data) {
return nil;
}
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
return jsonString;
}
+ (NSString *)jsonStringFromArray:(NSArray *)array {
if (!array || ![array isKindOfClass:[NSArray class]]) {
return nil;
}
NSData *data = [NSJSONSerialization dataWithJSONObject:array options:NSJSONWritingPrettyPrinted error:nil];
if (!data) {
return nil;
}
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
return jsonString;
}
+ (NSString *)signFromDict:(NSDictionary *)dict {
if (!dict || ![dict isKindOfClass:[NSDictionary class]]) {
return nil;
}
NSArray *keys = [dict allKeys];
NSArray *sortedKeys = [keys sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
return [obj1 compare:obj2 options:NSNumericSearch]; //
}];
NSString *plainText = @"";
for (NSString *key in sortedKeys) {
NSString *and = [plainText isEqualToString:@""] ? @"" : @"&";
NSString *value = [dict valueForKey:key];
// if ([value isKindOfClass:[NSDictionary class]]) {
// NSDictionary *dictValue = (NSDictionary *)value;
// value = [FATExtUtil jsonStringFromDict:dictValue];
// } else if ([key isKindOfClass:[NSArray class]]) {
// NSArray *arrayValue = (NSArray *)value;
// value = [FATExtUtil jsonStringFromArray:arrayValue];
// }
if ([key isEqualToString:@"sign"]) {
continue;
}
if ([value isKindOfClass:[NSString class]] || [value isKindOfClass:[NSNumber class]]) {
NSString *append = [NSString stringWithFormat:@"%@%@=%@", and, key, value];
plainText = [plainText stringByAppendingString:append];
}
}
// NSLog(@"扩展:%@", plainText);
NSString *digest = [[[SDKCoreClient sharedInstance].finoLicenseService fin_messageDigest:plainText] uppercaseString];
NSData *data = [digest dataUsingEncoding:NSUTF8StringEncoding];
NSData *encodeData = [[SDKCoreClient sharedInstance].finoLicenseService fin_encodeSMContent:data];
NSString *sign = [[NSString alloc] initWithData:encodeData encoding:NSUTF8StringEncoding];
// NSLog(@"扩展sign%@", sign);
return sign;
}
///
/// @param fileURL urlAVURLAsset .caf .aac .wav .mp3
+ (float)durtaionWithFileURL:(NSURL *)fileURL {
NSDictionary *options = @{AVURLAssetPreferPreciseDurationAndTimingKey : @(YES)};
AVURLAsset *recordAsset = [AVURLAsset URLAssetWithURL:fileURL options:options];
// ms
CMTime durationTime = recordAsset.duration;
durationTime.value = durationTime.value;
float seconds = CMTimeGetSeconds(durationTime);
float duration = seconds * 1000;
return duration;
}
///
/// @param fileURL url
+ (long long)fileSizeWithFileURL:(NSURL *)fileURL {
// Byte
NSFileManager *manager = [NSFileManager defaultManager];
long long fileSize = [[manager attributesOfItemAtPath:fileURL.path error:nil] fileSize];
return fileSize;
}
+ (NSString *)currentUserId {
NSString *currentUserId = [FATClient sharedClient].config.currentUserId;
NSString *productIdentification = [FATClient sharedClient].config.productIdentification;
if (!currentUserId || currentUserId.length == 0) {
if ([NSString fat_isEmptyWithString:productIdentification]) {
currentUserId = @"finclip_default";
} else {
currentUserId = productIdentification;
}
}
return currentUserId;
}
+ (BOOL)currentProductIdentificationIsEmpty {
NSString *productIdentification = [FATClient sharedClient].config.productIdentification;
return [NSString fat_isEmptyWithString:productIdentification];
}
+ (NSString *)currentProductIdentification {
NSString *productIdentification = [FATClient sharedClient].config.productIdentification;
return productIdentification;
}
+ (NSString *)getAppName {
NSDictionary *infoDict = [[NSBundle mainBundle] infoDictionary];
NSString *appName = [infoDict valueForKey:@"CFBundleDisplayName"];
if (!appName) appName = [infoDict valueForKey:@"CFBundleName"];
if (!appName) appName = [infoDict valueForKey:@"CFBundleExecutable"];
return appName;
}
+ (void)getNearbyPlacesByCategory:(NSString *)category coordinates:(CLLocationCoordinate2D)coordinates radius:(NSInteger)radius token:(NSString *)token
completion:(void (^)(NSDictionary *))completion {
NSURL *url = [NSURL URLWithString:[self searchApiHost]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"GET";
if (token && [token length] > 0) {
NSDictionary *parameters = @{
@"key" : [FATExtMapManager shareInstance].googleMapApiKey,
@"pagetoken" : token
};
NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
NSMutableArray *queryItems = [NSMutableArray array];
for (NSString *key in parameters) {
NSString *value = [NSString stringWithFormat:@"%@", parameters[key]];
[queryItems addObject:[NSURLQueryItem queryItemWithName:key value:value]];
}
urlComponents.queryItems = queryItems;
request.URL = urlComponents.URL;
} else {
NSDictionary *parameters = @{
@"key" : [FATExtMapManager shareInstance].placesApiKey,
@"radius" : @(radius),
@"location" : [NSString stringWithFormat:@"%f,%f", coordinates.latitude, coordinates.longitude],
@"type" : [category lowercaseString]
};
NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
NSMutableArray *queryItems = [NSMutableArray array];
for (NSString *key in parameters) {
NSString *value = [NSString stringWithFormat:@"%@", parameters[key]];
[queryItems addObject:[NSURLQueryItem queryItemWithName:key value:value]];
}
urlComponents.queryItems = queryItems;
request.URL = urlComponents.URL;
}
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
configuration.timeoutIntervalForRequest = 5.0;
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"Error: %@", error);
completion(nil);
return;
}
if (data) {
NSError *jsonError;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
if (jsonError) {
NSLog(@"Error: %@", jsonError);
completion(nil);
} else {
completion(json);
}
} else {
completion(nil);
}
}];
[task resume];
}
+ (NSArray *)convertPlaceDictToArray:(NSDictionary*)dict{
NSMutableArray *placeArrayM = [NSMutableArray array];
for (NSDictionary *dictItem in [dict objectForKey:@"results"]) {
FATMapPlace *place = [[FATMapPlace alloc] init];
place.name = dictItem[@"name"];
place.address = dictItem[@"vicinity"];
FATMapPlace *mark = [[FATMapPlace alloc] init];
NSDictionary *dict = dictItem[@"geometry"];
mark.name = dictItem[@"name"];
mark.address = dictItem[@"vicinity"];
double lat = [dict[@"location"][@"lat"] doubleValue];
double lng = [dict[@"location"][@"lng"] doubleValue];
place.location = [[CLLocation alloc] initWithLatitude:lat longitude:lng] ;
[placeArrayM addObject:place];
}
return placeArrayM;
}
+ (NSArray *)getCategories {
NSArray *list = @[@"Places",@"Bakery", @"Doctor", @"School", @"Taxi_stand", @"Hair_care", @"Restaurant", @"Pharmacy", @"Atm", @"Gym", @"Store", @"Spa"];
return list;
}
+ (NSString *)searchApiHost {
return @"https://maps.googleapis.com/maps/api/place/nearbysearch/json";
}
+ (NSString *)googlePhotosHost {
return @"https://maps.googleapis.com/maps/api/place/photo";
}
+ (NSString *)googlePlaceDetailsHost {
return @"https://maps.googleapis.com/maps/api/place/details/json";
}
@end

View File

@ -0,0 +1,22 @@
//
// FATLocationManager.h
// FinApplet
//
// Created by Haley on 2020/4/7.
// Copyright © 2020 finogeeks. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
@interface FATLocationManager : NSObject
@property (nonatomic, strong) CLLocation *location;
@property (nonatomic, strong) CLPlacemark *placemark;
+ (instancetype)manager;
- (void)updateLocation;
@end

View File

@ -0,0 +1,99 @@
//
// FATLocationManager.m
// FinApplet
//
// Created by Haley on 2020/4/7.
// Copyright © 2020 finogeeks. All rights reserved.
//
#import "FATLocationManager.h"
#import "FATWGS84ConvertToGCJ02.h"
#import "FATExtLocationManager.h"
static FATLocationManager *instance = nil;
@interface FATLocationManager () <CLLocationManagerDelegate>
@property (nonatomic, strong) FATExtLocationManager *locationManager;
@end
@implementation FATLocationManager
+ (instancetype)manager {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[FATLocationManager alloc] init];
});
return instance;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [super allocWithZone:zone];
});
return instance;
}
- (void)updateLocation {
if (![FATExtLocationManager locationServicesEnabled]) {
return;
}
CLAuthorizationStatus status = [FATExtLocationManager authorizationStatus];
if (status == kCLAuthorizationStatusAuthorizedWhenInUse ||
status == kCLAuthorizationStatusAuthorizedAlways ||
status == kCLAuthorizationStatusNotDetermined) {
//
FATExtLocationManager *locationManager = [[FATExtLocationManager alloc] init];
self.locationManager = locationManager;
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager requestWhenInUseAuthorization];
[locationManager startUpdatingLocation];
} else if (status == kCLAuthorizationStatusDenied) {
}
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
CLLocation *newLocation = [locations firstObject];
//
if (![FATWGS84ConvertToGCJ02ForAMapView isLocationOutOfChina:[newLocation coordinate]]) {
//coord
CLLocationCoordinate2D coord = [FATWGS84ConvertToGCJ02ForAMapView transformFromWGSToGCJ:[newLocation coordinate]];
newLocation = [[CLLocation alloc] initWithLatitude:coord.latitude longitude:coord.longitude];
}
self.location = newLocation;
[self.locationManager stopUpdatingLocation];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:newLocation completionHandler:^(NSArray<CLPlacemark *> *_Nullable placemarks, NSError *_Nullable error) {
if (error) {
return;
}
if (placemarks.count > 0) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
self.placemark = placemark;
// //
// NSString *province = placemark.administrativeArea;
// //
// NSLog(@"name,%@", placemark.name);
// //
// NSLog(@"thoroughfare,%@", placemark.thoroughfare);
// //
// NSLog(@"subThoroughfare,%@", placemark.subThoroughfare);
// //
// NSLog(@"locality,%@", placemark.locality);
// //
// NSLog(@"subLocality,%@", placemark.subLocality);
// //
// NSLog(@"country,%@", placemark.country);
}
}];
}
@end

View File

@ -0,0 +1,19 @@
//
// FATWGS84ConvertToGCJ02.h
// FinApplet
//
// Created by on 2018/8/9.
// Copyright © 2018 finogeeks. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
@interface FATWGS84ConvertToGCJ02ForAMapView : NSObject
//
+ (BOOL)isLocationOutOfChina:(CLLocationCoordinate2D)location;
//GCJ-02
+ (CLLocationCoordinate2D)transformFromWGSToGCJ:(CLLocationCoordinate2D)wgsLoc;
// gcj02wgs82
+ (CLLocationCoordinate2D)transformFromGCJToWGS:(CLLocationCoordinate2D)wgsLoc;
@end

View File

@ -0,0 +1,135 @@
//
// FATWGS84ConvertToGCJ02ForAMapView.m
// FinApplet
//
// Created by on 2018/8/9.
// Copyright © 2018 finogeeks. All rights reserved.
//
#import "FATWGS84ConvertToGCJ02.h"
#define RANGE_LON_MAX 137.8347
#define RANGE_LON_MIN 72.004
#define RANGE_LAT_MAX 55.8271
#define RANGE_LAT_MIN 0.8293
#define LAT_OFFSET_0(x,y) -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * sqrt(fabs(x))
#define LAT_OFFSET_1 (20.0 * sin(6.0 * x * M_PI) + 20.0 * sin(2.0 * x * M_PI)) * 2.0 / 3.0
#define LAT_OFFSET_2 (20.0 * sin(y * M_PI) + 40.0 * sin(y / 3.0 * M_PI)) * 2.0 / 3.0
#define LAT_OFFSET_3 (160.0 * sin(y / 12.0 * M_PI) + 320 * sin(y * M_PI / 30.0)) * 2.0 / 3.0
#define LON_OFFSET_0(x,y) 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * sqrt(fabs(x))
#define LON_OFFSET_1 (20.0 * sin(6.0 * x * M_PI) + 20.0 * sin(2.0 * x * M_PI)) * 2.0 / 3.0
#define LON_OFFSET_2 (20.0 * sin(x * M_PI) + 40.0 * sin(x / 3.0 * M_PI)) * 2.0 / 3.0
#define LON_OFFSET_3 (150.0 * sin(x / 12.0 * M_PI) + 300.0 * sin(x / 30.0 * M_PI)) * 2.0 / 3.0
#define jzA 6378245.0
#define jzEE 0.00669342162296594323
static const double fat_a = 6378245.0;
static const double fat_ee = 0.00669342162296594323;
@implementation FATWGS84ConvertToGCJ02ForAMapView
+ (CLLocationCoordinate2D)transformFromWGSToGCJ:(CLLocationCoordinate2D)wgsLoc {
CLLocationCoordinate2D adjustLoc;
if ([self isLocationOutOfChina:wgsLoc]) {
adjustLoc = wgsLoc;
} else {
double adjustLat = [self transformLatWithX:wgsLoc.longitude - 105.0 withY:wgsLoc.latitude - 35.0];
double adjustLon = [self transformLonWithX:wgsLoc.longitude - 105.0 withY:wgsLoc.latitude - 35.0];
double radLat = wgsLoc.latitude / 180.0 * M_PI;
double magic = sin(radLat);
magic = 1 - fat_ee * magic * magic;
double sqrtMagic = sqrt(magic);
adjustLat = (adjustLat * 180.0) / ((fat_a * (1 - fat_ee)) / (magic * sqrtMagic) * M_PI);
adjustLon = (adjustLon * 180.0) / (fat_a / sqrtMagic * cos(radLat) * M_PI);
adjustLoc.latitude = wgsLoc.latitude + adjustLat - 0.00039900; //
adjustLoc.longitude = wgsLoc.longitude + adjustLon;
}
return adjustLoc;
}
+ (CLLocationCoordinate2D)transformFromGCJToWGS:(CLLocationCoordinate2D)wgsLoc {
return [self gcj02Decrypt:wgsLoc.latitude gjLon:wgsLoc.longitude];
}
+ (CLLocationCoordinate2D)gcj02Decrypt:(double)gjLat gjLon:(double)gjLon {
CLLocationCoordinate2D gPt = [self gcj02Encrypt:gjLat bdLon:gjLon];
double dLon = gPt.longitude - gjLon;
double dLat = gPt.latitude - gjLat;
CLLocationCoordinate2D pt;
pt.latitude = gjLat - dLat;
pt.longitude = gjLon - dLon;
return pt;
}
+ (CLLocationCoordinate2D)gcj02Encrypt:(double)ggLat bdLon:(double)ggLon {
CLLocationCoordinate2D resPoint;
double mgLat;
double mgLon;
if ([self outOfChina:ggLat bdLon:ggLon]) {
resPoint.latitude = ggLat;
resPoint.longitude = ggLon;
return resPoint;
}
double dLat = [self transformLat:(ggLon - 105.0)bdLon:(ggLat - 35.0)];
double dLon = [self transformLon:(ggLon - 105.0) bdLon:(ggLat - 35.0)];
double radLat = ggLat / 180.0 * M_PI;
double magic = sin(radLat);
magic = 1 - jzEE * magic * magic;
double sqrtMagic = sqrt(magic);
dLat = (dLat * 180.0) / ((jzA * (1 - jzEE)) / (magic * sqrtMagic) * M_PI);
dLon = (dLon * 180.0) / (jzA / sqrtMagic * cos(radLat) * M_PI);
mgLat = ggLat + dLat;
mgLon = ggLon + dLon;
resPoint.latitude = mgLat;
resPoint.longitude = mgLon;
return resPoint;
}
+ (BOOL)outOfChina:(double)lat bdLon:(double)lon {
if (lon < RANGE_LON_MIN || lon > RANGE_LON_MAX)
return true;
if (lat < RANGE_LAT_MIN || lat > RANGE_LAT_MAX)
return true;
return false;
}
+ (double)transformLat:(double)x bdLon:(double)y {
double ret = LAT_OFFSET_0(x, y);
ret += LAT_OFFSET_1;
ret += LAT_OFFSET_2;
ret += LAT_OFFSET_3;
return ret;
}
+ (double)transformLon:(double)x bdLon:(double)y {
double ret = LON_OFFSET_0(x, y);
ret += LON_OFFSET_1;
ret += LON_OFFSET_2;
ret += LON_OFFSET_3;
return ret;
}
//
+ (BOOL)isLocationOutOfChina:(CLLocationCoordinate2D)location {
if (location.longitude < 72.004 || location.longitude > 137.8347 || location.latitude < 0.8293 || location.latitude > 55.8271)
return YES;
return NO;
}
+ (double)transformLatWithX:(double)x withY:(double)y {
double lat = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * sqrt(fabs(x));
lat += (20.0 * sin(6.0 * x * M_PI) + 20.0 * sin(2.0 * x * M_PI)) * 2.0 / 3.0;
lat += (20.0 * sin(y * M_PI) + 40.0 * sin(y / 3.0 * M_PI)) * 2.0 / 3.0;
lat += (160.0 * sin(y / 12.0 * M_PI) + 320 * sin(y * M_PI / 30.0)) * 2.0 / 3.0;
return lat;
}
+ (double)transformLonWithX:(double)x withY:(double)y {
double lon = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * sqrt(fabs(x));
lon += (20.0 * sin(6.0 * x * M_PI) + 20.0 * sin(2.0 * x * M_PI)) * 2.0 / 3.0;
lon += (20.0 * sin(x * M_PI) + 40.0 * sin(x / 3.0 * M_PI)) * 2.0 / 3.0;
lon += (150.0 * sin(x / 12.0 * M_PI) + 300.0 * sin(x / 30.0 * M_PI)) * 2.0 / 3.0;
return lon;
}
@end

View File

@ -0,0 +1,17 @@
//
// UIView+FATExtSafaFrame.h
// FinAppletExt
//
// Created by 耀 on 2023/5/25.
// Copyright © 2023 finogeeks. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIView (FATExtSafaFrame)
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,70 @@
//
// UIView+FATExtSafaFrame.m
// FinAppletExt
//
// Created by 耀 on 2023/5/25.
// Copyright © 2023 finogeeks. All rights reserved.
//
#import "UIView+FATExtSafaFrame.h"
#import <objc/runtime.h>
@implementation UIView (FATExtSafaFrame)
+ (void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Method method1 = class_getInstanceMethod(self.class, @selector(setFrame:));
Method method2 = class_getInstanceMethod(self.class, @selector(fatSafe_setFrame:));
method_exchangeImplementations(method1, method2);
Method method3 = class_getInstanceMethod(self.class, @selector(setCenter:));
Method method4 = class_getInstanceMethod(self.class, @selector(fatSafe_setCenter:));
method_exchangeImplementations(method3, method4);
});
}
- (void)fatSafe_setFrame:(CGRect)frame{
CGRect unitFrame = frame;
if(isnan(unitFrame.origin.x)){
return;
}
if(isnan(unitFrame.origin.y)){
return;
}
if(isnan(unitFrame.size.width)){
return;
}
if(isnan(unitFrame.size.height)){
return;
}
@try {
[self fatSafe_setFrame:unitFrame];
} @catch (NSException *exception) {
} @finally {
}
}
- (void)fatSafe_setCenter:(CGPoint)center{
CGPoint unitCenter = center;
if(isnan(unitCenter.x)){
return;
}
if(isnan(unitCenter.y)){
return;
}
@try {
[self fatSafe_setCenter:unitCenter];
} @catch (NSException *exception) {
} @finally {
}
}
@end

View File

@ -0,0 +1,21 @@
//
// FATAnnotation.h
// AppletDemo
//
// Created by Haley on 2020/4/17.
// Copyright © 2020 weidian. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
@interface FATAnnotation : NSObject <MKAnnotation>
@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *address;
- (instancetype)initWithCoordinate:(CLLocationCoordinate2D)coordinate;
@end

View File

@ -0,0 +1,20 @@
//
// FATAnnotation.m
// AppletDemo
//
// Created by Haley on 2020/4/17.
// Copyright © 2020 weidian. All rights reserved.
//
#import "FATAnnotation.h"
@implementation FATAnnotation
- (instancetype)initWithCoordinate:(CLLocationCoordinate2D)coordinate {
if (self = [super init]) {
self.coordinate = coordinate;
}
return self;
}
@end

View File

@ -0,0 +1,22 @@
//
// FATExtChoosePoiViewController.h
// FinAppletExt
//
// Created by 耀 on 2021/12/8.
//
#import <UIKit/UIKit.h>
#import <FinApplet/FinApplet.h>
NS_ASSUME_NONNULL_BEGIN
typedef void (^SureBlock)(NSDictionary *locationInfo);
@interface FATExtChoosePoiViewController : FATUIViewController
@property (nonatomic, copy) dispatch_block_t cancelBlock;
@property (nonatomic, copy) SureBlock sureBlock;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,388 @@
//
// FATExtChoosePoiViewController.m
// FinAppletExt
//
// Created by 耀 on 2021/12/8.
//
#import "FATExtChoosePoiViewController.h"
#import "FATLocationResultViewController.h"
#import "FATAnnotation.h"
#import "FATExtHelper.h"
#import "FATExtLocationManager.h"
#import "FATExtMapManager.h"
#import "FATExtUtil.h"
#import <CoreLocation/CoreLocation.h>
static NSString *kAnnotationId = @"FATAnnotationViewId";
static NSString *kUserAnnotationId = @"FATUserAnnotationViewId";
@interface FATExtChoosePoiViewController () <UITableViewDelegate, UITableViewDataSource, FATLocationResultDelegate, CLLocationManagerDelegate>
@property (nonatomic, strong) UIImageView *centerLocationView;
@property (nonatomic, strong) MKUserLocation *userLocation;
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) UIActivityIndicatorView *indicatorView;
@property (nonatomic, strong) UISearchController *searchController;
@property (nonatomic, strong) FATLocationResultViewController *locationResultVC;
@property (nonatomic, strong) FATExtLocationManager *locationManager;
@property (nonatomic, strong) NSMutableArray *dataArray;
@property (nonatomic, copy) NSString *cityName;
@end
@implementation FATExtChoosePoiViewController
- (NSMutableArray *)dataArray {
if (!_dataArray) {
_dataArray = [[NSMutableArray alloc] init];
}
return _dataArray;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.edgesForExtendedLayout = UIRectEdgeNone;
[self p_initNavigationBar];
[self p_initSubViews];
[self startLocation];
}
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
CGFloat width = self.view.bounds.size.width;
CGFloat height = self.view.bounds.size.height;
CGFloat searchBarH = self.searchController.searchBar.bounds.size.height;
CGFloat totalH = height - searchBarH;
self.centerLocationView.center = CGPointMake(width * 0.5, totalH * 0.5 * 0.5);
self.tableView.frame = CGRectMake(0, 0, width, height);
self.indicatorView.center = CGPointMake(width * 0.5, height * 0.5);
}
- (void)dealloc {
_searchController = nil;
_locationResultVC = nil;
}
#pragma mark - private method
- (void)p_initNavigationBar {
self.title = [[FATClient sharedClient] fat_localizedStringForKey:@"Location"];
NSString *cancel = [[FATClient sharedClient] fat_localizedStringForKey:@"Cancel"];
NSString *ok = [[FATClient sharedClient] fat_localizedStringForKey:@"OK"];
UIButton *cancelButton = [[UIButton alloc] init];
[cancelButton setTitle:cancel forState:UIControlStateNormal];
[cancelButton setTitleColor:[UIColor systemBlueColor] forState:UIControlStateNormal];
[cancelButton addTarget:self action:@selector(cancelItemClick) forControlEvents:UIControlEventTouchUpInside];
UIButton *okButton = [[UIButton alloc] init];
[okButton setTitle:ok forState:UIControlStateNormal];
[okButton setTitleColor:[UIColor systemBlueColor] forState:UIControlStateNormal];
[okButton addTarget:self action:@selector(sureItemClick) forControlEvents:UIControlEventTouchUpInside];
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:cancelButton];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:okButton];
}
- (void)p_initSubViews {
[self p_initSearchBar];
self.centerLocationView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 30, 30)];
self.centerLocationView.image = [FATExtHelper fat_ext_imageFromBundleWithName:@"fav_fileicon_loc90"];
[self.view addSubview:self.tableView];
[self.view addSubview:self.indicatorView];
[self.indicatorView startAnimating];
}
//
- (void)startLocation {
// CLog(@"--------开始定位");
self.locationManager = [[FATExtLocationManager alloc] init];
self.locationManager.delegate = self;
// ,
self.locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;
[self.locationManager requestWhenInUseAuthorization];
self.locationManager.distanceFilter = 10.0f;
[self.locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
if ([error code] == kCLErrorDenied) {
// NSLog(@"访问被拒绝");
}
if ([error code] == kCLErrorLocationUnknown) {
// NSLog(@"无法获取位置信息");
}
}
//
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
CLLocation *newLocation = locations[0];
CLLocationCoordinate2D centerCoordinate = newLocation.coordinate;
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
CLLocation *location = [[CLLocation alloc] initWithLatitude:centerCoordinate.latitude longitude:centerCoordinate.longitude];
[geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *array, NSError *error) {
CLPlacemark *placemark = nil;
if (!error) {
placemark = [array firstObject];
}
//
NSString *city = placemark.locality;
if (!city) {
city = placemark.administrativeArea;
}
self.cityName = city;
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(centerCoordinate, 1000, 1000);
request.region = region;
request.naturalLanguageQuery = [[FATClient sharedClient] fat_localizedStringForKey:@"Office Building"];
MKLocalSearch *localSearch = [[MKLocalSearch alloc] initWithRequest:request];
if([FATExtMapManager shareInstance].googleMapApiKey.length > 1){
[FATExtUtil getNearbyPlacesByCategory:request.naturalLanguageQuery coordinates: region.center radius:1000 token:@""
completion:^(NSDictionary * _Nonnull dict) {
self.dataArray = [[NSMutableArray alloc] initWithArray: [FATExtUtil convertPlaceDictToArray:dict]];
dispatch_async(dispatch_get_main_queue(), ^{
[self.indicatorView stopAnimating];
[self addSpecialCity];
[self.tableView reloadData];
});
}];
}else {
[localSearch startWithCompletionHandler:^(MKLocalSearchResponse *_Nullable response, NSError *_Nullable error) {
//NSMutableArray *placeArrayM = [NSMutableArray array];
// if (placemark) {
// FATMapPlace *place = [[FATMapPlace alloc] init];
// place.name = placemark.name;
// place.address = placemark.thoroughfare;
// place.location = placemark.location;
// place.selected = YES;
// [self.dataArray addObject:place];
// }
for (MKMapItem *item in response.mapItems) {
if (!item.isCurrentLocation) {
FATMapPlace *place = [[FATMapPlace alloc] init];
place.name = item.placemark.name;
place.address = item.placemark.thoroughfare;
place.location = item.placemark.location;
[self.dataArray addObject:place];
}
}
[self.indicatorView stopAnimating];
[self addSpecialCity];
[self.tableView reloadData];
}];
}
}];
[manager stopUpdatingLocation];
}
- (void)p_initSearchBar {
_locationResultVC = [FATLocationResultViewController new];
_locationResultVC.delegate = self;
_locationResultVC.searchBarHeight = self.searchController.searchBar.bounds.size.height;
_searchController = [[UISearchController alloc] initWithSearchResultsController:_locationResultVC];
_searchController.searchResultsUpdater = _locationResultVC;
NSString *placeholder = [[FATClient sharedClient] fat_localizedStringForKey:@"Search nearby"];
_searchController.searchBar.placeholder = placeholder;
_searchController.searchBar.backgroundColor = [UIColor colorWithRed:239 / 255.0 green:239 / 255.0 blue:244 / 255.0 alpha:1];
UITextField *searchField;
if (@available(iOS 13.0, *)) {
searchField = _searchController.searchBar.searchTextField;
} else {
searchField = [_searchController.searchBar valueForKey:@"searchField"];
}
searchField.layer.borderColor = [UIColor colorWithRed:218 / 255.0 green:219 / 255.0 blue:233 / 255.0 alpha:1].CGColor;
self.tableView.tableHeaderView = _searchController.searchBar;
}
#pragma mark - click events
- (void)cancelItemClick {
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
if (self.cancelBlock) {
self.cancelBlock();
}
}
- (void)sureItemClick {
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
FATMapPlace *selectPlace = nil;
for (FATMapPlace *place in self.dataArray) {
if (place.selected) {
selectPlace = place;
break;
}
}
NSString *type;
CLLocationCoordinate2D coordinate = selectPlace.location.coordinate;
NSMutableDictionary *locationInfo = [[NSMutableDictionary alloc] initWithDictionary:@{@"latitude" : [NSString stringWithFormat:@"%@", @(coordinate.latitude)],
@"longitude" : [NSString stringWithFormat:@"%@", @(coordinate.longitude)]}];
if ([selectPlace.name isEqualToString:[[FATClient sharedClient] fat_localizedStringForKey:@"Don't show location"]]) {
type = @"0";
} else if (!selectPlace.address) {
type = @"1";
[locationInfo setValue: selectPlace.name ?: @"" forKey:@"city"];
} else {
type = @"2";
[locationInfo setValue: selectPlace.address ?: @"" forKey:@"name"];
[locationInfo setValue: selectPlace.name ?: @"" forKey:@"address"];
}
[locationInfo setValue:type forKey:@"type"];
if (self.sureBlock) {
self.sureBlock(locationInfo);
}
}
- (UITableView *)tableView {
if (!_tableView) {
_tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
_tableView.dataSource = self;
_tableView.delegate = self;
_tableView.backgroundColor = [UIColor whiteColor];
_tableView.tableFooterView = [UIView new];
}
return _tableView;
}
- (UIActivityIndicatorView *)indicatorView {
if (!_indicatorView) {
_indicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
_indicatorView.hidesWhenStopped = YES;
}
return _indicatorView;
}
#pragma mark - FATLocationResultDelegate
- (void)selectedLocationWithLocation:(FATMapPlace *)place {
[self dismissViewControllerAnimated:NO completion:nil];
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
NSString *type;
CLLocationCoordinate2D coordinate = place.location.coordinate;
NSMutableDictionary *locationInfo = [[NSMutableDictionary alloc] initWithDictionary:@{@"latitude" : [NSString stringWithFormat:@"%@", @(coordinate.latitude)],
@"longitude" : [NSString stringWithFormat:@"%@", @(coordinate.longitude)]}];
if ([place.name isEqualToString:[[FATClient sharedClient] fat_localizedStringForKey:@"Don't show location"]]) {
type = @"0";
} else if (!place.address) {
type = @"1";
[locationInfo setValue: place.name ?: @"" forKey:@"city"];
} else {
type = @"2";
[locationInfo setValue: place.address ?: @"" forKey:@"name"];
[locationInfo setValue: place.name ?: @"" forKey:@"address"];
}
[locationInfo setValue:type forKey:@"type"];
if (self.sureBlock) {
self.sureBlock(locationInfo);
}
}
#pragma mark - MKMapViewDelegate
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
if (!self.userLocation) {
_userLocation = userLocation;
CLLocationCoordinate2D center = userLocation.location.coordinate;
if (center.latitude > 0 && center.longitude > 0) {
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(center, 1000, 1000);
mapView.centerCoordinate = center;
mapView.region = region;
self.locationResultVC.region = region;
}
}
}
//
- (void)addSpecialCity {
//
NSMutableArray *deleteArray = [[NSMutableArray alloc] init];
for (FATMapPlace *place in self.dataArray) {
if ([place.name isEqualToString:[[FATClient sharedClient] fat_localizedStringForKey:@"Don't show location"]]) {
[deleteArray insertObject:place atIndex:0];
}
if (place.name && !place.address) {
[deleteArray insertObject:place atIndex:0];
}
}
if (deleteArray.count != 0) {
[self.dataArray removeObjectsInArray:deleteArray];
}
FATMapPlace *place = [[FATMapPlace alloc] init];
place.name = self.cityName;
place.location = place.location;
place.selected = NO;
[self.dataArray insertObject:place atIndex:0];
FATMapPlace *NoPlace = [[FATMapPlace alloc] init];
NoPlace.name = [[FATClient sharedClient] fat_localizedStringForKey:@"Don't show location"];
NoPlace.selected = NO;
[self.dataArray insertObject:NoPlace atIndex:0];
}
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.dataArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *identifer = @"identifer";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifer];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifer];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.detailTextLabel.textColor = [UIColor grayColor];
}
FATMapPlace *place = self.dataArray[indexPath.row];
if ([place.name isEqualToString:[[FATClient sharedClient] fat_localizedStringForKey:@"Don't show location"]]) {
cell.textLabel.textColor = [UIColor fat_colorWithRGBHexString:@"0066ff" alpha:1.0];
} else {
if (@available(iOS 13.0, *)) {
cell.textLabel.textColor = UIColor.labelColor;
} else {
cell.textLabel.textColor = UIColor.blackColor;
}
}
cell.textLabel.text = place.name;
cell.detailTextLabel.text = place.address;
if (place.selected) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
for (FATMapPlace *place in self.dataArray) {
place.selected = NO;
}
FATMapPlace *place = self.dataArray[indexPath.row];
place.selected = YES;
[self.tableView reloadData];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(place.location.coordinate, 1000, 1000);
self.locationResultVC.region = region;
}
@end

View File

@ -0,0 +1,32 @@
//
// FATExtSliderView.h
// FinAppletGDMap
//
// Created by 耀 on 2021/12/13.
//
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import "FATMapPlace.h"
#define fatKScreenWidth ([UIScreen mainScreen].bounds.size.width)
#define fatKScreenHeight ([UIScreen mainScreen].bounds.size.height)
NS_ASSUME_NONNULL_BEGIN
typedef void (^SelectItemBlock)(FATMapPlace *locationInfo);
typedef void (^TopDistance)(float height, BOOL isTopOrBottom);
@interface FATExtSliderView : UIView
@property (nonatomic, copy) SelectItemBlock selectItemBlock;
@property (nonatomic, assign) float topH; //
@property (nonatomic, copy) TopDistance topDistance;
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) NSMutableArray<FATMapPlace *> *poiInfoListArray;
- (void)updateSearchFrameWithColcationCoordinate:(CLLocationCoordinate2D)coord;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,365 @@
//
// FATExtSliderView.m
// FinAppletGDMap
//
// Created by 耀 on 2021/12/13.
//
#import "FATExtSliderView.h"
#import "UIView+FATExtFrame.h"
#import <FinApplet/FinApplet.h>
#import "UIView+FATExtSafaFrame.h"
#import "FATExtUtil.h"
#import "FATExtMapManager.h"
@interface FATExtSliderView () <UITableViewDelegate, UITableViewDataSource, UIGestureRecognizerDelegate, UISearchControllerDelegate, UISearchBarDelegate>
@property (nonatomic, assign) float bottomH; //
@property (nonatomic, assign) float stop_y; //tableView
@property (nonatomic, strong) UISearchController *searchController;
@property (nonatomic, strong) NSMutableArray<FATMapPlace *> *tempPoiInfoListArray;
@property (nonatomic, assign) NSInteger selectNumber;
@property (nonatomic, strong) UISearchController *search;
@property (nonatomic, assign) CLLocationCoordinate2D locationCoordinate;
@property (nonatomic, assign) NSInteger pageIndex;
@property (nonatomic, strong) NSString *cityString;
@property (nonatomic, assign) MKCoordinateRegion region;
@end
@implementation FATExtSliderView
- (NSMutableArray<FATMapPlace *> *)poiInfoListArray {
if (!_poiInfoListArray) {
_poiInfoListArray = [[NSMutableArray alloc] init];
}
return _poiInfoListArray;
}
- (NSMutableArray<FATMapPlace *> *)tempPoiInfoListArray {
if (!_tempPoiInfoListArray) {
_tempPoiInfoListArray = [[NSMutableArray alloc] init];
}
return _tempPoiInfoListArray;
}
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self setUI];
}
return self;
}
- (void)setUI {
self.backgroundColor = [UIColor systemGrayColor];
self.bottomH = self.top;
self.pageIndex = 0;
self.selectNumber = 0;
UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
panGestureRecognizer.delegate = self;
[self addGestureRecognizer:panGestureRecognizer];
[self creatUI];
}
- (void)creatUI {
self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, fatKScreenWidth, self.frame.size.height) style:UITableViewStylePlain];
self.tableView.backgroundColor = [UIColor whiteColor];
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
self.tableView.showsVerticalScrollIndicator = NO;
self.tableView.delegate = self;
self.tableView.dataSource = self;
self.tableView.bounces = NO;
if (@available(iOS 11.0, *)) {
self.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
} else {
// Fallback on earlier versions
}
[self addSubview:self.tableView];
[self.tableView registerNib:[UINib nibWithNibName:@"SlideTableViewCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"SlideTableViewCell"];
self.tableView.tableHeaderView = self.searchController.searchBar;
self.search.delegate = self;
}
- (void)getData {
CLLocationCoordinate2D centerCoordinate = self.locationCoordinate;
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
CLLocation *location = [[CLLocation alloc] initWithLatitude:centerCoordinate.latitude longitude:centerCoordinate.longitude];
[geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *array, NSError *error) {
CLPlacemark *placemark = nil;
if (!error) {
placemark = [array firstObject];
}
MKCoordinateSpan span = MKCoordinateSpanMake(centerCoordinate.latitude, centerCoordinate.longitude);
MKCoordinateRegion newRegion = MKCoordinateRegionMake(centerCoordinate, span);
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.region = self.region;
request.naturalLanguageQuery = @"Place";
CLLocationCoordinate2D destCenter = self.region.center;
if(destCenter.latitude == 0){
destCenter = centerCoordinate;
}
if([FATExtMapManager shareInstance].googleMapApiKey.length > 1){
[FATExtUtil getNearbyPlacesByCategory:@"All" coordinates:destCenter radius:1000 token:@""
completion:^(NSDictionary * _Nonnull dict) {
NSMutableArray *placeArrayM = [NSMutableArray array];
// if (placemark) {
// FATMapPlace *place = [[FATMapPlace alloc] init];
// place.name = placemark.name;
// place.address = placemark.thoroughfare;
// place.location = placemark.location;
// place.selected = YES;
// [placeArrayM addObject:place];
// }
[placeArrayM addObjectsFromArray:[FATExtUtil convertPlaceDictToArray:dict]];
self.poiInfoListArray = [[NSMutableArray alloc] initWithArray: placeArrayM];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
}];
}else{
MKLocalSearch *localSearch = [[MKLocalSearch alloc] initWithRequest:request];
[localSearch startWithCompletionHandler:^(MKLocalSearchResponse *_Nullable response, NSError *_Nullable error) {
NSMutableArray *placeArrayM = [NSMutableArray array];
for (MKMapItem *item in response.mapItems) {
if (!item.isCurrentLocation) {
FATMapPlace *place = [[FATMapPlace alloc] init];
place.name = item.placemark.name;
place.address = item.placemark.thoroughfare;
place.location = item.placemark.location;
[placeArrayM addObject:place];
}
}
self.poiInfoListArray = [[NSMutableArray alloc] initWithArray:placeArrayM];
[self.tableView reloadData];
}];
}
}];
}
- (void)updateSearchFrameWithColcationCoordinate:(CLLocationCoordinate2D)coord {
// struct CLLocationCoordinate2D my2D = {40.0, 115.0};//self.locationCoordinate
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(self.locationCoordinate, 1000, 1000);
self.region = region;
self.locationCoordinate = coord;
[self.poiInfoListArray removeAllObjects];
[self.tableView reloadData];
[self getData];
}
- (void)p_searchLocationsWithSearchText:(NSString *)searchText {
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.region = self.region;
request.naturalLanguageQuery = searchText;
CLLocationCoordinate2D destCenter = self.region.center;
if(destCenter.latitude == 0){
destCenter = self.locationCoordinate;
}
if([FATExtMapManager shareInstance].googleMapApiKey.length > 1){
[FATExtUtil getNearbyPlacesByCategory:searchText coordinates:destCenter radius:1000 token:@""
completion:^(NSDictionary * _Nonnull dict) {
self.poiInfoListArray = [[NSMutableArray alloc] initWithArray: [FATExtUtil convertPlaceDictToArray:dict]];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
}];
}else { MKLocalSearch *localSearch = [[MKLocalSearch alloc] initWithRequest:request];
[localSearch startWithCompletionHandler:^(MKLocalSearchResponse *_Nullable response, NSError *_Nullable error) {
NSMutableArray *placeArrayM = [NSMutableArray array];
for (MKMapItem *item in response.mapItems) {
if (!item.isCurrentLocation) {
FATMapPlace *place = [[FATMapPlace alloc] init];
place.name = item.placemark.name;
place.address = item.placemark.thoroughfare;
place.location = item.placemark.location;
[placeArrayM addObject:place];
}
}
self.poiInfoListArray = [[NSMutableArray alloc] initWithArray:placeArrayM];
[self.tableView reloadData];
}];
}
}
#pragma mark -
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat currentPostion = scrollView.contentOffset.y;
self.stop_y = currentPostion;
if (self.top > self.topH) {
[scrollView setContentOffset:CGPointMake(0, 0)];
}
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
- (void)panAction:(UIPanGestureRecognizer *)pan {
//
CGPoint point = [pan translationInView:self];
// stop_ytableviewtableview0
if (self.stop_y > 0) {
// 0
[pan setTranslation:CGPointMake(0, 0) inView:self];
return;
}
// self.top
self.top += point.y;
if (self.top < self.topH) {
self.top = self.topH;
}
// self.bottomH
if (self.top > self.bottomH) {
self.top = self.bottomH;
}
//
//
if (pan.state == UIGestureRecognizerStateEnded || pan.state == UIGestureRecognizerStateCancelled) {
//
CGPoint velocity = [pan velocityInView:self];
CGFloat speed = 350;
if (velocity.y < -speed) {
[self goTop];
[pan setTranslation:CGPointMake(0, 0) inView:self];
return;
} else if (velocity.y > speed) {
[self goBack];
[pan setTranslation:CGPointMake(0, 0) inView:self];
return;
}
if (self.top > fatKScreenHeight / 2) {
[self goBack];
} else {
[self goTop];
}
}
[pan setTranslation:CGPointMake(0, 0) inView:self];
if (self.top != self.bottomH) {
if (!isnan(point.y)) {
if (self.topDistance) {
self.topDistance(point.y, false);
}
}
}
}
- (void)goTop {
if (self.top != self.bottomH) {
if (self.topDistance) {
if (!isnan(self.topH)) {
self.topDistance(self.topH, true);
}
}
}
[UIView animateWithDuration:0.5 animations:^{
self.top = self.topH;
} completion:^(BOOL finished){
}];
}
- (void)goBack {
if (self.topDistance) {
if (!isnan(self.bottomH)) {
self.topDistance(self.bottomH, true);
}
}
[UIView animateWithDuration:0.5 animations:^{
self.top = self.bottomH;
} completion:^(BOOL finished){
// self.tableView.userInteractionEnabled = NO;
}];
}
#pragma mark - UITableViewDelegate
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.poiInfoListArray.count;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 50;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *identifer = @"identifer";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifer];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifer];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.detailTextLabel.textColor = [UIColor grayColor];
}
cell.textLabel.text = self.poiInfoListArray[indexPath.row].name;
cell.detailTextLabel.text = self.poiInfoListArray[indexPath.row].address;
if (indexPath.row == self.selectNumber) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:NO];
self.selectNumber = indexPath.row;
[tableView reloadData];
FATMapPlace *poiInfo = self.poiInfoListArray[indexPath.row];
if (self.selectItemBlock) {
self.selectItemBlock(poiInfo);
}
}
#pragma mark - UISearchResultsUpdating
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
[self goTop];
self.tempPoiInfoListArray = [[NSMutableArray alloc] initWithArray:self.poiInfoListArray];
[self.poiInfoListArray removeAllObjects];
[self.tableView reloadData];
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
self.selectNumber = -1;
NSString *searchString = self.searchController.searchBar.text;
[self p_searchLocationsWithSearchText:searchString];
self.searchController.active = NO;
[self goBack];
self.searchController.searchBar.text = searchString;
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
[self goBack];
self.poiInfoListArray = [[NSMutableArray alloc] initWithArray:self.tempPoiInfoListArray];
[self.tableView reloadData];
}
- (UISearchController *)searchController {
if (!_searchController) {
_searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
_searchController.searchBar.delegate = self;
_searchController.dimsBackgroundDuringPresentation = NO;
_searchController.hidesNavigationBarDuringPresentation = NO;
_searchController.searchBar.autocapitalizationType = UITextAutocapitalizationTypeNone;
_searchController.searchBar.frame = CGRectMake(0, 0, fatKScreenWidth, 44);
NSString *placeholder = [[FATClient sharedClient] fat_localizedStringForKey:@"Search for location"];
_searchController.searchBar.placeholder = placeholder;
}
return _searchController;
}
@end

View File

@ -0,0 +1,27 @@
//
// FATLocationResultViewController.h
// AppletDemo
//
// Created by Haley on 2020/4/17.
// Copyright © 2020 weidian. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <FinApplet/FinApplet.h>
#import "FATMapPlace.h"
@protocol FATLocationResultDelegate <NSObject>
- (void)selectedLocationWithLocation:(FATMapPlace *)place;
@end
@interface FATLocationResultViewController : FATUIViewController <UISearchResultsUpdating>
@property (nonatomic, assign) MKCoordinateRegion region;
@property (nonatomic, weak) id<FATLocationResultDelegate> delegate;
@property (nonatomic, assign) NSInteger searchBarHeight;
@end

View File

@ -0,0 +1,124 @@
//
// FATLocationResultViewController.m
// AppletDemo
//
// Created by Haley on 2020/4/17.
// Copyright © 2020 weidian. All rights reserved.
//
#import "FATLocationResultViewController.h"
#import "FATExtMapManager.h"
#import "FATExtUtil.h"
@interface FATLocationResultViewController () <UITableViewDataSource, UITableViewDelegate>
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, copy) NSArray<FATMapPlace *> *places;
@property (nonatomic, strong) FATMapPlace *selectedPlace;
@end
@implementation FATLocationResultViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self p_initSubViews];
}
#pragma mark - private method
- (void)p_initSubViews {
self.edgesForExtendedLayout = UIRectEdgeNone;
CGFloat width = self.view.bounds.size.width;
CGFloat height = self.view.bounds.size.height;
self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, self.searchBarHeight, width, height - self.searchBarHeight - 60) style:UITableViewStylePlain];
self.tableView.dataSource = self;
self.tableView.delegate = self;
self.tableView.rowHeight = 60;
[self.view addSubview:self.tableView];
}
- (void)p_searchLocationsWithSearchText:(NSString *)searchText {
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.region = self.region;
request.naturalLanguageQuery = searchText;
MKLocalSearch *localSearch = [[MKLocalSearch alloc] initWithRequest:request];
if([FATExtMapManager shareInstance].googleMapApiKey.length > 1){
[FATExtUtil getNearbyPlacesByCategory:searchText coordinates:self.region.center radius:1000 token:@""
completion:^(NSDictionary * _Nonnull dict) {
self.places = [[FATExtUtil convertPlaceDictToArray:dict] copy];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
}];
}else{[localSearch startWithCompletionHandler:^(MKLocalSearchResponse *_Nullable response, NSError *_Nullable error) {
NSMutableArray *placeArrayM = [NSMutableArray array];
for (MKMapItem *item in response.mapItems) {
if (!item.isCurrentLocation) {
FATMapPlace *place = [[FATMapPlace alloc] init];
place.name = item.placemark.name;
place.address = item.placemark.thoroughfare;
place.location = item.placemark.location;
[placeArrayM addObject:place];
}
}
self.places = [placeArrayM copy];
[self.tableView reloadData];
}];
}
}
#pragma mark - UISearchResultsUpdating
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController {
NSString *searchString = searchController.searchBar.text;
[self p_searchLocationsWithSearchText:searchString];
}
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.places.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *identifer = @"placeCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifer];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifer];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.detailTextLabel.textColor = [UIColor grayColor];
}
FATMapPlace *place = self.places[indexPath.row];
cell.textLabel.text = place.name;
cell.detailTextLabel.text = place.address;
if (place.selected) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
for (FATMapPlace *place in self.places) {
place.selected = NO;
}
FATMapPlace *place = self.places[indexPath.row];
place.selected = YES;
[self.tableView reloadData];
if (self.delegate && [self.delegate respondsToSelector:@selector(selectedLocationWithLocation:)]) {
[self.delegate selectedLocationWithLocation:place];
}
[self dismissViewControllerAnimated:YES completion:nil];
}
@end

View File

@ -0,0 +1,23 @@
//
// FATMapPlace.h
// AppletDemo
//
// Created by Haley on 2020/4/17.
// Copyright © 2020 weidian. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <CoreLocation/CLPlacemark.h>
@interface FATMapPlace : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *address;
//@property (nonatomic, strong) CLPlacemark *placemark;
@property (nonatomic, strong) CLLocation *location;
@property (nonatomic, assign) BOOL selected;
@end

View File

@ -0,0 +1,13 @@
//
// FATMapPlace.m
// AppletDemo
//
// Created by Haley on 2020/4/17.
// Copyright © 2020 weidian. All rights reserved.
//
#import "FATMapPlace.h"
@implementation FATMapPlace
@end

View File

@ -0,0 +1,24 @@
//
// FATMapViewController.h
// AppletDemo
//
// Created by Haley on 2020/4/16.
// Copyright © 2020 weidian. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <FinApplet/FinApplet.h>
typedef void (^SureBlock)(NSDictionary *locationInfo);
@interface FATMapViewController : FATUIViewController
@property (nonatomic, copy) dispatch_block_t cancelBlock;
@property (nonatomic, copy) SureBlock sureBlock;
///
@property (nonatomic, strong) NSString *latitude;
///
@property (nonatomic, strong) NSString *longitude;
@end

View File

@ -0,0 +1,350 @@
//
// FATMapViewController.m
// AppletDemo
//
// Created by Haley on 2020/4/16.
// Copyright © 2020 weidian. All rights reserved.
//
#import "FATMapViewController.h"
#import "FATLocationResultViewController.h"
#import "FATAnnotation.h"
#import "FATExtHelper.h"
#import "FATExtSliderView.h"
#import "FATWGS84ConvertToGCJ02.h"
#import "FATExtLocationManager.h"
#import <MapKit/MapKit.h>
#import "UIView+FATExtSafaFrame.h"
#define fatKScreenWidth ([UIScreen mainScreen].bounds.size.width)
#define fatKScreenHeight ([UIScreen mainScreen].bounds.size.height)
static NSString *kAnnotationId = @"FATAnnotationViewId";
static NSString *kUserAnnotationId = @"FATUserAnnotationViewId";
@interface FATMapViewController () <MKMapViewDelegate, CLLocationManagerDelegate, FATLocationResultDelegate>
@property (nonatomic, strong) MKMapView *mapView;
@property (nonatomic, strong) MKUserLocation *userLocation;
@property (nonatomic, strong) UIButton *returnButton;
@property (nonatomic, strong) UIButton *determineButton;
@property (nonatomic, strong) UIButton *positionButton;
@property (nonatomic, strong) FATExtSliderView *slideView;
@property (nonatomic, strong) FATMapPlace *poiInfo;
@property (nonatomic, strong) MKPointAnnotation *centerAnnotation;
@property (nonatomic, strong) FATExtLocationManager *locationManager;
@end
@implementation FATMapViewController
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES animated:animated];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
// [self.navigationController setNavigationBarHidden:NO animated:animated];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear: animated];
_mapView.showsUserLocation = NO;
_mapView.userTrackingMode = MKUserTrackingModeNone;
[_mapView.layer removeAllAnimations];
[_mapView removeAnnotations:self.mapView.annotations];
[_mapView removeOverlays:self.mapView.overlays];
[_mapView removeFromSuperview];
_mapView.delegate = nil;
_mapView = nil;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.edgesForExtendedLayout = UIRectEdgeNone;
[self p_initSubViews];
[self settingMapCenter];
}
- (void)dealloc {
_mapView.showsUserLocation = NO;
_mapView.userTrackingMode = MKUserTrackingModeNone;
[_mapView.layer removeAllAnimations];
[_mapView removeAnnotations:self.mapView.annotations];
[_mapView removeOverlays:self.mapView.overlays];
[_mapView removeFromSuperview];
_mapView.delegate = nil;
_mapView = nil;
}
- (void)p_initSubViews {
//
BOOL isDark = false;
if (@available(iOS 12.0, *)) {
isDark = (self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark);
}
self.view.backgroundColor = isDark ? UIColor.blackColor : UIColor.whiteColor;
[self.view addSubview:self.mapView];
self.mapView.frame = CGRectMake(0, 0, fatKScreenWidth, fatKScreenHeight - 200);
self.centerAnnotation = [[MKPointAnnotation alloc] init];
self.centerAnnotation.coordinate = self.mapView.centerCoordinate;
[self.mapView addAnnotation:self.centerAnnotation];
CGFloat top = [UIView fat_statusHeight];
self.returnButton = [[UIButton alloc] initWithFrame:CGRectMake(16, top, 57, 32)];
[self.returnButton setImage:[FATExtHelper fat_ext_imageFromBundleWithName:@"map_back_n"] forState:UIControlStateNormal];
[self.returnButton addTarget:self action:@selector(cancelItemClick) forControlEvents:UIControlEventTouchUpInside];
[self.mapView addSubview:self.returnButton];
self.determineButton = [[UIButton alloc] initWithFrame:CGRectMake(self.view.frame.size.width - 16 - 57, top, 57, 32)];
NSString *ok = [[FATClient sharedClient] fat_localizedStringForKey:@"OK"];
[self.determineButton setTitle:ok forState:UIControlStateNormal];
[self.determineButton setTitleColor:[UIColor colorWithRed:255 / 255.0 green:255 / 255.0 blue:255 / 255.0 alpha:1 / 1.0] forState:UIControlStateNormal];
[self.determineButton setBackgroundColor:[UIColor colorWithRed:64 / 255.0 green:158 / 255.0 blue:255 / 255.0 alpha:1 / 1.0]];
[self.determineButton addTarget:self action:@selector(sureItemClick) forControlEvents:UIControlEventTouchUpInside];
self.determineButton.titleLabel.font = [UIFont systemFontOfSize:17];
[self.mapView addSubview:self.determineButton];
self.positionButton = [[UIButton alloc] initWithFrame:CGRectMake(self.view.frame.size.width - 73, fatKScreenHeight - 260, 45, 45)];
if (isDark) {
[self.positionButton setImage:[FATExtHelper fat_ext_imageFromBundleWithName:@"map_location_dn"] forState:UIControlStateNormal];
[self.positionButton setImage:[FATExtHelper fat_ext_imageFromBundleWithName:@"map_location_dp"] forState:UIControlStateHighlighted];
self.mapView.mapType = MKMapTypeStandard;
} else {
[self.positionButton setImage:[FATExtHelper fat_ext_imageFromBundleWithName:@"map_location_ln"] forState:UIControlStateNormal];
[self.positionButton setImage:[FATExtHelper fat_ext_imageFromBundleWithName:@"map_location_lp"] forState:UIControlStateHighlighted];
self.mapView.mapType = MKMapTypeStandard;
}
[self.positionButton addTarget:self action:@selector(locationOnClick) forControlEvents:UIControlEventTouchUpInside];
[self.mapView addSubview:self.positionButton];
__weak typeof(self) weakSelf = self;
self.slideView = [[FATExtSliderView alloc] initWithFrame:CGRectMake(0, fatKScreenHeight - 200, fatKScreenWidth, fatKScreenHeight - 250)];
self.slideView.backgroundColor = isDark ? UIColor.blackColor : UIColor.whiteColor;
self.slideView.tableView.backgroundColor = isDark ? UIColor.blackColor : UIColor.whiteColor;
self.slideView.topH = 300;
self.slideView.selectItemBlock = ^(FATMapPlace *locationInfo) {
CLLocationCoordinate2D centerCoord = {locationInfo.location.coordinate.latitude, locationInfo.location.coordinate.longitude};
weakSelf.poiInfo = locationInfo;
[UIView animateWithDuration:1 animations:^{
weakSelf.centerAnnotation.coordinate = centerCoord;
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(centerCoord, 1000, 1000);
weakSelf.mapView.centerCoordinate = centerCoord;
weakSelf.mapView.region = region;
}];
};
if ([self.latitude isEqualToString:@"nil"] || [self.longitude isEqualToString:@"nil"] || (!self.latitude && !self.longitude)) {
[self startStandardUpdates];
} else {
CLLocationCoordinate2D centerCoord = {[self.latitude doubleValue], [self.longitude doubleValue]};
self.mapView.centerCoordinate = centerCoord;
[self.slideView updateSearchFrameWithColcationCoordinate:self.mapView.centerCoordinate];
}
__block float heights = fatKScreenHeight - 200;
__block float positionButtonY = fatKScreenHeight - 260;
self.slideView.topDistance = ^(float height, BOOL isTopOrBottom) {
if (!isTopOrBottom) {
heights += height;
positionButtonY += height;
} else {
heights = height;
positionButtonY = height;
}
dispatch_async(dispatch_get_main_queue(), ^{
weakSelf.mapView.frame = CGRectMake(0, 0, fatKScreenWidth, heights);
weakSelf.positionButton.frame = CGRectMake(self.view.frame.size.width - 73, positionButtonY > fatKScreenHeight - 260 ? fatKScreenHeight - 260 : positionButtonY, 45, 45);
if (heights + weakSelf.slideView.frame.size.height < fatKScreenHeight) {
weakSelf.mapView.frame = CGRectMake(0, 0, fatKScreenWidth, fatKScreenHeight - weakSelf.slideView.frame.size.height);
weakSelf.positionButton.frame = CGRectMake(self.view.frame.size.width - 73, fatKScreenHeight - 260, 45, 45);
}
});
};
[self.view addSubview:self.slideView];
}
- (void)locationOnClick {
[self startStandardUpdates];
}
- (void)startStandardUpdates {
// if (![FATExtLocationManager locationServicesEnabled]) {
// return;
// }
CLAuthorizationStatus status = [FATExtLocationManager authorizationStatus];
if (status == kCLAuthorizationStatusAuthorizedWhenInUse ||
status == kCLAuthorizationStatusAuthorizedAlways ||
status == kCLAuthorizationStatusNotDetermined) {
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[self.locationManager requestWhenInUseAuthorization];
[self.locationManager startUpdatingLocation];
}
}
- (void)settingMapCenter {
if ([NSString fat_isEmptyWithString:self.latitude] || [NSString fat_isEmptyWithString:self.longitude]) {
return;
}
double LongitudeDelta = [self fat_getLongitudeDelta:14.00];
// double LatitudeDelta = LongitudeDelta * 2;
CLLocationCoordinate2D centerCoord = {[self judgeLatition:[self.latitude doubleValue]], [self judgeLongitude:[self.longitude doubleValue]]};
MKCoordinateRegion region = MKCoordinateRegionMake(centerCoord, MKCoordinateSpanMake(LongitudeDelta, LongitudeDelta));
[self.mapView setRegion:region animated:YES];
}
#pragma mark - click events
- (void)cancelItemClick {
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
if (self.cancelBlock) {
self.cancelBlock();
}
}
- (void)sureItemClick {
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
if (self.poiInfo == nil && self.slideView.poiInfoListArray.count > 0) {
self.poiInfo = self.slideView.poiInfoListArray.firstObject;
}
CLLocationCoordinate2D coordinate = self.poiInfo.location.coordinate;
NSDictionary *locationInfo = @{@"name" : self.poiInfo.name ?: @"",
@"address" : self.poiInfo.address ?: @"",
@"latitude" : @(coordinate.latitude),
@"longitude" : @(coordinate.longitude)};
if (self.sureBlock) {
self.sureBlock(locationInfo);
}
}
#pragma mark - FATLocationResultDelegate
- (void)selectedLocationWithLocation:(FATMapPlace *)place {
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(place.location.coordinate, 1000, 1000);
self.mapView.centerCoordinate = place.location.coordinate;
self.mapView.region = region;
}
#pragma mark - MKMapViewDelegate
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
if (!self.userLocation) {
_userLocation = userLocation;
CLLocationCoordinate2D center = [FATWGS84ConvertToGCJ02ForAMapView transformFromWGSToGCJ:userLocation.location.coordinate];
if (center.latitude > 0 && center.longitude > 0) {
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(center, 1000, 1000);
if ([NSString fat_isEmptyWithString:self.latitude] || [NSString fat_isEmptyWithString:self.longitude]) {
mapView.centerCoordinate = center;
mapView.region = region;
[self.mapView setRegion:region animated:YES];
self.centerAnnotation.coordinate = center;
}
}
[self.slideView updateSearchFrameWithColcationCoordinate:center];
}
}
/**
*
*
* @param manager
* @param locations
*/
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
CLLocation *location = [locations firstObject];
//
CLLocationCoordinate2D theCoordinate = location.coordinate;
//
MKCoordinateRegion theRegion;
theRegion.center = theCoordinate;
CLLocationCoordinate2D coord = [FATWGS84ConvertToGCJ02ForAMapView transformFromWGSToGCJ:theCoordinate];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(coord, 1000, 1000);
[self.mapView setRegion:region animated:YES];
self.centerAnnotation.coordinate = coord;
[self.locationManager stopUpdatingLocation];
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
CLLocationCoordinate2D centerCoordinate = self.mapView.centerCoordinate;
// CLLocationCoordinate2D centerCoordinate = self.centerAnnotation.coordinate;
[self.slideView updateSearchFrameWithColcationCoordinate:centerCoordinate];
}
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
CLLocationCoordinate2D centerCoordinate = mapView.centerCoordinate;
[UIView animateWithDuration:1 animations:^{
self.centerAnnotation.coordinate = centerCoordinate;
}];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MKUserLocation class]]) {
return nil;
}
static NSString *ID = @"anno";
MKPinAnnotationView *annoView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:ID];
if (annoView == nil) {
annoView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:ID];
//
annoView.canShowCallout = YES;
// 绿
}
return annoView;
}
- (double)fat_getLongitudeDelta:(double)scale {
double longitudeDelta = (360 * self.mapView.frame.size.width / 256.0 / pow(2, scale));
return longitudeDelta;
}
//
- (double)judgeLatition:(double)latitude {
if (latitude >= 90) {
latitude = 85.00;
}
if (latitude <= -90) {
latitude = -85.00;
}
return latitude;
}
//
- (double)judgeLongitude:(double)longitude {
if (longitude >= 180) {
longitude = 180.00;
}
if (longitude <= -180) {
longitude = -180.00;
}
return longitude;
}
- (FATExtLocationManager *)locationManager {
if (_locationManager == nil) {
_locationManager = [[FATExtLocationManager alloc] init];
_locationManager.delegate = self;
}
return _locationManager;
}
- (MKMapView *)mapView {
if (!_mapView) {
_mapView = [[MKMapView alloc] init];
_mapView.delegate = self;
_mapView.mapType = MKMapTypeStandard;
_mapView.showsUserLocation = YES;
_mapView.userTrackingMode = MKUserTrackingModeNone;
}
return _mapView;
}
@end

View File

@ -0,0 +1,33 @@
//
// FATOpenLocationViewController.h
// FinAppletExt
//
// Created by 耀 on 2021/12/9.
//
#import <UIKit/UIKit.h>
#import <FinApplet/FinApplet.h>
NS_ASSUME_NONNULL_BEGIN
typedef void (^SureBlock)(NSDictionary *locationInfo);
@interface FATOpenLocationViewController : FATUIViewController
@property (nonatomic, copy) dispatch_block_t cancelBlock;
@property (nonatomic, copy) SureBlock sureBlock;
///
@property (nonatomic, strong) NSString *latitude;
///
@property (nonatomic, strong) NSString *longitude;
@property (nonatomic, strong) NSString *scale;
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *address;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,339 @@
//
// FATOpenLocationViewController.m
// FinAppletExt
//
// Created by 耀 on 2021/12/9.
//
#import "FATOpenLocationViewController.h"
#import "FATExtHelper.h"
#import "MKMarkerView.h"
#import "FATExtLocationManager.h"
#import "FATWGS84ConvertToGCJ02.h"
#import "FATExtUtil.h"
#import <MapKit/MapKit.h>
@interface FATOpenLocationViewController () <MKMapViewDelegate, CLLocationManagerDelegate>
@property (nonatomic, strong) MKMapView *mapView;
@property (nonatomic, strong) UIButton *locationButton;
@property (nonatomic, strong) UIButton *returnButton;
@property (nonatomic, strong) FATExtLocationManager *locationManager;
@property (nonatomic, assign) double Delta;
@end
@implementation FATOpenLocationViewController
- (MKMapView *)mapView {
if (!_mapView) {
_mapView = [[MKMapView alloc] init];
_mapView.delegate = self;
_mapView.mapType = MKMapTypeStandard;
_mapView.showsUserLocation = YES;
_mapView.userTrackingMode = MKUserTrackingModeNone;
}
return _mapView;
}
- (FATExtLocationManager *)locationManager {
if (_locationManager == nil) {
_locationManager = [[FATExtLocationManager alloc] init];
_locationManager.delegate = self;
}
return _locationManager;
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES animated:animated];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self fatCreatUI];
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 20, self.view.frame.size.height)];
view.backgroundColor = UIColor.clearColor;
[self.view addSubview:view];
UIScreenEdgePanGestureRecognizer *edgeGes = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(edgePan:)];
edgeGes.edges = UIRectEdgeLeft;
[view addGestureRecognizer:edgeGes];
}
- (void)dealloc {
// _mapView.showsUserLocation = NO;
// _mapView.userTrackingMode = MKUserTrackingModeNone;
[_mapView.layer removeAllAnimations];
[_mapView removeAnnotations:self.mapView.annotations];
[_mapView removeOverlays:self.mapView.overlays];
[_mapView removeFromSuperview];
_mapView.delegate = nil;
_mapView = nil;
}
- (void)edgePan:(UIPanGestureRecognizer *)recognizer {
[self dismissViewControllerAnimated:YES completion:^{
}];
}
- (void)fatCreatUI {
CGFloat width = self.view.bounds.size.width;
CGFloat height = self.view.bounds.size.height;
CGFloat bottomViewHeight = 100;
self.mapView.frame = CGRectMake(0, 0, width, height);
[self.view addSubview:self.mapView];
CGFloat top = [UIView fat_statusHeight];
self.returnButton = [[UIButton alloc] initWithFrame:CGRectMake(16, top, 50, 50)];
[self.returnButton setImage:[FATExtHelper fat_ext_imageFromBundleWithName:@"map_back_n"] forState:UIControlStateNormal];
[self.returnButton addTarget:self action:@selector(returnOnClick) forControlEvents:UIControlEventTouchUpInside];
[self.mapView addSubview:self.returnButton];
self.locationButton = [[UIButton alloc] initWithFrame:CGRectMake(width - 48 - 16.5, height - bottomViewHeight - 24.5 - 48, 48, 48)];
//
BOOL isDark = false;
if (@available(iOS 13.0, *)) {
isDark = (self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark);
}
if (isDark) {
[self.locationButton setImage:[FATExtHelper fat_ext_imageFromBundleWithName:@"map_location_dn"] forState:UIControlStateNormal];
[self.locationButton setImage:[FATExtHelper fat_ext_imageFromBundleWithName:@"map_location_dp"] forState:UIControlStateHighlighted];
} else {
[self.locationButton setImage:[FATExtHelper fat_ext_imageFromBundleWithName:@"map_location_ln"] forState:UIControlStateNormal];
[self.locationButton setImage:[FATExtHelper fat_ext_imageFromBundleWithName:@"map_location_lp"] forState:UIControlStateHighlighted];
}
[self.locationButton addTarget:self action:@selector(locationOnClick) forControlEvents:UIControlEventTouchUpInside];
[self.mapView addSubview:self.locationButton];
UIView *bgView = [[UIView alloc] initWithFrame:CGRectMake(0, height - bottomViewHeight, width, bottomViewHeight)];
if (@available(iOS 13.0, *)) {
bgView.backgroundColor = UIColor.systemGray6Color;
} else {
// Fallback on earlier versions
}
[self.mapView addSubview:bgView];
UILabel *nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 25.5, width - 70, 31)];
nameLabel.font = [UIFont systemFontOfSize:22];
nameLabel.text = self.name;
nameLabel.textColor = isDark ? [UIColor colorWithRed:208 / 255.0 green:208 / 255.0 blue:208 / 255.0 alpha:1 / 1.0] : [UIColor colorWithRed:34 / 255.0 green:34 / 255.0 blue:34 / 255.0 alpha:1 / 1.0];
[bgView addSubview:nameLabel];
UILabel *addressLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 65.5, width - 70, 16.5)];
addressLabel.font = [UIFont systemFontOfSize:12];
addressLabel.text = self.address;
addressLabel.textColor = UIColor.lightGrayColor;
[bgView addSubview:addressLabel];
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(bgView.frame.size.width - 70, bottomViewHeight / 2 - 25, 50, 50)];
[button setImage:[FATExtHelper fat_ext_imageFromBundleWithName:@"map_navigation_n"] forState:UIControlStateNormal];
[button setImage:[FATExtHelper fat_ext_imageFromBundleWithName:@"map_navigation_p"] forState:UIControlStateHighlighted];
button.layer.cornerRadius = 25;
[button addTarget:self action:@selector(navigationOnClick) forControlEvents:UIControlEventTouchUpInside];
[bgView addSubview:button];
double delta = [self.scale doubleValue];
if (delta < 5) {
delta = 5.00;
}
if (delta > 18) {
delta = 18.00;
}
double LongitudeDelta = [self fat_getLongitudeDelta:delta];
self.Delta = LongitudeDelta;
CLLocationCoordinate2D centerCoord = {[self judgeLatition:[self.latitude doubleValue]], [self judgeLongitude:[self.longitude doubleValue]]};
[self.mapView setRegion:MKCoordinateRegionMake(centerCoord, MKCoordinateSpanMake(LongitudeDelta, LongitudeDelta)) animated:YES];
//
MKMarker *marker = [[MKMarker alloc] init];
marker.coordinate = centerCoord;
[self.mapView addAnnotation:marker];
}
- (void)locationOnClick {
[self startStandardUpdates];
}
- (void)returnOnClick {
[self dismissViewControllerAnimated:YES completion:^{
}];
}
- (void)startStandardUpdates {
if (![FATExtLocationManager locationServicesEnabled]) {
return;
}
CLAuthorizationStatus status = [FATExtLocationManager authorizationStatus];
if (status == kCLAuthorizationStatusAuthorizedWhenInUse ||
status == kCLAuthorizationStatusAuthorizedAlways ||
status == kCLAuthorizationStatusNotDetermined) {
//
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[self.locationManager requestWhenInUseAuthorization];
[self.locationManager startUpdatingLocation];
} else if (status == kCLAuthorizationStatusDenied) {
}
}
- (double)fat_getLongitudeDelta:(double)scale {
double longitudeDelta = (360 * self.mapView.frame.size.width / 256.0 / pow(2, scale));
return longitudeDelta;
}
- (void)navigationOnClick {
[self fat_openMapApp:@{@"latitude" : self.latitude, @"longitude" : self.longitude, @"destination" : self.name}];
}
/**
*
*
* @param manager
* @param locations
*/
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
CLLocation *location = [locations firstObject];
//
CLLocationCoordinate2D coord = [FATWGS84ConvertToGCJ02ForAMapView transformFromWGSToGCJ:location.coordinate];
CLLocation *newLocations = [[CLLocation alloc] initWithLatitude:coord.latitude longitude:coord.longitude];
[self.mapView setRegion:MKCoordinateRegionMake(newLocations.coordinate, MKCoordinateSpanMake(self.Delta, self.Delta)) animated:YES];
[self.locationManager stopUpdatingLocation];
}
- (nullable MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
// If the annotation is the user location, just return nil.Annotation,使
if ([annotation isKindOfClass:[MKUserLocation class]]) {
return nil;
}
if ([annotation isKindOfClass:MKMarker.class]) {
MKMarker *marker = (MKMarker *)annotation;
MKAnnotationView *markerView = [mapView dequeueReusableAnnotationViewWithIdentifier:@"markerView"];
markerView.canShowCallout = YES;
markerView.annotation = marker;
markerView.image = marker.image;
return markerView;
}
return nil;
}
- (void)fat_openMapApp:(NSDictionary *)data {
/*
appurl Scheme
1.URL Scheme
2. baidumap
3. iosamap
4. comgooglemaps
IOS9plisturl scheme.
LSApplicationQueriesSchemes URL Scheme :
*/
// 1.app
NSString *appName = [FATExtUtil getAppName];
NSString *title = [NSString stringWithFormat:@"%@%@", [[FATClient sharedClient] fat_localizedStringForKey:@"Navigate to"], data[@"destination"]];
CLLocationCoordinate2D coordinate = {[data[@"latitude"] doubleValue], [data[@"longitude"] doubleValue]};
//
// 1.UIAlertController
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title
message:nil
preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction *appleAction = [UIAlertAction actionWithTitle:[[FATClient sharedClient] fat_localizedStringForKey:@"Apple Maps"] style:UIAlertActionStyleDefault handler:^(UIAlertAction *_Nonnull action) {
CLLocationCoordinate2D loc = CLLocationCoordinate2DMake(coordinate.latitude, coordinate.longitude);
MKMapItem *currentLocation = [MKMapItem mapItemForCurrentLocation];
MKMapItem *toLocation = [[MKMapItem alloc] initWithPlacemark:[[MKPlacemark alloc] initWithCoordinate:loc addressDictionary:nil]];
toLocation.name = data[@"destination"] ? data[@"destination"] : @"未知地点";
[MKMapItem openMapsWithItems:@[ currentLocation, toLocation ]
launchOptions:@{MKLaunchOptionsDirectionsModeKey : MKLaunchOptionsDirectionsModeDriving,
MKLaunchOptionsShowsTrafficKey : [NSNumber numberWithBool:YES]}];
}];
[appleAction setValue:[self labelColor] forKey:@"titleTextColor"];
UIAlertAction *bdAction = [UIAlertAction actionWithTitle:[[FATClient sharedClient] fat_localizedStringForKey:@"Baidu Maps"] style:UIAlertActionStyleDefault handler:^(UIAlertAction *_Nonnull action) {
NSString *urlString = [[NSString stringWithFormat:@"baidumap://map/direction?origin={{我的位置}}&destination=latlng:%f,%f|name=目的地&mode=driving&coord_type=gcj02", coordinate.latitude, coordinate.longitude] stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlString]];
}];
[bdAction setValue:[self labelColor] forKey:@"titleTextColor"];
UIAlertAction *gdAction = [UIAlertAction actionWithTitle:[[FATClient sharedClient] fat_localizedStringForKey:@"Amap"] style:UIAlertActionStyleDefault handler:^(UIAlertAction *_Nonnull action) {
NSString *urlString = [[NSString stringWithFormat:@"iosamap://path?sourceApplication=%@&backScheme=%@&dlat=%f&dlon=%f&dev=0&t=0&dname=%@", appName, @"iosamap://", coordinate.latitude, coordinate.longitude, data[@"destination"]] stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlString]];
}];
[gdAction setValue:[self labelColor] forKey:@"titleTextColor"];
UIAlertAction *googleAction = [UIAlertAction actionWithTitle:[[FATClient sharedClient] fat_localizedStringForKey:@"Google Maps"] style:UIAlertActionStyleDefault handler:^(UIAlertAction *_Nonnull action) {
NSString *urlString = [[NSString stringWithFormat:@"comgooglemaps://?x-source=%@&x-success=%@&saddr=&daddr=%f,%f&directionsmode=driving", appName, @"comgooglemaps://", coordinate.latitude, coordinate.longitude] stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlString]];
}];
[googleAction setValue:[self labelColor] forKey:@"titleTextColor"];
UIAlertAction *tencentAction = [UIAlertAction actionWithTitle:[[FATClient sharedClient] fat_localizedStringForKey:@"Tencent Maps"] style:UIAlertActionStyleDefault handler:^(UIAlertAction *_Nonnull action) {
NSString *urlString = [[NSString stringWithFormat:@"qqmap://map/routeplan?from=我的位置&type=drive&to=%@&tocoord=%f,%f&coord_type=1&referer={ios.blackfish.XHY}",data[@"destination"],coordinate.latitude,coordinate.longitude] stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlString]];
}];
[tencentAction setValue:[self labelColor] forKey:@"titleTextColor"];
NSString *cancel = [[FATClient sharedClient] fat_localizedStringForKey:@"Cancel"];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:cancel style:UIAlertActionStyleCancel handler:^(UIAlertAction *_Nonnull action){
// [alertController ]
}];
[cancelAction setValue:[self labelColor] forKey:@"titleTextColor"];
// 1.app
[alertController addAction:appleAction];
if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"baidumap://"]]) {
[alertController addAction:bdAction];
}
if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"iosamap://"]]) {
[alertController addAction:gdAction];
}
if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"comgooglemaps://"]]) {
[alertController addAction:googleAction];
}
if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"qqmap://"]]){
[alertController addAction:tencentAction];
}
[alertController addAction:cancelAction];
UIViewController *topVC = [[UIApplication sharedApplication] fat_topViewController];
[topVC presentViewController:alertController animated:YES completion:nil];
}
- (UIColor *)labelColor {
if (@available(iOS 12.0, *)) {
BOOL isDark = (self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark);
return isDark ? [UIColor colorWithRed:208/255.0 green:208/255.0 blue:208/255.0 alpha:1/1.0] : [UIColor colorWithRed:34/255.0 green:34/255.0 blue:34/255.0 alpha:1/1.0];
} else {
return [UIColor colorWithRed:34/255.0 green:34/255.0 blue:34/255.0 alpha:1/1.0];
}
}
//
- (double)judgeLatition:(double)latitude {
if (latitude >= 90) {
latitude = 85.00;
}
if (latitude <= -90) {
latitude = -85.00;
}
return latitude;
}
//
- (double)judgeLongitude:(double)longitude {
if (longitude >= 180) {
longitude = 180.00;
}
if (longitude <= -180) {
longitude = -180.00;
}
return longitude;
}
@end

View File

@ -0,0 +1,66 @@
//
// FATExtRecorder.h
// HLProject
//
// Created by Haley on 2021/12/28.
// Copyright © 2021 Haley. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioToolbox.h>
typedef NS_ENUM(NSUInteger, FATFrameState) {
FATFrameStatePrepareToSend,
FATFrameStateAlreadyWillSend,
FATFrameStateAlreadySent
};
@class FATExtRecorder;
@protocol FATExtRecorderDelegate <NSObject>
- (void)extRecorder:(FATExtRecorder *)recorder
onFrameData:(NSData *)frameData
frameIndex:(NSInteger)frameIndex
isLastFrame:(BOOL)isLastFrame;
- (void)extRecorderDidCompletion:(FATExtRecorder *)recorder;
- (void)extRecorderBeginInterruption:(FATExtRecorder *)recorder;
- (void)extRecorderEndInterruption:(FATExtRecorder *)recorder withOptions:(NSUInteger)flags;
- (void)extRecorder:(FATExtRecorder *)recorder onError:(NSError *)error;
@end
@interface FATExtRecorder : NSObject
@property (nonatomic, assign) BOOL isStarted;
@property (nonatomic, assign) BOOL isRecording;
@property (nonatomic, assign) BOOL isPausing;
@property (nonatomic, strong) NSString *recordFilePath;
@property (nonatomic, weak) id<FATExtRecorderDelegate> delegate;
@property (nonatomic, readonly, copy) NSString *recorderId;
@property (nonatomic, strong) NSMutableArray *frameInfoArray;
@property (nonatomic, assign) FATFrameState frameState;
@property (nonatomic, assign) BOOL waitToSendBuffer;
@property (nonatomic, copy) void(^eventCallBack)(NSInteger eventType,NSString *eventName, NSDictionary *paramDic,NSDictionary *extDic);
- (BOOL)startRecordWithDict:(NSDictionary *)dict appId:(NSString *)appId;
- (BOOL)pauseRecord;
- (BOOL)resumeRecord;
- (BOOL)stopRecord;
@end

View File

@ -0,0 +1,799 @@
//
// FATExtRecorder.m
// HLProject
//
// Created by Haley on 2021/12/28.
// Copyright © 2021 Haley. All rights reserved.
//
#import "FATExtRecorder.h"
#import "FATExtUtil.h"
#import "lame.h"
#import <FinApplet/FinApplet.h>
#define FATDefaultBufferSize 4096 //4096,4096,4096
#define QUEUE_BUFFER_SIZE 3 //
@interface FATExtRecorder ()
{
AudioQueueRef audioQRef; //
AudioStreamBasicDescription inputDescription; //
AudioStreamBasicDescription outputDescription; //
AudioQueueBufferRef audioBuffers[QUEUE_BUFFER_SIZE]; //
AudioConverterRef _encodeConvertRef;
lame_t lame;
FILE *mp3;
int pcm_buffer_size;
uint8_t pcm_buffer[FATDefaultBufferSize*2];
}
@property (nonatomic, assign) AudioFileID recordFileID; //
@property (nonatomic, assign) SInt64 recordPacketNum;
@property (nonatomic, copy) NSString *recorderId;
//
@property (nonatomic, assign) UInt32 mChannelsPerFrame;
//
@property (nonatomic, assign) UInt32 mSampleRate;
//
@property (nonatomic, assign) UInt32 encodeBitRate;
//
@property (nonatomic, assign) int duration;
//
@property (nonatomic, copy) NSString *format;
@property (nonatomic, assign) long long frameSize;
@property (nonatomic, assign) BOOL shouldFrameCallback;
@property (nonatomic, assign) NSInteger currentBufferIndex;
// buffer
@property (nonatomic, strong) NSMutableData *currentFrameData;
@property (nonatomic, assign) long long currentFrameOffset;
@end
@implementation FATExtRecorder
void FATAudioInputCallbackHandler(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer, const AudioTimeStamp *inStartTime, UInt32 inNumPackets, const AudioStreamPacketDescription *inPacketDesc) {
FATExtRecorder *recorder = (__bridge FATExtRecorder *)(inUserData);
[recorder processAudioBuffer:inBuffer inStartTime:inStartTime inNumPackets:inNumPackets inPacketDesc:inPacketDesc audioQueue:inAQ];
}
OSStatus FATAudioConverterComplexInputDataProc(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets, AudioBufferList *ioData, AudioStreamPacketDescription **outDataPacketDescription, void *inUserData) {
FATExtRecorder *recorder = (__bridge FATExtRecorder *)(inUserData);
BOOL result = [recorder handleConverterDataProcWithBufferList:ioData];
if (result) {
return noErr;
}
return -1;
}
#pragma mark - override
- (instancetype)init {
self = [super init];
if (self) {
[self p_addNotifications];
}
return self;
}
- (void)dealloc {
// NSLog(@"FATExtRecorder---dealloc");
[[NSNotificationCenter defaultCenter] removeObserver:self];
AudioQueueDispose(audioQRef, true);
}
- (void)handleInterruption:(NSNotification *)notification {
NSDictionary *info = notification.userInfo;
AVAudioSessionInterruptionType type = [info[AVAudioSessionInterruptionTypeKey] unsignedIntegerValue];
if (type == AVAudioSessionInterruptionTypeBegan) {
if ([self.delegate respondsToSelector:@selector(extRecorderBeginInterruption:)]) {
[self.delegate extRecorderBeginInterruption:self];
}
} else {
AVAudioSessionInterruptionOptions options = [info[AVAudioSessionInterruptionOptionKey] unsignedIntegerValue];
if (options == AVAudioSessionInterruptionOptionShouldResume) {
//Handle Resume
}
if ([self.delegate respondsToSelector:@selector(extRecorderEndInterruption:withOptions:)]) {
[self.delegate extRecorderEndInterruption:self withOptions:options];
}
}
}
- (BOOL)startRecordWithDict:(NSDictionary *)dict appId:(NSString *)appId {
self.currentBufferIndex = 0;
self.currentFrameOffset = 0;
self.currentFrameData = [[NSMutableData alloc] init];
self.frameState = FATFrameStatePrepareToSend;
self.frameInfoArray = [NSMutableArray array];
memset(pcm_buffer, 0, pcm_buffer_size);
pcm_buffer_size = 0;
self.recorderId = appId;
// 1.
//
NSString *audioSource;
if (!audioSource || ![audioSource isKindOfClass:[NSString class]]) {
audioSource = @"auto";
} else {
audioSource = dict[@"audioSource"];
}
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
if ([audioSource isEqualToString:@"buildInMic"]) {
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker error:NULL];
} else if ([audioSource isEqualToString:@"headsetMic"]) {
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionAllowBluetooth error:NULL];
} else {
if (@available(iOS 10.0, *)) {
// 4545
// NSUInteger options = AVAudioSessionCategoryOptionMixWithOthers | AVAudioSessionCategoryOptionAllowBluetooth | AVAudioSessionCategoryOptionAllowAirPlay;
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord mode:AVAudioSessionModeDefault options:45 error:NULL];
} else {
NSUInteger options = AVAudioSessionCategoryOptionMixWithOthers | AVAudioSessionCategoryOptionAllowBluetooth;
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:options error:NULL];
}
}
[audioSession setActive:YES error:NULL];
// 1.1
NSString *format = [self _format:dict];
self.format = format;
AudioFormatID formatID = [self _formatIDWithFormat:format];
inputDescription.mFormatID = formatID;
// 1.2.
NSString *numberOfChannelsString = dict[@"numberOfChannels"];
if (![self _isValidWithNumberOfChannelsString:numberOfChannelsString]) {
if ([self.delegate respondsToSelector:@selector(extRecorder:onError:)]) {
NSError *error = [NSError errorWithDomain:@"FATExtRecorder" code:-1 userInfo:@{NSLocalizedDescriptionKey:@"operateRecorder:fail channel error"}];
[self.delegate extRecorder:self onError:error];
}
return NO;
}
NSNumber *numberOfChannelsNub = [NSNumber numberWithInt:[numberOfChannelsString intValue]];
if (numberOfChannelsString == nil) {
numberOfChannelsNub = @(2);
}
if ([format isEqualToString:@"aac"]) {
// aac
numberOfChannelsNub = @(1);
}
inputDescription.mChannelsPerFrame = [numberOfChannelsNub intValue];
self.mChannelsPerFrame = [numberOfChannelsNub intValue];
// 1.3.
NSString *sampleRateString = dict[@"sampleRate"];
NSNumber *sampleRateNub;
if (sampleRateString == nil || ![sampleRateString isKindOfClass:[NSString class]]) {
sampleRateNub = @(8000);
} else {
sampleRateNub = [NSNumber numberWithInt:[sampleRateString intValue]];
}
inputDescription.mSampleRate = [sampleRateNub floatValue];
self.mSampleRate = inputDescription.mSampleRate;
// 1.4.
NSString *encodeBitRateString = dict[@"encodeBitRate"];
NSNumber *encodeBitRateNub;
if (encodeBitRateString == nil || ![encodeBitRateString isKindOfClass:[NSString class]]) {
encodeBitRateNub = @(48000);
} else {
encodeBitRateNub = [NSNumber numberWithInt:[encodeBitRateString intValue]];
}
self.encodeBitRate = [encodeBitRateNub floatValue];
NSString *durationString = dict[@"duration"];
NSNumber *durationNub;
if (durationString == nil || ![durationString isKindOfClass:[NSString class]]) {
durationNub = @(60000);
} else {
durationNub = [NSNumber numberWithInt:[durationString intValue]];
}
if ([durationNub intValue] <= 0) {
durationNub = @(60000);
}
if ([durationNub intValue] > 600000) {
durationNub = @(600000);
}
self.duration = [durationNub intValue];
//
inputDescription.mFormatID = kAudioFormatLinearPCM;
inputDescription.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
inputDescription.mBitsPerChannel = 16;
//
inputDescription.mBytesPerFrame = (inputDescription.mBitsPerChannel / 8) * inputDescription.mChannelsPerFrame;
//
inputDescription.mBytesPerPacket = inputDescription.mBytesPerFrame;
//
inputDescription.mFramesPerPacket = 1;
// 2.
NSString *fileName = [self _fileNameWithFormat:format];
NSString *filePath = [[FATExtUtil tmpDirWithAppletId:appId] stringByAppendingPathComponent:fileName];
self.recordFilePath = filePath;
if ([format isEqualToString:@"mp3"]) {
mp3 = fopen([self.recordFilePath cStringUsingEncoding:1], "wb");
lame = lame_init();
//
lame_set_in_samplerate(lame, inputDescription.mSampleRate);
//
lame_set_num_channels(lame, inputDescription.mChannelsPerFrame);
lame_set_VBR(lame, vbr_default);
lame_init_params(lame);
} else if ([format isEqualToString:@"aac"]) {
NSError *error;
if (![self _createConverter:&error]) {
if ([self.delegate respondsToSelector:@selector(extRecorder:onError:)]) {
[self.delegate extRecorder:self onError:error];
}
return NO;
}
[self copyEncoderCookieToFile];
}
OSStatus status = AudioQueueNewInput(&inputDescription, FATAudioInputCallbackHandler, (__bridge void *)(self), NULL, NULL, 0, &audioQRef);
if ( status != kAudioSessionNoError ) {
if ([self.delegate respondsToSelector:@selector(extRecorder:onError:)]) {
NSError *error = [NSError errorWithDomain:@"FATExtRecorder" code:-1 userInfo:@{NSLocalizedDescriptionKey:@"AudioQueueNewInput fail"}];
[self.delegate extRecorder:self onError:error];
}
return NO;
}
// 1.5 frameSize
NSString *frameSizeString = dict[@"frameSize"];
if (![frameSizeString isKindOfClass:[NSString class]]) {
frameSizeString = nil;
}
//inbuffercallBackframeSize
long long bufferByteSize = FATDefaultBufferSize;
if ([frameSizeString floatValue]> 0.00 && [self _canCallbackFormat:format]) {
self.shouldFrameCallback = YES;
self.frameSize = (long long)[frameSizeString floatValue] * 1024;
}
if ([format isEqualToString:@"aac"]) {
// aac10242
bufferByteSize = 1024 * 2 * self.mChannelsPerFrame;
}
for (int i = 0; i < QUEUE_BUFFER_SIZE; i++){
AudioQueueAllocateBuffer(audioQRef, bufferByteSize, &audioBuffers[i]);
AudioQueueEnqueueBuffer(audioQRef, audioBuffers[i], 0, NULL);
}
CFURLRef url = CFURLCreateWithString(kCFAllocatorDefault, (CFStringRef)self.recordFilePath, NULL);
//
if ([format isEqualToString:@"aac"]) {
AudioFileCreateWithURL(url, kAudioFileCAFType, &outputDescription, kAudioFileFlags_EraseFile, &_recordFileID);
} else {
AudioFileCreateWithURL(url, kAudioFileCAFType, &inputDescription, kAudioFileFlags_EraseFile, &_recordFileID);
}
CFRelease(url);
self.recordPacketNum = 0;
status = AudioQueueStart(audioQRef, NULL);
if (status != kAudioSessionNoError) {
if ([self.delegate respondsToSelector:@selector(extRecorder:onError:)]) {
NSError *error = [NSError errorWithDomain:@"FATExtRecorder" code:-1 userInfo:@{NSLocalizedDescriptionKey:@"AudioQueueStart fail"}];
[self.delegate extRecorder:self onError:error];
}
AudioQueueStop(audioQRef, NULL);
return NO;
}
self.isStarted = YES;
self.isRecording = YES;
return YES;
}
- (BOOL)pauseRecord {
OSStatus status = AudioQueuePause(audioQRef);
if (status != kAudioSessionNoError) {
if ([self.delegate respondsToSelector:@selector(extRecorder:onError:)]) {
NSError *error = [NSError errorWithDomain:@"FATExtRecorder" code:-1 userInfo:@{NSLocalizedDescriptionKey:@"pause fail"}];
[self.delegate extRecorder:self onError:error];
}
return NO;
}
self.isRecording = NO;
self.isPausing = YES;
return YES;
}
- (BOOL)resumeRecord {
OSStatus status = AudioQueueStart(audioQRef, NULL);
if (status != kAudioSessionNoError) {
if ([self.delegate respondsToSelector:@selector(extRecorder:onError:)]) {
NSError *error = [NSError errorWithDomain:@"FATExtRecorder" code:-1 userInfo:@{NSLocalizedDescriptionKey:@"resume fail"}];
[self.delegate extRecorder:self onError:error];
}
return NO;
}
self.isRecording = YES;
self.isPausing = NO;
return YES;
}
- (BOOL)stopRecord {
if (self.isRecording) {
self.isRecording = NO;
}
self.isStarted = NO;
//
AudioQueueStop(audioQRef, true);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
AudioFileClose(_recordFileID);
[self didEndRecord];
});
return YES;
}
#pragma mark - private
- (void)processAudioBuffer:(AudioQueueBufferRef)inBuffer inStartTime:(AudioTimeStamp *)inStartTime inNumPackets:(UInt32)inNumPackets inPacketDesc:(AudioStreamPacketDescription *)inPacketDesc audioQueue:(AudioQueueRef)audioQueueRef
{
const int audioSize = inBuffer->mAudioDataByteSize;
// NSLog(@"processAudioBuffer---inNumPackets:%d, size:%d", inNumPackets, audioSize);
if (inNumPackets > 0) {
if ([self.format isEqualToString:@"mp3"]) {
unsigned char mp3_buffer[audioSize];
// 1char *charshort *short2
// 2packet 1 ; 2 Bytes; 4 Bytes
// nsamples = inBuffer->mAudioDataByteSize / 2;
// nsamples = inBuffer->mAudioDataByteSize / 4;
// nsamples inNumPackets;
int nsamples = inNumPackets;
/**
使lame_encode_buffer_interleaved
lame_encode_buffer //16
lame_encode_buffer_interleaved //
lame_encode_buffer_float //32
*/
int recvLen;
if (self.mChannelsPerFrame == 1) {
//
recvLen = lame_encode_buffer(lame, inBuffer->mAudioData, NULL, nsamples, mp3_buffer, audioSize);
} else {
recvLen = lame_encode_buffer_interleaved(lame, inBuffer->mAudioData, nsamples, mp3_buffer, audioSize);
}
//
fwrite(mp3_buffer, recvLen, 1, mp3);
if (self.shouldFrameCallback) {
[self.currentFrameData appendBytes:mp3_buffer length:recvLen];
}
// NSLog(@"%d", recvLen);
} else if ([self.format isEqualToString:@"pcm"]) {
// MP3
void *bufferData = inBuffer->mAudioData;
UInt32 buffersize = inBuffer->mAudioDataByteSize;
if (self.shouldFrameCallback) {
[self.currentFrameData appendBytes:bufferData length:buffersize];
}
AudioFileWritePackets(self.recordFileID, FALSE, audioSize, inPacketDesc, self.recordPacketNum, &inNumPackets, inBuffer->mAudioData);
self.recordPacketNum += inNumPackets;
} else if ([self.format isEqualToString:@"aac"]) {
memcpy(pcm_buffer + pcm_buffer_size, inBuffer->mAudioData, inBuffer->mAudioDataByteSize);
pcm_buffer_size = pcm_buffer_size + inBuffer->mAudioDataByteSize;
long long willEncodePCMBufferSize = 1024 * 2 * self.mChannelsPerFrame;
if (pcm_buffer_size >= willEncodePCMBufferSize) {
AudioBufferList *bufferList = [self convertedAACBufferListWith:inBuffer];
memcpy(pcm_buffer, pcm_buffer + willEncodePCMBufferSize, pcm_buffer_size - willEncodePCMBufferSize);
pcm_buffer_size = pcm_buffer_size - willEncodePCMBufferSize;
void *bufferData = inBuffer->mAudioData;
UInt32 buffersize = inBuffer->mAudioDataByteSize;
if (self.shouldFrameCallback) {
[self.currentFrameData appendBytes:bufferData length:buffersize];
}
// free memory
if (bufferList) {
free(bufferList->mBuffers[0].mData);
free(bufferList);
}
}
} else if ([self.format isEqualToString:@"wav"]) {
// wav
void *bufferData = inBuffer->mAudioData;
UInt32 buffersize = inBuffer->mAudioDataByteSize;
AudioFileWritePackets(self.recordFileID, FALSE, audioSize, inPacketDesc, self.recordPacketNum, &inNumPackets, inBuffer->mAudioData);
self.recordPacketNum += inNumPackets;
}
if (self.shouldFrameCallback) {
if ([self.format isEqualToString:@"pcm"]) {
long long fileSize = [self _getFileSize:self.recordFilePath];
long long currentFrameSize;
if (self.currentBufferIndex == 0) {
currentFrameSize = fileSize - FATDefaultBufferSize;
self.currentFrameOffset = FATDefaultBufferSize;
} else {
currentFrameSize = fileSize - self.currentFrameOffset;
}
if (fileSize > self.frameSize) {
if ([self.delegate respondsToSelector:@selector(extRecorder:onFrameData:frameIndex:isLastFrame:)]) {
[self.delegate extRecorder:self onFrameData:self.currentFrameData frameIndex:self.currentBufferIndex isLastFrame:NO];
}
self.currentFrameData = [[NSMutableData alloc] init];
self.currentBufferIndex++;
}
} else if ([self.format isEqualToString:@"mp3"]) {
long long fileSize = [self _getFileSize:self.recordFilePath];
long long currentFrameSize;
if (self.currentBufferIndex == 0) {
currentFrameSize = fileSize - FATDefaultBufferSize;
self.currentFrameOffset = FATDefaultBufferSize;
} else {
currentFrameSize = fileSize - self.currentFrameOffset;
}
if (currentFrameSize > self.frameSize) {
//
NSString *frameFilePath = [self.recordFilePath stringByDeletingPathExtension];
frameFilePath = [frameFilePath stringByAppendingFormat:@"_%d", self.currentBufferIndex];
frameFilePath = [frameFilePath stringByAppendingPathExtension:self.recordFilePath.pathExtension];
BOOL result = [self.currentFrameData writeToFile:frameFilePath atomically:YES];
// NSLog(@"写入文件:%@, 结果:%d",frameFilePath.lastPathComponent, result);
if ([self.delegate respondsToSelector:@selector(extRecorder:onFrameData:frameIndex:isLastFrame:)]) {
[self.delegate extRecorder:self onFrameData:self.currentFrameData frameIndex:self.currentBufferIndex isLastFrame:NO];
}
self.currentFrameData = [[NSMutableData alloc] init];
self.currentFrameOffset += currentFrameSize;
self.currentBufferIndex++;
}
} else if ([self.format isEqualToString:@"aac"]) {
long long fileSize = [self _getFileSize:self.recordFilePath];
// NSLog(@"fileSize:%lld", fileSize);
long long currentFrameSize;
if (self.currentBufferIndex == 0) {
currentFrameSize = fileSize - FATDefaultBufferSize;
self.currentFrameOffset = FATDefaultBufferSize;
} else {
currentFrameSize = fileSize - self.currentFrameOffset;
}
if (currentFrameSize > self.frameSize) {
//
// NSLog(@"currentFrameSize:%d", currentFrameSize);
NSString *frameFilePath = [self.recordFilePath stringByDeletingPathExtension];
frameFilePath = [frameFilePath stringByAppendingFormat:@"_%d", self.currentBufferIndex];
frameFilePath = [frameFilePath stringByAppendingPathExtension:self.recordFilePath.pathExtension];
BOOL result = [self.currentFrameData writeToFile:frameFilePath atomically:YES];
// NSLog(@"写入文件:%@, 结果:%d",frameFilePath.lastPathComponent, result);
if ([self.delegate respondsToSelector:@selector(extRecorder:onFrameData:frameIndex:isLastFrame:)]) {
[self.delegate extRecorder:self onFrameData:self.currentFrameData frameIndex:self.currentBufferIndex isLastFrame:NO];
}
self.currentFrameData = [[NSMutableData alloc] init];
self.currentFrameOffset += currentFrameSize;
self.currentBufferIndex++;
}
}
}
}
NSTimeInterval recordDuration = inStartTime->mSampleTime / self.mSampleRate * 1000.0;
if (recordDuration >= self.duration) {
if (self.isRecording) {
[self stopRecord];
}
return;
}
if (self.isRecording || self.isPausing) {
// 便使
AudioQueueEnqueueBuffer(audioQueueRef, inBuffer, 0, NULL);
}
}
- (BOOL)handleConverterDataProcWithBufferList:(AudioBufferList *)bufferList
{
if ([self.format isEqualToString:@"aac"]) {
bufferList->mBuffers[0].mData = pcm_buffer;
bufferList->mBuffers[0].mNumberChannels = self.mChannelsPerFrame;
bufferList->mBuffers[0].mDataByteSize = 1024 * 2 * self.mChannelsPerFrame;
return YES;
}
return NO;
}
- (void)didEndRecord {
if ([self.format isEqualToString:@"mp3"]) {
// VBR ,
lame_mp3_tags_fid(lame, mp3);
lame_close(lame);
fclose(mp3);
}
if (self.currentFrameData.length > 0) {
NSString *frameFilePath = [self.recordFilePath stringByDeletingPathExtension];
frameFilePath = [frameFilePath stringByAppendingFormat:@"_%d", self.currentBufferIndex];
frameFilePath = [frameFilePath stringByAppendingPathExtension:self.recordFilePath.pathExtension];
BOOL result = [self.currentFrameData writeToFile:frameFilePath atomically:YES];
// NSLog(@"Last写入文件:%@, 结果:%d",frameFilePath.lastPathComponent, result);
if ([self.delegate respondsToSelector:@selector(extRecorder:onFrameData:frameIndex:isLastFrame:)]) {
[self.delegate extRecorder:self onFrameData:self.currentFrameData frameIndex:self.currentBufferIndex isLastFrame:YES];
}
self.currentFrameData = nil;
self.currentFrameOffset = 0;
self.currentBufferIndex = 0;
}
if ([self.delegate respondsToSelector:@selector(extRecorderDidCompletion:)]) {
[self.delegate extRecorderDidCompletion:self];
}
// ()
UIViewController *vc = [[UIApplication sharedApplication] fat_topViewController];
UINavigationController<FATCapsuleViewProtocol> *nav = (UINavigationController<FATCapsuleViewProtocol> *)vc.navigationController;
if ([nav respondsToSelector:@selector(controlCapsuleStateButton:state:animate:)]) {
[nav controlCapsuleStateButton:YES state:FATCapsuleButtonStateMicroPhone animate:NO];
}
}
- (void)p_addNotifications {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleInterruption:) name:AVAudioSessionInterruptionNotification object:nil];
}
#pragma mark - tool method
- (NSString *)_format:(NSDictionary *)data {
NSString *format = data[@"format"];
if (!format || ![format isKindOfClass:[NSString class]]) {
format = @"aac";
}
format = [format lowercaseString];
NSArray *validFormats = @[@"mp3", @"aac", @"wav", @"pcm"];
if (![validFormats containsObject:format]) {
return @"aac";
}
return format;
}
- (AudioFormatID)_formatIDWithFormat:(NSString *)format {
return kAudioFormatLinearPCM;
}
- (BOOL)_isValidWithNumberOfChannelsString:(NSString *)numberOfChannelsString {
if (!numberOfChannelsString) {
return YES;
}
if (![numberOfChannelsString isKindOfClass:[NSString class]]) {
return NO;
}
if ([numberOfChannelsString isEqualToString:@"1"] || [numberOfChannelsString isEqualToString:@"2"]) {
return YES;
}
return NO;
}
- (NSString *)_fileNameWithFormat:(NSString *)format {
NSString *currentDt = [NSString stringWithFormat:@"%f", [[NSDate date] timeIntervalSince1970]];
NSData *data = [currentDt dataUsingEncoding:NSUTF8StringEncoding];
NSString *nameMD5 = [[FATExtUtil fat_md5WithBytes:(char *)[data bytes] length:data.length] lowercaseString];
NSString *extensionName = [self _extensionNameWithFormat:format];
NSString *fileName = [NSString stringWithFormat:@"tmp_%@%@", nameMD5, extensionName];
return fileName;
}
- (NSString *)_extensionNameWithFormat:(NSString *)format {
// if ([format isEqualToString:@"aac"]) {
// return @".m4a";
// }
if ([format isEqualToString:@"pcm"]) {
return @".caf";
}
NSString *ext = [NSString stringWithFormat:@".%@", format];
return ext;
}
- (BOOL)_canCallbackFormat:(NSString *)format
{
if ([format isEqualToString:@"mp3"]) {
return YES;
}
if ([format isEqualToString:@"pcm"]) {
return YES;
}
if ([format isEqualToString:@"aac"]) {
return YES;
}
return NO;
}
- (long long)_getFileSize:(NSString *)path
{
NSFileManager *filemanager = [NSFileManager defaultManager];
if (![filemanager fileExistsAtPath:path]) {
return 0;
}
NSDictionary *attributes = [filemanager attributesOfItemAtPath:path error:nil];
NSNumber *theFileSize = [attributes objectForKey:NSFileSize];
return [theFileSize longLongValue];
}
- (BOOL)_createConverter:(NSError **)aError {
// encodeConverterComplexInputDataProc
AudioStreamBasicDescription sourceDes = inputDescription; //
AudioStreamBasicDescription targetDes; //
//
memset(&targetDes, 0, sizeof(targetDes));
targetDes.mFormatID = kAudioFormatMPEG4AAC;
targetDes.mSampleRate = inputDescription.mSampleRate ;
targetDes.mChannelsPerFrame = inputDescription.mChannelsPerFrame;
targetDes.mFramesPerPacket = 1024; // AACtargetDes.mFramesPerPacket1024AAC1024inNumPackets
OSStatus status = 0;
UInt32 targetSize = sizeof(targetDes);
status = AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, 0, NULL, &targetSize, &targetDes);
memset(&outputDescription, 0, sizeof(outputDescription));
memcpy(&outputDescription, &targetDes, targetSize);
//
AudioClassDescription audioClassDes;
status = AudioFormatGetPropertyInfo(kAudioFormatProperty_Encoders,
sizeof(targetDes.mFormatID),
&targetDes.mFormatID,
&targetSize);
UInt32 numEncoders = targetSize/sizeof(AudioClassDescription);
AudioClassDescription audioClassArr[numEncoders];
AudioFormatGetProperty(kAudioFormatProperty_Encoders,
sizeof(targetDes.mFormatID),
&targetDes.mFormatID,
&targetSize,
audioClassArr);
for (int i = 0; i < numEncoders; i++) {
if (audioClassArr[i].mSubType == kAudioFormatMPEG4AAC && audioClassArr[i].mManufacturer == kAppleSoftwareAudioCodecManufacturer) {
memcpy(&audioClassDes, &audioClassArr[i], sizeof(AudioClassDescription));
break;
}
}
status = AudioConverterNewSpecific(&sourceDes, &targetDes, 1, &audioClassDes, &_encodeConvertRef);
if (status != noErr) {
*aError = [NSError errorWithDomain:@"FATExtRecorder" code:-1 userInfo:@{NSLocalizedDescriptionKey:@"create converter fail"}];
// NSLog(@"Error : New convertRef failed");
return NO;
}
targetSize = sizeof(sourceDes);
status = AudioConverterGetProperty(_encodeConvertRef, kAudioConverterCurrentInputStreamDescription, &targetSize, &sourceDes);
targetSize = sizeof(targetDes);
status = AudioConverterGetProperty(_encodeConvertRef, kAudioConverterCurrentOutputStreamDescription, &targetSize, &targetDes);
//
UInt32 bitRate = self.encodeBitRate;
targetSize = sizeof(bitRate);
status = AudioConverterSetProperty(_encodeConvertRef,
kAudioConverterEncodeBitRate,
targetSize, &bitRate);
if (status != noErr) {
*aError = [NSError errorWithDomain:@"FATExtRecorder" code:-1 userInfo:@{NSLocalizedDescriptionKey:@"encodeBitRate not applicable"}];
// NSLog(@"Error : set encodeBitRate failed");
return NO;
}
return YES;
}
- (void)copyEncoderCookieToFile {
UInt32 cookieSize = 0;
OSStatus status = AudioConverterGetPropertyInfo(_encodeConvertRef, kAudioConverterCompressionMagicCookie, &cookieSize, NULL);
if (status != noErr || cookieSize == 0) {
return;
}
char *cookie = (char *)malloc(cookieSize * sizeof(char));
status = AudioConverterGetProperty(_encodeConvertRef, kAudioConverterCompressionMagicCookie, &cookieSize, cookie);
if (status == noErr) {
status = AudioFileSetProperty(_recordFileID, kAudioFilePropertyMagicCookieData, cookieSize, cookie);
if (status == noErr) {
UInt32 willEatTheCookie = false;
status = AudioFileGetPropertyInfo(_recordFileID, kAudioFilePropertyMagicCookieData, NULL, &willEatTheCookie);
printf("Writing magic cookie to destination file: %u\n cookie:%d \n", (unsigned int)cookieSize, willEatTheCookie);
} else {
printf("Even though some formats have cookies, some files don't take them and that's OK\n");
}
} else {
printf("Could not Get kAudioConverterCompressionMagicCookie from Audio Converter!\n");
}
free(cookie);
}
- (AudioBufferList *)convertedAACBufferListWith:(AudioQueueBufferRef)inBuffer
{
UInt32 maxPacketSize = 0;
UInt32 size = sizeof(maxPacketSize);
OSStatus status;
status = AudioConverterGetProperty(_encodeConvertRef,
kAudioConverterPropertyMaximumOutputPacketSize,
&size,
&maxPacketSize);
AudioBufferList *bufferList = (AudioBufferList *)malloc(sizeof(AudioBufferList));
bufferList->mNumberBuffers = 1;
bufferList->mBuffers[0].mNumberChannels = self.mChannelsPerFrame;
bufferList->mBuffers[0].mData = malloc(maxPacketSize);
bufferList->mBuffers[0].mDataByteSize = 1024 * 2 * self.mChannelsPerFrame;
UInt32 inNumPackets = 1;
AudioStreamPacketDescription outputPacketDescriptions;
status = AudioConverterFillComplexBuffer(_encodeConvertRef,
FATAudioConverterComplexInputDataProc,
(__bridge void * _Nullable)(self),
&inNumPackets,
bufferList,
&outputPacketDescriptions);
if (status != noErr) {
free(bufferList->mBuffers[0].mData);
free(bufferList);
return nil;
}
status = AudioFileWritePackets(self.recordFileID,
FALSE,
bufferList->mBuffers[0].mDataByteSize,
&outputPacketDescriptions,
self.recordPacketNum,
&inNumPackets,
bufferList->mBuffers[0].mData);
if (status == noErr) {
self.recordPacketNum += inNumPackets; //
} else {
// NSLog(@"数据写入失败");
}
return bufferList;
}
@end

View File

@ -0,0 +1,105 @@
//
// FATExtBaseApi.h
// FinAppletExtension
//
// Created by Haley on 2020/8/11.
// Copyright © 2020 finogeeks. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <FinApplet/FinApplet.h>
@class FATAppletInfo;
@protocol FATApiHanderContextDelegate <NSObject>
//
- (UIViewController *)getCurrentViewController;
//id
- (NSString *)getCurrentPageId;
/// APIservicepage
/// eventName
/// eventType 0: service(callSubscribeHandlerWithEvent) 1:page(callSubscribeHandlerWithEvent) int便
/// paramDic
/// extDic 便 webId servicejsContextKeyjsContextValueserviceJSContext
- (void)sendResultEvent:(NSInteger)eventType eventName:(NSString *)eventName eventParams:(NSDictionary *)param extParams:(NSDictionary *)extDic;
@optional
- (NSString *)insertChildView:(UIView *)childView viewId:(NSString *)viewId parentViewId:(NSString *)parentViewId isFixed:(BOOL)isFixed isHidden:(BOOL)isHidden;
//hideNO使
/// @param childView
/// @param viewId id
/// @param parentViewId idWkScrollViewidcid
/// @param isFixed NOYESNOYES
- (void)updateChildViewHideProperty:(UIView *)childView viewId:(NSString *)viewId parentViewId:(NSString *)parentViewId isFixed:(BOOL)isFixed isHidden:(BOOL)isHidden complete:(void(^)(BOOL result))complete;
- (UIView *)getChildViewById:(NSString *)viewId;
- (BOOL)removeChildView:(NSString *)viewId;
@end
@protocol FATApiProtocol <NSObject>
@required
@property (nonatomic, strong) FATAppletInfo *appletInfo;
/**
api
*/
@property (nonatomic, readonly, copy) NSString *command;
/**
*/
@property (nonatomic, readonly, copy) NSDictionary<NSString *, id> *param;
@property (nonatomic, weak) id<FATApiHanderContextDelegate> context;
/**
API,
@param success
@param failure
@param cancel
*/
- (void)setupApiWithSuccess:(void (^)(NSDictionary<NSString *, id> *successResult))success
failure:(void (^)(NSDictionary *failResult))failure
cancel:(void (^)(NSDictionary *cancelResult))cancel;
@optional
/**
api
*/
- (NSString *)setupSyncApi;
@end
@interface FATExtBaseApi : NSObject<FATApiProtocol>
@property (nonatomic, copy, readonly) NSDictionary *param;
@property (nonatomic, strong) FATAppletInfo *appletInfo;
/**
api
*/
@property (nonatomic, readonly, copy) NSString *command;
@property (nonatomic, weak) id<FATApiHanderContextDelegate> context;
//+ (FATExtBaseApi *)apiWithCommand:(NSString *)command param:(NSDictionary *)param;
//- (void)setupApiWithCallback:(FATExtensionApiCallback)callback;
//APIsdkAPIAPI使sdkAPI
+ (id<FATApiProtocol>)fat_apiWithApiClass:(NSString *)apiClassName params:(NSDictionary *)params;
@end

View File

@ -0,0 +1,180 @@
//
// FATExtBaseApi.m
// FinAppletExtension
//
// Created by Haley on 2020/8/11.
// Copyright © 2020 finogeeks. All rights reserved.
//
#import "FATExtBaseApi.h"
#import <objc/runtime.h>
@implementation FATExtBaseApi
- (void)setupApiWithSuccess:(void (^)(NSDictionary<NSString *, id> *successResult))success
failure:(void (^)(NSDictionary *failResult))failure
cancel:(void (^)(NSDictionary *cancelResult))cancel {
//
if (cancel) {
cancel(nil);
}
if (success) {
success(@{});
}
if (failure) {
failure(nil);
}
}
/**
api
*/
- (NSString *)setupSyncApi {
return nil;
}
+ (id<FATApiProtocol>)fat_apiWithApiClass:(NSString *)apiClassName params:(NSDictionary *)params {
if (!apiClassName) {
return nil;
}
Class apiClass = NSClassFromString(apiClassName);
if (!apiClass) {
return nil;
}
id apiObj = [[apiClass alloc]init];
if (![apiObj conformsToProtocol:@protocol(FATApiProtocol)]) {
return nil;
}
id<FATApiProtocol> api = (id<FATApiProtocol>)apiObj;
NSString *apiName = @"";
//
NSArray *apiNameArray = [apiClassName componentsSeparatedByString:@"_"];
if (apiNameArray && apiNameArray.count > 1) {
apiName = apiNameArray[1];
}
[self setAPiObjectProperty:api command:apiName params:params];
return api;
}
+ (void)setAPiObjectProperty:(id<FATApiProtocol>) api command:(NSString *)command params:(NSDictionary *)param {
if (![api isKindOfClass:NSObject.class]) {
return;
}
NSObject *apiObj = (NSObject *)api;
[apiObj setValue:command forKey:@"command"];
[apiObj setValue:param forKey:@"param"];
//postMessageparamsNSString
if ([param isKindOfClass:NSDictionary.class]) {
for (NSString *datakey in param.allKeys) {
NSString *propertyKey = datakey;
@autoreleasepool {
objc_property_t property = class_getProperty([apiObj class], [propertyKey UTF8String]);
if (!property) {
continue;
}
id value = [param objectForKey:datakey];
id safetyValue = [self parseFromKeyValue:value];
if (!safetyValue) continue;
NSString *propertyType = [NSString stringWithUTF8String:property_copyAttributeValue(property, "T")];
propertyType = [propertyType stringByReplacingOccurrencesOfString:@"@" withString:@""];
propertyType = [propertyType stringByReplacingOccurrencesOfString:@"\\" withString:@""];
propertyType = [propertyType stringByReplacingOccurrencesOfString:@"\"" withString:@""];
//NSLog(@"propertyType:%@,value是%@", propertyType,value);
//
if (
[propertyType isEqualToString:@"NSString"] ||
[propertyType isEqualToString:@"NSArray"] ||
[propertyType isEqualToString:@"NSDictionary"]) {
if (![safetyValue isKindOfClass:NSClassFromString(propertyType)]) {
continue;
}
}
//NSNumberstring
//
[apiObj setValue:safetyValue forKey:propertyKey];
}
}
}
}
//+ (id)parseFromKeyValue:(id)value {
// //
// if ([value isKindOfClass:[NSNull class]]) {
// return nil;
// }
//
// if ([value isKindOfClass:[NSNumber class]]) { //
// value = [NSString stringWithFormat:@"%@", value];
// }
//
// return value;
//}
//// -
+ (id)parseFromKeyValue:(id)value {
//
if ([value isKindOfClass:[NSNull class]]) {
return nil;
}
if ([value isKindOfClass:[NSNumber class]]) { //
value = [NSString stringWithFormat:@"%@", value];
} else if ([value isKindOfClass:[NSArray class]]) { //
value = [self parseFromArray:value];
} else if ([value isKindOfClass:[NSDictionary class]]) { //
value = [self parseFromDictionary:value];
}
return value;
}
// -
+ (NSDictionary *)parseFromDictionary:(NSDictionary *)container {
if ([container isKindOfClass:[NSDictionary class]]) {
NSMutableDictionary *result = [NSMutableDictionary new];
for (id key in container.allKeys) {
@autoreleasepool {
id value = container[key];
id safetyValue = [self parseFromKeyValue:value];
if (!safetyValue) {
safetyValue = @"";
}
[result setObject:safetyValue forKey:key];
}
}
return result;
}
return container;
}
// -
+ (NSArray *)parseFromArray:(NSArray *)container {
if ([container isKindOfClass:[NSArray class]]) {
NSMutableArray *result = [NSMutableArray new];
for (int i = 0; i < container.count; i++) {
@autoreleasepool {
id value = container[i];
id safetyValue = [self parseFromKeyValue:value];
if (!safetyValue) {
safetyValue = @"";
}
[result addObject:safetyValue];
}
}
return result;
}
return container;
}
@end

View File

@ -0,0 +1,27 @@
//
// FATExt_recorderManager.h
// FinAppletExt
//
// Created by Haley on 2021/1/21.
// Copyright © 2021 finogeeks. All rights reserved.
//
#import "FATExtBaseApi.h"
NS_ASSUME_NONNULL_BEGIN
@interface FATExt_recorderManager : FATExtBaseApi
/**
*/
@property (nonatomic, copy) NSString *method;
/**
*/
@property (nonatomic, copy) NSDictionary *data;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,87 @@
//
// FATExt_recorderManager.m
// FinAppletExt
//
// Created by Haley on 2021/1/21.
// Copyright © 2021 finogeeks. All rights reserved.
//
#import "FATExt_recorderManager.h"
#import "FATExtRecordManager.h"
#import "FATClient+ext.h"
#import "FATExtUtil.h"
@implementation FATExt_recorderManager
- (void)setupApiWithSuccess:(void (^)(NSDictionary<NSString *, id> *successResult))success
failure:(void (^)(NSDictionary *failResult))failure
cancel:(void (^)(NSDictionary *cancelResult))cancel {
NSArray *validMethods = @[@"start",@"pause",@"resume",@"stop",@"onFrameRecordedRemove"];
NSString *method = self.method;
if (![validMethods containsObject:method]) {
return;
}
__block NSDictionary *dataDict = self.data;
FATAppletInfo *appInfo = [[FATClient sharedClient] currentApplet];
BOOL result = [[FATExtRecordManager shareManager] checkRecordWithMethod:method data:dataDict appletId:appInfo.appId];
if (!result) {
return;
}
if ([method isEqualToString:@"start"]) {
[[FATClient sharedClient] fat_requestAppletAuthorize:FATAuthorizationTypeMicrophone appletId:appInfo.appId complete:^(NSInteger status) {
if (status == 1) { //
if (failure) {
failure(@{@"errMsg" : @"unauthorized,用户未授予麦克风权限"});
}
NSDictionary *params = @{
@"method" : @"onError",
@"data" : @{@"errMsg" : @"operateRecorder:fail fail_system permissionn denied"},
};
if (self.context) {
[self.context sendResultEvent:0 eventName:@"onRecorderManager" eventParams:params extParams:nil];
}
return;
}
if (status == 2) { //sdk
if (failure) {
failure(@{@"errMsg" : @"unauthorized disableauthorized,SDK被禁止申请麦克风权限"});
}
return;
}
dataDict = [self checkAACAuioParams:dataDict];
[[FATExtRecordManager shareManager] startRecordWithData:dataDict appletId:appInfo.appId eventBlock:^(NSInteger eventType, NSString *eventName, NSDictionary *paramDic, NSDictionary *extDic) {
if (self.context) {
[self.context sendResultEvent:eventType eventName:eventName eventParams:paramDic extParams:extDic];
}
}];
}];
} else if ([method isEqualToString:@"pause"]) {
[[FATExtRecordManager shareManager] pauseRecordWithData:dataDict appletId:appInfo.appId];
} else if ([method isEqualToString:@"resume"]) {
[[FATExtRecordManager shareManager] resumeRecordWithData:dataDict appletId:appInfo.appId];
} else if ([method isEqualToString:@"stop"]) {
[[FATExtRecordManager shareManager] stopRecordWithData:dataDict appletId:appInfo.appId];
} else if ([method isEqualToString:@"onFrameRecordedRemove"]) {
[[FATExtRecordManager shareManager] sendRecordFrameBufferWithData:dataDict appletId:appInfo.appId];
}
}
/// aacsampleRate800016000
/// - Parameter dic:
- (NSDictionary *)checkAACAuioParams:(NSDictionary *)dic {
NSMutableDictionary *data = [[NSMutableDictionary alloc] initWithDictionary:dic];
if ([dic[@"format"] isEqualToString:@"aac"]) {
NSString *encodeBitRate = dic[@"encodeBitRate"];
NSString *sampleRate = dic[@"sampleRate"];
NSString *numberOfChannels = dic[@"numberOfChannels"];
if ([encodeBitRate isEqualToString:@"48000"] && [numberOfChannels isEqualToString:@"2"] && [sampleRate isEqualToString:@"8000"]) {
[data setValue:@"16000" forKey:@"sampleRate"];
}
}
return data;
}
@end

View File

@ -0,0 +1,16 @@
//
// Copyright (c) 2017, finogeeks.com
// All rights reserved.
//
//
//
#import "FATExtBaseApi.h"
/**
wx.stopRecord1
*/
@interface FATExt_startRecord : FATExtBaseApi
@end

View File

@ -0,0 +1,44 @@
//
// Copyright (c) 2017, finogeeks.com
// All rights reserved.
//
//
//
#import "FATExt_startRecord.h"
#import "FATExtAVManager.h"
#import "FATClient+ext.h"
#import <AVFoundation/AVFoundation.h>
@implementation FATExt_startRecord
- (void)setupApiWithSuccess:(void (^)(NSDictionary<NSString *, id> *successResult))success
failure:(void (^)(NSDictionary *failResult))failure
cancel:(void (^)(NSDictionary *cancelResult))cancel {
FATAppletInfo *appInfo = [[FATClient sharedClient] currentApplet];
[[FATClient sharedClient] fat_requestAppletAuthorize:FATAuthorizationTypeMicrophone appletId:appInfo.appId complete:^(NSInteger status) {
if (status == 1) {
if (failure) {
failure(@{@"errMsg" : @"unauthorized,用户未授予麦克风权限"});
}
return;
} else if (status == 2) {
if (failure) {
failure(@{@"errMsg" : @"unauthorized disableauthorized,SDK被禁止申请麦克风权限"});
}
return;
}
[[FATExtAVManager sharedManager] startRecordWithSuccess:^(NSString *tempFilePath) {
if (success) {
success(@{@"tempFilePath" : tempFilePath});
}
} fail:^(NSString *msg) {
if (failure) {
failure(@{@"errMsg" : msg});
}
}];
}];
}
@end

View File

@ -0,0 +1,15 @@
//
// Copyright (c) 2017, finogeeks.com
// All rights reserved.
//
//
//
#import "FATExtBaseApi.h"
/**
*/
@interface FATExt_stopRecord : FATExtBaseApi
@end

View File

@ -0,0 +1,22 @@
//
// Copyright (c) 2017, finogeeks.com
// All rights reserved.
//
//
//
#import "FATExt_stopRecord.h"
#import "FATExtAVManager.h"
@implementation FATExt_stopRecord
- (void)setupApiWithSuccess:(void (^)(NSDictionary<NSString *, id> *successResult))success
failure:(void (^)(NSDictionary *failResult))failure
cancel:(void (^)(NSDictionary *cancelResult))cancel {
[[FATExtAVManager sharedManager] stopRecord];
if (success) {
success(@{});
}
}
@end

View File

@ -0,0 +1,17 @@
//
// FATExtNavigationController.h
// FinAppletExt
//
// Created by 耀 on 2022/10/28.
// Copyright © 2022 finogeeks. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface FATExtNavigationController : UINavigationController
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,32 @@
//
// FATExtNavigationController.m
// FinAppletExt
//
// Created by 耀 on 2022/10/28.
// Copyright © 2022 finogeeks. All rights reserved.
//
#import "FATExtNavigationController.h"
@interface FATExtNavigationController ()
@end
@implementation FATExtNavigationController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
//
- (BOOL)shouldAutorotate {
return NO;
}
//
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
@end

View File

@ -0,0 +1,38 @@
//
// FATExt_LocationUpdateManager.h
// FinAppletExt
//
// Created by 耀 on 2022/11/6.
//
#import <Foundation/Foundation.h>
#import "FATExtBaseApi.h"
#import "FATExtLocationManager.h"
NS_ASSUME_NONNULL_BEGIN
@interface FATExt_LocationUpdateManager : NSObject
+ (instancetype)sharedManager;
@property (nonatomic, strong) FATExtLocationManager *locationManager;
@property (nonatomic, assign) BOOL locationIsInit;
@property (nonatomic, copy) NSString *appletId;
@property (nonatomic, weak) id<FATApiHanderContextDelegate> context;
- (void)startLocationUpdateType:(NSString *)type isAllowsBackgroundLocationUpdates:(BOOL)result withAppId:(NSString *)appId Success:(void (^)(NSDictionary<NSString *, id> *successResult))success
failure:(void (^)(NSDictionary *failResult))failure
cancel:(void (^)(NSDictionary *cancelResult))cancel;
- (void)onLocationUpdate;
- (void)stopLocationUpdate;
- (void)checkLocationState;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,200 @@
//
// FATExt_LocationUpdateManager.m
// FinAppletExt
//
// Created by 耀 on 2022/11/6.
//
#import "FATExt_LocationUpdateManager.h"
#import <FinApplet/FinApplet.h>
#import "FATWGS84ConvertToGCJ02.h"
#import <FinApplet/FinApplet.h>
static FATExt_LocationUpdateManager *instance = nil;
NSString *const FATExtAppletUpdateBackgroudPermissions = @"FATAppletUpdateBackgroudPermissions";
@interface FATExt_LocationUpdateManager ()<CLLocationManagerDelegate>
@property (nonatomic, copy) NSString *type;
@property (nonatomic, copy) void (^success)(NSDictionary<NSString *, id> *_Nonnull);
@property (nonatomic, copy) void (^failure)(NSDictionary *_Nullable);
@property (nonatomic, copy) void (^cancel)(NSDictionary *_Nullable);
@end
@implementation FATExt_LocationUpdateManager
+ (instancetype)sharedManager {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[[self class] alloc] init];
});
return instance;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [super allocWithZone:zone];
});
return instance;
}
- (instancetype)init {
self = [super init];
if (self) {
//
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appletClose:) name:FATAppletDestroyNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(permissionsUpdate:) name:FATExtAppletUpdateBackgroudPermissions object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appletEnterBackground:) name:FATAppletEnterBackgroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidForeground:) name:FATAppletForegroundNotification object:nil];
}
return self;
}
#pragma
- (void)appletClose:(NSNotification *)notification {
NSDictionary *dic = notification.userInfo;
NSString *appletId = [dic objectForKey:@"appletId"];
//
if (appletId && [appletId isEqualToString:self.appletId] && self.locationIsInit) {
[self stopLocationUpdate];
}
}
- (void)permissionsUpdate:(NSNotification *)notification {
NSDictionary *dic = notification.userInfo;
NSInteger type = [[dic objectForKey:@"type"] integerValue];
if (type == 0 ) {
[self stopLocationUpdate];
}
if (_locationManager.allowsBackgroundLocationUpdates && self.locationIsInit) {
if (type == 1) {
[self stopLocationUpdate];
}
}
}
- (void)appletEnterBackground:(NSNotification *)notification {
if (!_locationManager.allowsBackgroundLocationUpdates && self.locationIsInit) {
[_locationManager stopUpdatingLocation];
}
}
- (void)appDidForeground:(NSNotification *)notification {
if (!_locationManager.allowsBackgroundLocationUpdates && self.locationIsInit) {
if ([CLLocationManager locationServicesEnabled] && ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse || [CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedAlways)) {
[_locationManager startUpdatingLocation];
}
}
}
- (void)checkLocationState {
if (self.locationIsInit) {
//
UIViewController *vc = [[UIApplication sharedApplication] fat_topViewController];
UINavigationController<FATCapsuleViewProtocol> *nav = (UINavigationController<FATCapsuleViewProtocol> *)vc.navigationController;
if ([nav respondsToSelector:@selector(controlCapsuleStateButton:state:animate:)]) {
[nav controlCapsuleStateButton:NO state:FATCapsuleButtonStateLocation animate:YES];
}
}
}
- (void)startLocationUpdateType:(NSString *)type isAllowsBackgroundLocationUpdates:(BOOL)result withAppId:(NSString *)appId Success:(void (^)(NSDictionary<NSString *, id> *successResult))success
failure:(void (^)(NSDictionary *failResult))failure
cancel:(void (^)(NSDictionary *cancelResult))cancel {
//
if (self.locationIsInit && _locationManager.allowsBackgroundLocationUpdates == result) {
return;
}
//
_locationManager = [[FATExtLocationManager alloc] init];
_locationManager.delegate = self;
_locationManager.desiredAccuracy = kCLLocationAccuracyBest;
_locationManager.allowsBackgroundLocationUpdates = result;
_locationManager.pausesLocationUpdatesAutomatically = YES;
[_locationManager requestWhenInUseAuthorization];
self.type = type;
self.locationIsInit = YES;
if ([CLLocationManager locationServicesEnabled] && ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse || [CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedAlways)) {
[self onLocationUpdate];
}
self.appletId = appId;
self.success = success;
self.failure = failure;
}
- (void)onLocationUpdate {
[_locationManager startUpdatingLocation];
}
- (void)stopLocationUpdate {
[_locationManager stopUpdatingLocation];
if (self.context) {
[self.context sendResultEvent:0 eventName:@"offLocationChange" eventParams:@{} extParams:nil];
}
self.appletId = @"";
self.locationIsInit = NO;
}
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
CLLocation *newLocation = [locations objectAtIndex:0];
// gcj02
NSString *typeString = @"gcj02";
CLLocationCoordinate2D coord = [FATWGS84ConvertToGCJ02ForAMapView transformFromWGSToGCJ:[newLocation coordinate]];
newLocation = [[CLLocation alloc] initWithLatitude:coord.latitude longitude:coord.longitude];
if ([self.type isEqualToString:@"wgs84"]) {
CLLocationCoordinate2D coord = [FATWGS84ConvertToGCJ02ForAMapView transformFromGCJToWGS:[newLocation coordinate]];
newLocation = [[CLLocation alloc] initWithLatitude:coord.latitude longitude:coord.longitude];
typeString = @"wgs84";
}
CLLocationCoordinate2D coordinate = newLocation.coordinate;
NSDictionary *params = @{@"altitude" : @(newLocation.altitude),
@"latitude" : @(coordinate.latitude),
@"longitude" : @(coordinate.longitude),
@"speed" : @(newLocation.speed),
@"accuracy" : @(newLocation.horizontalAccuracy),
@"type" : typeString,
@"verticalAccuracy" : @(newLocation.verticalAccuracy),
@"horizontalAccuracy" : @(newLocation.horizontalAccuracy)
};
if (self.context) {
[self.context sendResultEvent:0 eventName:@"onLocationChange" eventParams:params extParams:nil];
}
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
if (self.context) {
[self.context sendResultEvent:0 eventName:@"onLocationChangeError" eventParams:@{} extParams:nil];
}
[self stopLocationUpdate];
if (self.failure) {
self.failure(@{});
}
}
//- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
// if (status == kCLAuthorizationStatusAuthorizedAlways || status == kCLAuthorizationStatusAuthorizedWhenInUse) {
// [self onLocationUpdate];
// if (self.success) {
// self.success(@{});
// }
// } else {
// if (self.failure) {
// self.failure(@{@"errMsg" : @"system permission denied"});
// }
// [self stopLocationUpdate];
// }
//}
@end

View File

@ -0,0 +1,17 @@
//
// FATExt_chooseLocation.h
// FinAppletExt
//
// Created by Haley on 2020/8/19.
// Copyright © 2020 finogeeks. All rights reserved.
//
#import "FATExtBaseApi.h"
@interface FATExt_chooseLocation : FATExtBaseApi
///
@property (nonatomic, strong) NSString *latitude;
///
@property (nonatomic, strong) NSString *longitude;
@end

View File

@ -0,0 +1,97 @@
//
// FATExt_chooseLocation.m
// FinAppletExt
//
// Created by Haley on 2020/8/19.
// Copyright © 2020 finogeeks. All rights reserved.
//
#import "FATExt_chooseLocation.h"
#import "FATMapViewController.h"
#import "FATClient+ext.h"
#import "FATExtMapManager.h"
#import "FATExtNavigationController.h"
#import "FATExt_locationAuthManager.h"
#import <CoreLocation/CoreLocation.h>
@implementation FATExt_chooseLocation
- (void)setupApiWithSuccess:(void (^)(NSDictionary<NSString *, id> *successResult))success
failure:(void (^)(NSDictionary *failResult))failure
cancel:(void (^)(NSDictionary *cancelResult))cancel {
// if (![CLLocationManager locationServicesEnabled]) {
// if (callback) {
// callback(FATExtensionCodeFailure, @{@"errMsg" : @"location service not open"});
// }
// return;
// }
NSString *mapClassStr = NSStringFromClass([FATExtMapManager shareInstance].mapClass);
NSString *apiName = nil;
if ([mapClassStr isEqualToString:@"FATBDMapView"]) {
apiName = @"FATBDExt_chooseLocation";
} else if ([mapClassStr isEqualToString:@"FATTXMapView"]) {
apiName = @"FATTXExt_chooseLocation";
} else if ([mapClassStr isEqualToString:@"FATGDMapView"]) {
apiName = @"FATGDExt_chooseLocation";
}
if (apiName) {
id<FATApiProtocol> api = [self.class fat_apiWithApiClass:apiName params:self.param];
if (api) {
api.appletInfo = self.appletInfo;
api.context = self.context;
[api setupApiWithSuccess:success failure:failure cancel:cancel];
return;
}
}
[[FATClient sharedClient] fat_requestAppletAuthorize:FATAuthorizationTypeLocation appletId:self.appletInfo.appId complete:^(NSInteger status) {
if (status == 0) {
[[FATExt_locationAuthManager shareInstance] fat_requestAppletLocationAuthorize:self.appletInfo isBackground:NO withComplete:^(BOOL status) {
if (status) {
[self callChooseLocationWithSuccess:success failure:failure cancel:cancel];
} else {
if (failure) {
failure(@{@"errMsg" : @"system permission denied"});
}
}
}];
} else if (status == 1) {
//
if (failure) {
failure(@{@"errMsg" : @"unauthorized,用户未授予位置权限"});
}
} else {
if (failure) {
failure(@{@"errMsg" : @"unauthorized disableauthorized,SDK被禁止申请位置权限"});
}
}
}];
}
- (void)callChooseLocationWithSuccess:(void (^)(NSDictionary<NSString *, id> *_Nonnull))success failure:(void (^)(NSDictionary *_Nullable))failure cancel:(void (^)(NSDictionary *cancelResult))cancel {
//
UIViewController *topVC = [[UIApplication sharedApplication] fat_topViewController];
FATMapViewController *mapVC = [[FATMapViewController alloc] init];
mapVC.latitude = self.latitude;
mapVC.longitude = self.longitude;
mapVC.cancelBlock = ^{
cancel(nil);
};
mapVC.sureBlock = ^(NSDictionary *locationInfo) {
success(locationInfo);
};
FATExtNavigationController *nav = [[FATExtNavigationController alloc] initWithRootViewController:mapVC];
if (@available(iOS 15, *)) {
UINavigationBarAppearance *barAppearance = [[UINavigationBarAppearance alloc] init];
[barAppearance configureWithOpaqueBackground];
barAppearance.backgroundColor = [UIColor whiteColor];
nav.navigationBar.standardAppearance = barAppearance;
nav.navigationBar.scrollEdgeAppearance = barAppearance;
}
[topVC presentViewController:nav animated:YES completion:nil];
}
@end

View File

@ -0,0 +1,16 @@
//
// FATExt_choosePoi.h
// FinAppletExt
//
// Created by 耀 on 2021/12/7.
//
#import "FATExtBaseApi.h"
NS_ASSUME_NONNULL_BEGIN
@interface FATExt_choosePoi : FATExtBaseApi
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,92 @@
//
// FATExt_choosePoi.m
// FinAppletExt
//
// Created by 耀 on 2021/12/7.
//
#import "FATExt_choosePoi.h"
#import "FATLocationManager.h"
#import "FATWGS84ConvertToGCJ02.h"
#import "FATClient+ext.h"
#import "FATExtChoosePoiViewController.h"
#import "FATExtMapManager.h"
#import "FATExtNavigationController.h"
#import "FATExt_locationAuthManager.h"
#import <FinApplet/FinApplet.h>
@implementation FATExt_choosePoi
- (void)setupApiWithSuccess:(void (^)(NSDictionary<NSString *, id> *successResult))success
failure:(void (^)(NSDictionary *failResult))failure
cancel:(void (^)(NSDictionary *cancelResult))cancel {
// FATAppletInfo *appInfo = [[FATClient sharedClient] currentApplet];
//使sdkAPI
NSString *mapClassStr = NSStringFromClass([FATExtMapManager shareInstance].mapClass);
NSString *apiName = nil;
if ([mapClassStr isEqualToString:@"FATBDMapView"]) {
apiName = @"FATBDExt_choosePoi";
} else if ([mapClassStr isEqualToString:@"FATTXMapView"]) {
apiName = @"FATTXExt_choosePoi";
}
if (apiName) {
id<FATApiProtocol> api = [self.class fat_apiWithApiClass:apiName params:self.param];
if (api) {
api.appletInfo = self.appletInfo;
api.context = self.context;
[api setupApiWithSuccess:success failure:failure cancel:cancel];
return;
}
}
[[FATClient sharedClient] fat_requestAppletAuthorize:FATAuthorizationTypeLocation appletId:self.appletInfo.appId complete:^(NSInteger status) {
if (status == 0) {
//
[[FATExt_locationAuthManager shareInstance] fat_requestAppletLocationAuthorize:self.appletInfo isBackground:NO withComplete:^(BOOL status) {
if (status) {
[self callChooseLocationWithWithSuccess:success failure:failure cancel:cancel];
} else {
if (failure) {
failure(@{@"errMsg" : @"system permission denied"});
}
}
}];
} else if (status == 1) {
//
if (failure) {
failure(@{@"errMsg" : @"unauthorized,用户未授予位置权限"});
}
} else {
if (failure) {
failure(@{@"errMsg" : @"unauthorized disableauthorized,SDK被禁止申请位置权限"});
}
}
}];
}
- (void)callChooseLocationWithWithSuccess:(void (^)(NSDictionary<NSString *, id> *successResult))success
failure:(void (^)(NSDictionary *failResult))failure
cancel:(void (^)(NSDictionary *cancelResult))cancel {
//
UIViewController *topVC = [[UIApplication sharedApplication] fat_topViewController];
FATExtChoosePoiViewController *mapVC = [[FATExtChoosePoiViewController alloc] init];
mapVC.cancelBlock = ^{
cancel(nil);
};
mapVC.sureBlock = ^(NSDictionary *locationInfo) {
success(locationInfo);
};
FATExtNavigationController *nav = [[FATExtNavigationController alloc] initWithRootViewController:mapVC];
if (@available(iOS 15, *)) {
UINavigationBarAppearance *barAppearance = [[UINavigationBarAppearance alloc] init];
[barAppearance configureWithOpaqueBackground];
barAppearance.backgroundColor = [UIColor whiteColor];
nav.navigationBar.standardAppearance = barAppearance;
nav.navigationBar.scrollEdgeAppearance = barAppearance;
}
[topVC presentViewController:nav animated:YES completion:nil];
}
@end

View File

@ -0,0 +1,22 @@
//
// FATExt_getLocation.h
// FinAppletExt
//
// Created by Haley on 2020/12/10.
// Copyright © 2020 finogeeks. All rights reserved.
//
#import "FATExtBaseApi.h"
@interface FATExt_getLocation : FATExtBaseApi
@property (nonatomic, copy) NSString *type;
@property (nonatomic, assign) BOOL altitude;
@property (nonatomic, assign) BOOL isHighAccuracy;
@property (nonatomic, assign) NSInteger highAccuracyExpireTime;
@end

View File

@ -0,0 +1,142 @@
//
// FATExt_getLocation.m
// FinAppletExt
//
// Created by Haley on 2020/12/10.
// Copyright © 2020 finogeeks. All rights reserved.
//
#import "FATExt_getLocation.h"
#import "FATLocationManager.h"
#import "FATWGS84ConvertToGCJ02.h"
#import "FATClient+ext.h"
#import "FATExtLocationManager.h"
#import "FATExtMapManager.h"
#import "FATExt_locationAuthManager.h"
#import <FinApplet/FinApplet.h>
@interface FATExt_getLocation () <CLLocationManagerDelegate>
@property (nonatomic, strong) FATExtLocationManager *locationManager;
@property (nonatomic, strong) FATExtBaseApi *strongSelf;
@property (nonatomic, copy) void (^success)(NSDictionary<NSString *, id> *_Nonnull);
@property (nonatomic, copy) void (^failure)(NSDictionary *_Nullable);
@property (nonatomic, strong) NSTimer *locationUpdateTimer;
@end
@implementation FATExt_getLocation
- (void)setupApiWithSuccess:(void (^)(NSDictionary<NSString *, id> *successResult))success
failure:(void (^)(NSDictionary *failResult))failure
cancel:(void (^)(NSDictionary *cancelResult))cancel {
NSString *mapClassStr = NSStringFromClass([FATExtMapManager shareInstance].mapClass);
NSString *apiName = nil;
if ([mapClassStr isEqualToString:@"FATBDMapView"]) {
apiName = @"FATBDExt_getLocation";
} else if ([mapClassStr isEqualToString:@"FATTXMapView"]) {
apiName = @"FATTXExt_getLocation";
} else if ([mapClassStr isEqualToString:@"FATGDMapView"]) {
apiName = @"FATGDExt_getLocation";
}
if (apiName) {
id<FATApiProtocol> api = [self.class fat_apiWithApiClass:apiName params:self.param];
if (api) {
api.appletInfo = self.appletInfo;
api.context = self.context;
[api setupApiWithSuccess:success failure:failure cancel:cancel];
return;
}
}
self.success = success;
self.failure = failure;
// FATAppletInfo *appInfo = [[FATClient sharedClient] currentApplet];
[[FATClient sharedClient] fat_requestAppletAuthorize:FATAuthorizationTypeLocation appletId:self.appletInfo.appId complete:^(NSInteger status) {
if (status == 0) {
//
[[FATExt_locationAuthManager shareInstance] fat_requestAppletLocationAuthorize:self.appletInfo isBackground:NO withComplete:^(BOOL status) {
if (status) {
[self startUpdateLocation];
} else {
if (failure) {
failure(@{@"errMsg" : @"system permission denied"});
}
}
}];
} else if (status == 1) {
//
if (failure) {
failure(@{@"errMsg" : @"unauthorized,用户未授予位置权限"});
}
} else {
if (failure) {
failure(@{@"errMsg" : @"unauthorized disableauthorized,SDK被禁止申请位置权限"});
}
}
}];
}
- (void)startUpdateLocation {
_locationManager = [[FATExtLocationManager alloc] init];
_locationManager.delegate = self;
if (self.isHighAccuracy) {
_locationManager.desiredAccuracy = kCLLocationAccuracyBest;
} else {
_locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
}
[_locationManager requestWhenInUseAuthorization];
[_locationManager startUpdatingLocation];
_strongSelf = self;
__weak typeof(self) weak_self = self;
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 10);
dispatch_after(time, dispatch_get_global_queue(0, 0), ^{
weak_self.strongSelf = nil;
});
}
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
CLLocation *newLocation = [locations objectAtIndex:0];
NSString *typeString = @"wgs84";
//
if ([self.type isEqualToString:@"gcj02"]) {
//coord
CLLocationCoordinate2D coord = [FATWGS84ConvertToGCJ02ForAMapView transformFromWGSToGCJ:[newLocation coordinate]];
newLocation = [[CLLocation alloc] initWithLatitude:coord.latitude longitude:coord.longitude];
typeString = @"gcj02";
}
[FATLocationManager manager].location = newLocation;
CLLocationCoordinate2D coordinate = newLocation.coordinate;
if (self.success) {
NSDictionary *params = @{@"altitude" : @(newLocation.altitude),
@"latitude" : @(coordinate.latitude),
@"longitude" : @(coordinate.longitude),
@"speed" : @(newLocation.speed),
@"accuracy" : @(newLocation.horizontalAccuracy),
@"type" : typeString,
@"verticalAccuracy" : @(newLocation.verticalAccuracy),
@"horizontalAccuracy" : @(newLocation.horizontalAccuracy)
};
NSMutableDictionary *dataDic = [[NSMutableDictionary alloc] initWithDictionary:params];
if (!self.altitude) {
[dataDic removeObjectForKey:@"altitude"];
}
self.success(dataDic);
}
[_locationManager stopUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
if (self.failure) {
self.failure(nil);
}
}
@end

View File

@ -0,0 +1,21 @@
//
// FATExt_locationAuthManager.h
// FinAppletExt
//
// Created by 耀 on 2022/12/24.
//
#import <Foundation/Foundation.h>
#import <FinApplet/FinApplet.h>
NS_ASSUME_NONNULL_BEGIN
@interface FATExt_locationAuthManager : NSObject
+ (instancetype)shareInstance;
- (void)fat_requestAppletLocationAuthorize:(FATAppletInfo *)appletInfo isBackground:(BOOL)isBackground withComplete:(void (^)(BOOL status))complete;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,136 @@
//
// FATExt_locationAuthManager.m
// FinAppletExt
//
// Created by 耀 on 2022/12/24.
//
#import "FATExt_locationAuthManager.h"
#import <CoreLocation/CoreLocation.h>
@interface FATExt_locationAuthManager () <CLLocationManagerDelegate>
@property (nonatomic, strong) CLLocationManager *locationManager;
@property (nonatomic, strong) NSMutableArray *locationAuthCompleteArray;
@property (nonatomic, strong) NSMutableArray<FATAppletInfo*> *appletInfoArray;
@property (nonatomic, strong) NSMutableDictionary *authTypeDic; //keyId value
@end
static FATExt_locationAuthManager *instance = nil;
@implementation FATExt_locationAuthManager
+ (instancetype)shareInstance {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[FATExt_locationAuthManager alloc] init];
});
return instance;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [super allocWithZone:zone];
});
return instance;
}
- (instancetype)init {
self = [super init];
if (self) {
[self p_init];
}
return self;
}
- (void)p_init {
_locationAuthCompleteArray = [NSMutableArray array];
_appletInfoArray = [[NSMutableArray alloc]init];
_authTypeDic = [[NSMutableDictionary alloc]init];
}
- (void)fat_requestAppletLocationAuthorize:(FATAppletInfo *)appletInfo isBackground:(BOOL)isBackground withComplete:(void (^)(BOOL status))complete {
CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
if (status == kCLAuthorizationStatusAuthorizedWhenInUse || status == kCLAuthorizationStatusAuthorizedAlways) {
[self notifyApp:appletInfo authType:isBackground ? FATAuthorizationTypeLocationBackground : FATAuthorizationTypeLocation authResult:FATAuthorizationStatusAuthorized];
if (complete) {
complete(YES);
}
return;
}
if (status != kCLAuthorizationStatusNotDetermined) {
[self notifyApp:appletInfo authType:isBackground ? FATAuthorizationTypeLocationBackground : FATAuthorizationTypeLocation authResult:FATAuthorizationStatusDenied];
if (complete) {
complete(NO);
}
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
[self.locationAuthCompleteArray addObject:complete];
if (appletInfo) {
[self.appletInfoArray addObject:appletInfo];
if (appletInfo.appId) {
[self.authTypeDic setValue:isBackground ? @(FATAuthorizationTypeLocationBackground) : @(FATAuthorizationTypeLocation) forKey:appletInfo.appId];
}
}
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
[self.locationManager requestWhenInUseAuthorization];
});
return;
}
- (void)notifyApp:(FATAppletInfo *)appletInfo authType:(FATAuthorizationType)type authResult:(FATAuthorizationStatus)result {
id<FATAppletAuthDelegate> delegate = [FATClient sharedClient].authDelegate;
if (delegate && [delegate respondsToSelector:@selector(applet:didRequestAuth:withResult:)]) {
[delegate applet:appletInfo didRequestAuth:type withResult:result];
}
}
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
if (status == kCLAuthorizationStatusNotDetermined) {
return;
}
for (FATAppletInfo *appInfo in self.appletInfoArray) {
FATAuthorizationStatus authStatus = FATAuthorizationStatusDenied;
if (status == kCLAuthorizationStatusAuthorizedWhenInUse || status == kCLAuthorizationStatusAuthorizedAlways) {
authStatus = FATAuthorizationStatusAuthorized;
}
NSNumber *authtype = [self.authTypeDic objectForKey:appInfo.appId];
FATAuthorizationType type = FATAuthorizationTypeLocation;
if (authtype) {
type = [authtype integerValue];
}
[self notifyApp:appInfo authType:type authResult:authStatus];
}
[self.appletInfoArray removeAllObjects];
[self.authTypeDic removeAllObjects];
if (status == kCLAuthorizationStatusAuthorizedWhenInUse || status == kCLAuthorizationStatusAuthorizedAlways) {
for (int i = 0; i < self.locationAuthCompleteArray.count; i++) {
void(^locationComplete)(BOOL status) = self.locationAuthCompleteArray[i];
locationComplete(YES);
}
[self.locationAuthCompleteArray removeAllObjects];
return;
}
for (int i = 0; i < self.locationAuthCompleteArray.count; i++) {
void(^locationComplete)(BOOL status) = self.locationAuthCompleteArray[i];
locationComplete(NO);
}
[self.locationAuthCompleteArray removeAllObjects];
}
@end

View File

@ -0,0 +1,18 @@
//
// FATExt_locationChange.h
// FinAppletExt
//
// Created by 耀 on 2022/11/6.
//
#import "FATExtBaseApi.h"
NS_ASSUME_NONNULL_BEGIN
@interface FATExt_locationChange : FATExtBaseApi
@property (nonatomic, assign) BOOL enable;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,30 @@
//
// FATExt_locationChange.m
// FinAppletExt
//
// Created by 耀 on 2022/11/6.
//
#import "FATExt_locationChange.h"
#import "FATClient+ext.h"
#import "FATExt_LocationUpdateManager.h"
@implementation FATExt_locationChange
- (void)setupApiWithSuccess:(void (^)(NSDictionary<NSString *, id> *successResult))success
failure:(void (^)(NSDictionary *failResult))failure
cancel:(void (^)(NSDictionary *cancelResult))cancel {
// if (self.enable) {
// [FATExt_LocationUpdateManager sharedManager].context = self.context;
// [[FATExt_LocationUpdateManager sharedManager] onLocationUpdate];
// } else {
// [FATExt_LocationUpdateManager sharedManager].context = self.context;
// [[FATExt_LocationUpdateManager sharedManager] stopLocationUpdate];
// }
if (success) {
success(@{});
}
}
@end

View File

@ -0,0 +1,27 @@
//
// FATExt_openLocation.h
// FinAppletExt
//
// Created by 耀 on 2021/12/7.
//
#import "FATExtBaseApi.h"
NS_ASSUME_NONNULL_BEGIN
@interface FATExt_openLocation : FATExtBaseApi
///
@property (nonatomic, strong) NSString *latitude;
///
@property (nonatomic, strong) NSString *longitude;
@property (nonatomic, strong) NSString *scale;
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *address;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,98 @@
//
// FATExt_openLocation.m
// FinAppletExt
//
// Created by 耀 on 2021/12/7.
//
#import "FATExt_openLocation.h"
#import "FATWGS84ConvertToGCJ02.h"
#import "FATClient+ext.h"
#import "FATOpenLocationViewController.h"
#import "FATExtMapManager.h"
#import "FATExtNavigationController.h"
#import "FATExt_locationAuthManager.h"
#import <FinApplet/FinApplet.h>
@implementation FATExt_openLocation
- (void)setupApiWithSuccess:(void (^)(NSDictionary<NSString *, id> *successResult))success
failure:(void (^)(NSDictionary *failResult))failure
cancel:(void (^)(NSDictionary *cancelResult))cancel {
// if (![CLLocationManager locationServicesEnabled]) {
// if (callback) {
// callback(FATExtensionCodeFailure, @{@"errMsg" : @"location service not open"});
// }
// return;
// }
NSString *mapClassStr = NSStringFromClass([FATExtMapManager shareInstance].mapClass);
NSString *apiName = nil;
if ([mapClassStr isEqualToString:@"FATBDMapView"]) {
apiName = @"FATBDExt_openLocation";
} else if ([mapClassStr isEqualToString:@"FATGDMapView"]) {
apiName = @"FATGDExt_openLocation";
} else if ([mapClassStr isEqualToString:@"FATTXMapView"]) {
apiName = @"FATTXExt_openLocation";
}
if (apiName) {
id<FATApiProtocol> api = [self.class fat_apiWithApiClass:apiName params:self.param];
if (api) {
api.appletInfo = self.appletInfo;
api.context = self.context;
[api setupApiWithSuccess:success failure:failure cancel:cancel];
return;
}
}
[[FATClient sharedClient] fat_requestAppletAuthorize:FATAuthorizationTypeLocation appletId:self.appletInfo.appId complete:^(NSInteger status) {
if (status == 0) {
//
[[FATExt_locationAuthManager shareInstance] fat_requestAppletLocationAuthorize:self.appletInfo isBackground:NO withComplete:^(BOOL status) {
if (status) {
[self callChooseLocationWithCallback];
if (success) {
success(@{});
}
} else {
if (failure) {
failure(@{@"errMsg" : @"system permission denied"});
}
}
}];
} else if (status == 1) {
//
if (failure) {
failure(@{@"errMsg" : @"unauthorized,用户未授予位置权限"});
}
} else {
if (failure) {
failure(@{@"errMsg" : @"unauthorized disableauthorized,SDK被禁止申请位置权限"});
}
}
}];
}
- (void)callChooseLocationWithCallback {
//
UIViewController *topVC = [[UIApplication sharedApplication] fat_topViewController];
FATOpenLocationViewController *mapVC = [[FATOpenLocationViewController alloc] init];
mapVC.latitude = self.latitude;
mapVC.longitude = self.longitude;
mapVC.scale = self.scale;
mapVC.name = self.name ? self.name : @"[位置]";
mapVC.address = self.address;
FATExtNavigationController *nav = [[FATExtNavigationController alloc] initWithRootViewController:mapVC];
if (@available(iOS 15, *)) {
UINavigationBarAppearance *barAppearance = [[UINavigationBarAppearance alloc] init];
[barAppearance configureWithOpaqueBackground];
barAppearance.backgroundColor = [UIColor whiteColor];
nav.navigationBar.standardAppearance = barAppearance;
nav.navigationBar.scrollEdgeAppearance = barAppearance;
}
[topVC presentViewController:nav animated:YES completion:nil];
}
@end

View File

@ -0,0 +1,18 @@
//
// FATExt_startLocationUpdate.h
// FinAppletExt
//
// Created by 耀 on 2022/11/3.
//
#import "FATExtBaseApi.h"
NS_ASSUME_NONNULL_BEGIN
@interface FATExt_startLocationUpdate : FATExtBaseApi
@property (nonatomic, copy) NSString *type;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,44 @@
//
// FATExt_startLocationUpdate.m
// FinAppletExt
//
// Created by 耀 on 2022/11/3.
//
#import "FATExt_startLocationUpdate.h"
#import "FATClient+ext.h"
#import "FATExt_LocationUpdateManager.h"
#import "FATExt_locationAuthManager.h"
@implementation FATExt_startLocationUpdate
- (void)setupApiWithSuccess:(void (^)(NSDictionary<NSString *, id> *successResult))success
failure:(void (^)(NSDictionary *failResult))failure
cancel:(void (^)(NSDictionary *cancelResult))cancel {
[[FATClient sharedClient] fat_requestAppletAuthorize:FATAuthorizationTypeLocation appletId:self.appletInfo.appId complete:^(NSInteger status) {
if (status == 0) {
[[FATExt_locationAuthManager shareInstance] fat_requestAppletLocationAuthorize:self.appletInfo isBackground:NO withComplete:^(BOOL status) {
if (status) {
[FATExt_LocationUpdateManager sharedManager].context = self.context;
[[FATExt_LocationUpdateManager sharedManager] startLocationUpdateType:self.type isAllowsBackgroundLocationUpdates:NO withAppId:self.appletInfo.appId Success:success failure:failure cancel:cancel];
} else {
if (failure) {
failure(@{@"errMsg" : @"system permission denied"});
}
}
}];
} else if (status == 1) {
//
if (failure) {
failure(@{@"errMsg" : @"unauthorized,用户未授予位置权限"});
}
} else {
if (failure) {
failure(@{@"errMsg" : @"unauthorized disableauthorized,SDK被禁止申请位置权限"});
}
}
}];
}
@end

View File

@ -0,0 +1,18 @@
//
// FATExt_startLocationUpdateBackground.h
// FinAppletExt
//
// Created by 耀 on 2022/11/3.
//
#import "FATExtBaseApi.h"
NS_ASSUME_NONNULL_BEGIN
@interface FATExt_startLocationUpdateBackground : FATExtBaseApi
@property (nonatomic, copy) NSString *type;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,58 @@
//
// FATExt_startLocationUpdateBackground.m
// FinAppletExt
//
// Created by 耀 on 2022/11/3.
//
#import "FATExt_startLocationUpdateBackground.h"
#import "FATClient+ext.h"
#import "FATExt_LocationUpdateManager.h"
#import "FATExt_locationAuthManager.h"
@implementation FATExt_startLocationUpdateBackground
- (void)setupApiWithSuccess:(void (^)(NSDictionary<NSString *, id> *successResult))success
failure:(void (^)(NSDictionary *failResult))failure
cancel:(void (^)(NSDictionary *cancelResult))cancel {
if ([FATExt_LocationUpdateManager sharedManager].locationIsInit && [FATExt_LocationUpdateManager sharedManager].locationManager.allowsBackgroundLocationUpdates && ![self.appletInfo.appId isEqualToString:[FATExt_LocationUpdateManager sharedManager].appletId]) {
if (failure) {
failure(@{@"errMsg" : @"reach max concurrent background count"});
}
return;
}
[[FATClient sharedClient] fat_requestAppletAuthorize:FATAuthorizationTypeLocationBackground appletId:self.appletInfo.appId complete:^(NSInteger status) {
NSInteger SDKSatus = status;
if (status == 3) {
//
[[FATExt_locationAuthManager shareInstance] fat_requestAppletLocationAuthorize:self.appletInfo isBackground:YES withComplete:^(BOOL status) {
if (status) {
[FATExt_LocationUpdateManager sharedManager].context = self.context;
[[FATExt_LocationUpdateManager sharedManager] startLocationUpdateType:self.type isAllowsBackgroundLocationUpdates:SDKSatus == 3 ? YES : NO withAppId:self.appletInfo.appId Success:success failure:failure cancel:cancel];
} else {
if (failure) {
failure(@{@"errMsg" : @"system permission denied"});
}
}
}];
} else if (status == 2) {
// [[FATExt_LocationUpdateManager sharedManager] stopLocationUpdate];
if (failure) {
failure(@{@"errMsg" : @"unauthorized,用户未授予位置权限"});
}
} else if (status == 1) {
// [[FATExt_LocationUpdateManager sharedManager] stopLocationUpdate];
if (failure) {
failure(@{@"errMsg" : @"unauthorized,用户未授予后台定位权限"});
}
} else {
// [[FATExt_LocationUpdateManager sharedManager] stopLocationUpdate];
if (failure) {
failure(@{@"errMsg" : @"unauthorized disableauthorized,SDK被禁止申请位置权限"});
}
}
}];
}
@end

View File

@ -0,0 +1,16 @@
//
// FATExt_stopLocationUpdate.h
// FinAppletExt
//
// Created by 耀 on 2022/11/18.
//
#import "FATExtBaseApi.h"
NS_ASSUME_NONNULL_BEGIN
@interface FATExt_stopLocationUpdate : FATExtBaseApi
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,30 @@
//
// FATExt_stopLocationUpdate.m
// FinAppletExt
//
// Created by 耀 on 2022/11/18.
//
#import "FATExt_stopLocationUpdate.h"
#import "FATClient+ext.h"
#import "FATExt_LocationUpdateManager.h"
@implementation FATExt_stopLocationUpdate
- (void)setupApiWithSuccess:(void (^)(NSDictionary<NSString *, id> *successResult))success
failure:(void (^)(NSDictionary *failResult))failure
cancel:(void (^)(NSDictionary *cancelResult))cancel {
if (![self.appletInfo.appId isEqualToString:[FATExt_LocationUpdateManager sharedManager].appletId]) {
if (success) {
success(@{});
}
return;
}
[FATExt_LocationUpdateManager sharedManager].context = self.context;
[[FATExt_LocationUpdateManager sharedManager] stopLocationUpdate];
if (success) {
success(@{});
}
}
@end

View File

@ -0,0 +1,17 @@
//
// FATExt_insertNativeMap.h
// FinAppletExt
//
// Created by on 2022/9/18.
// Copyright © 2022 finogeeks. All rights reserved.
//
#import "FATExtBaseApi.h"
NS_ASSUME_NONNULL_BEGIN
@interface FATExt_insertNativeMap : FATExtBaseApi
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,50 @@
//
// FATExt_insertNativeMap.m
// FinAppletExt
//
// Created by on 2022/9/18.
// Copyright © 2022 finogeeks. All rights reserved.
//
#import "FATExt_insertNativeMap.h"
#import "FATMapViewDelegate.h"
#import "FATMapView.h"
#import "FATExtMapManager.h"
@implementation FATExt_insertNativeMap
- (void)setupApiWithSuccess:(void (^)(NSDictionary<NSString *, id> *successResult))success
failure:(void (^)(NSDictionary *failResult))failure
cancel:(void (^)(NSDictionary *cancelResult))cancel {
UIView<FATMapViewDelegate> *mapObject = [[FATExtMapManager shareInstance].mapClass alloc];
UIView<FATMapViewDelegate> *mapView = [mapObject initWithParam:self.param mapPageId:self.appletInfo.appId];
mapView.eventCallBack = ^(NSString *eventName, NSDictionary *paramDic) {
if (self.context) {
[self.context sendResultEvent:1 eventName:eventName eventParams:paramDic extParams:nil];
}
};
if (self.context && [self.context respondsToSelector:@selector(insertChildView:viewId:parentViewId:isFixed:isHidden:)]) {
NSString *parentId = self.param[@"cid"];
if (parentId && parentId.length > 0) { //
CGRect frame = mapView.frame;
frame.origin = CGPointZero;
mapView.frame = frame;
}
BOOL isHidden = [self.param[@"hide"] boolValue];
NSString *viewId = [self.context insertChildView:mapView viewId:self.param[@"mapId"] parentViewId:self.param[@"cid"] isFixed:NO isHidden:isHidden];
if (viewId && viewId.length > 0) {
if (success) {
success(@{});
}
} else {
if (failure) {
failure(@{});
}
}
} else {
if (failure) {
failure(@{});
}
}
}
@end

View File

@ -0,0 +1,26 @@
//
// FATExt_invokeMapTask.h
// FBRetainCycleDetector
//
// Created by 耀 on 2021/9/2.
//
#import "FATExtBaseApi.h"
NS_ASSUME_NONNULL_BEGIN
@interface FATExt_invokeMapTask : FATExtBaseApi
@property (nonatomic, copy) NSString *eventName;
@property (nonatomic, copy) NSString *mapId;
@property (nonatomic, copy) NSString *key;
@property (nonatomic, copy) NSDictionary *data;
@property (nonatomic, assign) NSInteger nativeViewId;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,169 @@
//
// FATExt_invokeMapTask.m
// FBRetainCycleDetector
//
// Created by 耀 on 2021/9/2.
//
#import "FATExt_invokeMapTask.h"
#import "FATMapView.h"
#import "FATExtMapManager.h"
#import "FATExtUtil.h"
@implementation FATExt_invokeMapTask
- (void)setupApiWithSuccess:(void (^)(NSDictionary<NSString *, id> *successResult))success
failure:(void (^)(NSDictionary *failResult))failure
cancel:(void (^)(NSDictionary *cancelResult))cancel {
UIView<FATMapViewDelegate> *map = nil;
if (self.context && [self.context respondsToSelector:@selector(getChildViewById:)]) {
UIView *targetView = [self.context getChildViewById:self.param[@"mapId"]];
if (targetView && [targetView conformsToProtocol:@protocol(FATMapViewDelegate)]) {
map = (UIView<FATMapViewDelegate> *)targetView;
}
}
if (!map) {
if (failure) {
failure(@{@"errMsg" : @"map view not exist"});
}
return;
}
if ([self.eventName isEqualToString:@"getCenterLocation"]) {
NSMutableDictionary *dic = [[NSMutableDictionary alloc] initWithDictionary:[map fat_getCenter]];
if (success) {
success(dic);
}
} else if ([self.eventName isEqualToString:@"getRegion"]) {
NSDictionary *dic = [map fat_mapgetRegion];
if (success) {
success(dic);
}
} else if ([self.eventName isEqualToString:@"getScale"]) {
double scale = [map fat_getScale];
if (success) {
success(@{@"scale" : [NSNumber numberWithDouble:scale]});
}
} else if ([self.eventName isEqualToString:@"includePoints"]) {
[map fat_includePoints:self.data];
if (success) {
success(@{});
}
} else if ([self.eventName isEqualToString:@"moveToLocation"]) {
NSString *status = [map fat_moveToLocation:self.data];
if ([status isEqualToString:@"fail"]) {
if (failure) {
failure(@{@"errMsg" : @"not show user location"});
}
} else {
if (success) {
success(@{});
}
}
} else if ([self.eventName isEqualToString:@"fromScreenLocation"]) {
NSDictionary *dic = [map fat_fromScreenLocation];
if (success) {
success(dic);
}
} else if ([self.eventName isEqualToString:@"toScreenLocation"]) {
// bug
CGPoint point = [map fat_toScreenLocation:self.data];
if (success) {
success(@{@"x" : @(point.x),
@"y" : @(point.y)});
};
} else if ([self.eventName isEqualToString:@"openMapApp"]) {
[map fat_openMapApp:self.data];
if (success) {
success(@{});
};
} else if ([self.eventName isEqualToString:@"addMarkers"]) {
[map fat_addMarkers:self.data];
if (success) {
success(@{});
};
} else if ([self.eventName isEqualToString:@"removeMarkers"]) {
[map fat_removeMarkers:self.data];
if (success) {
success(@{});
};
} else if ([self.eventName isEqualToString:@"translateMarker"]) {
BOOL isExit = [map fat_translateMarker:self.data];
if (isExit) {
if (success) {
success(@{});
};
} else {
if (failure) {
failure(@{@"errMsg" : @"error markerid"});
}
}
} else if ([self.eventName isEqualToString:@"moveAlong"]) {
BOOL isExit = [map fat_moveAlong:self.data];
if (isExit) {
if (success) {
success(@{});
};
} else {
NSArray *pathArray = [[NSArray alloc] initWithArray:self.data[@"path"]];
if (pathArray.count == 0 || ![pathArray isKindOfClass:[NSArray class]]) {
if (failure) {
failure(@{@"errMsg" : @"parameter error: parameter.duration should be Number instead of Undefined;"});
}
} else {
if (failure) {
failure(@{@"errMsg" : @"error markerid"});
}
}
}
} else if ([self.eventName isEqualToString:@"setCenterOffset"]) {
if ([map respondsToSelector:@selector(mapSetCenterOffset:)]) {
[map mapSetCenterOffset:self.data];
if (success) {
success(@{});
};
} else {
if (failure) {
failure(@{@"errMsg" : @"not support"});
};
}
} else if ([self.eventName isEqualToString:@"getRotate"]) {
if ([map respondsToSelector:@selector(fat_getRotate)]) {
NSDictionary *dic = [map fat_getRotate];
if (success) {
success(dic);
}
} else {
if (failure) {
failure(@{@"errMsg" : @"not support"});
};
}
} else if ([self.eventName isEqualToString:@"getSkew"]) {
if ([map respondsToSelector:@selector(fat_getskew)]) {
NSDictionary *dic = [map fat_getskew];
if (success) {
success(dic);
}
} else {
if (failure) {
failure(@{@"errMsg" : @"not support"});
};
}
} else if ([self.eventName isEqualToString:@"initMarkerCluster"]) {
if (failure) {
failure(@{@"errMsg" : @"not support"});
};
} else if ([self.eventName isEqualToString:@"setLocMarkerIcon"]) {
if ([map respondsToSelector:@selector(fat_setLocMarkerIcon:)]) {
[map fat_setLocMarkerIcon:self.data];
if (success) {
success(@{});
}
} else {
if (failure) {
failure(@{@"errMsg" : @"not support"});
};
}
}
}
@end

View File

@ -0,0 +1,17 @@
//
// FATExt_removeNativeMap.h
// FinAppletExt
//
// Created by on 2022/9/18.
// Copyright © 2022 finogeeks. All rights reserved.
//
#import "FATExtBaseApi.h"
NS_ASSUME_NONNULL_BEGIN
@interface FATExt_removeNativeMap : FATExtBaseApi
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,32 @@
//
// FATExt_removeNativeMap.m
// FinAppletExt
//
// Created by on 2022/9/18.
// Copyright © 2022 finogeeks. All rights reserved.
//
#import "FATExt_removeNativeMap.h"
@implementation FATExt_removeNativeMap
- (void)setupApiWithSuccess:(void (^)(NSDictionary<NSString *, id> *successResult))success
failure:(void (^)(NSDictionary *failResult))failure
cancel:(void (^)(NSDictionary *cancelResult))cancel {
if (self.context && [self.context respondsToSelector:@selector(removeChildView:)]) {
BOOL result = [self.context removeChildView:self.param[@"mapId"]];
if (result) {
if (success) {
success(@{});
}
} else {
if (failure) {
failure(@{});
}
}
} else {
if (failure) {
failure(@{});
}
}
}
@end

View File

@ -0,0 +1,17 @@
//
// FATExt_updateNativeMap.h
// FinAppletExt
//
// Created by on 2022/9/18.
// Copyright © 2022 finogeeks. All rights reserved.
//
#import "FATExtBaseApi.h"
NS_ASSUME_NONNULL_BEGIN
@interface FATExt_updateNativeMap : FATExtBaseApi
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,51 @@
//
// FATExt_updateNativeMap.m
// FinAppletExt
//
// Created by on 2022/9/18.
// Copyright © 2022 finogeeks. All rights reserved.
//
#import "FATExt_updateNativeMap.h"
#import "FATMapViewDelegate.h"
@implementation FATExt_updateNativeMap
- (void)setupApiWithSuccess:(void (^)(NSDictionary<NSString *, id> *successResult))success
failure:(void (^)(NSDictionary *failResult))failure
cancel:(void (^)(NSDictionary *cancelResult))cancel {
if (self.context && [self.context respondsToSelector:@selector(getChildViewById:)]) {
UIView *targetView = [self.context getChildViewById:self.param[@"mapId"]];
if (targetView && [targetView conformsToProtocol:@protocol(FATMapViewDelegate)]) {
UIView<FATMapViewDelegate> *mapView = (UIView<FATMapViewDelegate> *)targetView;
if (mapView && [mapView respondsToSelector:@selector(updateWithParam:)]) {
//hide
if ([self.param objectForKey:@"hide"]) {
BOOL hide = [[self.param objectForKey:@"hide"] boolValue];
if (hide) {
[targetView removeFromSuperview];
} else {
if (self.context && [self.context respondsToSelector:@selector(updateChildViewHideProperty:viewId:parentViewId:isFixed:isHidden:complete:)]) {
[self.context updateChildViewHideProperty:targetView viewId:self.param[@"mapId"] parentViewId:self.param[@"cid"] isFixed:NO isHidden:hide complete:nil];
}
}
}
[mapView updateWithParam:self.param];
if (success) {
success(@{});
}
} else {
if (failure) {
NSDictionary *dictParam = @{};
failure(dictParam);
}
}
}
} else {
if (failure) {
NSDictionary *dictParam = @{};
failure(dictParam);
}
}
}
@end

View File

@ -0,0 +1,17 @@
//
// FATExt_updateNativeMapMarkers.h
// FinAppletExt
//
// Created by on 2022/9/18.
// Copyright © 2022 finogeeks. All rights reserved.
//
#import "FATExtBaseApi.h"
NS_ASSUME_NONNULL_BEGIN
@interface FATExt_updateNativeMapMarkers : FATExtBaseApi
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,39 @@
//
// FATExt_updateNativeMapMarkers.m
// FinAppletExt
//
// Created by on 2022/9/18.
// Copyright © 2022 finogeeks. All rights reserved.
//
#import "FATExt_updateNativeMapMarkers.h"
#import "FATMapViewDelegate.h"
@implementation FATExt_updateNativeMapMarkers
- (void)setupApiWithSuccess:(void (^)(NSDictionary<NSString *, id> *successResult))success
failure:(void (^)(NSDictionary *failResult))failure
cancel:(void (^)(NSDictionary *cancelResult))cancel {
if (self.context && [self.context respondsToSelector:@selector(getChildViewById:)]) {
UIView *targetView = [self.context getChildViewById:self.param[@"mapId"]];
if (targetView && [targetView conformsToProtocol:@protocol(FATMapViewDelegate)]) {
UIView<FATMapViewDelegate> *mapView = (UIView<FATMapViewDelegate> *)targetView;
if (mapView && [mapView respondsToSelector:@selector(updateNativeMapMarkers:)]) {
[mapView updateNativeMapMarkers:self.param];
} else {
if (failure) {
NSDictionary *dictParam = @{};
failure(dictParam);
}
}
}
} else {
if (failure) {
NSDictionary *dictParam = @{};
failure(dictParam);
}
}
}
@end

View File

@ -0,0 +1,70 @@
//
// FATMapView.h
// FBRetainCycleDetector
//
// Created by 耀 on 2021/10/9.
//
#import <MapKit/MapKit.h>
#import "FATMapViewDelegate.h"
NS_ASSUME_NONNULL_BEGIN
@interface FATMapView : MKMapView <FATMapViewDelegate>
/// Subscribepage
/// eventName
/// resultDic
@property (nonatomic, copy) void(^eventCallBack)(NSString *eventName, NSDictionary *paramDic);
- (instancetype)initWithParam:(NSDictionary *)param mapPageId:(NSString *)pageId;
- (void)updateWithParam:(NSDictionary *)param;
///
- (NSDictionary *)fat_getCenter;
///
- (NSDictionary *)fat_getskew;
///
- (double)fat_getScale;
///
/// @param data
- (NSString *)fat_moveToLocation:(NSDictionary *)data;
///
/// @param data
- (void)fat_includePoints:(NSDictionary *)data;
///
- (NSDictionary *)fat_mapgetRegion;
///
- (NSDictionary *)fat_fromScreenLocation;
///
/// @param data
- (CGPoint)fat_toScreenLocation:(NSDictionary *)data;
/// app
- (void)fat_openMapApp:(NSDictionary *)data;
///
- (void)fat_addMarkers:(NSDictionary *)data;
///
- (void)fat_removeMarkers:(NSDictionary *)data;
///
- (BOOL)fat_translateMarker:(NSDictionary *)data;
/// 沿 marker
- (BOOL)fat_moveAlong:(NSDictionary *)data;
//- (void)fat_setLocMarkerIcon:(NSDictionary *)data;
@end
NS_ASSUME_NONNULL_END

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,26 @@
//
// MKMarkerView.h
// FBRetainCycleDetector
//
// Created by 耀 on 2021/9/14.
//
#import <MapKit/MapKit.h>
NS_ASSUME_NONNULL_BEGIN
///
@interface MKMarker : NSObject <MKAnnotation>
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *subtitle;
@property (nonatomic, strong) UIImage *image;
@property (nonatomic, copy) NSString *idString;
@end
@interface MKMarkerView : MKAnnotationView
+ (instancetype)dequeueMarkerViewWithMap:(MKMapView *)mapView annotation:(id<MKAnnotation>)annotation;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,62 @@
//
// MKMarkerView.h
// FBRetainCycleDetector
//
// Created by 耀 on 2021/9/14.
//
#import "MKMarkerView.h"
@implementation MKMarker
@synthesize title;
@synthesize coordinate = _coordinate;
- (void)setCoordinate:(CLLocationCoordinate2D)newCoordinate {
_coordinate = newCoordinate;
}
- (CLLocationCoordinate2D)coordinate {
return _coordinate;
}
@end
@interface MKMarkerView ()
@property (nonatomic, strong) UIImageView *imageView;
@end
@implementation MKMarkerView
+ (instancetype)dequeueMarkerViewWithMap:(MKMapView *)mapView annotation:(id<MKAnnotation>)annotation {
if ([annotation isKindOfClass:MKMarker.class]) {
MKMarker *marker = (MKMarker *)annotation;
MKMarkerView *markerView = (MKMarkerView *)[mapView dequeueReusableAnnotationViewWithIdentifier:@"markerView"];
if (markerView == nil) {
markerView = [[MKMarkerView alloc] initWithAnnotation:marker reuseIdentifier:@"markerView"];
}
markerView.annotation = marker;
markerView.image = marker.image;
return markerView;
}
return nil;
}
- (instancetype)initWithAnnotation:(id<MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
if (self) {
// self.calloutOffset = CGPointMake(0.5f, 0.97f);
self.canShowCallout = YES; //
// [self addSubview:self.imageView];
}
return self;
}
- (BOOL)isEnabled {
return YES;
}
- (BOOL)isSelected {
return YES;
}
@end

View File

@ -0,0 +1,11 @@
//
// FinAppletExtension.h
// FinAppletExtension
//
// Created by Haley on 2020/08/11.
// Copyright © 2019 finogeeks. All rights reserved.
//
// In this header, you should import all the public headers of your framework using statements like #import <FinAppletExt/FinAppletExt.h>
#import "FATExtClient.h"

View File

@ -0,0 +1,25 @@
Copyright (c) 2017, weidian.com
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Some files were not shown because too many files have changed in this diff Show More