Compare commits

...

40 Commits

Author SHA1 Message Date
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
152 changed files with 10133 additions and 82 deletions

View File

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

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip

View File

@ -0,0 +1,46 @@
// The code is already well written and doesn't need any improvement.
// However, I will add some comments to make it more readable.
package com.finogeeks.mop.api;
import android.content.Context;
import androidx.annotation.Nullable;
import org.json.JSONException;
import org.json.JSONObject;
public abstract class SyncApi extends BaseApi {
public SyncApi(Context context) {
super(context);
}
// This method is used to invoke the API.
@Nullable
public abstract String invoke(String url, JSONObject jsonObject);
// This method is used to get the success response.
public JSONObject getSuccessRes(String message) {
JSONObject jsonObject = new JSONObject();
String key = "errMsg";
try {
jsonObject.put(key, message + ":ok");
return jsonObject;
} catch (JSONException e) {
e.printStackTrace();
return jsonObject;
}
}
// This method is used to get the failure response.
public String getFailureRes(String message, String error) {
JSONObject jsonObject = new JSONObject();
String key = "errMsg";
try {
return jsonObject.put(key, message + ":fail " + error).toString();
} catch (JSONException e) {
e.printStackTrace();
return "{\"errMsg\":" + message + "\":fail \"" + error + "}";
}
}
}

View File

@ -33,11 +33,13 @@ public class ExtensionApiModule extends BaseApi {
@Override @Override
public String[] apis() { public String[] apis() {
return new String[]{"registerExtensionApi","addWebExtentionApi"}; return new String[]{"registerExtensionApi", "registerSyncExtensionApi", "addWebExtentionApi"};
} }
@Override @Override
public void invoke(String s, Map param, ICallback iCallback) { public void invoke(String s, Map param, ICallback iCallback) {
boolean isFinAppProcess = FinAppClient.INSTANCE.isFinAppProcess(getContext());
Log.d(TAG, "ExtensionApiModule invoke register api s:" + s + " param:" + param +" isFinAppProcess:"+isFinAppProcess);
if (s.equals("registerExtensionApi")) { if (s.equals("registerExtensionApi")) {
MethodChannel channel = MopPluginService.getInstance().getMethodChannel(); MethodChannel channel = MopPluginService.getInstance().getMethodChannel();
String name = (String) param.get("name"); String name = (String) param.get("name");
@ -50,7 +52,7 @@ public class ExtensionApiModule extends BaseApi {
@Override @Override
public void invoke(String s, JSONObject jsonObject, com.finogeeks.lib.applet.interfaces.ICallback iCallback) { public void invoke(String s, JSONObject jsonObject, com.finogeeks.lib.applet.interfaces.ICallback iCallback) {
Log.d("MopPlugin", "invoke extensionApi:" + s + ",params:" + jsonObject); Log.d("MopPlugin", "invoke extensionApi:" + s + ",params:" + jsonObject+" isFinAppProcess:"+isFinAppProcess);
Map params = GsonUtil.gson.fromJson(jsonObject.toString(), HashMap.class); Map params = GsonUtil.gson.fromJson(jsonObject.toString(), HashMap.class);
handler.post(() -> { handler.post(() -> {
channel.invokeMethod("extensionApi:" + name, params, new MethodChannel.Result() { channel.invokeMethod("extensionApi:" + name, params, new MethodChannel.Result() {
@ -87,6 +89,63 @@ public class ExtensionApiModule extends BaseApi {
iCallback.onFail(); iCallback.onFail();
} }
@Override
public void notImplemented() {
iCallback.onFail();
}
});
});
}
});
} else if (s.equals("registerSyncExtensionApi")) {
MethodChannel channel = MopPluginService.getInstance().getMethodChannel();
String name = (String) param.get("name");
Log.d(TAG, "registerSyncExtensionApi:" + name);
FinAppClient.INSTANCE.getExtensionApiManager().registerApi(new com.finogeeks.lib.applet.api.BaseApi(getContext()) {
@Override
public String[] apis() {
return new String[]{name};
}
@Override
public void invoke(String s, JSONObject jsonObject, com.finogeeks.lib.applet.interfaces.ICallback iCallback) {
Log.d("MopPlugin", "sync invoke extensionApi:" + s + ",params:" + jsonObject);
Map params = GsonUtil.gson.fromJson(jsonObject.toString(), HashMap.class);
handler.post(() -> {
channel.invokeMethod("syncextensionapi:" + name, params, new MethodChannel.Result() {
@Override
public void success(Object result) {
String json = GsonUtil.gson.toJson(result);
Log.d(ExtensionApiModule.TAG, "channel invokeMethod:" + name
+ " success, result=" + result + ", json=" + json);
JSONObject ret = null;
if (json != null && !json.equals("null")) {
try {
ret = new JSONObject(json);
if (ret.has("errMsg")) {
String errMsg = ret.getString("errMsg");
if (errMsg.startsWith(name + ":fail")) {
iCallback.onFail(ret);
return;
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
iCallback.onSuccess(ret);
}
@Override
public void error(String errorCode, String errorMessage, Object errorDetails) {
FLog.e(ExtensionApiModule.TAG, "channel invokeMethod:" + name
+ " error, errorCode=" + errorCode
+ ", errorMessage=" + errorMessage
+ ", errorDetails=" + errorDetails);
iCallback.onFail();
}
@Override @Override
public void notImplemented() { public void notImplemented() {
iCallback.onFail(); iCallback.onFail();

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

@ -21,6 +21,6 @@
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1.0</string> <string>1.0</string>
<key>MinimumOSVersion</key> <key>MinimumOSVersion</key>
<string>9.0</string> <string>11.0</string>
</dict> </dict>
</plist> </plist>

View File

@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project # Uncomment this line to define a global platform for your project
platform :ios, '9.0' platform :ios, '11.0'
source 'ssh://gitlab.finogeeks.club/finclip-ios/DevPods' source 'ssh://gitlab.finogeeks.club/finclip-ios/DevPods'
source 'ssh://gitlab.finogeeks.club/finclip-ios/FinPods' source 'ssh://gitlab.finogeeks.club/finclip-ios/FinPods'

View File

@ -3,7 +3,7 @@
archiveVersion = 1; archiveVersion = 1;
classes = { classes = {
}; };
objectVersion = 51; objectVersion = 54;
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
@ -231,10 +231,12 @@
}; };
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
); );
inputPaths = ( inputPaths = (
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
); );
name = "Thin Binary"; name = "Thin Binary";
outputPaths = ( outputPaths = (
@ -262,6 +264,7 @@
}; };
9740EEB61CF901F6004384FC /* Run Script */ = { 9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
); );
@ -351,7 +354,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0; IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos; SUPPORTED_PLATFORMS = iphoneos;
@ -430,7 +433,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0; IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = YES; MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos; SDKROOT = iphoneos;
@ -479,7 +482,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0; IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos; SUPPORTED_PLATFORMS = iphoneos;

View File

@ -43,5 +43,7 @@
</array> </array>
<key>UIViewControllerBasedStatusBarAppearance</key> <key>UIViewControllerBasedStatusBarAppearance</key>
<false/> <false/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict> </dict>
</plist> </plist>

View File

@ -216,7 +216,7 @@ class MyAppletHandler extends AppletHandler {
} }
@override @override
Future<List<CustomMenu>> getCustomMenus(String appId) { List<CustomMenu> getCustomMenus(String appId) {
CustomMenu menu1 = CustomMenu('WXTest', 'https://img1.baidu.com/it/u=2878938773,1765835171&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500', '百度图标', 'common'); CustomMenu menu1 = CustomMenu('WXTest', 'https://img1.baidu.com/it/u=2878938773,1765835171&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500', '百度图标', 'common');
menu1.darkImage = 'https://img95.699pic.com/xsj/14/46/mh.jpg%21/fw/700/watermark/url/L3hzai93YXRlcl9kZXRhaWwyLnBuZw/align/southeast'; menu1.darkImage = 'https://img95.699pic.com/xsj/14/46/mh.jpg%21/fw/700/watermark/url/L3hzai93YXRlcl9kZXRhaWwyLnBuZw/align/southeast';
@ -233,7 +233,7 @@ class MyAppletHandler extends AppletHandler {
// CustomMenu('WXShareAPPFriends', 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSpvugSNLs9R7iopz_noeotAelvgzYj-74iCg&usqp=CAU', '微信好朋友', 'common'), // CustomMenu('WXShareAPPFriends', 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSpvugSNLs9R7iopz_noeotAelvgzYj-74iCg&usqp=CAU', '微信好朋友', 'common'),
// CustomMenu('WXShareAPPMoments', 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR7cO4KB4e5-Ugdcq4pIyWunliH7LZRZzguKQ&usqp=CAU', '微信朋友圈', 'common'), // CustomMenu('WXShareAPPMoments', 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR7cO4KB4e5-Ugdcq4pIyWunliH7LZRZzguKQ&usqp=CAU', '微信朋友圈', 'common'),
]; ];
return Future.value(customMenus); return customMenus;
} }
@override @override

View File

@ -5,27 +5,31 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: async name: async
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.9.0" version: "2.11.0"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
name: boolean_selector name: boolean_selector
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.1.0" version: "2.1.1"
characters: characters:
dependency: transitive dependency: transitive
description: description:
name: characters name: characters
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.2.1" version: "1.3.0"
clock: clock:
dependency: transitive dependency: transitive
description: description:
name: clock name: clock
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.1.1" version: "1.1.1"
@ -33,13 +37,15 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: collection name: collection
sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.16.0" version: "1.17.1"
cupertino_icons: cupertino_icons:
dependency: "direct main" dependency: "direct main"
description: description:
name: cupertino_icons name: cupertino_icons
sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.0.5" version: "1.0.5"
@ -47,6 +53,7 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: fake_async name: fake_async
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.3.1" version: "1.3.1"
@ -59,6 +66,7 @@ packages:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: flutter_lints name: flutter_lints
sha256: b543301ad291598523947dc534aaddc5aaad597b709d2426d3a0e0d44c5cb493
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.0.4" version: "1.0.4"
@ -66,6 +74,7 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: flutter_plugin_android_lifecycle name: flutter_plugin_android_lifecycle
sha256: c224ac897bed083dabf11f238dd11a239809b446740be0c2044608c50029ffdf
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.0.9" version: "2.0.9"
@ -74,10 +83,19 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
js:
dependency: transitive
description:
name: js
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.6.7"
lints: lints:
dependency: transitive dependency: transitive
description: description:
name: lints name: lints
sha256: a2c3d198cb5ea2e179926622d433331d8b58374ab8f29cdda6e863bd62fd369c
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.0.1" version: "1.0.1"
@ -85,37 +103,41 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: matcher name: matcher
sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.12.12" version: "0.12.15"
material_color_utilities: material_color_utilities:
dependency: transitive dependency: transitive
description: description:
name: material_color_utilities name: material_color_utilities
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.1.5" version: "0.2.0"
meta: meta:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.8.0" version: "1.9.1"
mop: mop:
dependency: "direct main" dependency: "direct main"
description: description:
path: ".." path: ".."
relative: true relative: true
source: path source: path
version: "2.41.1" version: "2.41.5"
path: path:
dependency: transitive dependency: transitive
description: description:
name: path name: path
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.8.2" version: "1.8.3"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
@ -125,34 +147,39 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: source_span name: source_span
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.9.0" version: "1.9.1"
stack_trace: stack_trace:
dependency: transitive dependency: transitive
description: description:
name: stack_trace name: stack_trace
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.10.0" version: "1.11.0"
stream_channel: stream_channel:
dependency: transitive dependency: transitive
description: description:
name: stream_channel name: stream_channel
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.1.0" version: "2.1.1"
string_scanner: string_scanner:
dependency: transitive dependency: transitive
description: description:
name: string_scanner name: string_scanner
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.1.1" version: "1.2.0"
term_glyph: term_glyph:
dependency: transitive dependency: transitive
description: description:
name: term_glyph name: term_glyph
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.2.1" version: "1.2.1"
@ -160,16 +187,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.4.12" version: "0.5.1"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:
name: vector_math name: vector_math
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.1.2" version: "2.1.4"
sdks: sdks:
dart: ">=2.17.0-0 <3.0.0" dart: ">=3.0.0-0 <4.0.0"
flutter: ">=3.0.0" flutter: ">=3.0.0"

View File

@ -57,31 +57,33 @@
} }
- (BOOL)appletInfo:(FATAppletInfo *)appletInfo didClickMoreBtnAtPath:(NSString *)path { - (BOOL)appletInfo:(FATAppletInfo *)appletInfo didClickMoreBtnAtPath:(NSString *)path {
NSLog(@"appletInfo:didClickMoreBtnAtPath"); NSLog(@"didClickMoreBtnAtPath:%@,appletInfo=%@",path,appletInfo);
__block BOOL flag; return NO;
FlutterMethodChannel *channel = [[MopPlugin instance] methodChannel]; // __block BOOL flag;
[channel invokeMethod:@"extensionApi:customCapsuleMoreButtonClick" arguments:@{@"appId": appletInfo.appId} result:^(id _Nullable result) { // FlutterMethodChannel *channel = [[MopPlugin instance] methodChannel];
CFRunLoopStop(CFRunLoopGetMain()); // NSLog(@"appletInfo:didClickMoreBtnAtPath,appId=%@,path=%@,channel=%@",appletInfo.appId,path,channel);
if ([result isKindOfClass:[NSNumber class]]) { // [channel invokeMethod:@"extensionApi:customCapsuleMoreButtonClick" arguments:@{@"appId": appletInfo.appId} result:^(id _Nullable result) {
flag = [result boolValue]; // CFRunLoopStop(CFRunLoopGetMain());
} // if ([result isKindOfClass:[NSNumber class]]) {
}]; // flag = [result boolValue];
CFRunLoopRun(); // }
// }];
return flag; // CFRunLoopRun();
//
// return flag;
} }
- (NSArray<id<FATAppletMenuProtocol>> *)customMenusInApplet:(FATAppletInfo *)appletInfo atPath:(NSString *)path { - (NSArray<id<FATAppletMenuProtocol>> *)customMenusInApplet:(FATAppletInfo *)appletInfo atPath:(NSString *)path {
NSLog(@"customMenusInApplet"); NSLog(@"customMenusInApplet:%@,appletInfo=%@",path,appletInfo);
__block NSArray *list;
FlutterMethodChannel *channel = [[MopPlugin instance] methodChannel]; NSDictionary<NSString *, NSString *> *item1 = @{@"menuId": @"shareToChatPicId", @"title": @"Share to friends", @"image": @"miniChat", @"darkImage": @"miniChat", @"type": @"common"};
[channel invokeMethod:@"extensionApi:getCustomMenus" arguments:@{@"appId": appletInfo.appId} result:^(id _Nullable result) { NSDictionary<NSString *, NSString *> *item2 = @{@"menuId": @"shareToOutsidePicId", @"title": @"Share to others", @"image": @"miniSend", @"darkImage": @"miniSend", @"type": @"common"};
CFRunLoopStop(CFRunLoopGetMain()); NSDictionary<NSString *, NSString *> *item3 = @{@"menuId": @"shareToMomentPicId", @"title": @"Share to Moment", @"image": @"miniMoments", @"darkImage": @"miniMoments", @"type": @"common"};
if ([result isKindOfClass:[NSArray class]]) { NSDictionary<NSString *, NSString *> *item4 = @{@"menuId": @"shareQrcodePicId", @"title": @"Phiz code", @"image": @"qrCode", @"darkImage": @"qrCode", @"type": @"common"};
list = result;
}
}]; NSArray<NSDictionary<NSString *, NSString *> *> *list = @[item1, item2, item3,item4];
CFRunLoopRun(); NSLog(@"customMenusInApplet:%@,list=%@",path,list);
NSMutableArray *models = [NSMutableArray array]; NSMutableArray *models = [NSMutableArray array];
for (NSDictionary<NSString *, NSString *> *data in list) { for (NSDictionary<NSString *, NSString *> *data in list) {
@ -112,7 +114,9 @@
return models; return models;
} }
- (void)clickCustomItemMenuWithInfo:(NSDictionary *)contentInfo inApplet:(FATAppletInfo *)appletInfo completion:(void (^)(FATExtensionCode code, NSDictionary *result))completion { - (void)clickCustomItemMenuWithInfo:(NSDictionary *)contentInfo inApplet:(FATAppletInfo *)appletInfo completion:(void (^)(FATExtensionCode code, NSDictionary *result))completion {
NSLog(@"HJH1,clickCustomItemMenuWithInfo");
NSError *parseError = nil; NSError *parseError = nil;
NSMutableDictionary *shareDic = [[NSMutableDictionary alloc] initWithDictionary:[self dictionaryRepresentation:appletInfo]]; NSMutableDictionary *shareDic = [[NSMutableDictionary alloc] initWithDictionary:[self dictionaryRepresentation:appletInfo]];
[shareDic setValue:@{@"desc" : shareDic[@"originalInfo"][@"customData"][@"detailDescription"]} forKey:@"params"]; [shareDic setValue:@{@"desc" : shareDic[@"originalInfo"][@"customData"][@"detailDescription"]} forKey:@"params"];
@ -133,6 +137,7 @@
if ([@"Desktop" isEqualToString:contentInfo[@"menuId"]]) { if ([@"Desktop" isEqualToString:contentInfo[@"menuId"]]) {
[self addToDesktopItemClick:appletInfo path:contentInfo[@"path"]]; [self addToDesktopItemClick:appletInfo path:contentInfo[@"path"]];
} }
NSLog(@"HJH2,clickCustomItemMenuWithInfo");
} }
- (NSDictionary *)dictionaryRepresentation:(FATAppletInfo *)object { - (NSDictionary *)dictionaryRepresentation:(FATAppletInfo *)object {

View File

@ -7,6 +7,7 @@
#import "Mop_initSDK.h" #import "Mop_initSDK.h"
#import "MOPTools.h" #import "MOPTools.h"
#import "FinAppletExt.h"
@implementation MOP_initSDK @implementation MOP_initSDK
@ -35,6 +36,9 @@
storeConfig.encryptServerData = [dict[@"encryptServerData"] boolValue]; storeConfig.encryptServerData = [dict[@"encryptServerData"] boolValue];
storeConfig.enablePreloadFramework = [storeConfig.apiServer isEqualToString:@"https://api.finclip.com"]; storeConfig.enablePreloadFramework = [storeConfig.apiServer isEqualToString:@"https://api.finclip.com"];
[storeArrayM addObject:storeConfig]; [storeArrayM addObject:storeConfig];
//google map key
[[FATExtClient sharedClient] registerGoogleMapService:dict[@"googleMapApiKey"] placesKey:dict[@"googleMapApiKey"]];
} }
config = [FATConfig configWithStoreConfigs:storeArrayM]; config = [FATConfig configWithStoreConfigs:storeArrayM];
} else { } else {
@ -70,7 +74,6 @@
config.language = FATPreferredLanguageSimplifiedChinese; config.language = FATPreferredLanguageSimplifiedChinese;
} }
NSError* error = nil; NSError* error = nil;
FATUIConfig *uiconfig = [[FATUIConfig alloc]init]; FATUIConfig *uiconfig = [[FATUIConfig alloc]init];
if (_uiConfig) { if (_uiConfig) {

View File

@ -7,7 +7,10 @@
#import "MOP_initialize.h" #import "MOP_initialize.h"
#import <FinApplet/FinApplet.h> #import <FinApplet/FinApplet.h>
#import <FinAppletExt/FinAppletExt.h> //#import <FinAppletExt/FinAppletExt.h>
#import "FinAppletExt.h"
//#import <FinAppletClipBoard/FinAppletClipBoard.h>
#import <FinAppletBLE/FinAppletBLE.h>
#import "MOPTools.h" #import "MOPTools.h"
@implementation MOP_initialize @implementation MOP_initialize
@ -126,8 +129,9 @@
// [[FATExtClient sharedClient] fat_prepareExtensionApis]; // [[FATExtClient sharedClient] fat_prepareExtensionApis];
[[FATClient sharedClient].logManager initLogWithLogDir:nil logLevel:FATLogLevelVerbose consoleLog:YES]; [[FATClient sharedClient].logManager initLogWithLogDir:nil logLevel:FATLogLevelVerbose consoleLog:YES];
[[FATClient sharedClient] setEnableLog:YES]; [[FATClient sharedClient] setEnableLog:YES];
// ClipBoard
// [FATClipBoardComponent registerComponent];
success(@{}); success(@{});

View File

@ -0,0 +1,18 @@
//
// MOP_registerSyncExtensionApi.h
// mop
//
// Created by Stewen on 2023/6/30.
//
#import "MOPBaseApi.h"
NS_ASSUME_NONNULL_BEGIN
@interface MOP_registerSyncExtensionApi : MOPBaseApi
@property(nonatomic, copy) NSString* name;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,33 @@
//
// MOP_registerSyncExtensionApi.m
// mop
//
// Created by Stewen on 2023/6/30.
//
#import "MOP_registerSyncExtensionApi.h"
#import "MopPlugin.h"
#import <FinApplet/FinApplet.h>
#import "PhizLanguageData.h"
@implementation MOP_registerSyncExtensionApi
- (void)setupApiWithSuccess:(void (^)(NSDictionary<NSString *,id> * _Nonnull))success failure:(void (^)(id _Nullable))failure cancel:(void (^)(void))cancel
{
NSLog(@"MOP_registerSyncExtensionApi,name=%@",self.name);
FlutterMethodChannel *channel = [[MopPlugin instance] methodChannel];
[[FATClient sharedClient] registerSyncExtensionApi:self.name handler:^NSDictionary *(FATAppletInfo *appletInfo, id param) {
if([self.name isEqualToString:@"getLanguageCodeSync"]){
NSDictionary *resultDict = [NSDictionary dictionary];
NSString* shortCode = [PhizLanguageData sharedInstance].languageCode;
NSString* countryCode = [PhizLanguageData sharedInstance].countryCode;
resultDict = @{@"languageCode":shortCode,@"countryCode":countryCode};
return resultDict;
}
return @{};
}];
success(@{});
}
@end

View File

@ -0,0 +1,20 @@
//
// PhizLanguageData.h
// FinDemo
//
// Created by stewen on 2023/8/4.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface PhizLanguageData : NSObject
@property (nonatomic, copy) NSString *languageCode;
@property (nonatomic, copy) NSString *countryCode;
+ (instancetype)sharedInstance;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,23 @@
//
// PhizLanguageData.m
// FinDemo
//
// Created by stewen on 2023/8/4.
//
#import "PhizLanguageData.h"
@implementation PhizLanguageData
+ (instancetype)sharedInstance {
static PhizLanguageData *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
sharedInstance.languageCode = @"en"; // Set default language code
sharedInstance.countryCode = @"US";
});
return sharedInstance;
}
@end

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

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