├── .gitattributes ├── .gitignore ├── README.md ├── analysis_options.yaml ├── fl_amap ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── android │ ├── .gitignore │ ├── build.gradle │ ├── consumer-rules.pro │ ├── settings.gradle │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ └── fl │ │ │ └── amap │ │ │ ├── AMapGeoFence.kt │ │ │ ├── AMapLocation.kt │ │ │ └── AMapPlugin.kt │ │ └── res │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ └── mipmap-xxxhdpi │ │ └── ic_launcher.png ├── example │ ├── .gitignore │ ├── README.md │ ├── analysis_options.yaml │ ├── android │ │ ├── .gitignore │ │ ├── app │ │ │ ├── amap.jks │ │ │ ├── build.gradle.kts │ │ │ └── src │ │ │ │ ├── debug │ │ │ │ └── AndroidManifest.xml │ │ │ │ ├── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ ├── kotlin │ │ │ │ │ └── com │ │ │ │ │ │ └── fl │ │ │ │ │ │ └── amap │ │ │ │ │ │ └── example │ │ │ │ │ │ └── MainActivity.kt │ │ │ │ └── res │ │ │ │ │ ├── drawable-v21 │ │ │ │ │ └── launch_background.xml │ │ │ │ │ ├── drawable │ │ │ │ │ └── launch_background.xml │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── values-night │ │ │ │ │ └── styles.xml │ │ │ │ │ └── values │ │ │ │ │ └── styles.xml │ │ │ │ └── profile │ │ │ │ └── AndroidManifest.xml │ │ ├── build.gradle.kts │ │ ├── gradle.properties │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ └── gradle-wrapper.properties │ │ └── settings.gradle.kts │ ├── ios │ │ ├── .gitignore │ │ ├── Flutter │ │ │ ├── AppFrameworkInfo.plist │ │ │ ├── Debug.xcconfig │ │ │ └── Release.xcconfig │ │ ├── Podfile │ │ ├── Runner.xcodeproj │ │ │ ├── project.pbxproj │ │ │ └── xcshareddata │ │ │ │ └── xcschemes │ │ │ │ └── Runner.xcscheme │ │ ├── Runner.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ └── WorkspaceSettings.xcsettings │ │ └── Runner │ │ │ ├── AppDelegate.swift │ │ │ ├── Assets.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ ├── Contents.json │ │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ │ ├── Icon-App-20x20@1x.png │ │ │ │ ├── Icon-App-20x20@2x.png │ │ │ │ ├── Icon-App-20x20@3x.png │ │ │ │ ├── Icon-App-29x29@1x.png │ │ │ │ ├── Icon-App-29x29@2x.png │ │ │ │ ├── Icon-App-29x29@3x.png │ │ │ │ ├── Icon-App-40x40@1x.png │ │ │ │ ├── Icon-App-40x40@2x.png │ │ │ │ ├── Icon-App-40x40@3x.png │ │ │ │ ├── Icon-App-60x60@2x.png │ │ │ │ ├── Icon-App-60x60@3x.png │ │ │ │ ├── Icon-App-76x76@1x.png │ │ │ │ ├── Icon-App-76x76@2x.png │ │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ │ └── LaunchImage.imageset │ │ │ │ ├── Contents.json │ │ │ │ ├── LaunchImage.png │ │ │ │ ├── LaunchImage@2x.png │ │ │ │ ├── LaunchImage@3x.png │ │ │ │ └── README.md │ │ │ ├── Base.lproj │ │ │ ├── LaunchScreen.storyboard │ │ │ └── Main.storyboard │ │ │ ├── Info.plist │ │ │ ├── Runner-Bridging-Header.h │ │ │ └── Runner.entitlements │ ├── lib │ │ ├── main.dart │ │ └── src │ │ │ ├── coordinate_converter_page.dart │ │ │ ├── geo_fence_page.dart │ │ │ └── loaction_page.dart │ └── pubspec.yaml ├── format.sh ├── ios │ ├── .gitignore │ ├── Classes │ │ ├── AMapGeoFence.swift │ │ ├── AMapLocation.swift │ │ └── AMapPlugin.swift │ ├── Resources │ │ └── PrivacyInfo.xcprivacy │ └── fl_amap.podspec ├── lib │ ├── fl_amap.dart │ └── src │ │ ├── amap_geo_fence.dart │ │ ├── amap_location.dart │ │ └── enum.dart └── pubspec.yaml ├── fl_amap_map ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── android │ ├── .gitignore │ ├── build.gradle │ ├── consumer-rules.pro │ ├── settings.gradle │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── fl │ │ └── amap │ │ └── map │ │ ├── AMapMapPlugin.kt │ │ ├── Extension.kt │ │ └── map │ │ ├── AMapPlatformViewFactory.kt │ │ ├── AMapView.kt │ │ └── AMapViewListener.kt ├── example │ ├── .gitignore │ ├── README.md │ ├── analysis_options.yaml │ ├── android │ │ ├── .gitignore │ │ ├── app │ │ │ ├── amap.jks │ │ │ ├── build.gradle.kts │ │ │ └── src │ │ │ │ ├── debug │ │ │ │ └── AndroidManifest.xml │ │ │ │ ├── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ ├── kotlin │ │ │ │ │ └── com │ │ │ │ │ │ └── fl │ │ │ │ │ │ └── amap │ │ │ │ │ │ └── example │ │ │ │ │ │ └── MainActivity.kt │ │ │ │ └── res │ │ │ │ │ ├── drawable-v21 │ │ │ │ │ └── launch_background.xml │ │ │ │ │ ├── drawable │ │ │ │ │ └── launch_background.xml │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── values-night │ │ │ │ │ └── styles.xml │ │ │ │ │ └── values │ │ │ │ │ └── styles.xml │ │ │ │ └── profile │ │ │ │ └── AndroidManifest.xml │ │ ├── build.gradle.kts │ │ ├── gradle.properties │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ └── gradle-wrapper.properties │ │ └── settings.gradle.kts │ ├── ios │ │ ├── .gitignore │ │ ├── Flutter │ │ │ ├── AppFrameworkInfo.plist │ │ │ ├── Debug.xcconfig │ │ │ └── Release.xcconfig │ │ ├── Podfile │ │ ├── Runner.xcodeproj │ │ │ ├── project.pbxproj │ │ │ └── xcshareddata │ │ │ │ └── xcschemes │ │ │ │ └── Runner.xcscheme │ │ ├── Runner.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ └── WorkspaceSettings.xcsettings │ │ ├── Runner │ │ │ ├── AppDelegate.swift │ │ │ ├── Assets.xcassets │ │ │ │ ├── AppIcon.appiconset │ │ │ │ │ ├── Contents.json │ │ │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ │ │ ├── Icon-App-20x20@1x.png │ │ │ │ │ ├── Icon-App-20x20@2x.png │ │ │ │ │ ├── Icon-App-20x20@3x.png │ │ │ │ │ ├── Icon-App-29x29@1x.png │ │ │ │ │ ├── Icon-App-29x29@2x.png │ │ │ │ │ ├── Icon-App-29x29@3x.png │ │ │ │ │ ├── Icon-App-40x40@1x.png │ │ │ │ │ ├── Icon-App-40x40@2x.png │ │ │ │ │ ├── Icon-App-40x40@3x.png │ │ │ │ │ ├── Icon-App-60x60@2x.png │ │ │ │ │ ├── Icon-App-60x60@3x.png │ │ │ │ │ ├── Icon-App-76x76@1x.png │ │ │ │ │ ├── Icon-App-76x76@2x.png │ │ │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ │ │ └── LaunchImage.imageset │ │ │ │ │ ├── Contents.json │ │ │ │ │ ├── LaunchImage.png │ │ │ │ │ ├── LaunchImage@2x.png │ │ │ │ │ ├── LaunchImage@3x.png │ │ │ │ │ └── README.md │ │ │ ├── Base.lproj │ │ │ │ ├── LaunchScreen.storyboard │ │ │ │ └── Main.storyboard │ │ │ ├── Info.plist │ │ │ └── Runner-Bridging-Header.h │ │ └── RunnerTests │ │ │ └── RunnerTests.swift │ ├── lib │ │ ├── main.dart │ │ └── src │ │ │ └── map_view_page.dart │ └── pubspec.yaml ├── ios │ ├── .gitignore │ ├── Classes │ │ ├── AMapPlugin.swift │ │ ├── Extension.swift │ │ └── map │ │ │ ├── AMapPlatformViewFactory.swift │ │ │ ├── AMapView.swift │ │ │ └── AMapViewDelegate.swift │ ├── Resources │ │ └── PrivacyInfo.xcprivacy │ └── fl_amap_map.podspec ├── lib │ ├── fl_amap_map.dart │ └── src │ │ ├── amap_view.dart │ │ ├── controller.dart │ │ ├── controller_for_android.dart │ │ ├── controller_for_ios.dart │ │ ├── enum.dart │ │ └── model.dart └── pubspec.yaml ├── format.sh └── pubspec.yaml /.gitattributes: -------------------------------------------------------------------------------- 1 | *.dart linguist-language=Dart 2 | *.h linguist-language=Dart 3 | *.m linguist-language=Dart 4 | *.html linguist-language=Dart 5 | *.xml linguist-language=Dart 6 | *.xml linguist-language=Dart 7 | *.java linguist-language=Dart 8 | *.md linguist-language=Dart 9 | *.cmd linguist-language=Dart 10 | *.dart linguist-language=Dart 11 | *.swift linguist-language=Dart -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # OSX 3 | # 4 | .DS_Store 5 | 6 | 7 | # Xcode 8 | # 9 | build/ 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata 19 | *.xccheckout 20 | *.moved-aside 21 | DerivedData 22 | *.hmap 23 | *.ipa 24 | *.xcuserstate 25 | project.xcworkspace 26 | 27 | 28 | # Android/IntelliJ 29 | # 30 | build/ 31 | .idea 32 | .gradle 33 | local.properties 34 | *.iml 35 | *.lock 36 | *.packages 37 | 38 | # BUCK 39 | buck-out/ 40 | \.buckd/ 41 | *.keystore 42 | /.dart_tool/ 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 高德地图 2 | 3 | ### [fl_amap](https://github.com/Wayaer/fl_amap/tree/main/fl_amap) 4 | 5 | - 高德定位 地理围栏 6 | 7 | ### [fl_amap_amap](https://github.com/Wayaer/fl_amap/tree/main/fl_amap_map) 8 | 9 | - 高德地图(...) 10 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml -------------------------------------------------------------------------------- /fl_amap/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # OSX 3 | # 4 | .DS_Store 5 | 6 | 7 | # Xcode 8 | # 9 | build/ 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata 19 | *.xccheckout 20 | *.moved-aside 21 | DerivedData 22 | *.hmap 23 | *.ipa 24 | *.xcuserstate 25 | project.xcworkspace 26 | 27 | 28 | # Android/IntelliJ 29 | # 30 | build/ 31 | .idea 32 | .gradle 33 | local.properties 34 | *.iml 35 | *.lock 36 | *.packages 37 | 38 | # BUCK 39 | buck-out/ 40 | \.buckd/ 41 | *.keystore 42 | /.dart_tool/ 43 | -------------------------------------------------------------------------------- /fl_amap/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 3.4.3 2 | 3 | * 修复在 ios 上的错误 4 | 5 | ## 3.4.2 6 | 7 | * JDK to 17 8 | * `setAMapKey` 改为 ` FlAMap().setAMapKey()` 9 | 10 | ## 3.4.0 11 | 12 | * 迁移至 3.27 13 | 14 | ## 3.3.0 15 | 16 | * 高德定位初始化添加默认配置 17 | 18 | ## 3.2.0 19 | 20 | * 支持其他地图经纬度转换 `coordinateConverter()` 21 | * 支持校验是否为有效经纬度 `isAMapDataAvailable()` 22 | * 支持坐标点距离计算(仅支持android)`calculateLineDistance()` 23 | 24 | ## 3.1.0 25 | 26 | * 更新 android sdk版本 27 | 28 | ## 3.0.1 29 | 30 | * 修改ios默认定位精度为十米级,和上个版本一致 31 | * 修改ios默认获取逆地理位置 32 | 33 | ## 3.0.0 34 | 35 | * 设置定位参数,返回定位信息均添加详细文档说明,且数据完整 36 | * 区分`android`和`ios` 37 | 的返回定位信息,返回数据均有不同,且数据完整,`AMapLocation`、`AMapLocationForIOS`、 38 | `AMapLocationForAndroid` 39 | * 区分`android`和`ios` 40 | 的定位参数配置,可进行多次配置更新,`AMapLocationOptionForIOS`、`AMapLocationOptionForAndroid` 41 | * `android`支持设置前台任务服务,保证后台定位常驻,使用`enableBackgroundLocation` 42 | 和`disableBackgroundLocation`开启和关闭 43 | * `ios`添加 `headingAvailable`(设备是否支持方向识别)、`startUpdatingHeading`( 44 | 开始获取设备朝向)、`stopUpdatingHeading`(停止获取设备朝向)、`dismissHeadingCalibrationDisplay`( 45 | 停止设备朝向校准显示) 46 | 47 | ## 2.5.3 48 | 49 | * Upgrade the Android AMap locating SDK 50 | * Add `namespace` in Android 51 | 52 | ## 2.5.1 53 | 54 | * Fixed issues on ios 55 | 56 | ## 2.5.0 57 | 58 | * Modify some nouns 59 | 60 | ## 2.3.1+1 61 | 62 | * Upgrade gradle version 63 | 64 | ## 2.1.0 65 | 66 | * Upgrade the Android AMap locating SDK 67 | * Compatible with flutter 3.0.0 68 | 69 | ## 2.0.0 70 | 71 | * Upgrade the Android AMap locating SDK to 5.6.0 72 | * To upgrade the ios AMap SDK to 2.8.0, run the `pod update` command to update the SDK to 2.8.0 73 | * Add SDK compliance use scheme [AMap doc](https://lbs.amap.com/news/sdkhgsy) 74 | 75 | ## 1.2.0 76 | 77 | * Change IOS OC to swift 78 | * Simplify geofencing services 79 | * Fix bugs 80 | 81 | ## 1.1.0 82 | 83 | * Remove instance , direct initialization 84 | * Update gradle version 85 | * Update kotlin version 86 | 87 | ## 1.0.0 88 | 89 | * Add Singleton Pattern 90 | * Upgrade Android Gradle 91 | * Upgrade Android AMap SDK version 92 | 93 | ## 0.2.1 94 | 95 | * Upgrade Android AMap SDK version 96 | * Add platform restrictions 97 | 98 | ## 0.2.0 99 | 100 | * Add AMapGeoFence 101 | 102 | ## 0.1.3 103 | 104 | * Update Android com.android.tools.build:gradle version 105 | * Replace jcenter() to mavenCentral() 106 | 107 | ## 0.1.2 108 | 109 | * Add Android proguard rules 110 | 111 | ## 0.1.1 112 | 113 | * Normative approach 114 | * Fix bugs 115 | * Modify APIs 116 | * Android add consumer-rules.pro 117 | 118 | ## 0.0.6 119 | 120 | * Example update to 2.12.1 121 | * Update dart version to 2.12.1 122 | 123 | ## 0.0.3 124 | 125 | * Support single location 126 | * Support location monitoring -------------------------------------------------------------------------------- /fl_amap/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Wayaer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /fl_amap/README.md: -------------------------------------------------------------------------------- 1 | 高德地图定位flutter组件。 2 | 3 | 目前实现获取定位和监听定位功能。 4 | 5 | 1、申请一个key 6 | http://lbs.amap.com/api/ios-sdk/guide/create-project/get-key 7 | 8 | 直接在dart文件中设置key 9 | 10 | * 权限申请需要额外使用 [permission_handler](https://pub.dev/packages/permission_handler) 或者其他的第三方包 11 | 12 | # ios 13 | 14 | 1. 在info.plist中增加: 15 | 16 | ``` 17 | NSLocationWhenInUseUsageDescription 18 | 要用定位 19 | ``` 20 | 21 | 如果ios定位没有返回逆地理信息,添加一下内容 22 | 23 | ``` 24 | NSAppTransportSecurity 25 | 26 | NSAllowsArbitraryLoads 27 | 28 | NSAllowsArbitraryLoadsForMedia 29 | 30 | NSAllowsArbitraryLoadsInWebContent 31 | 32 | /// 解决ios HTTP 警告,需要添加的 33 | NSExceptionDomains 34 | 35 | restios.amap.com/key> 36 | 37 | NSExceptionAllowsInsecureHTTPLoads 38 | 39 | NSIncludesSubdomains 40 | 41 | NSExceptionMinimumTLSVersion 42 | TLSv1.2 43 | 44 | 45 | 46 | ``` 47 | 48 | 2. iOS 9及以上版本使用后台定位功能, 需要保证"Background Modes"中的"Location updates"处于选中状态 49 | 50 | 3.使用地理围栏 51 | 52 | iOS14及以上版本使用地理围栏功能,需要在plist中配置NSLocationTemporaryUsageDescriptionDictionary字典描述, 53 | 且添加自定义Key描述地理围栏的使用场景,此描述会在申请临时精确定位权限的弹窗中展示。 54 | 该回调触发条件:拥有定位权限,但是没有获得精确定位权限的情况下,会触发该回调。此方法实现调用申请临时精确定位权限API即可; 55 | 56 | ** 需要注意,在iOS9及之后版本的系统中,如果您希望程序在后台持续检测围栏触发行为,需要保证manager的 57 | allowsBackgroundLocationUpdates 为 YES, 58 | 设置为YES的时候必须保证 Background Modes 中的 Location updates 处于选中状态,否则会抛出异常。 59 | 60 | # android 61 | 62 | - `android/src/main/AndroidManifest.xml` 添加以下内容 具体参考 `example` 63 | 64 | ```xml 65 | 66 | 67 | 68 | /// 需要配置的 69 | 70 | 71 | 72 | 73 | ``` 74 | 75 | ## 开始使用 76 | 77 | ## 高德定位功能 78 | 79 | - 设置key 80 | 81 | ```dart 82 | 83 | Future setAMapKey() async { 84 | final bool key = await FlAMap().setAMapKey( 85 | iosKey: 'ios key', 86 | androidKey: 'android key'); 87 | 88 | if (key != null && key) print('高德地图ApiKey设置成功'); 89 | } 90 | 91 | ``` 92 | 93 | - 初始化定位参数 94 | 95 | ```dart 96 | Future initialize() async { 97 | /// 获取权限 98 | if (getPermissions) return; 99 | 100 | /// 初始化AMap 101 | final bool data = await FlAMapLocation().initialize(); 102 | if (data) { 103 | show('初始化成功'); 104 | } 105 | } 106 | 107 | ``` 108 | 109 | - 单次获取定位 110 | 111 | ```dart 112 | Future getLocation() async { 113 | /// 务必先初始化 并获取权限 114 | if (getPermissions) return; 115 | AMapLocation location = await FlAMapLocation().getLocation(); 116 | if (isAndroid) { 117 | AMapLocation is AMapLocationForAndroid; 118 | } 119 | if (isIOS) { 120 | AMapLocation is AMapLocationForIOS; 121 | } 122 | } 123 | 124 | ``` 125 | 126 | - 开启定位变化监听 127 | 128 | ```dart 129 | Future startLocationChange() async { 130 | /// 务必先初始化 并获取权限 131 | FlAMapLocation().addListener( 132 | 133 | /// 连续定位回调 android & ios 均支持 134 | onLocationChanged: (AMapLocation? location) { 135 | locationState.value = location; 136 | }, 137 | 138 | /// ios连续定位 错误监听 仅在ios中生效 139 | onLocationFailed: (AMapLocationError? error) { 140 | text.value = 'ios 连续定位错误:${error?.toMap()}'; 141 | }, 142 | 143 | /// 监听设备朝向变化 仅在ios中生效 144 | onHeadingChanged: (AMapLocationHeading? heading) { 145 | headingState.value = heading; 146 | }, 147 | 148 | /// 监听权限状态变化 仅在ios中生效 149 | onAuthorizationChanged: (int? status) { 150 | text.value = 'ios 权限状态变化:$status'; 151 | }); 152 | } 153 | 154 | ``` 155 | 156 | - 关闭定位变化监听 157 | 158 | ```dart 159 | void stopLocation() { 160 | FlAMapLocation().stopLocation(); 161 | } 162 | ``` 163 | 164 | - 关闭定位服务 165 | 166 | ```dart 167 | void dispose() { 168 | FlAMapLocation().dispose(); 169 | } 170 | ``` 171 | 172 | - 开启前台任务 仅支持android 8.0 + 173 | 如需开启前台任务需要添加以下配置 至 `android/src/main/AndroidManifest.xml` 具体参考 `example` 174 | 175 | ```xml 176 | 177 | 178 | /// 需要添加的权限 179 | 180 | 181 | /// 需要配置的服务 182 | 184 | 185 | 186 | ``` 187 | 188 | ```dart 189 | 190 | void enableBackgroundLocation() { 191 | FlAMapLocation().enableBackgroundLocation( 192 | AMapNotificationForAndroid( 193 | notificationId: 999, 194 | title: '我在定位', 195 | content: '我正在定位', 196 | channelId: 'channelId', 197 | channelName: 'name', 198 | lightColor: Colors.red)); 199 | } 200 | ``` 201 | 202 | - 关闭前台任务 仅支持android 203 | 204 | ```dart 205 | void disableBackgroundLocation() { 206 | FlAMapLocation().disableBackgroundLocation(); 207 | } 208 | ``` 209 | 210 | - 设备是否支持方向识别 仅支持ios 211 | 212 | ```dart 213 | void headingAvailable() async { 214 | final result = await location.headingAvailable(); 215 | } 216 | ``` 217 | 218 | - 开始获取设备朝向 仅支持ios 219 | 220 | ```dart 221 | void startUpdatingHeading() async { 222 | await location.startUpdatingHeading(); 223 | } 224 | ``` 225 | 226 | - 停止获取设备朝向 仅支持ios 227 | 228 | ```dart 229 | void stopUpdatingHeading() async { 230 | await location.stopUpdatingHeading(); 231 | } 232 | ``` 233 | 234 | - 停止设备朝向校准显示 仅支持ios 235 | 236 | ```dart 237 | void dismissHeadingCalibrationDisplay() async { 238 | await location.dismissHeadingCalibrationDisplay(); 239 | } 240 | ``` 241 | 242 | ## 高德地理围栏功能 243 | 244 | - 初始化地理围栏 245 | 246 | ```dart 247 | 248 | Future get initialize async { 249 | final bool data = await FlAMapGeoFence().initialize(GeoFenceActivateAction.stayed); 250 | if (data) { 251 | show('初始化地理围栏:$data'); 252 | } 253 | } 254 | 255 | ``` 256 | 257 | - 关闭围栏服务 258 | 259 | ```dart 260 | void dispose() { 261 | super.dispose(); 262 | FlAMapGeoFence().dispose(); 263 | } 264 | ``` 265 | 266 | - 根据POI添加围栏 267 | 268 | ```dart 269 | Future addPOI() async { 270 | final AMapPoiModel model = AMapPoiModel( 271 | keyword: '首开广场', 272 | poiType: '写字楼', 273 | city: '北京', 274 | size: 1, 275 | customId: '000FATE23(考勤打卡)'); 276 | final bool state = await FlAMapGeoFence().addPOI(model); 277 | } 278 | ``` 279 | 280 | - 根据坐标关键字添加围栏 281 | 282 | ```dart 283 | Future addLatLng() async { 284 | final LatLng latLng = LatLng(39.933921, 116.372927); 285 | final AMapLatLngModel model = AMapLatLngModel( 286 | latLng: latLng, 287 | keyword: '首开广场', 288 | poiType: '', 289 | customId: '000FATE23(考勤打卡)', 290 | size: 20, 291 | aroundRadius: 1000); 292 | final bool state = await FlAMapGeoFence().addLatLng(model); 293 | } 294 | ``` 295 | 296 | - 添加行政区划围栏 297 | 298 | ```dart 299 | Future addDistrict() async { 300 | final bool state = await FlAMapGeoFence().addDistrict( 301 | keyword: '海淀区', customId: '000FATE23(考勤打卡)'); 302 | } 303 | ``` 304 | 305 | - 添加圆形围栏 306 | 307 | ```dart 308 | Future addCircle() async { 309 | final LatLng latLng = LatLng(30.651411, 103.998638); 310 | final bool state = await FlAMapGeoFence().addCircle( 311 | latLng: latLng, 312 | radius: 10, 313 | customId: '000FATE23(考勤打卡)'); 314 | } 315 | ``` 316 | 317 | - 添加多边形围栏 318 | 319 | ```dart 320 | Future addCustom() async { 321 | final bool state = await FlAMapGeoFence().addCustom(latLngs: [ 322 | LatLng(39.933921, 116.372927), 323 | LatLng(39.907261, 116.376532), 324 | LatLng(39.900611, 116.418161), 325 | LatLng(39.941949, 116.435497), 326 | ], customId: '000FATE23(考勤打卡)'); 327 | } 328 | ``` 329 | 330 | - 获取所有围栏信息 331 | 332 | ```dart 333 | Future getAll() async { 334 | /// 传入 customID 获取指定标识的围栏信息 仅支持ios 335 | final List data = await FlAMapGeoFence().getAll(); 336 | } 337 | ``` 338 | 339 | - 删除地理围栏 340 | 341 | ```dart 342 | Future remove() async { 343 | /// 传入 customID 删除指定标识的围栏 344 | /// 不传 删除所有围栏 345 | final bool state = await FlAMapGeoFence().remove(); 346 | } 347 | ``` 348 | 349 | - 暂停监听围栏 350 | 351 | ```dart 352 | Future pause() async { 353 | /// 传入 customID 暂停指定标识的围栏 354 | /// 不传 暂停所有围栏 355 | final bool state = await FlAMapGeoFence().pause(); 356 | } 357 | ``` 358 | 359 | - 开始监听围栏 360 | 361 | ```dart 362 | Future start() async { 363 | /// 传入 customID 开始指定标识的围栏 364 | /// 不传 开始所有围栏 365 | final bool state = await FlAMapGeoFence().start(); 366 | } 367 | ``` -------------------------------------------------------------------------------- /fl_amap/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml -------------------------------------------------------------------------------- /fl_amap/android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /fl_amap/android/build.gradle: -------------------------------------------------------------------------------- 1 | group 'fl.amap' 2 | version '1.0' 3 | 4 | buildscript { 5 | repositories { 6 | google() 7 | mavenCentral() 8 | } 9 | 10 | dependencies { 11 | classpath 'com.android.tools.build:gradle:8.5.2' 12 | } 13 | } 14 | 15 | rootProject.allprojects { 16 | repositories { 17 | google() 18 | mavenCentral() 19 | } 20 | } 21 | 22 | apply plugin: 'com.android.library' 23 | apply plugin: 'kotlin-android' 24 | 25 | android { 26 | compileSdk = 34 27 | 28 | if (project.android.hasProperty("namespace")) { 29 | namespace 'fl.amap' 30 | } 31 | 32 | compileOptions { 33 | sourceCompatibility = JavaVersion.VERSION_17 34 | targetCompatibility = JavaVersion.VERSION_17 35 | } 36 | 37 | kotlinOptions { 38 | jvmTarget = JavaVersion.VERSION_17.toString() 39 | } 40 | 41 | sourceSets { 42 | main.java.srcDirs += 'src/main/kotlin' 43 | } 44 | 45 | defaultConfig { 46 | minSdk = 21 47 | consumerProguardFiles 'consumer-rules.pro' 48 | } 49 | 50 | packagingOptions { 51 | merge 'AndroidManifest.xml' 52 | merge 'R.txt' 53 | merge 'classes.jar' 54 | merge 'proguard.txt' 55 | } 56 | 57 | dependencies { 58 | api 'com.amap.api:location:6.4.9' 59 | } 60 | } -------------------------------------------------------------------------------- /fl_amap/android/consumer-rules.pro: -------------------------------------------------------------------------------- 1 | -keep class com.amap.api.location.**{*;} 2 | -keep class com.amap.api.fence.**{*;} 3 | -keep class com.autonavi.aps.amapapi.model.**{*;} 4 | -keep class com.loc.**{*;} 5 | -------------------------------------------------------------------------------- /fl_amap/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'fl_amap' 2 | -------------------------------------------------------------------------------- /fl_amap/android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | 16 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /fl_amap/android/src/main/kotlin/fl/amap/AMapPlugin.kt: -------------------------------------------------------------------------------- 1 | package fl.amap 2 | 3 | import io.flutter.embedding.engine.plugins.FlutterPlugin 4 | import io.flutter.plugin.common.MethodCall 5 | import io.flutter.plugin.common.MethodChannel 6 | 7 | 8 | class AMapPlugin : FlutterPlugin { 9 | private var location: AMapLocation? = null 10 | private var geoFence: AMapGeoFence? = null 11 | 12 | override fun onAttachedToEngine(plugin: FlutterPlugin.FlutterPluginBinding) { 13 | location = AMapLocation(plugin) 14 | geoFence = AMapGeoFence(plugin) 15 | } 16 | 17 | 18 | override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { 19 | location?.detached() 20 | geoFence?.detached() 21 | } 22 | 23 | } 24 | 25 | -------------------------------------------------------------------------------- /fl_amap/android/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap/android/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /fl_amap/android/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap/android/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /fl_amap/android/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap/android/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /fl_amap/android/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap/android/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /fl_amap/android/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap/android/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /fl_amap/example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | .lock 12 | .iml 13 | .metadata 14 | 15 | # IntelliJ related 16 | *.iml 17 | *.ipr 18 | *.iws 19 | .idea/ 20 | 21 | # The .vscode folder contains launch configuration and tasks you configure in 22 | # VS Code which you may wish to be included in version control, so this line 23 | # is commented out by default. 24 | #.vscode/ 25 | 26 | # Flutter/Dart/Pub related 27 | **/doc/api/ 28 | **/ios/Flutter/.last_build_id 29 | .dart_tool/ 30 | .flutter-plugins 31 | .flutter-plugins-dependencies 32 | .packages 33 | .pub-cache/ 34 | .pub/ 35 | /build/ 36 | 37 | # Web related 38 | lib/generated_plugin_registrant.dart 39 | 40 | # Symbolication related 41 | app.*.symbols 42 | 43 | # Obfuscation related 44 | app.*.map.json 45 | 46 | # Android Studio will place build artifacts here 47 | /android/app/debug 48 | /android/app/profile 49 | /android/app/release 50 | -------------------------------------------------------------------------------- /fl_amap/example/README.md: -------------------------------------------------------------------------------- 1 | # example -------------------------------------------------------------------------------- /fl_amap/example/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml -------------------------------------------------------------------------------- /fl_amap/example/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | .cxx 13 | .kotlin -------------------------------------------------------------------------------- /fl_amap/example/android/app/amap.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap/example/android/app/amap.jks -------------------------------------------------------------------------------- /fl_amap/example/android/app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("com.android.application") 3 | id("kotlin-android") 4 | id("dev.flutter.flutter-gradle-plugin") 5 | } 6 | 7 | android { 8 | namespace = "com.fl.amap.example" 9 | compileSdk = flutter.compileSdkVersion 10 | 11 | compileOptions { 12 | sourceCompatibility = JavaVersion.VERSION_21 13 | targetCompatibility = JavaVersion.VERSION_21 14 | } 15 | 16 | kotlinOptions { 17 | jvmTarget = JavaVersion.VERSION_21.toString() 18 | } 19 | 20 | defaultConfig { 21 | applicationId = "com.fl.amap.example" 22 | minSdk = flutter.minSdkVersion 23 | targetSdk = flutter.targetSdkVersion 24 | versionCode = flutter.versionCode 25 | versionName = flutter.versionName 26 | } 27 | 28 | signingConfigs { 29 | create("release") { 30 | storeFile = file("amap.jks") 31 | storePassword = "amap123" 32 | keyAlias = "amap" 33 | keyPassword = "amap123" 34 | } 35 | } 36 | 37 | buildTypes { 38 | getByName("debug") { 39 | signingConfig = signingConfigs.getByName("release") 40 | proguardFiles(getDefaultProguardFile("proguard-android.txt"), "consumer-rules.pro") 41 | } 42 | getByName("release") { 43 | signingConfig = signingConfigs.getByName("release") 44 | proguardFiles(getDefaultProguardFile("proguard-android.txt"), "consumer-rules.pro") 45 | } 46 | } 47 | 48 | } 49 | 50 | flutter { 51 | source = "../.." 52 | } 53 | -------------------------------------------------------------------------------- /fl_amap/example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /fl_amap/example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 15 | 23 | 24 | 27 | 28 | 29 | 30 | 31 | 32 | 34 | 37 | 42 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /fl_amap/example/android/app/src/main/kotlin/com/fl/amap/example/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.fl.amap.example 2 | 3 | import androidx.annotation.NonNull 4 | import io.flutter.embedding.android.FlutterActivity 5 | import io.flutter.embedding.engine.FlutterEngine 6 | import io.flutter.plugins.GeneratedPluginRegistrant 7 | 8 | class MainActivity: FlutterActivity() { 9 | override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { 10 | GeneratedPluginRegistrant.registerWith(flutterEngine); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /fl_amap/example/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /fl_amap/example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /fl_amap/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /fl_amap/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /fl_amap/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /fl_amap/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /fl_amap/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /fl_amap/example/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /fl_amap/example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /fl_amap/example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /fl_amap/example/android/build.gradle.kts: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | } 7 | 8 | val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get() 9 | rootProject.layout.buildDirectory.value(newBuildDir) 10 | 11 | subprojects { 12 | val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) 13 | project.layout.buildDirectory.value(newSubprojectBuildDir) 14 | } 15 | subprojects { 16 | project.evaluationDependsOn(":app") 17 | } 18 | 19 | tasks.register("clean") { 20 | delete(rootProject.layout.buildDirectory) 21 | } 22 | -------------------------------------------------------------------------------- /fl_amap/example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /fl_amap/example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip 6 | -------------------------------------------------------------------------------- /fl_amap/example/android/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | val flutterSdkPath = run { 3 | val properties = java.util.Properties() 4 | file("local.properties").inputStream().use { properties.load(it) } 5 | val flutterSdkPath = properties.getProperty("flutter.sdk") 6 | require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } 7 | flutterSdkPath 8 | } 9 | 10 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") 11 | 12 | repositories { 13 | google() 14 | mavenCentral() 15 | gradlePluginPortal() 16 | } 17 | } 18 | 19 | plugins { 20 | id("dev.flutter.flutter-plugin-loader") version "1.0.0" 21 | id("com.android.application") version "8.7.0" apply false 22 | id("org.jetbrains.kotlin.android") version "2.0.20" apply false 23 | } 24 | 25 | include(":app") 26 | -------------------------------------------------------------------------------- /fl_amap/example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /fl_amap/example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 12.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /fl_amap/example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /fl_amap/example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /fl_amap/example/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | platform :ios, '13.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | end 36 | 37 | post_install do |installer| 38 | installer.pods_project.targets.each do |target| 39 | flutter_additional_ios_build_settings(target) 40 | # Start of the permission_handler configuration 41 | target.build_configurations.each do |config| 42 | config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [ 43 | '$(inherited)', 44 | 45 | ## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse] 46 | 'PERMISSION_LOCATION=1', 47 | ] 48 | end 49 | # End of the permission_handler configuration 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @main 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CADisableMinimumFrameDurationOnPhone 6 | 7 | CFBundleDevelopmentRegion 8 | $(DEVELOPMENT_LANGUAGE) 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | FlAMap 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(FLUTTER_BUILD_NUMBER) 25 | LSRequiresIPhoneOS 26 | 27 | NSAppTransportSecurity 28 | 29 | NSAllowsArbitraryLoads 30 | 31 | NSAllowsArbitraryLoadsForMedia 32 | 33 | NSAllowsArbitraryLoadsInWebContent 34 | 35 | NSExceptionDomains 36 | 37 | restios.amap.com 38 | 39 | NSExceptionAllowsInsecureHTTPLoads 40 | 41 | NSExceptionMinimumTLSVersion 42 | TLSv1.2 43 | NSIncludesSubdomains 44 | 45 | 46 | 47 | 48 | NSLocationAlwaysAndWhenInUseUsageDescription 49 | 获取定位 50 | NSLocationAlwaysUsageDescription 51 | 获取定位 52 | NSLocationWhenInUseUsageDescription 53 | 获取定位 54 | UIApplicationSupportsIndirectInputEvents 55 | 56 | UIBackgroundModes 57 | 58 | fetch 59 | location 60 | processing 61 | remote-notification 62 | 63 | UILaunchStoryboardName 64 | LaunchScreen 65 | UIMainStoryboardFile 66 | Main 67 | UISupportedInterfaceOrientations 68 | 69 | UIInterfaceOrientationPortrait 70 | 71 | UISupportedInterfaceOrientations~ipad 72 | 73 | UIInterfaceOrientationPortrait 74 | UIInterfaceOrientationPortraitUpsideDown 75 | UIInterfaceOrientationLandscapeLeft 76 | UIInterfaceOrientationLandscapeRight 77 | 78 | UIViewControllerBasedStatusBarAppearance 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /fl_amap/example/ios/Runner/Runner.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.networking.wifi-info 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /fl_amap/example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:example/src/coordinate_converter_page.dart'; 2 | import 'package:example/src/geo_fence_page.dart'; 3 | import 'package:example/src/loaction_page.dart'; 4 | import 'package:fl_amap/fl_amap.dart'; 5 | import 'package:fl_extended/fl_extended.dart'; 6 | import 'package:flutter/material.dart'; 7 | import 'package:permission_handler/permission_handler.dart'; 8 | 9 | void main() { 10 | WidgetsFlutterBinding.ensureInitialized(); 11 | runApp(MaterialApp( 12 | navigatorKey: FlExtended().navigatorKey, 13 | scaffoldMessengerKey: FlExtended().scaffoldMessengerKey, 14 | debugShowCheckedModeBanner: false, 15 | title: 'FlAMap', 16 | theme: ThemeData.light(), 17 | darkTheme: ThemeData.dark(), 18 | home: Scaffold( 19 | appBar: AppBar(title: const Text('高德定位')), body: const App()))); 20 | } 21 | 22 | class App extends StatelessWidget { 23 | const App({super.key}); 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | bool isInit = false; 28 | return Universal( 29 | width: double.infinity, 30 | mainAxisAlignment: MainAxisAlignment.center, 31 | crossAxisAlignment: CrossAxisAlignment.center, 32 | children: [ 33 | ElevatedText( 34 | onPressed: () async { 35 | isInit = await FlAMap().setAMapKey( 36 | iosKey: '7d3261c06027bdc87aca547c99ad5b2f', 37 | // iosKey: 'e0e98395277890e48caa0c4bed423ead', 38 | androidKey: '77418e726d0eefc0ac79a8619b5f4d97', 39 | isAgree: true, 40 | isContains: true, 41 | isShow: true); 42 | showToast('高德地图ApiKey设置$isInit'); 43 | }, 44 | text: '设置高德key'), 45 | ElevatedText( 46 | onPressed: () { 47 | if (!isInit) { 48 | showToast('请先设置高德key'); 49 | return; 50 | } 51 | push(const AMapLocationPage()); 52 | }, 53 | text: '高德定位功能'), 54 | ElevatedText( 55 | onPressed: () { 56 | if (!isInit) { 57 | showToast('请先设置高德key'); 58 | return; 59 | } 60 | push(const AMapGeoFencePage()); 61 | }, 62 | text: '高德地理围栏功能'), 63 | ElevatedText( 64 | onPressed: () { 65 | push(const CoordinateConverterPage()); 66 | }, 67 | text: '坐标转换器'), 68 | ]); 69 | } 70 | } 71 | 72 | class ElevatedText extends StatelessWidget { 73 | const ElevatedText({super.key, required this.text, required this.onPressed}); 74 | 75 | final String text; 76 | final VoidCallback onPressed; 77 | 78 | @override 79 | Widget build(BuildContext context) => 80 | ElevatedButton(onPressed: onPressed, child: Text(text)); 81 | } 82 | 83 | Future getPermission(Permission permission) async { 84 | final PermissionStatus status = await permission.request(); 85 | if (!status.isGranted) { 86 | await openAppSettings(); 87 | return await permission.request().isGranted; 88 | } 89 | return status.isGranted; 90 | } 91 | -------------------------------------------------------------------------------- /fl_amap/example/lib/src/coordinate_converter_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:example/main.dart'; 2 | import 'package:fl_amap/fl_amap.dart'; 3 | import 'package:fl_extended/fl_extended.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class CoordinateConverterPage extends StatefulWidget { 7 | const CoordinateConverterPage({super.key}); 8 | 9 | @override 10 | State createState() => 11 | _CoordinateConverterPageState(); 12 | } 13 | 14 | class _CoordinateConverterPageState extends State { 15 | LatLng? otherLatLng; 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return Scaffold( 20 | appBar: AppBar(title: const Text('高德地理围栏')), 21 | body: Padding( 22 | padding: const EdgeInsets.all(12.0), 23 | child: Column(children: children), 24 | )); 25 | } 26 | 27 | TextEditingController latitudeController = 28 | TextEditingController(text: '39.950842'); 29 | TextEditingController longitudeController = 30 | TextEditingController(text: '116.360072'); 31 | 32 | CoordType coordType = CoordType.baidu; 33 | 34 | List get children => [ 35 | Row(children: [ 36 | TextField( 37 | controller: longitudeController, 38 | decoration: InputDecoration(hintText: 'longitude')) 39 | .expanded, 40 | 20.widthBox, 41 | TextField( 42 | controller: latitudeController, 43 | decoration: InputDecoration(hintText: 'latitude'), 44 | ).expanded, 45 | ]), 46 | 20.heightBox, 47 | PopupMenuButton( 48 | initialValue: coordType, 49 | onSelected: (value) { 50 | coordType = value; 51 | }, 52 | child: Universal( 53 | mainAxisSize: MainAxisSize.min, 54 | direction: Axis.horizontal, 55 | padding: EdgeInsets.symmetric(vertical: 10), 56 | children: [ 57 | Text('转换类型:${coordType.name}'), 58 | 10.widthBox, 59 | Icon(Icons.arrow_circle_down_rounded) 60 | ]), 61 | itemBuilder: (_) => CoordType.values 62 | .builder((e) => PopupMenuItem(value: e, child: Text(e.name)))), 63 | ElevatedText(text: '转换', onPressed: convert), 64 | if (otherLatLng != null) 65 | Padding( 66 | padding: const EdgeInsets.all(8.0), 67 | child: Text('转换后的坐标:\n${otherLatLng?.toMap()}', 68 | textAlign: TextAlign.center)), 69 | ]; 70 | 71 | convert() async { 72 | final latitude = double.tryParse(latitudeController.text); 73 | final longitude = double.tryParse(longitudeController.text); 74 | if (latitude == null || longitude == null) { 75 | showToast('请输入正确的经纬度'); 76 | return; 77 | } 78 | final result = await FlAMapLocation() 79 | .coordinateConverter(LatLng(latitude, longitude), coordType); 80 | if (result == null) { 81 | showToast('转换失败'); 82 | return; 83 | } 84 | switch (result.code) { 85 | case null: 86 | break; 87 | case CoordinateConverterResultCode.success: 88 | if (result.latLng != null) { 89 | otherLatLng = result.latLng; 90 | setState(() {}); 91 | } 92 | break; 93 | case CoordinateConverterResultCode.exception: 94 | if (result.message != null) { 95 | showToast(result.message!); 96 | } 97 | break; 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /fl_amap/example/lib/src/geo_fence_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:example/main.dart'; 2 | import 'package:fl_amap/fl_amap.dart'; 3 | import 'package:fl_dio/fl_dio.dart'; 4 | import 'package:fl_extended/fl_extended.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:permission_handler/permission_handler.dart'; 7 | 8 | class AMapGeoFencePage extends StatefulWidget { 9 | const AMapGeoFencePage({super.key}); 10 | 11 | @override 12 | State createState() => _AMapGeoFencePageState(); 13 | } 14 | 15 | class _AMapGeoFencePageState extends State { 16 | late ValueNotifier text = ValueNotifier('未初始化'); 17 | String customID = 'TestCustomID'; 18 | 19 | ValueNotifier geoFenceState = 20 | ValueNotifier(null); 21 | 22 | final geoFence = FlAMapGeoFence(); 23 | 24 | ValueNotifier json = ValueNotifier(null); 25 | 26 | /// 获取定位权限 27 | Future get getPermissions async { 28 | if (!await getPermission(Permission.location)) { 29 | show('未获取到定位权限'); 30 | return false; 31 | } 32 | return true; 33 | } 34 | 35 | /// 初始化地理围栏 36 | Future initGeoFence() async { 37 | if (!await getPermissions) return; 38 | final bool data = await geoFence.initialize(GeoFenceActivateAction.stayed); 39 | if (data) { 40 | show('初始化地理围栏:$data'); 41 | } 42 | } 43 | 44 | @override 45 | Widget build(BuildContext context) => Scaffold( 46 | appBar: AppBar(title: const Text('高德地理围栏')), 47 | body: Universal( 48 | padding: const EdgeInsets.all(8.0), 49 | isScroll: true, 50 | width: double.infinity, 51 | mainAxisAlignment: MainAxisAlignment.center, 52 | children: [ 53 | Container( 54 | margin: const EdgeInsets.symmetric(horizontal: 10), 55 | padding: const EdgeInsets.all(10), 56 | alignment: Alignment.center, 57 | decoration: BoxDecoration( 58 | borderRadius: BorderRadius.circular(10), 59 | color: Colors.grey.withValues(alpha: 0.3)), 60 | child: ValueListenableBuilder( 61 | valueListenable: text, 62 | builder: (_, String value, __) => Text(value, 63 | textAlign: TextAlign.center, 64 | style: const TextStyle(fontSize: 18)))), 65 | const SizedBox(height: 10), 66 | Wrap( 67 | runSpacing: 10, 68 | spacing: 10, 69 | alignment: WrapAlignment.center, 70 | children: [ 71 | ElevatedText(onPressed: initGeoFence, text: 'initialize'), 72 | ElevatedText( 73 | onPressed: () { 74 | geoFence.dispose(); 75 | show('未初始化'); 76 | }, 77 | text: 'dispose'), 78 | ElevatedText( 79 | onPressed: () async { 80 | final AMapPoiModel model = AMapPoiModel( 81 | keyword: '首开广场', 82 | poiType: '写字楼', 83 | city: '北京', 84 | size: 1, 85 | customID: customID); 86 | final result = await geoFence.addPOI(model); 87 | show('addPOI : ${result?.toMap()}'); 88 | }, 89 | text: '添加POI围栏'), 90 | ElevatedText( 91 | onPressed: () async { 92 | final LatLng latLng = LatLng(30.630259, 103.974113); 93 | final model = AMapGeoFenceLatLngModel( 94 | latLng: latLng, 95 | keyword: '西部智谷', 96 | poiType: '', 97 | customID: customID, 98 | size: 20, 99 | aroundRadius: 10000); 100 | final result = await geoFence.addLatLng(model); 101 | show('addLatLng : ${result?.toMap()}'); 102 | }, 103 | text: '添加经纬度围栏'), 104 | ElevatedText( 105 | onPressed: () async { 106 | final result = await geoFence.addDistrict( 107 | keyword: '海淀区', customID: customID); 108 | show('addDistrict : ${result?.toMap()}'); 109 | }, 110 | text: '添加行政区划围栏'), 111 | ElevatedText( 112 | onPressed: () async { 113 | final LatLng latLng = LatLng(30.651411, 103.998638); 114 | final result = await geoFence.addCircle( 115 | latLng: latLng, radius: 10, customID: customID); 116 | show('addCircle : ${result?.toMap()}'); 117 | }, 118 | text: '添加圆形围栏'), 119 | ElevatedText( 120 | onPressed: () async { 121 | final result = 122 | await geoFence.addCustom(latLng: [ 123 | LatLng(39.933921, 116.372927), 124 | LatLng(39.907261, 116.376532), 125 | LatLng(39.900611, 116.418161), 126 | LatLng(39.941949, 116.435497), 127 | ], customID: customID); 128 | show('addCustom : ${result?.toMap()}'); 129 | }, 130 | text: '添加多边形围栏'), 131 | ElevatedText( 132 | onPressed: () async { 133 | final List data = 134 | await geoFence.getAll(); 135 | if (data.isEmpty) { 136 | json.value = '没有添加围栏信息'; 137 | } else { 138 | json.value = data 139 | .map((AMapGeoFenceModel e) => e.toMap()) 140 | .toList(); 141 | } 142 | }, 143 | text: '获取所有围栏信息'), 144 | ElevatedText( 145 | onPressed: () async { 146 | final bool state = await geoFence.remove(); 147 | show('remove : $state'); 148 | json.value = '没有添加围栏信息'; 149 | }, 150 | text: '删除所有地理围栏'), 151 | ]), 152 | ElevatedText( 153 | onPressed: () async { 154 | final bool state = await geoFence.start( 155 | customID: customID, 156 | onGeoFenceChanged: (AMapGeoFenceStatusModel? geoFence) { 157 | show('围栏状态 : ${getStatus(geoFence?.status)}'); 158 | geoFenceState.value = geoFence; 159 | }); 160 | show('start : $state'); 161 | }, 162 | text: '开始围栏状态监听'), 163 | ElevatedText( 164 | onPressed: () async { 165 | final bool state = await geoFence.pause(customID: customID); 166 | show('pause : $state'); 167 | }, 168 | text: '暂停状态围栏监听'), 169 | Padding( 170 | padding: const EdgeInsets.all(20.0), 171 | child: ValueListenableBuilder( 172 | valueListenable: geoFenceState, 173 | builder: (_, AMapGeoFenceStatusModel? value, __) => Text( 174 | 'customID : ${value?.customID}\n' 175 | '围栏类型 type : ${getType(value?.type)}\n' 176 | '围栏状态 status : ${getStatus(value?.status)}\n' 177 | '围栏ID fenceID : ${value?.fenceID}\n', 178 | style: const TextStyle(fontSize: 15)))), 179 | Padding( 180 | padding: const EdgeInsets.all(20.0), 181 | child: ValueListenableBuilder( 182 | valueListenable: json, 183 | builder: (_, dynamic value, __) { 184 | if (value is Map) return JsonParse(value); 185 | if (value is List) return JsonParse.list(value); 186 | return Text(value.toString()); 187 | })) 188 | ])); 189 | 190 | String getType(GenFenceType? type) { 191 | switch (type) { 192 | case GenFenceType.circle: 193 | return '圆形地理围栏'; 194 | case GenFenceType.custom: 195 | return '多边形地理围栏'; 196 | case GenFenceType.poi: 197 | return '(POI)地理围栏'; 198 | case GenFenceType.district: 199 | return '行政区划地理围栏'; 200 | default: 201 | return '未知类型'; 202 | } 203 | } 204 | 205 | String getStatus(GenFenceStatus? status) { 206 | switch (status) { 207 | case GenFenceStatus.inside: 208 | return '在范围内'; 209 | case GenFenceStatus.outside: 210 | return '在范围外'; 211 | case GenFenceStatus.stayed: 212 | return '停留(在范围内超过10分钟)'; 213 | default: 214 | return '未知状态'; 215 | } 216 | } 217 | 218 | void show(String str) { 219 | text.value = str; 220 | } 221 | 222 | @override 223 | void dispose() { 224 | super.dispose(); 225 | geoFence.dispose(); 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /fl_amap/example/lib/src/loaction_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:example/main.dart'; 2 | import 'package:fl_amap/fl_amap.dart'; 3 | import 'package:fl_dio/fl_dio.dart'; 4 | import 'package:fl_extended/fl_extended.dart'; 5 | import 'package:flutter/foundation.dart'; 6 | import 'package:flutter/material.dart'; 7 | import 'package:permission_handler/permission_handler.dart'; 8 | 9 | class AMapLocationPage extends StatefulWidget { 10 | const AMapLocationPage({super.key}); 11 | 12 | @override 13 | State createState() => _AMapLocationPageState(); 14 | } 15 | 16 | class _AMapLocationPageState extends State { 17 | late ValueNotifier text = ValueNotifier('未初始化'); 18 | late ValueNotifier locationState = ValueNotifier(null); 19 | late ValueNotifier headingState = ValueNotifier(null); 20 | final location = FlAMapLocation(); 21 | 22 | /// 获取定位权限 23 | Future get getPermissions async { 24 | if (!await getPermission(Permission.location)) { 25 | text.value = '未获取到定位权限'; 26 | return false; 27 | } 28 | return true; 29 | } 30 | 31 | /// 初始化定位 32 | Future initLocation() async { 33 | if (!await getPermissions) return; 34 | 35 | /// 初始化AMap 36 | final bool data = await location.initialize(); 37 | text.value = '初始化定位:$data'; 38 | } 39 | 40 | @override 41 | void initState() { 42 | super.initState(); 43 | location.addListener( 44 | 45 | /// 连续定位回调 android & ios 均支持 46 | onLocationChanged: (AMapLocation? location) { 47 | locationState.value = location; 48 | }, 49 | 50 | /// ios连续定位 错误监听 仅在ios中生效 51 | onLocationFailed: (AMapLocationError? error) { 52 | text.value = 'ios 连续定位错误:${error?.toMap()}'; 53 | }, 54 | 55 | /// 监听设备朝向变化 仅在ios中生效 56 | onHeadingChanged: (AMapLocationHeading? heading) { 57 | headingState.value = heading; 58 | }, 59 | 60 | /// 监听权限状态变化 仅在ios中生效 61 | onAuthorizationChanged: (int? status) { 62 | text.value = 'ios 权限状态变化:$status'; 63 | }); 64 | } 65 | 66 | @override 67 | Widget build(BuildContext context) => Scaffold( 68 | appBar: AppBar(title: const Text('高德定位')), 69 | body: Universal( 70 | isScroll: true, 71 | width: double.infinity, 72 | padding: const EdgeInsets.all(8.0), 73 | mainAxisAlignment: MainAxisAlignment.center, 74 | children: [ 75 | Container( 76 | margin: const EdgeInsets.symmetric(horizontal: 10), 77 | padding: const EdgeInsets.all(10), 78 | alignment: Alignment.center, 79 | decoration: BoxDecoration( 80 | borderRadius: BorderRadius.circular(10), 81 | color: Colors.grey.withValues(alpha: 0.3)), 82 | child: ValueListenableBuilder( 83 | valueListenable: text, 84 | builder: (_, String value, __) => Text(value, 85 | textAlign: TextAlign.center, 86 | style: const TextStyle(fontSize: 18)))), 87 | const SizedBox(height: 10), 88 | Wrap( 89 | runSpacing: 10, 90 | spacing: 10, 91 | alignment: WrapAlignment.center, 92 | children: [ 93 | ElevatedText(onPressed: initLocation, text: 'initialize'), 94 | ElevatedText( 95 | onPressed: () { 96 | location.dispose(); 97 | locationState.value = null; 98 | text.value = '未初始化'; 99 | }, 100 | text: 'dispose'), 101 | ElevatedText(onPressed: getLocation, text: '直接获取定位'), 102 | ElevatedText(onPressed: startLocationState, text: '开启监听定位'), 103 | ElevatedText( 104 | onPressed: () async { 105 | var result = 106 | await getPermission(Permission.notification); 107 | if (result) { 108 | result = await location.enableBackgroundLocation( 109 | AMapNotificationForAndroid( 110 | notificationId: 999, 111 | title: '我在定位', 112 | content: '我正在定位', 113 | channelId: 'channelId', 114 | channelName: 'name', 115 | lightColor: Colors.red)); 116 | text.value = '开启前台任务 $result'; 117 | } else { 118 | text.value = '开启前台任务 未获得权限'; 119 | } 120 | }, 121 | text: '开启前台任务'), 122 | ElevatedText( 123 | onPressed: () async { 124 | final result = 125 | await location.disableBackgroundLocation(); 126 | text.value = '关闭前台任务 $result'; 127 | }, 128 | text: '关闭前台任务'), 129 | ElevatedText( 130 | onPressed: () async { 131 | locationState.value = null; 132 | final result = await location.stopLocation(); 133 | text.value = '定位监听关闭 $result'; 134 | }, 135 | text: '关闭监听定位'), 136 | if (TargetPlatform.iOS == defaultTargetPlatform) ...[ 137 | ElevatedText( 138 | onPressed: () async { 139 | final result = await location.headingAvailable(); 140 | text.value = 'ios 设备是否支持方向识别:$result'; 141 | }, 142 | text: '设备是否支持方向识别'), 143 | ElevatedText( 144 | onPressed: () async { 145 | final result = await location.startUpdatingHeading(); 146 | text.value = 'ios 开始获取设备朝向 $result'; 147 | }, 148 | text: '开始获取设备朝向'), 149 | ElevatedText( 150 | onPressed: () async { 151 | final result = await location.stopUpdatingHeading(); 152 | headingState.value = null; 153 | text.value = 'ios 停止获取设备朝向 $result'; 154 | }, 155 | text: '停止获取设备朝向'), 156 | ElevatedText( 157 | onPressed: () async { 158 | final result = 159 | await location.dismissHeadingCalibrationDisplay(); 160 | text.value = 'ios 停止设备朝向校准显示 $result'; 161 | }, 162 | text: '停止设备朝向校准显示'), 163 | ], 164 | ]), 165 | Padding( 166 | padding: const EdgeInsets.all(20.0), 167 | child: ValueListenableBuilder( 168 | valueListenable: locationState, 169 | builder: (_, AMapLocation? value, __) { 170 | return value == null 171 | ? const Text('暂无定位信息') 172 | : JsonParse(value.toMapForPlatform()); 173 | })), 174 | if (TargetPlatform.iOS == defaultTargetPlatform) 175 | Padding( 176 | padding: const EdgeInsets.all(20.0), 177 | child: ValueListenableBuilder( 178 | valueListenable: headingState, 179 | builder: (_, AMapLocationHeading? value, __) { 180 | return value == null 181 | ? const Text('暂无Heading信息') 182 | : JsonParse(value.toMap()); 183 | })), 184 | ])); 185 | 186 | Future getLocation() async { 187 | if (!await getPermissions) return; 188 | text.value = '单次定位获取'; 189 | locationState.value = null; 190 | locationState.value = await location.getLocation(); 191 | } 192 | 193 | Future startLocationState() async { 194 | if (!await getPermissions) return; 195 | locationState.value = null; 196 | final bool data = await FlAMapLocation().startLocation(); 197 | text.value = '开启连续定位${!data ? '失败' : '成功'}'; 198 | } 199 | 200 | @override 201 | void dispose() { 202 | super.dispose(); 203 | location.dispose(); 204 | text.dispose(); 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /fl_amap/example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: example 2 | description: A new Flutter project. 3 | publish_to: 'none' 4 | version: 1.0.0 5 | 6 | environment: 7 | sdk: '>=3.6.0 <4.0.0' 8 | flutter: '>=3.27.0' 9 | 10 | dependencies: 11 | fl_amap: 12 | path: ../ 13 | flutter: 14 | sdk: flutter 15 | fl_extended: ^1.7.2 16 | fl_dio: ^1.4.0 17 | permission_handler: ^11.4.0 18 | 19 | dev_dependencies: 20 | flutter_lints: ^5.0.0 21 | 22 | flutter: 23 | uses-material-design: true 24 | -------------------------------------------------------------------------------- /fl_amap/format.sh: -------------------------------------------------------------------------------- 1 | dart format lib 2 | dart format example/lib -------------------------------------------------------------------------------- /fl_amap/ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | .generated/ 16 | 17 | *.pbxuser 18 | *.mode1v3 19 | *.mode2v3 20 | *.perspectivev3 21 | 22 | !default.pbxuser 23 | !default.mode1v3 24 | !default.mode2v3 25 | !default.perspectivev3 26 | 27 | xcuserdata 28 | 29 | *.moved-aside 30 | 31 | *.pyc 32 | *sync/ 33 | Icon? 34 | .tags* 35 | 36 | /Flutter/Generated.xcconfig 37 | -------------------------------------------------------------------------------- /fl_amap/ios/Classes/AMapGeoFence.swift: -------------------------------------------------------------------------------- 1 | import AMapLocationKit 2 | import Flutter 3 | import Foundation 4 | 5 | class AMapGeoFence: NSObject, AMapGeoFenceManagerDelegate { 6 | var channel: FlutterMethodChannel 7 | private var manager: AMapGeoFenceManager? 8 | private var result: FlutterResult? 9 | 10 | init(_ binaryMessenger: FlutterBinaryMessenger) { 11 | channel = FlutterMethodChannel(name: "fl.amap.GeoFence", binaryMessenger: 12 | binaryMessenger) 13 | super.init() 14 | channel.setMethodCallHandler(handle) 15 | } 16 | 17 | public func setMethodCallHandler() { 18 | channel.setMethodCallHandler(handle) 19 | } 20 | 21 | public func detach() { 22 | channel.setMethodCallHandler(nil) 23 | } 24 | 25 | func handle(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { 26 | self.result = result 27 | switch call.method { 28 | case "initialize": 29 | manager = manager ?? AMapGeoFenceManager() 30 | manager?.delegate = self 31 | result(initGeoFenceOption(call)) 32 | case "dispose": 33 | manager?.removeAllGeoFenceRegions() 34 | manager?.delegate = nil 35 | manager = nil 36 | result(manager == nil) 37 | case "getAll": 38 | result(getAllGeoFence(call.arguments as? String)) 39 | case "addPOI": 40 | let args = call.arguments as! [String: Any?] 41 | manager?.addKeywordPOIRegionForMonitoring(withKeyword: args["keyword"] as? String, poiType: args["type"] as? String, city: args["city"] as? String, size: args["size"] as! Int, customID: args["customID"] as? String) 42 | case "addLatLng": 43 | let args = call.arguments as! [String: Any?] 44 | let coordinate = CLLocationCoordinate2DMake(args["latitude"] as! Double, args["longitude"] as! Double) 45 | manager?.addAroundPOIRegionForMonitoring(withLocationPoint: coordinate, aroundRadius: Int(args["aroundRadius"] as! Double), keyword: args["keyword"] as? String, poiType: args["type"] as? String, size: args["size"] as! Int, customID: args["customID"] as? String) 46 | case "addDistrict": 47 | let args = call.arguments as! [String: Any?] 48 | manager?.addDistrictRegionForMonitoring(withDistrictName: args["keyword"] as? String, customID: args["customID"] as? String) 49 | case "addCircle": 50 | let args = call.arguments as! [String: Any?] 51 | let coordinate = CLLocationCoordinate2DMake(args["latitude"] as! Double, args["longitude"] as! Double) 52 | manager?.addCircleRegionForMonitoring(withCenter: coordinate, radius: args["radius"] as! Double, customID: args["customID"] as? String) 53 | case "addCustom": 54 | let args = call.arguments as! [String: Any?] 55 | let latLngs = args["latLng"] as! [[String: Double]] 56 | var coordinates = [CLLocationCoordinate2D]() 57 | for latLng in latLngs { 58 | coordinates.append(CLLocationCoordinate2D( 59 | latitude: latLng["latitude"]!, longitude: latLng["longitude"]! 60 | )) 61 | } 62 | manager?.addPolygonRegionForMonitoring(withCoordinates: &coordinates, count: latLngs.count, customID: args["customID"] as? String) 63 | case "remove": 64 | let customID = call.arguments as? String 65 | if customID != nil { 66 | manager?.removeGeoFenceRegions(withCustomID: customID) 67 | } else { 68 | manager?.removeAllGeoFenceRegions() 69 | } 70 | result(manager != nil) 71 | case "start": 72 | manager?.startGeoFenceRegions(withCustomID: call.arguments as? String) 73 | result(true) 74 | case "pause": 75 | manager?.pauseGeoFenceRegions(withCustomID: call.arguments as? String) 76 | result(true) 77 | default: 78 | result(FlutterMethodNotImplemented) 79 | } 80 | } 81 | 82 | func getAllGeoFence(_ customId: String?) -> [[String: Any?]] { 83 | var list = [[String: Any?]]() 84 | let fences = manager?.geoFenceRegions(withCustomID: customId) 85 | if fences == nil { 86 | return list 87 | } 88 | for region in fences! { 89 | if region is AMapGeoFenceRegion { 90 | let map = regionToMap(region as! AMapGeoFenceRegion) 91 | if map != nil { 92 | list.append(map!) 93 | } 94 | } 95 | } 96 | return list 97 | } 98 | 99 | func initGeoFenceOption(_ call: FlutterMethodCall) -> Bool { 100 | if manager == nil { 101 | return false 102 | } 103 | let args = call.arguments as! [AnyHashable: Any] 104 | switch args["action"] as! Int { 105 | case 0: 106 | manager!.activeAction = .inside 107 | case 1: 108 | manager!.activeAction = .outside 109 | case 2: 110 | manager!.activeAction = [.inside, .outside] 111 | case 3: 112 | manager!.activeAction = [.inside, .outside, .stayed] 113 | default: 114 | manager!.activeAction = [.inside, .outside, .stayed] 115 | } 116 | return true 117 | } 118 | 119 | /// 获取围栏创建后的回调 120 | /// 在如下回调中知道创建的围栏是否成功,以及查看所创建围栏的具体内容 121 | func amapGeoFenceManager(_ manager: AMapGeoFenceManager!, didAddRegionForMonitoringFinished regions: [AMapGeoFenceRegion]?, customID: String?, error: Error?) { 122 | result?([ 123 | "customId": customID as Any, 124 | "geoFenceList": regions?.map { $0.data } as Any, 125 | "errorCode": (error as? NSError)?.code as? Int?, 126 | ]) 127 | } 128 | 129 | /// 围栏状态改变时的回调 130 | func amapGeoFenceManager(_ manager: AMapGeoFenceManager!, didGeoFencesStatusChangedFor region: AMapGeoFenceRegion!, customID: String?, error: Error?) { 131 | channel.invokeMethod("onGeoFencesStatus", arguments: [ 132 | "region": region.data, 133 | "customId": customID as Any, 134 | "errorCode": (error as? NSError)?.code as? Int?, 135 | ]) 136 | } 137 | 138 | func amapLocationManager(_ manager: AMapGeoFenceManager!, doRequireTemporaryFullAccuracyAuth locationManager: CLLocationManager!, completion: ((Error?) -> Void)!) {} 139 | 140 | func amapGeoFenceManager(_ manager: AMapGeoFenceManager!, doRequireLocationAuth locationManager: CLLocationManager!) {} 141 | 142 | func regionToMap(_ region: AMapGeoFenceRegion) -> [String: Any?]? { 143 | if region is AMapGeoFenceCircleRegion { 144 | return (region as! AMapGeoFenceCircleRegion).circleData 145 | } else if region is AMapGeoFencePOIRegion { 146 | return (region as! AMapGeoFencePOIRegion).poiData 147 | } else if region is AMapGeoFencePolygonRegion { 148 | return (region as! AMapGeoFencePolygonRegion).polygonData 149 | } else if region is AMapGeoFenceDistrictRegion { 150 | return (region as! AMapGeoFenceDistrictRegion).districtData 151 | } 152 | return nil 153 | } 154 | } 155 | 156 | extension AMapGeoFenceRegion { 157 | var data: [String: Any?] { 158 | [ 159 | "customID": customID, 160 | "status": fenceStatus.rawValue, 161 | "type": regionType.rawValue, 162 | "location": currentLocation?.data, 163 | "fenceID": identifier, 164 | ] 165 | } 166 | } 167 | 168 | extension AMapGeoFenceCircleRegion { 169 | var circleData: [String: Any?] { 170 | var map = [:] as [String: Any?] 171 | for (key, value) in data { 172 | map[key] = value 173 | } 174 | map["center"] = center.data 175 | map["radius"] = radius 176 | return map 177 | } 178 | } 179 | 180 | extension AMapGeoFencePOIRegion { 181 | var poiData: [String: Any?] { 182 | var map = [:] as [String: Any?] 183 | for (key, value) in circleData { 184 | map[key] = value 185 | } 186 | map["poiItem"] = poiItem.data 187 | return map 188 | } 189 | } 190 | 191 | extension AMapGeoFencePolygonRegion { 192 | var polygonData: [String: Any?] { 193 | var map = [:] as [String: Any?] 194 | for (key, value) in data { 195 | map[key] = value 196 | } 197 | map["count"] = count 198 | map["point"] = coordinates.pointee.data 199 | return map 200 | } 201 | } 202 | 203 | extension AMapGeoFenceDistrictRegion { 204 | var districtData: [String: Any?] { 205 | var map = [:] as [String: Any?] 206 | for (key, value) in data { 207 | map[key] = value 208 | } 209 | map["districtItem"] = districtItem.data 210 | map["pointList"] = polylinePoints.map { points in 211 | points.map { point in 212 | point.data 213 | } 214 | } 215 | return map 216 | } 217 | } 218 | 219 | extension AMapLocationDistrictItem { 220 | var data: [String: Any?] { 221 | [ 222 | "cityCode": cityCode, 223 | "district": district, 224 | "districtCode": districtCode, 225 | "pointList": polylinePoints.map { points in 226 | points.map { point in 227 | point.data 228 | } 229 | }, 230 | ] 231 | } 232 | } 233 | 234 | extension AMapLocationPOIItem { 235 | var data: [String: Any?] { 236 | [ 237 | "pId": pId, 238 | "name": name, 239 | "type": type, 240 | "typeCode": typeCode, 241 | "address": address, 242 | "location": location.data, 243 | "tel": tel, 244 | "province": province, 245 | "city": city, 246 | "district": district, 247 | ] 248 | } 249 | } 250 | 251 | extension CLLocationCoordinate2D { 252 | var data: [String: Any?] { 253 | [ 254 | "latitude": latitude, 255 | "longitude": longitude, 256 | ] 257 | } 258 | } 259 | 260 | extension AMapLocationPoint { 261 | var data: [String: Any?] { 262 | [ 263 | "latitude": latitude, 264 | "longitude": longitude, 265 | ] 266 | } 267 | } 268 | -------------------------------------------------------------------------------- /fl_amap/ios/Classes/AMapPlugin.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | 3 | public class AMapPlugin: NSObject, FlutterPlugin { 4 | private var location: AMapLocation 5 | private var geoFence: AMapGeoFence 6 | 7 | public static func register(with registrar: FlutterPluginRegistrar) { 8 | _ = AMapPlugin(registrar.messenger()) 9 | } 10 | 11 | init(_ binaryMessenger: FlutterBinaryMessenger) { 12 | location = AMapLocation(binaryMessenger) 13 | geoFence = AMapGeoFence(binaryMessenger) 14 | super.init() 15 | } 16 | 17 | public func detachFromEngine(for registrar: FlutterPluginRegistrar) { 18 | location.detach() 19 | geoFence.detach() 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /fl_amap/ios/Resources/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyTrackingDomains 6 | 7 | NSPrivacyAccessedAPITypes 8 | 9 | NSPrivacyCollectedDataTypes 10 | 11 | NSPrivacyTracking 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /fl_amap/ios/fl_amap.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 3 | # 4 | Pod::Spec.new do |s| 5 | s.name = 'fl_amap' 6 | s.version = '0.0.1' 7 | s.summary = 'A Flutter plugin.' 8 | s.description = <<-DESC 9 | A new Flutter plugin. 10 | DESC 11 | s.homepage = 'http://example.com' 12 | s.license = { :file => '../LICENSE' } 13 | s.author = { 'Your Company' => 'email@example.com' } 14 | s.source = { :path => '.' } 15 | s.source_files = 'Classes/**/*' 16 | s.dependency 'Flutter' 17 | s.dependency 'AMapLocation' 18 | s.static_framework = true 19 | s.platform = :ios, '12.0' 20 | # Flutter.framework does not contain a i386 slice. 21 | s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } 22 | s.swift_version = '5.0' 23 | 24 | end 25 | 26 | -------------------------------------------------------------------------------- /fl_amap/lib/fl_amap.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter/services.dart'; 4 | 5 | part 'src/amap_geo_fence.dart'; 6 | 7 | part 'src/amap_location.dart'; 8 | 9 | part 'src/enum.dart'; 10 | 11 | class FlAMap { 12 | factory FlAMap() => _singleton ??= FlAMap._(); 13 | 14 | FlAMap._(); 15 | 16 | static FlAMap? _singleton; 17 | 18 | /// 设置ios&android的key 19 | Future setAMapKey({ 20 | required String iosKey, 21 | required String androidKey, 22 | 23 | /// 设置是否同意用户授权政策 设置为true才可以调用其他功能 24 | bool isAgree = true, 25 | 26 | /// 设置包含隐私政策 设置为true才可以调用其他功能 27 | bool isContains = true, 28 | 29 | /// 并展示用户授权弹窗 设置为true才可以调用其他功能 30 | bool isShow = true, 31 | }) async { 32 | if (!_supportPlatform) return false; 33 | String? key; 34 | if (_isAndroid) key = androidKey; 35 | if (_isIOS) key = iosKey; 36 | if (key == null) return false; 37 | final state = await FlAMapLocation()._channel.invokeMethod('setApiKey', { 38 | 'key': key, 39 | 'isAgree': isAgree, 40 | 'isContains': isContains, 41 | 'isShow': isShow 42 | }); 43 | return state == true; 44 | } 45 | } 46 | 47 | bool get _supportPlatform { 48 | if (!kIsWeb && (_isAndroid || _isIOS)) return true; 49 | debugPrint('Not support platform for $defaultTargetPlatform'); 50 | return false; 51 | } 52 | 53 | bool get _isAndroid => defaultTargetPlatform == TargetPlatform.android; 54 | 55 | bool get _isIOS => defaultTargetPlatform == TargetPlatform.iOS; 56 | 57 | class LatLng { 58 | LatLng(this.latitude, this.longitude); 59 | 60 | LatLng.fromMap(Map map) 61 | : latitude = map['latitude'] as double?, 62 | longitude = map['longitude'] as double?; 63 | 64 | /// 维度 65 | double? latitude; 66 | 67 | /// 经度 68 | double? longitude; 69 | 70 | Map toMap() => 71 | {'latitude': latitude, 'longitude': longitude}; 72 | } 73 | -------------------------------------------------------------------------------- /fl_amap/lib/src/enum.dart: -------------------------------------------------------------------------------- 1 | part of '../fl_amap.dart'; 2 | 3 | enum GenFenceType { 4 | /// 圆形地理围栏 5 | circle, 6 | 7 | /// 多边形地理围栏 8 | custom, 9 | 10 | /// 兴趣点(POI)地理围栏 11 | poi, 12 | 13 | /// 行政区划地理围栏 14 | district 15 | } 16 | 17 | enum GenFenceStatus { 18 | /// 未知 19 | none, 20 | 21 | /// 在范围内 22 | inside, 23 | 24 | /// 在范围外 25 | outside, 26 | 27 | /// 停留(在范围内超过10分钟) 28 | stayed, 29 | 30 | /// android 定位失败时,围栏状态无法进行检测 31 | locFailed 32 | } 33 | 34 | enum GeoFenceActivateAction { 35 | /// 进入地理围栏 36 | onlyInside, 37 | 38 | /// 退出地理围栏 39 | onlyOutside, 40 | 41 | /// 监听进入并退出 42 | insideAndOutside, 43 | 44 | /// 停留在地理围栏内10分钟 45 | stayed, 46 | } 47 | -------------------------------------------------------------------------------- /fl_amap/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: fl_amap 2 | description: AMap location plugin for flutter, supports single positioning and continuous positioning 3 | version: 3.4.3 4 | repository: https://github.com/Wayaer/fl_amap/tree/main/fl_amap 5 | 6 | environment: 7 | sdk: '>=3.0.0 <4.0.0' 8 | flutter: '>=3.10.0' 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | 14 | dev_dependencies: 15 | flutter_lints: ^5.0.0 16 | 17 | flutter: 18 | plugin: 19 | platforms: 20 | android: 21 | package: fl.amap 22 | pluginClass: AMapPlugin 23 | ios: 24 | pluginClass: AMapPlugin 25 | -------------------------------------------------------------------------------- /fl_amap_map/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # OSX 3 | # 4 | .DS_Store 5 | 6 | 7 | # Xcode 8 | # 9 | build/ 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata 19 | *.xccheckout 20 | *.moved-aside 21 | DerivedData 22 | *.hmap 23 | *.ipa 24 | *.xcuserstate 25 | project.xcworkspace 26 | 27 | 28 | # Android/IntelliJ 29 | # 30 | build/ 31 | .idea 32 | .gradle 33 | local.properties 34 | *.iml 35 | *.lock 36 | *.packages 37 | 38 | # BUCK 39 | buck-out/ 40 | \.buckd/ 41 | *.keystore 42 | /.dart_tool/ 43 | -------------------------------------------------------------------------------- /fl_amap_map/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.0.1 2 | 3 | * 4 | -------------------------------------------------------------------------------- /fl_amap_map/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Wayaer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /fl_amap_map/README.md: -------------------------------------------------------------------------------- 1 | ## 高德地图flutter组件。 2 | 3 | ### 目前实现获取定位、监听定位和部分地图功能 (依赖此插件无需再依赖[fl_amap](https://pub.dev/packages/fl_amap)) 4 | 5 | 1、申请一个key 6 | http://lbs.amap.com/api/ios-sdk/guide/create-project/get-key 7 | 8 | 直接在dart文件中设置key 9 | 10 | # ios 11 | 12 | 1. 在info.plist中增加: 13 | 14 | ``` 15 | NSLocationWhenInUseUsageDescription 16 | 要用定位 17 | ``` 18 | 19 | 2. iOS 9及以上版本使用后台定位功能, 需要保证"Background Modes"中的"Location updates"处于选中状态 20 | 21 | 3.使用地理围栏 22 | 23 | iOS14及以上版本使用地理围栏功能,需要在plist中配置NSLocationTemporaryUsageDescriptionDictionary字典描述, 24 | 且添加自定义Key描述地理围栏的使用场景,此描述会在申请临时精确定位权限的弹窗中展示。 25 | 该回调触发条件:拥有定位权限,但是没有获得精确定位权限的情况下,会触发该回调。此方法实现调用申请临时精确定位权限API即可; 26 | 27 | ** 需要注意,在iOS9及之后版本的系统中,如果您希望程序在后台持续检测围栏触发行为,需要保证manager的 allowsBackgroundLocationUpdates 为 YES, 28 | 设置为YES的时候必须保证 Background Modes 中的 Location updates 处于选中状态,否则会抛出异常。 29 | 30 | # android 31 | 32 | - `android/src/main/AndroidManifest.xml` 添加以下内容 具体参考 `example` 33 | 34 | ```xml 35 | 36 | 37 | ``` 38 | 39 | ## 开始使用 40 | 41 | ## 高德定位功能 42 | 43 | - 设置key 44 | 45 | ```dart 46 | 47 | Future setAMapKey() async { 48 | final key = await FlAMapMap().setAMapKey( 49 | iosKey: 'ios key', 50 | androidKey: 'android key'); 51 | 52 | if (key != null && key) print('高德地图ApiKey设置成功'); 53 | } 54 | 55 | ``` 56 | 57 | - 初始化定位参数 58 | 59 | ```dart 60 | Future initialize() async { 61 | /// 获取权限 62 | if (getPermissions) return; 63 | 64 | /// 初始化AMap 65 | final bool data = await FlAMapLocation().initialize(AMapLocationOption()); 66 | if (data) { 67 | show('初始化成功'); 68 | } 69 | } 70 | 71 | ``` 72 | 73 | - 单次获取定位 74 | 75 | ```dart 76 | Future getLocation() async { 77 | /// 务必先初始化 并获取权限 78 | if (getPermissions) return; 79 | AMapLocation location = await FlAMapLocation().getLocation(true); 80 | } 81 | 82 | ``` 83 | 84 | - 开启定位变化监听 85 | 86 | ```dart 87 | Future startLocationChange() async { 88 | /// 务必先初始化 并获取权限 89 | if (getPermissions) return; 90 | final bool data = 91 | await FlAMapLocation().startLocationChanged(onLocationChanged: 92 | (AMapLocation location) { 93 | locationState.value = location; 94 | text.value = '位置更新$i次'; 95 | }); 96 | print(!data ? '开启成功' : '开启失败'); 97 | } 98 | 99 | ``` 100 | 101 | - 关闭定位变化监听 102 | 103 | ```dart 104 | void stopLocation() { 105 | FlAMapLocation().stopLocation(); 106 | } 107 | ``` 108 | 109 | - 关闭定位服务 110 | 111 | ```dart 112 | void dispose() { 113 | super.dispose(); 114 | FlAMapLocation().dispose(); 115 | } 116 | ``` 117 | 118 | ## 高德地理围栏功能 119 | 120 | - 初始化地理围栏 121 | 122 | ```dart 123 | 124 | Future get initialize async { 125 | final bool data = await FlAMapGeoFence().initialize(GeoFenceActivateAction.stayed); 126 | if (data) { 127 | show('初始化地理围栏:$data'); 128 | } 129 | } 130 | 131 | ``` 132 | 133 | - 关闭围栏服务 134 | 135 | ```dart 136 | void dispose() { 137 | super.dispose(); 138 | FlAMapGeoFence().dispose(); 139 | } 140 | ``` 141 | 142 | - 根据POI添加围栏 143 | 144 | ```dart 145 | Future addPOI() async { 146 | final AMapPoiModel model = AMapPoiModel( 147 | keyword: '首开广场', 148 | poiType: '写字楼', 149 | city: '北京', 150 | size: 1, 151 | customId: '000FATE23(考勤打卡)'); 152 | final bool state = await FlAMapGeoFence().addPOI(model); 153 | } 154 | ``` 155 | 156 | - 根据坐标关键字添加围栏 157 | 158 | ```dart 159 | Future addLatLng() async { 160 | final LatLng latLong = LatLng(39.933921, 116.372927); 161 | final AMapLatLngModel model = AMapLatLngModel( 162 | latLong: latLong, 163 | keyword: '首开广场', 164 | poiType: '', 165 | customId: '000FATE23(考勤打卡)', 166 | size: 20, 167 | aroundRadius: 1000); 168 | final bool state = await FlAMapGeoFence().addLatLng(model); 169 | } 170 | ``` 171 | 172 | - 添加行政区划围栏 173 | 174 | ```dart 175 | Future addDistrict() async { 176 | final bool state = await FlAMapGeoFence().addDistrict( 177 | keyword: '海淀区', customId: '000FATE23(考勤打卡)'); 178 | } 179 | ``` 180 | 181 | - 添加圆形围栏 182 | 183 | ```dart 184 | Future addCircle() async { 185 | final LatLng latLong = LatLng(30.651411, 103.998638); 186 | final bool state = await FlAMapGeoFence().addCircle( 187 | latLong: latLong, 188 | radius: 10, 189 | customId: '000FATE23(考勤打卡)'); 190 | } 191 | ``` 192 | 193 | - 添加多边形围栏 194 | 195 | ```dart 196 | Future addCustom() async { 197 | final bool state = await FlAMapGeoFence().addCustom(latLongs: [ 198 | LatLng(39.933921, 116.372927), 199 | LatLng(39.907261, 116.376532), 200 | LatLng(39.900611, 116.418161), 201 | LatLng(39.941949, 116.435497), 202 | ], customId: '000FATE23(考勤打卡)'); 203 | } 204 | ``` 205 | 206 | - 获取所有围栏信息 207 | 208 | ```dart 209 | Future getAll() async { 210 | /// 传入 customID 获取指定标识的围栏信息 仅支持ios 211 | final List data = await FlAMapGeoFence().getAll(); 212 | } 213 | ``` 214 | 215 | - 删除地理围栏 216 | 217 | ```dart 218 | Future remove() async { 219 | /// 传入 customID 删除指定标识的围栏 220 | /// 不传 删除所有围栏 221 | final bool state = await FlAMapGeoFence().remove(); 222 | } 223 | ``` 224 | 225 | - 暂停监听围栏 226 | 227 | ```dart 228 | Future pause() async { 229 | /// 传入 customID 暂停指定标识的围栏 230 | /// 不传 暂停所有围栏 231 | final bool state = await FlAMapGeoFence().pause(); 232 | } 233 | ``` 234 | 235 | - 开始监听围栏 236 | 237 | ```dart 238 | Future start() async { 239 | /// 传入 customID 开始指定标识的围栏 240 | /// 不传 开始所有围栏 241 | final bool state = await FlAMapGeoFence().start(); 242 | } 243 | ``` -------------------------------------------------------------------------------- /fl_amap_map/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml -------------------------------------------------------------------------------- /fl_amap_map/android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /fl_amap_map/android/build.gradle: -------------------------------------------------------------------------------- 1 | group 'fl.amap' 2 | version '1.0' 3 | 4 | buildscript { 5 | repositories { 6 | google() 7 | mavenCentral() 8 | } 9 | 10 | dependencies { 11 | classpath 'com.android.tools.build:gradle:8.5.2' 12 | } 13 | } 14 | 15 | rootProject.allprojects { 16 | repositories { 17 | google() 18 | mavenCentral() 19 | } 20 | } 21 | 22 | apply plugin: 'com.android.library' 23 | apply plugin: 'kotlin-android' 24 | 25 | android { 26 | compileSdk = 34 27 | 28 | if (project.android.hasProperty("namespace")) { 29 | namespace 'fl.amap' 30 | } 31 | 32 | compileOptions { 33 | sourceCompatibility = JavaVersion.VERSION_17 34 | targetCompatibility = JavaVersion.VERSION_17 35 | } 36 | 37 | kotlinOptions { 38 | jvmTarget = JavaVersion.VERSION_17.toString() 39 | } 40 | 41 | sourceSets { 42 | main.java.srcDirs += 'src/main/kotlin' 43 | } 44 | defaultConfig { 45 | minSdk = 21 46 | consumerProguardFiles 'consumer-rules.pro' 47 | } 48 | packagingOptions { 49 | merge 'AndroidManifest.xml' 50 | merge 'R.txt' 51 | merge 'classes.jar' 52 | merge 'proguard.txt' 53 | } 54 | 55 | dependencies { 56 | api 'com.amap.api:3dmap:10.0.600' 57 | } 58 | 59 | } 60 | 61 | 62 | -------------------------------------------------------------------------------- /fl_amap_map/android/consumer-rules.pro: -------------------------------------------------------------------------------- 1 | -keep class com.amap.api.location.**{*;} 2 | -keep class com.amap.api.fence.**{*;} 3 | -keep class com.autonavi.aps.amapapi.model.**{*;} 4 | -keep class com.loc.**{*;} 5 | -------------------------------------------------------------------------------- /fl_amap_map/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'fl_amap' 2 | -------------------------------------------------------------------------------- /fl_amap_map/android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /fl_amap_map/android/src/main/kotlin/fl/amap/map/AMapMapPlugin.kt: -------------------------------------------------------------------------------- 1 | package fl.amap.map 2 | 3 | import android.content.Context 4 | import androidx.lifecycle.Lifecycle 5 | import com.amap.api.location.AMapLocationClient 6 | import com.amap.api.maps.MapsInitializer 7 | import fl.amap.map.map.AMapPlatformViewFactory 8 | import fl.channel.FlChannelPlugin 9 | import fl.channel.FlEventChannel 10 | import io.flutter.embedding.engine.plugins.FlutterPlugin 11 | import io.flutter.embedding.engine.plugins.activity.ActivityAware 12 | import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding 13 | import io.flutter.embedding.engine.plugins.lifecycle.HiddenLifecycleReference 14 | import io.flutter.plugin.common.BinaryMessenger 15 | import io.flutter.plugin.common.MethodCall 16 | import io.flutter.plugin.common.MethodChannel 17 | 18 | 19 | class AMapMapPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware { 20 | private lateinit var channel: MethodChannel 21 | private lateinit var context: Context 22 | private lateinit var binaryMessenger: BinaryMessenger 23 | 24 | 25 | companion object { 26 | var lifecycle: Lifecycle? = null 27 | var flEventChannel: FlEventChannel? = null 28 | } 29 | 30 | override fun onAttachedToEngine(plugin: FlutterPlugin.FlutterPluginBinding) { 31 | binaryMessenger = plugin.binaryMessenger 32 | channel = MethodChannel(plugin.binaryMessenger, "fl_amap_map") 33 | context = plugin.applicationContext 34 | channel.setMethodCallHandler(this) 35 | plugin.platformViewRegistry.registerViewFactory( 36 | "fl_amap_map", AMapPlatformViewFactory(plugin.binaryMessenger) 37 | ) 38 | } 39 | 40 | override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { 41 | when (call.method) { 42 | "setApiKey" -> { 43 | val key = call.argument("key")!! 44 | val isAgree = call.argument("isAgree")!! 45 | val isContains = call.argument("isContains")!! 46 | val isShow = call.argument("isShow")!! 47 | val enableHTTPS = call.argument("enableHTTPS")!! 48 | AMapLocationClient.updatePrivacyAgree(context, isAgree) 49 | AMapLocationClient.updatePrivacyShow(context, isContains, isShow) 50 | AMapLocationClient.setApiKey(key) 51 | MapsInitializer.setApiKey(key) 52 | MapsInitializer.initialize(context) 53 | MapsInitializer.setProtocol(if (enableHTTPS) MapsInitializer.HTTPS else MapsInitializer.HTTP) 54 | MapsInitializer.updatePrivacyAgree(context, isAgree) 55 | MapsInitializer.updatePrivacyShow(context, isContains, isShow) 56 | flEventChannel = FlChannelPlugin.getEventChannel("fl_amap_map_event") 57 | result.success(true) 58 | } 59 | } 60 | 61 | } 62 | 63 | override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { 64 | channel.setMethodCallHandler(null) 65 | } 66 | 67 | override fun onAttachedToActivity(binding: ActivityPluginBinding) { 68 | val reference = binding.lifecycle as HiddenLifecycleReference 69 | lifecycle = reference.lifecycle 70 | } 71 | 72 | override fun onDetachedFromActivityForConfigChanges() { 73 | onDetachedFromActivity() 74 | } 75 | 76 | override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) { 77 | onAttachedToActivity(binding) 78 | } 79 | 80 | override fun onDetachedFromActivity() { 81 | lifecycle = null 82 | } 83 | 84 | } 85 | 86 | -------------------------------------------------------------------------------- /fl_amap_map/android/src/main/kotlin/fl/amap/map/Extension.kt: -------------------------------------------------------------------------------- 1 | package fl.amap.map 2 | 3 | import android.location.Location 4 | import com.amap.api.maps.model.* 5 | import com.autonavi.amap.mapcore.DPoint 6 | import com.autonavi.amap.mapcore.IPoint 7 | 8 | val Location.data: Map 9 | get() = mapOf( 10 | "accuracy" to accuracy, 11 | "altitude" to altitude, 12 | "speed" to speed, 13 | "timestamp" to (time.toDouble() / 1000), 14 | "latLng" to mapOf( 15 | "latitude" to latitude, 16 | "longitude" to longitude, 17 | ), 18 | "provider" to provider, 19 | "bearing" to bearing, 20 | ) 21 | 22 | val LatLng.data: Map 23 | get() = mapOf( 24 | "latitude" to latitude, 25 | "longitude" to longitude, 26 | ) 27 | val IPoint.data: Map 28 | get() = mapOf( 29 | "x" to x, 30 | "y" to y, 31 | ) 32 | val DPoint.data: Map 33 | get() = mapOf( 34 | "x" to x, 35 | "y" to y, 36 | ) 37 | val CameraPosition.data: Map 38 | get() = mapOf( 39 | "target" to target.data, 40 | "zoom" to zoom, 41 | "tilt" to tilt, 42 | "bearing" to bearing, 43 | "isAbroad" to isAbroad, 44 | ) 45 | 46 | 47 | val MarkerOptions.data: Map 48 | get() = mapOf( 49 | "anchorU" to anchorU, 50 | "anchorV" to anchorV, 51 | "infoWindowOffsetX" to infoWindowOffsetX, 52 | "infoWindowOffsetY" to infoWindowOffsetY, 53 | "alpha" to alpha, 54 | "altitude" to altitude, 55 | "period" to period, 56 | "position" to position, 57 | "rotateAngle" to rotateAngle, 58 | "snippet" to snippet, 59 | "title" to title, 60 | "zIndex" to zIndex, 61 | "isDraggable" to isDraggable, 62 | "isVisible" to isVisible, 63 | "isFlat" to isFlat, 64 | "isInfoWindowAutoOverturn" to isInfoWindowAutoOverturn, 65 | "isInfoWindowEnable" to isInfoWindowEnable, 66 | ) 67 | val Marker.data: Map 68 | get() = mapOf( 69 | "options" to options.data, 70 | "alpha" to alpha, 71 | "altitude" to altitude, 72 | "id" to id, 73 | "period" to period, 74 | "position" to position, 75 | "rotateAngle" to rotateAngle, 76 | "snippet" to snippet, 77 | "title" to title, 78 | "zIndex" to zIndex, 79 | "geoPoint" to geoPoint.data, 80 | "isRemoved" to isRemoved, 81 | "isClickable" to isClickable, 82 | "isDraggable" to isDraggable, 83 | "isVisible" to isVisible, 84 | "isFlat" to isFlat, 85 | "isViewMode" to isViewMode, 86 | "isInfoWindowAutoOverturn" to isInfoWindowAutoOverturn, 87 | "isInfoWindowEnable" to isInfoWindowEnable, 88 | ) 89 | 90 | 91 | val Poi.data: Map 92 | get() = mapOf( 93 | "latLng" to coordinate.data, 94 | "name" to name, 95 | "poiId" to poiId, 96 | ) 97 | -------------------------------------------------------------------------------- /fl_amap_map/android/src/main/kotlin/fl/amap/map/map/AMapPlatformViewFactory.kt: -------------------------------------------------------------------------------- 1 | package fl.amap.map.map 2 | 3 | import android.content.Context 4 | import io.flutter.plugin.common.BinaryMessenger 5 | import io.flutter.plugin.common.MethodChannel 6 | import io.flutter.plugin.common.StandardMessageCodec 7 | import io.flutter.plugin.platform.PlatformView 8 | import io.flutter.plugin.platform.PlatformViewFactory 9 | 10 | class AMapPlatformViewFactory( 11 | private val binaryMessenger: BinaryMessenger, 12 | ) : PlatformViewFactory(StandardMessageCodec.INSTANCE) { 13 | 14 | override fun create(context: Context?, viewId: Int, args: Any?): PlatformView { 15 | val channel = MethodChannel(binaryMessenger, "fl_amap_map_$viewId") 16 | return AMapView(context, channel, viewId, args as Map<*, *>) 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /fl_amap_map/android/src/main/kotlin/fl/amap/map/map/AMapView.kt: -------------------------------------------------------------------------------- 1 | package fl.amap.map.map 2 | 3 | import android.content.Context 4 | import android.os.Bundle 5 | import android.view.View 6 | import androidx.lifecycle.DefaultLifecycleObserver 7 | import androidx.lifecycle.LifecycleOwner 8 | import com.amap.api.maps.AMap 9 | import com.amap.api.maps.CameraUpdateFactory 10 | import com.amap.api.maps.TextureMapView 11 | import com.amap.api.maps.model.* 12 | import fl.amap.map.AMapMapPlugin.Companion.lifecycle 13 | import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding.OnSaveInstanceStateListener 14 | import io.flutter.plugin.common.MethodCall 15 | import io.flutter.plugin.common.MethodChannel 16 | import io.flutter.plugin.common.MethodChannel.MethodCallHandler 17 | import io.flutter.plugin.platform.PlatformView 18 | 19 | 20 | class AMapView( 21 | context: Context?, private var channel: MethodChannel, private var viewId: Int, args: Map<*, *> 22 | ) : DefaultLifecycleObserver, OnSaveInstanceStateListener, MethodCallHandler, PlatformView { 23 | private var mapview: TextureMapView 24 | private var mapViewListener: AMapViewListener? = null 25 | 26 | init { 27 | channel.setMethodCallHandler(this) 28 | mapview = TextureMapView(context) 29 | setOptions(args) 30 | 31 | lifecycle?.addObserver(this) 32 | } 33 | 34 | override fun onCreate(owner: LifecycleOwner) { 35 | mapview.onCreate(null) 36 | } 37 | 38 | override fun onResume(owner: LifecycleOwner) { 39 | mapview.onResume() 40 | } 41 | 42 | override fun onPause(owner: LifecycleOwner) { 43 | mapview.onPause() 44 | } 45 | 46 | override fun onDestroy(owner: LifecycleOwner) { 47 | mapview.onDestroy() 48 | lifecycle?.removeObserver(this) 49 | } 50 | 51 | override fun onSaveInstanceState(bundle: Bundle) { 52 | mapview.onSaveInstanceState(bundle) 53 | } 54 | 55 | override fun onRestoreInstanceState(bundle: Bundle?) { 56 | mapview.onCreate(bundle) 57 | } 58 | 59 | override fun getView(): View { 60 | return mapview 61 | } 62 | 63 | override fun dispose() { 64 | 65 | } 66 | 67 | override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { 68 | when (call.method) { 69 | "setOptions" -> setOptions(call.arguments as Map<*, *>) 70 | "dispose" -> { 71 | mapViewListener?.removeListener() 72 | mapViewListener = null 73 | channel.setMethodCallHandler(null) 74 | mapview.onDestroy() 75 | lifecycle?.removeObserver(this) 76 | } 77 | 78 | "addListener" -> { 79 | if (mapViewListener == null) { 80 | mapViewListener = AMapViewListener(viewId, mapview.map) 81 | } 82 | result.success(true) 83 | } 84 | 85 | "removeListener" -> { 86 | mapViewListener?.removeListener() 87 | mapViewListener = null 88 | result.success(true) 89 | } 90 | 91 | "setCenter" -> { 92 | val animated = call.argument("animated")!! 93 | val cameraUpdate = CameraUpdateFactory.newCameraPosition( 94 | CameraPosition( 95 | LatLng( 96 | call.argument("latitude")!!, call.argument("longitude")!! 97 | ), 98 | call.argument("zoom")!!.toFloat(), 99 | call.argument("tilt")!!.toFloat(), 100 | call.argument("bearing")!!.toFloat() 101 | ) 102 | ) 103 | if (animated) { 104 | mapview.map.animateCamera(cameraUpdate) 105 | } else { 106 | mapview.map.moveCamera(cameraUpdate) 107 | } 108 | result.success(true) 109 | } 110 | 111 | "reloadMap" -> { 112 | mapview.map.reloadMap() 113 | result.success(true) 114 | } 115 | 116 | "setRenderFps" -> { 117 | mapview.map.setRenderFps(call.arguments as Int) 118 | result.success(true) 119 | } 120 | 121 | "setTrackingMode" -> { 122 | val mode = call.argument("mode") ?: 0 123 | val locationStyle = MyLocationStyle() 124 | locationStyle.myLocationType(mode) 125 | mapview.map.myLocationStyle = locationStyle 126 | result.success(true) 127 | } 128 | 129 | "addMarker" -> { 130 | val markerOptions = MarkerOptions() 131 | val marker = mapview.map.addMarker(markerOptions) 132 | result.success(marker.id) 133 | } 134 | 135 | else -> result.notImplemented() 136 | } 137 | } 138 | 139 | private fun setOptions(args: Map<*, *>) { 140 | val map = mapview.map 141 | val options = map.uiSettings 142 | options.isZoomControlsEnabled = false 143 | val latitude = args["latitude"] as Double 144 | val longitude = args["longitude"] as Double 145 | val zoom = (args["zoom"] as Double).toFloat() 146 | val tilt = (args["tilt"] as Double).toFloat() 147 | val bearing = (args["bearing"] as Double).toFloat() 148 | map.moveCamera( 149 | CameraUpdateFactory.newCameraPosition( 150 | CameraPosition(LatLng(latitude, longitude), zoom, tilt, bearing) 151 | ) 152 | ) 153 | options.isRotateGesturesEnabled = args["isRotateGesturesEnabled"] as Boolean 154 | options.isCompassEnabled = args["showCompass"] as Boolean 155 | options.isScaleControlsEnabled = args["showScale"] as Boolean 156 | options.isScrollGesturesEnabled = args["isScrollGesturesEnabled"] as Boolean 157 | options.isZoomGesturesEnabled = args["isZoomGesturesEnabled"] as Boolean 158 | options.isTiltGesturesEnabled = args["isTiltGesturesEnabled"] as Boolean 159 | options.isMyLocationButtonEnabled = args["showUserLocationButton"] as Boolean 160 | map.isMyLocationEnabled = args["showUserLocation"] as Boolean 161 | options.setZoomInByScreenCenter(args["zoomingInPivotsAroundAnchorPoint"] as Boolean) 162 | map.mapType = (args["mapType"] as Int) + 1 163 | map.isTouchPoiEnable = args["isTouchPoiEnable"] as Boolean 164 | map.isTrafficEnabled = args["showTraffic"] as Boolean 165 | map.showIndoorMap(args["showIndoorMap"] as Boolean) 166 | map.showMapText(args["showMapText"] as Boolean) 167 | map.showBuildings(args["showBuildings"] as Boolean) 168 | val language = args["language"] as Int 169 | map.setMapLanguage(if (language == 0) AMap.CHINESE else AMap.ENGLISH) 170 | map.maxZoomLevel = (args["maxZoom"] as Double).toFloat() 171 | map.minZoomLevel = (args["minZoom"] as Double).toFloat() 172 | } 173 | 174 | } -------------------------------------------------------------------------------- /fl_amap_map/android/src/main/kotlin/fl/amap/map/map/AMapViewListener.kt: -------------------------------------------------------------------------------- 1 | package fl.amap.map.map 2 | 3 | import android.graphics.Bitmap 4 | import android.graphics.Rect 5 | import android.location.Location 6 | import android.view.MotionEvent 7 | import android.view.View 8 | import com.amap.api.maps.AMap 9 | import com.amap.api.maps.CustomRenderer 10 | import com.amap.api.maps.LocationSource 11 | import com.amap.api.maps.SwipeDismissTouchListener 12 | import com.amap.api.maps.WearMapView 13 | import com.amap.api.maps.model.* 14 | import com.autonavi.base.ae.gmap.AMapAppRequestParam 15 | import fl.amap.map.AMapMapPlugin.Companion.flEventChannel 16 | import fl.amap.map.data 17 | import fl.channel.FlChannelPlugin 18 | import fl.channel.FlEventChannel 19 | import javax.microedition.khronos.egl.EGLConfig 20 | import javax.microedition.khronos.opengles.GL10 21 | 22 | // AMap.CancelableCallback, AMap.ImageInfoWindowAdapter,AMap.OnCacheRemoveListener,AMap.InfoWindowAdapter, AMap.OnMapScreenShotListener, AMap.OnMapSnapshotListener, AMap.OnPolylineClickListener, CustomRenderer, LocationSource, LocationSource.OnLocationChangedListener, AMap.OnMultiPointClickListener, SwipeDismissTouchListener.DismissCallbacks, WearMapView.OnDismissCallback 23 | class AMapViewListener(private var viewId: Int, private var map: AMap) : AMap.AMapAppResourceRequestListener, 24 | 25 | AMap.OnCameraChangeListener, AMap.OnIndoorBuildingActiveListener, AMap.OnInfoWindowClickListener, 26 | AMap.OnMapClickListener, AMap.OnMapLoadedListener, AMap.OnMapLongClickListener, AMap.OnMapTouchListener, 27 | AMap.OnMarkerClickListener, AMap.OnMarkerDragListener, AMap.OnMyLocationChangeListener, AMap.OnPOIClickListener { 28 | 29 | init { 30 | map.addAMapAppResourceListener(this) 31 | map.addOnCameraChangeListener(this) 32 | map.addOnIndoorBuildingActiveListener(this) 33 | map.addOnInfoWindowClickListener(this) 34 | map.addOnMapClickListener(this) 35 | map.addOnMapLoadedListener(this) 36 | map.addOnMapLongClickListener(this) 37 | map.addOnMapTouchListener(this) 38 | map.addOnMarkerClickListener(this) 39 | map.addOnMarkerDragListener(this) 40 | map.addOnMyLocationChangeListener(this) 41 | map.addOnPOIClickListener(this) 42 | } 43 | 44 | override fun onMapLoaded() { 45 | val map = getIdMap() 46 | map["method"] = "onMapLoaded" 47 | flEventChannel?.send(map) 48 | } 49 | 50 | override fun onMyLocationChange(location: Location?) { 51 | val map = getIdMap() 52 | map["method"] = "onMyLocationChange" 53 | location?.data?.let { map.putAll(it) } 54 | flEventChannel?.send(map) 55 | } 56 | 57 | override fun onCameraChange(position: CameraPosition?) { 58 | val map = getIdMap() 59 | map["method"] = "onCameraChange" 60 | position?.data?.let { map.putAll(it) } 61 | flEventChannel?.send(map) 62 | } 63 | 64 | override fun onCameraChangeFinish(position: CameraPosition?) { 65 | val map = getIdMap() 66 | map["method"] = "onCameraChangeFinish" 67 | position?.data?.let { map.putAll(it) } 68 | flEventChannel?.send(map) 69 | } 70 | 71 | override fun onMapClick(latlng: LatLng?) { 72 | val map = getIdMap() 73 | map["method"] = "onMapClick" 74 | latlng?.let { map.putAll(it.data) } 75 | flEventChannel?.send(map) 76 | } 77 | 78 | override fun onMapLongClick(latlng: LatLng?) { 79 | val map = getIdMap() 80 | map["method"] = "onMapLongClick" 81 | latlng?.let { map.putAll(it.data) } 82 | flEventChannel?.send(map) 83 | } 84 | 85 | override fun onPOIClick(poi: Poi?) { 86 | val map = getIdMap() 87 | map["method"] = "onPOIClick" 88 | poi?.let { map["poi"] = listOf(it.data) } 89 | flEventChannel?.send(map) 90 | } 91 | 92 | override fun onMarkerClick(marker: Marker?): Boolean { 93 | val map = getIdMap() 94 | map["method"] = "onMarkerClick" 95 | marker?.let { map.putAll(it.data) } 96 | flEventChannel?.send(map) 97 | return true 98 | } 99 | 100 | override fun onMarkerDragStart(marker: Marker?) { 101 | val map = getIdMap() 102 | map["method"] = "onMarkerDragStart" 103 | marker?.let { map.putAll(it.data) } 104 | flEventChannel?.send(map) 105 | } 106 | 107 | override fun onMarkerDrag(marker: Marker?) { 108 | val map = getIdMap() 109 | map["method"] = "onMarkerDrag" 110 | marker?.let { map.putAll(it.data) } 111 | flEventChannel?.send(map) 112 | } 113 | 114 | override fun onMarkerDragEnd(marker: Marker?) { 115 | val map = getIdMap() 116 | map["method"] = "onMarkerDragEnd" 117 | marker?.let { map.putAll(it.data) } 118 | flEventChannel?.send(map) 119 | } 120 | 121 | 122 | override fun onRequest(param: AMapAppRequestParam?) { 123 | val map = getIdMap() 124 | map["method"] = "onRequest" 125 | flEventChannel?.send(map) 126 | } 127 | 128 | 129 | override fun OnIndoorBuilding(info: IndoorBuildingInfo?) { 130 | val map = getIdMap() 131 | map["method"] = "onIndoorBuilding" 132 | flEventChannel?.send(map) 133 | } 134 | 135 | override fun onInfoWindowClick(marker: Marker?) { 136 | val map = getIdMap() 137 | map["method"] = "onInfoWindowClick" 138 | marker?.let { map.putAll(it.data) } 139 | flEventChannel?.send(map) 140 | } 141 | 142 | 143 | override fun onTouch(event: MotionEvent?) { 144 | val map = getIdMap() 145 | map["method"] = "onTouch" 146 | flEventChannel?.send(map) 147 | } 148 | 149 | 150 | private fun getIdMap(): MutableMap { 151 | return mutableMapOf("id" to viewId) 152 | } 153 | 154 | fun removeListener() { 155 | map.removeAMapAppResourceListener(this) 156 | map.removeOnCameraChangeListener(this) 157 | map.removeOnIndoorBuildingActiveListener(this) 158 | map.removeOnInfoWindowClickListener(this) 159 | map.removeOnMapClickListener(this) 160 | map.removeOnMapLoadedListener(this) 161 | map.removeOnMapLongClickListener(this) 162 | map.removeOnMapTouchListener(this) 163 | map.removeOnMarkerClickListener(this) 164 | map.removeOnMarkerDragListener(this) 165 | map.removeOnMyLocationChangeListener(this) 166 | map.removeOnPOIClickListener(this) 167 | } 168 | 169 | } -------------------------------------------------------------------------------- /fl_amap_map/example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | .lock 12 | .iml 13 | .metadata 14 | 15 | # IntelliJ related 16 | *.iml 17 | *.ipr 18 | *.iws 19 | .idea/ 20 | 21 | # The .vscode folder contains launch configuration and tasks you configure in 22 | # VS Code which you may wish to be included in version control, so this line 23 | # is commented out by default. 24 | #.vscode/ 25 | 26 | # Flutter/Dart/Pub related 27 | **/doc/api/ 28 | **/ios/Flutter/.last_build_id 29 | .dart_tool/ 30 | .flutter-plugins 31 | .flutter-plugins-dependencies 32 | .packages 33 | .pub-cache/ 34 | .pub/ 35 | /build/ 36 | 37 | # Web related 38 | lib/generated_plugin_registrant.dart 39 | 40 | # Symbolication related 41 | app.*.symbols 42 | 43 | # Obfuscation related 44 | app.*.map.json 45 | 46 | # Android Studio will place build artifacts here 47 | /android/app/debug 48 | /android/app/profile 49 | /android/app/release 50 | -------------------------------------------------------------------------------- /fl_amap_map/example/README.md: -------------------------------------------------------------------------------- 1 | # example -------------------------------------------------------------------------------- /fl_amap_map/example/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml -------------------------------------------------------------------------------- /fl_amap_map/example/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /.kotlin 6 | /gradlew.bat 7 | /local.properties 8 | GeneratedPluginRegistrant.java 9 | 10 | # Remember to never publicly share your keystore. 11 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 12 | key.properties 13 | **/*.keystore 14 | **/*.jks 15 | .cxx 16 | .kotlin 17 | -------------------------------------------------------------------------------- /fl_amap_map/example/android/app/amap.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap_map/example/android/app/amap.jks -------------------------------------------------------------------------------- /fl_amap_map/example/android/app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("com.android.application") 3 | id("kotlin-android") 4 | id("dev.flutter.flutter-gradle-plugin") 5 | } 6 | 7 | android { 8 | namespace = "com.fl.amap.example" 9 | compileSdk = flutter.compileSdkVersion 10 | 11 | compileOptions { 12 | sourceCompatibility = JavaVersion.VERSION_21 13 | targetCompatibility = JavaVersion.VERSION_21 14 | } 15 | 16 | kotlinOptions { 17 | jvmTarget = JavaVersion.VERSION_21.toString() 18 | } 19 | 20 | defaultConfig { 21 | applicationId = "com.fl.amap.example" 22 | minSdk = flutter.minSdkVersion 23 | targetSdk = flutter.targetSdkVersion 24 | versionCode = flutter.versionCode 25 | versionName = flutter.versionName 26 | } 27 | signingConfigs { 28 | create("release") { 29 | storeFile = file("amap.jks") 30 | storePassword = "amap123" 31 | keyAlias = "amap" 32 | keyPassword = "amap123" 33 | } 34 | } 35 | 36 | buildTypes { 37 | getByName("debug") { 38 | signingConfig = signingConfigs.getByName("release") 39 | proguardFiles(getDefaultProguardFile("proguard-android.txt"), "consumer-rules.pro") 40 | } 41 | getByName("release") { 42 | signingConfig = signingConfigs.getByName("release") 43 | proguardFiles(getDefaultProguardFile("proguard-android.txt"), "consumer-rules.pro") 44 | } 45 | } 46 | } 47 | 48 | flutter { 49 | source = "../.." 50 | } 51 | -------------------------------------------------------------------------------- /fl_amap_map/example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /fl_amap_map/example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 15 | 16 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /fl_amap_map/example/android/app/src/main/kotlin/com/fl/amap/example/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.fl.amap.example 2 | 3 | import androidx.annotation.NonNull 4 | import io.flutter.embedding.android.FlutterActivity 5 | import io.flutter.embedding.engine.FlutterEngine 6 | import io.flutter.plugins.GeneratedPluginRegistrant 7 | 8 | class MainActivity: FlutterActivity() { 9 | override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { 10 | GeneratedPluginRegistrant.registerWith(flutterEngine); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /fl_amap_map/example/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /fl_amap_map/example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /fl_amap_map/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap_map/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /fl_amap_map/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap_map/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /fl_amap_map/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap_map/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /fl_amap_map/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap_map/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /fl_amap_map/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap_map/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /fl_amap_map/example/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /fl_amap_map/example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /fl_amap_map/example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /fl_amap_map/example/android/build.gradle.kts: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | } 7 | 8 | val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get() 9 | rootProject.layout.buildDirectory.value(newBuildDir) 10 | 11 | subprojects { 12 | val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) 13 | project.layout.buildDirectory.value(newSubprojectBuildDir) 14 | } 15 | subprojects { 16 | project.evaluationDependsOn(":app") 17 | } 18 | 19 | tasks.register("clean") { 20 | delete(rootProject.layout.buildDirectory) 21 | } 22 | -------------------------------------------------------------------------------- /fl_amap_map/example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /fl_amap_map/example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip -------------------------------------------------------------------------------- /fl_amap_map/example/android/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | val flutterSdkPath = run { 3 | val properties = java.util.Properties() 4 | file("local.properties").inputStream().use { properties.load(it) } 5 | val flutterSdkPath = properties.getProperty("flutter.sdk") 6 | require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } 7 | flutterSdkPath 8 | } 9 | 10 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") 11 | 12 | repositories { 13 | google() 14 | mavenCentral() 15 | gradlePluginPortal() 16 | } 17 | } 18 | 19 | plugins { 20 | id("dev.flutter.flutter-plugin-loader") version "1.0.0" 21 | id("com.android.application") version "8.7.0" apply false 22 | id("org.jetbrains.kotlin.android") version "2.0.20" apply false 23 | } 24 | 25 | include(":app") 26 | -------------------------------------------------------------------------------- /fl_amap_map/example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 12.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | platform :ios, '13.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | target 'RunnerTests' do 36 | inherit! :search_paths 37 | end 38 | end 39 | 40 | post_install do |installer| 41 | installer.pods_project.targets.each do |target| 42 | flutter_additional_ios_build_settings(target) 43 | # Start of the permission_handler configuration 44 | target.build_configurations.each do |config| 45 | config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [ 46 | '$(inherited)', 47 | 48 | ## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse] 49 | 'PERMISSION_LOCATION=1', 50 | ] 51 | end 52 | # End of the permission_handler configuration 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 43 | 49 | 50 | 51 | 52 | 53 | 64 | 66 | 72 | 73 | 74 | 75 | 81 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @main 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap_map/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap_map/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap_map/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wayaer/fl_amap/e92db535d2c715d4e41be7326059ec1f5b524dae/fl_amap_map/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CADisableMinimumFrameDurationOnPhone 6 | 7 | CFBundleDevelopmentRegion 8 | $(DEVELOPMENT_LANGUAGE) 9 | CFBundleDisplayName 10 | FlAMap 11 | CFBundleExecutable 12 | $(EXECUTABLE_NAME) 13 | CFBundleIdentifier 14 | $(PRODUCT_BUNDLE_IDENTIFIER) 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | FlAMap 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | $(FLUTTER_BUILD_NAME) 23 | CFBundleSignature 24 | ???? 25 | CFBundleVersion 26 | $(FLUTTER_BUILD_NUMBER) 27 | LSRequiresIPhoneOS 28 | 29 | NSAppTransportSecurity 30 | 31 | NSAllowsArbitraryLoads 32 | 33 | NSAllowsArbitraryLoadsForMedia 34 | 35 | NSAllowsArbitraryLoadsInWebContent 36 | 37 | 38 | NSLocationAlwaysAndWhenInUseUsageDescription 39 | 获取定位 40 | NSLocationAlwaysUsageDescription 41 | 获取定位 42 | NSLocationWhenInUseUsageDescription 43 | 获取定位 44 | UIApplicationSupportsIndirectInputEvents 45 | 46 | UIBackgroundModes 47 | 48 | fetch 49 | location 50 | processing 51 | remote-notification 52 | 53 | UILaunchStoryboardName 54 | LaunchScreen 55 | UIMainStoryboardFile 56 | Main 57 | UISupportedInterfaceOrientations 58 | 59 | UIInterfaceOrientationLandscapeLeft 60 | UIInterfaceOrientationLandscapeRight 61 | UIInterfaceOrientationPortrait 62 | UIInterfaceOrientationPortraitUpsideDown 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /fl_amap_map/example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /fl_amap_map/example/ios/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | import XCTest 4 | 5 | class RunnerTests: XCTestCase { 6 | 7 | func testExample() { 8 | // If you add code to the Runner application, consider adding tests here. 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /fl_amap_map/example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:example/src/map_view_page.dart'; 2 | import 'package:fl_amap_map/fl_amap_map.dart'; 3 | import 'package:fl_extended/fl_extended.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:permission_handler/permission_handler.dart'; 6 | 7 | void main() { 8 | WidgetsFlutterBinding.ensureInitialized(); 9 | runApp(MaterialApp( 10 | navigatorKey: FlExtended().navigatorKey, 11 | scaffoldMessengerKey: FlExtended().scaffoldMessengerKey, 12 | debugShowCheckedModeBanner: false, 13 | theme: ThemeData.light(), 14 | darkTheme: ThemeData.dark(), 15 | title: 'FlAMap', 16 | home: const App())); 17 | } 18 | 19 | class App extends StatelessWidget { 20 | const App({super.key}); 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | bool isInit = false; 25 | return Scaffold( 26 | appBar: AppBar(title: const Text('高德地图')), 27 | body: Universal( 28 | width: double.infinity, 29 | mainAxisAlignment: MainAxisAlignment.center, 30 | crossAxisAlignment: CrossAxisAlignment.center, 31 | children: [ 32 | ElevatedText( 33 | onPressed: () async { 34 | isInit = await FlAMapMap().setAMapKey( 35 | iosKey: '7d3261c06027bdc87aca547c99ad5b2f', 36 | androidKey: '77418e726d0eefc0ac79a8619b5f4d97', 37 | isAgree: true, 38 | isContains: true, 39 | isShow: true); 40 | showToast('高德地图ApiKey设置$isInit'); 41 | }, 42 | text: '设置高德key'), 43 | ElevatedText( 44 | onPressed: () async { 45 | if (!isInit) { 46 | showToast('请先设置高德key'); 47 | return; 48 | } 49 | if (!await getPermission(Permission.location)) { 50 | showToast('未获取到定位权限'); 51 | return; 52 | } 53 | push(const MapViewPage()); 54 | }, 55 | text: '高德地图'), 56 | ])); 57 | } 58 | } 59 | 60 | class ElevatedText extends StatelessWidget { 61 | const ElevatedText({super.key, required this.text, required this.onPressed}); 62 | 63 | final String text; 64 | final VoidCallback onPressed; 65 | 66 | @override 67 | Widget build(BuildContext context) => ElevatedButton(onPressed: onPressed, child: Text(text)); 68 | } 69 | 70 | Future getPermission(Permission permission) async { 71 | final PermissionStatus status = await permission.request(); 72 | if (!status.isGranted) { 73 | await openAppSettings(); 74 | return await permission.request().isGranted; 75 | } 76 | return status.isGranted; 77 | } 78 | -------------------------------------------------------------------------------- /fl_amap_map/example/lib/src/map_view_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:fl_amap_map/fl_amap_map.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class MapViewPage extends StatefulWidget { 5 | const MapViewPage({super.key}); 6 | 7 | @override 8 | State createState() => _MapViewPageState(); 9 | } 10 | 11 | class _MapViewPageState extends State { 12 | AMapController? controller; 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return Scaffold( 17 | appBar: AppBar(title: const Text('高德地图')), 18 | body: AMapView( 19 | options: const AMapOptions( 20 | mapType: MapType.standardNight, 21 | showCompass: true, 22 | showMapText: true, 23 | showTraffic: true, 24 | showUserLocation: true, 25 | showUserLocationButton: true, 26 | latLng: LatLng(30.572961, 104.066301)), 27 | onCreateController: (AMapController controller) { 28 | this.controller = controller; 29 | controller.setTrackingMode(TrackingMode.none); 30 | controller.android?.addListener(); 31 | controller.ios?.addListener(); 32 | })); 33 | } 34 | 35 | @override 36 | void dispose() { 37 | controller?.dispose(); 38 | super.dispose(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /fl_amap_map/example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: example 2 | description: A new Flutter project. 3 | publish_to: 'none' 4 | version: 1.0.0 5 | 6 | environment: 7 | sdk: '>=3.0.0 <4.0.0' 8 | flutter: '>=3.24.0' 9 | 10 | dependencies: 11 | fl_amap_map: 12 | path: ../ 13 | flutter: 14 | sdk: flutter 15 | fl_extended: ^1.7.2 16 | fl_dio: ^1.4.0 17 | flutter_curiosity: ^6.6.0 18 | permission_handler: ^11.4.0 19 | 20 | dev_dependencies: 21 | flutter_lints: ^5.0.0 22 | 23 | flutter: 24 | uses-material-design: true 25 | -------------------------------------------------------------------------------- /fl_amap_map/ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | .generated/ 16 | 17 | *.pbxuser 18 | *.mode1v3 19 | *.mode2v3 20 | *.perspectivev3 21 | 22 | !default.pbxuser 23 | !default.mode1v3 24 | !default.mode2v3 25 | !default.perspectivev3 26 | 27 | xcuserdata 28 | 29 | *.moved-aside 30 | 31 | *.pyc 32 | *sync/ 33 | Icon? 34 | .tags* 35 | 36 | /Flutter/Generated.xcconfig 37 | -------------------------------------------------------------------------------- /fl_amap_map/ios/Classes/AMapPlugin.swift: -------------------------------------------------------------------------------- 1 | import fl_channel 2 | import Flutter 3 | import MAMapKit 4 | 5 | public class AMapMapPlugin: NSObject, FlutterPlugin { 6 | private var channel: FlutterMethodChannel? 7 | private var binaryMessenger: FlutterBinaryMessenger 8 | public static var flEventChannel: FlEventChannel? 9 | 10 | public static func register(with registrar: FlutterPluginRegistrar) { 11 | let channel = FlutterMethodChannel(name: "fl_amap_map", binaryMessenger: 12 | registrar.messenger()) 13 | let instance = AMapMapPlugin(channel, registrar.messenger()) 14 | registrar.addMethodCallDelegate(instance, channel: channel) 15 | registrar.register(AMapPlatformViewFactory(registrar), withId: "fl_amap_map", gestureRecognizersBlockingPolicy: FlutterPlatformViewGestureRecognizersBlockingPolicyWaitUntilTouchesEnded) 16 | } 17 | 18 | init(_ channel: FlutterMethodChannel, _ binaryMessenger: FlutterBinaryMessenger) { 19 | self.channel = channel 20 | self.binaryMessenger = binaryMessenger 21 | super.init() 22 | } 23 | 24 | public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { 25 | switch call.method { 26 | case "setApiKey": 27 | let args = call.arguments as! [String: Any?] 28 | let key = args["key"] as! String 29 | let isAgree = args["isAgree"] as! Bool 30 | let isContains = args["isContains"] as! Bool 31 | let isShow = args["isShow"] as! Bool 32 | AMapServices.shared().apiKey = key 33 | AMapServices.shared().enableHTTPS = args["enableHTTPS"] as! Bool 34 | MAMapView.updatePrivacyAgree(isAgree ? .didAgree : .notAgree) 35 | MAMapView.updatePrivacyShow(isShow ? .didShow : .notShow, privacyInfo: isContains ? .didContain : .notContain) 36 | AMapMapPlugin.flEventChannel = FlChannelPlugin.getEventChannel("fl_amap_map_event") 37 | result(true) 38 | default: 39 | result(FlutterMethodNotImplemented) 40 | } 41 | } 42 | 43 | public func detachFromEngine(for registrar: FlutterPluginRegistrar) { 44 | channel?.setMethodCallHandler(nil) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /fl_amap_map/ios/Classes/Extension.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MAMapKit 3 | 4 | extension Dictionary { 5 | mutating func merge(_ other: S) 6 | where S: Sequence, S.Iterator.Element == (key: Key, value: Value) 7 | { 8 | for (k, v) in other { 9 | self[k] = v 10 | } 11 | } 12 | } 13 | 14 | extension CLLocationCoordinate2D { 15 | var data: [String: Any?] { 16 | [ 17 | "longitude": longitude, 18 | "latitude": latitude, 19 | ] 20 | } 21 | } 22 | 23 | extension MATouchPoi { 24 | var data: [String: Any?] { 25 | [ 26 | "latLng": coordinate.data, 27 | "name": name, 28 | "poiId": uid, 29 | ] 30 | } 31 | } 32 | 33 | extension CLHeading { 34 | var data: [String: Any?] { 35 | [ 36 | "x": x, 37 | "y": y, 38 | "z": z, 39 | "timestamp": timestamp.timeIntervalSince1970, 40 | "magneticHeading": magneticHeading, 41 | "trueHeading": trueHeading, 42 | "headingAccuracy": headingAccuracy, 43 | ] 44 | } 45 | } 46 | 47 | extension CLLocation { 48 | var data: [String: Any?] { 49 | [ 50 | "latLng": coordinate.data, 51 | "accuracy": (horizontalAccuracy + verticalAccuracy) / 2, 52 | "altitude": altitude, 53 | "speed": speed, 54 | "timestamp": timestamp.timeIntervalSince1970, 55 | ] 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /fl_amap_map/ios/Classes/map/AMapPlatformViewFactory.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | 3 | public class AMapPlatformViewFactory: NSObject, FlutterPlatformViewFactory { 4 | private var registrar: FlutterPluginRegistrar 5 | 6 | init(_ registrar: FlutterPluginRegistrar) { 7 | self.registrar = registrar 8 | super.init() 9 | } 10 | 11 | public func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?) -> FlutterPlatformView { 12 | let channel = FlutterMethodChannel(name: "fl_amap_map_\(viewId)", binaryMessenger: registrar.messenger()) 13 | let options = args as! [String: Any] 14 | return AMapView(channel: channel, frame: frame, viewId: viewId, options: options) 15 | } 16 | 17 | public func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol { 18 | FlutterStandardMessageCodec.sharedInstance() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /fl_amap_map/ios/Classes/map/AMapView.swift: -------------------------------------------------------------------------------- 1 | import AMapFoundationKit 2 | import Flutter 3 | import MAMapKit 4 | 5 | public class AMapView: NSObject, FlutterPlatformView { 6 | private var channel: FlutterMethodChannel? 7 | private var mapview: MAMapView? 8 | private var viewId: Int64 9 | private var mapviewDelegate: AMapViewDelegate? 10 | 11 | init(channel: FlutterMethodChannel, frame: CGRect, viewId: Int64, options: [String: Any]) { 12 | self.channel = channel 13 | self.viewId = viewId 14 | mapview = MAMapView(frame: frame) 15 | super.init() 16 | channel.setMethodCallHandler(handle) 17 | mapview!.accessibilityElementsHidden = false 18 | setOptions(args: options) 19 | } 20 | 21 | public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { 22 | switch call.method { 23 | case "setOptions": 24 | let options = call.arguments as! [String: Any] 25 | setOptions(args: options) 26 | case "reloadMap": 27 | mapview?.reloadMap() 28 | result(true) 29 | case "setRenderFps": 30 | mapview?.maxRenderFrame = UInt(call.arguments as! Int) 31 | result(true) 32 | case "setCenter": 33 | let args = call.arguments as! [String: Any] 34 | mapview?.setCenter(CLLocationCoordinate2D(latitude: args["latitude"] as! Double, longitude: args["longitude"] as! Double), animated: args["animated"] as! Bool) 35 | result(true) 36 | case "setTrackingMode": 37 | let args = call.arguments as! [String: Any] 38 | let mode = args["mode"] as! Int 39 | var trackingMode = MAUserTrackingMode.follow 40 | if mode == 0 { 41 | trackingMode = MAUserTrackingMode.none 42 | } else if mode == 7 { 43 | trackingMode = MAUserTrackingMode.followWithHeading 44 | } 45 | mapview?.setUserTrackingMode(trackingMode, animated: args["animated"] as! Bool) 46 | result(true) 47 | case "addListener": 48 | if mapviewDelegate == nil, mapview != nil { 49 | mapviewDelegate = AMapViewDelegate(viewId) 50 | mapview!.delegate = mapviewDelegate 51 | } 52 | result(mapviewDelegate != nil) 53 | case "removeListener": 54 | mapviewDelegate = nil 55 | mapview?.delegate = nil 56 | result(mapviewDelegate == nil) 57 | 58 | case "dispose": 59 | mapview = nil 60 | mapview?.removeObserver(self, forKeyPath: "frame") 61 | channel?.setMethodCallHandler(nil) 62 | channel = nil 63 | result(true) 64 | case "addOverlays": 65 | // mapview?.addOverlays( /* <#T##overlays: [Any]!##[Any]!#> */, level: <#T##MAOverlayLevel#>) 66 | case "addAnnotation": 67 | let point = MAPointAnnotation() 68 | point.coordinate = CLLocationCoordinate2D(latitude: 39.979590, longitude: 116.352792) 69 | mapview?.addAnnotation(point) 70 | default: 71 | result(FlutterMethodNotImplemented) 72 | } 73 | } 74 | 75 | func setOptions(args: [String: Any?]) { 76 | let animated = args["animated"] as! Bool 77 | mapview?.rotationDegree = CGFloat(args["tilt"] as! Double) 78 | mapview?.isRotateEnabled = args["isTiltGesturesEnabled"] as! Bool 79 | mapview?.cameraDegree = CGFloat(args["bearing"] as! Double) 80 | mapview?.mapType = MAMapType(rawValue: args["mapType"] as! Int) ?? MAMapType.standard 81 | mapview?.setZoomLevel(CGFloat(args["zoom"] as! Double), animated: animated) 82 | mapview?.maxZoomLevel = args["maxZoom"] as! Double 83 | mapview?.minZoomLevel = args["minZoom"] as! Double 84 | mapview?.isZoomEnabled = args["isZoomGesturesEnabled"] as! Bool 85 | mapview?.zoomingInPivotsAroundAnchorPoint = args["zoomingInPivotsAroundAnchorPoint"] as! Bool 86 | mapview?.isRotateCameraEnabled = args["isRotateGesturesEnabled"] as! Bool 87 | mapview?.showsUserLocation = args["showUserLocation"] as! Bool 88 | mapview?.allowsBackgroundLocationUpdates = args["allowsBackgroundLocationUpdates"] as! Bool 89 | mapview?.showsCompass = args["showCompass"] as! Bool 90 | mapview?.showsScale = args["showScale"] as! Bool 91 | mapview?.isScrollEnabled = args["isScrollGesturesEnabled"] as! Bool 92 | mapview?.touchPOIEnabled = args["isTouchPoiEnable"] as! Bool 93 | mapview?.isShowTraffic = args["showTraffic"] as! Bool 94 | mapview?.isShowsIndoorMap = args["showIndoorMap"] as! Bool 95 | mapview?.isShowsLabels = args["showMapText"] as! Bool 96 | mapview?.isShowsBuildings = args["showBuildings"] as! Bool 97 | mapview?.mapLanguage = NSNumber(value: args["language"] as! Int) 98 | mapview?.centerCoordinate = CLLocationCoordinate2D(latitude: args["latitude"] as! Double, longitude: args["longitude"] as! Double) 99 | } 100 | 101 | public func view() -> UIView { 102 | mapview! 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /fl_amap_map/ios/Resources/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyTrackingDomains 6 | 7 | NSPrivacyAccessedAPITypes 8 | 9 | NSPrivacyCollectedDataTypes 10 | 11 | NSPrivacyTracking 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /fl_amap_map/ios/fl_amap_map.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 3 | # 4 | Pod::Spec.new do |s| 5 | s.name = 'fl_amap_map' 6 | s.version = '0.0.1' 7 | s.summary = 'A Flutter plugin.' 8 | s.description = <<-DESC 9 | A new Flutter plugin. 10 | DESC 11 | s.homepage = 'https://github.com/Wayaer/fl_amap.git' 12 | s.license = { :file => '../LICENSE' } 13 | s.author = { 'email' => 'wayaer@foxmail.com' } 14 | s.source = { :path => '.' } 15 | s.source_files = 'Classes/**/*' 16 | s.dependency 'Flutter' 17 | s.dependency 'AMap3DMap' 18 | s.dependency 'fl_channel' 19 | s.static_framework = true 20 | s.ios.deployment_target = '12.0' 21 | s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } 22 | s.swift_version = '5.0' 23 | 24 | end 25 | 26 | -------------------------------------------------------------------------------- /fl_amap_map/lib/fl_amap_map.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:ffi'; 3 | 4 | import 'package:fl_channel/fl_channel.dart'; 5 | import 'package:flutter/foundation.dart'; 6 | import 'package:flutter/gestures.dart'; 7 | import 'package:flutter/material.dart'; 8 | import 'package:flutter/services.dart'; 9 | 10 | part 'src/amap_view.dart'; 11 | 12 | part 'src/controller.dart'; 13 | 14 | part 'src/model.dart'; 15 | 16 | part 'src/enum.dart'; 17 | 18 | part 'src/controller_for_android.dart'; 19 | 20 | part 'src/controller_for_ios.dart'; 21 | 22 | class FlAMapMap { 23 | final MethodChannel _channel = MethodChannel('fl_amap_map'); 24 | 25 | factory FlAMapMap() => _singleton ??= FlAMapMap._(); 26 | 27 | FlAMapMap._(); 28 | 29 | static FlAMapMap? _singleton; 30 | 31 | FlEventChannel? _flEventChannel; 32 | 33 | /// 设置ios&android的key 34 | Future setAMapKey({ 35 | required String iosKey, 36 | required String androidKey, 37 | 38 | /// 设置是否同意用户授权政策 设置为true才可以调用其他功能 39 | bool isAgree = true, 40 | 41 | /// 设置包含隐私政策 设置为true才可以调用其他功能 42 | bool isContains = true, 43 | 44 | /// 并展示用户授权弹窗 设置为true才可以调用其他功能 45 | bool isShow = true, 46 | bool enableHTTPS = true, 47 | }) async { 48 | if (!_supportPlatform) return false; 49 | String? key; 50 | if (_isAndroid) key = androidKey; 51 | if (_isIOS) key = iosKey; 52 | if (key == null) return false; 53 | _flEventChannel ??= await FlChannel().create('${_channel.name}_event'); 54 | final state = await _channel.invokeMethod( 55 | 'setApiKey', {'key': key, 'isAgree': isAgree, 'isContains': isContains, 'isShow': isShow, 'enableHTTPS': enableHTTPS}); 56 | return state ?? false; 57 | } 58 | 59 | void dispose() { 60 | _flEventChannel?.dispose(); 61 | _flEventChannel = null; 62 | } 63 | } 64 | 65 | bool get _supportPlatform { 66 | if (!kIsWeb && (_isAndroid || _isIOS)) return true; 67 | debugPrint('Not support platform for $defaultTargetPlatform'); 68 | return false; 69 | } 70 | 71 | bool get _isAndroid => defaultTargetPlatform == TargetPlatform.android; 72 | 73 | bool get _isIOS => defaultTargetPlatform == TargetPlatform.iOS; 74 | 75 | class LatLng { 76 | const LatLng(this.latitude, this.longitude); 77 | 78 | LatLng.fromMap(Map map) 79 | : latitude = map['latitude'] as double?, 80 | longitude = map['longitude'] as double?; 81 | 82 | final double? latitude; 83 | final double? longitude; 84 | 85 | Map toMap() => {'latitude': latitude, 'longitude': longitude}; 86 | } 87 | -------------------------------------------------------------------------------- /fl_amap_map/lib/src/amap_view.dart: -------------------------------------------------------------------------------- 1 | part of '../fl_amap_map.dart'; 2 | 3 | typedef OnAMapControllerCreated = void Function(AMapController controller); 4 | 5 | class AMapView extends StatefulWidget { 6 | const AMapView( 7 | {super.key, 8 | this.gestureRecognizers, 9 | this.onCreateController, 10 | this.options = const AMapOptions(latLng: LatLng(30.651411, 103.998638))}); 11 | 12 | /// 需要应用到地图上的手势集合 13 | final Set>? gestureRecognizers; 14 | 15 | /// AMapController 回调 16 | final OnAMapControllerCreated? onCreateController; 17 | 18 | /// 初始配置信息 19 | final AMapOptions options; 20 | 21 | @override 22 | State createState() => _AMapViewState(); 23 | } 24 | 25 | class _AMapViewState extends State { 26 | @override 27 | Widget build(BuildContext context) { 28 | if (defaultTargetPlatform == TargetPlatform.android) { 29 | return AndroidView( 30 | viewType: 'fl_amap_map', 31 | onPlatformViewCreated: onPlatformViewCreated, 32 | gestureRecognizers: widget.gestureRecognizers, 33 | creationParams: widget.options.toMap(), 34 | creationParamsCodec: const StandardMessageCodec()); 35 | } else if (defaultTargetPlatform == TargetPlatform.iOS) { 36 | return UiKitView( 37 | viewType: 'fl_amap_map', 38 | onPlatformViewCreated: onPlatformViewCreated, 39 | gestureRecognizers: widget.gestureRecognizers, 40 | creationParams: widget.options.toMap(), 41 | creationParamsCodec: const StandardMessageCodec()); 42 | } 43 | return Text('当前平台:$defaultTargetPlatform, 不支持使用高德地图插件'); 44 | } 45 | 46 | Future onPlatformViewCreated(int id) async { 47 | final AMapController controller = AMapController(id: id); 48 | widget.onCreateController?.call(controller); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /fl_amap_map/lib/src/controller.dart: -------------------------------------------------------------------------------- 1 | part of '../fl_amap_map.dart'; 2 | 3 | class AMapController { 4 | AMapController({required this.id}) { 5 | _channel = MethodChannel('fl_amap_map_$id'); 6 | if (_isAndroid) _android = AMapControllerForAndroid(_channel, id); 7 | if (_isIOS) _ios = AMapControllerForIOS(_channel, id); 8 | } 9 | 10 | final int id; 11 | 12 | late MethodChannel _channel; 13 | 14 | /// 仅 android 可用 15 | AMapControllerForAndroid? _android; 16 | 17 | AMapControllerForAndroid? get android => _android; 18 | 19 | /// 仅 ios 可用 20 | AMapControllerForIOS? _ios; 21 | 22 | AMapControllerForIOS? get ios => _ios; 23 | 24 | /// 设置地图配置信息 25 | Future setOptions(AMapOptions options) async { 26 | final result = await _channel.invokeMethod('setOptions', options.toMap()); 27 | return result ?? false; 28 | } 29 | 30 | /// 销毁地图 31 | Future dispose() async { 32 | final result = await _channel.invokeMethod('dispose'); 33 | return result ?? false; 34 | } 35 | 36 | /// 最大帧数,有效的帧数为:60、30、20、10等能被60整除的数。默认为60 37 | Future setRenderFps(int fps) async { 38 | final result = await _channel.invokeMethod('setRenderFps', fps); 39 | return result ?? false; 40 | } 41 | 42 | /// 重新加载地图 43 | Future reloadMap() async { 44 | final result = await _channel.invokeMethod('reloadMap'); 45 | return result ?? false; 46 | } 47 | 48 | /// 设置地图定位跟随模式 49 | Future setTrackingMode(TrackingMode mode, {bool animated = true}) async { 50 | int modeIndex = mode.index; 51 | if (modeIndex > 2 && _isIOS) modeIndex = 1; 52 | final result = await _channel.invokeMethod('setTrackingMode', { 53 | 'mode': modeIndex, 54 | 'animated': animated, 55 | }); 56 | return result ?? false; 57 | } 58 | } 59 | 60 | -------------------------------------------------------------------------------- /fl_amap_map/lib/src/controller_for_android.dart: -------------------------------------------------------------------------------- 1 | part of '../fl_amap_map.dart'; 2 | 3 | typedef AMapLocationChangeListener = void Function(Location location); 4 | typedef AMapLoadedListener = void Function(); 5 | typedef AMapLatLngListener = void Function(LatLng latLng); 6 | typedef AMapPOIPressedListener = void Function(List poi); 7 | typedef AMapMarkerPressedListener = void Function(Marker marker); 8 | 9 | class AMapControllerForAndroid { 10 | AMapControllerForAndroid(this._channel, this._id); 11 | 12 | final MethodChannel _channel; 13 | final int _id; 14 | 15 | /// 添加回调监听 16 | Future addListener({ 17 | /// 定位改变回调 18 | AMapLocationChangeListener? onLocationChange, 19 | 20 | /// 地图加载完成回调 21 | AMapLoadedListener? onMapLoaded, 22 | 23 | /// 单击地图回调 24 | AMapLatLngListener? onMapPressed, 25 | 26 | /// 长按地图回调 27 | AMapLatLngListener? onMapLongPressed, 28 | 29 | /// poi 点击回调 30 | AMapPOIPressedListener? onPOIPressed, 31 | 32 | /// marker 点击回调 33 | AMapMarkerPressedListener? onMarkerPressed, 34 | }) async { 35 | /// 初始化原生sdk listener 36 | final result = await _channel.invokeMethod('addListener'); 37 | 38 | /// 添加消息监听通道 39 | FlAMapMap()._flEventChannel?.listen((data) { 40 | if (data is! Map || data['id'] != _id) return; 41 | final method = data['method']; 42 | debugPrint('消息回调==$method===$data'); 43 | switch (method) { 44 | case 'Loaded': 45 | onMapLoaded?.call(); 46 | break; 47 | case 'LocationChange': 48 | onLocationChange?.call(Location.fromMap(data)); 49 | break; 50 | case 'Pressed': 51 | onMapPressed?.call(LatLng.fromMap(data)); 52 | break; 53 | case 'LongPressed': 54 | onMapLongPressed?.call(LatLng.fromMap(data)); 55 | break; 56 | case 'MarkerPressed': 57 | onMarkerPressed?.call(Marker.formMap(data)); 58 | break; 59 | case 'POIPressed': 60 | onPOIPressed?.call(getPoiList(data['poi'])); 61 | break; 62 | } 63 | }); 64 | return result == true; 65 | } 66 | 67 | /// 重新加载地图 68 | Future addMarker() async { 69 | final marker = await _channel.invokeMapMethod('addMarker'); 70 | return marker == null ? null : Marker.formMap(marker); 71 | } 72 | } 73 | 74 | class MarkerOptions {} 75 | 76 | class Marker { 77 | Marker.formMap(Map map) 78 | : title = map['title'] as String?, 79 | snippet = map['snippet'] as String?, 80 | draggable = map['draggable'] as bool?, 81 | visible = map['visible'] as bool?, 82 | alpha = map['alpha'] as Double?, 83 | latLng = LatLng.fromMap(map['latLng']); 84 | 85 | /// 在地图上标记位置的经纬度值 86 | final LatLng? latLng; 87 | 88 | /// 点标记的标题 89 | final String? title; 90 | 91 | /// 点标记的内容 92 | final String? snippet; 93 | 94 | /// 点标记是否可拖拽 95 | final bool? draggable; 96 | 97 | /// 点标记是否可见 98 | final bool? visible; 99 | 100 | /// 点的透明度 101 | final Double? alpha; 102 | } 103 | -------------------------------------------------------------------------------- /fl_amap_map/lib/src/controller_for_ios.dart: -------------------------------------------------------------------------------- 1 | part of '../fl_amap_map.dart'; 2 | 3 | class AMapControllerForIOS { 4 | const AMapControllerForIOS(this._channel, this._id); 5 | 6 | final MethodChannel _channel; 7 | final int _id; 8 | 9 | /// 添加回调监听 10 | Future addListener() async { 11 | /// 初始化原生sdk listener 12 | final result = await _channel.invokeMethod('addListener'); 13 | 14 | /// 添加消息监听通道 15 | FlAMapMap()._flEventChannel?.listen((data) { 16 | if (data is! Map || data['id'] != _id) return; 17 | final method = data['method']; 18 | debugPrint('消息回调==$method===$data'); 19 | switch (method) {} 20 | }); 21 | return result == true; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /fl_amap_map/lib/src/enum.dart: -------------------------------------------------------------------------------- 1 | part of '../fl_amap_map.dart'; 2 | 3 | enum MapType { 4 | /// 普通地图 ios 0 android 1 5 | standard, 6 | 7 | /// 卫星地图 ios 1 android 2 8 | satellite, 9 | 10 | /// 黑夜地图 ios 2 android 3 11 | standardNight, 12 | 13 | /// 导航模式 ios 3 android 4 14 | navi, 15 | 16 | /// 公交模式 ios 4 android 5 17 | bus, 18 | } 19 | 20 | enum MapLanguage { chinese, english } 21 | 22 | enum TrackingMode { 23 | /// 不追踪用户的location更新 24 | none, 25 | 26 | /// 定位一次,且将视角移动到地图中心点。 27 | locate, 28 | 29 | /// 连续定位、且将视角移动到地图中心点,定位蓝点跟随设备移动。(1秒1次定位) 30 | follow, 31 | 32 | /// 连续定位、且将视角移动到地图中心点,地图依照设备方向旋转,定位点会跟随设备移动。(1秒1次定位) 33 | /// 仅支持 Android 34 | followRotate, 35 | 36 | /// 连续定位、且将视角移动到地图中心点,定位点依照设备方向旋转,并且会跟随设备移动。(1秒1次定位)默认执行此种模式。 37 | /// 仅支持 Android 38 | followLocationRotate, 39 | 40 | /// 连续定位、蓝点不会移动到地图中心点,定位点依照设备方向旋转,并且蓝点会跟随设备移动。 41 | /// 仅支持 Android 42 | followLocationRotateNoCenter, 43 | 44 | /// 连续定位、蓝点不会移动到地图中心点,地图依照设备方向旋转,并且蓝点会跟随设备移动。 45 | /// 仅支持 Android 46 | followRotateNoCenter, 47 | 48 | /// 追踪用户的location与heading更新 49 | /// 仅支持 IOS 50 | followWithHeading, 51 | } 52 | -------------------------------------------------------------------------------- /fl_amap_map/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: fl_amap_map 2 | description: AMap location and AMap plugin for flutter, supports single positioning and continuous positioning 3 | version: 0.0.1 4 | repository: https://github.com/Wayaer/fl_amap/tree/main/fl_amap_amap 5 | 6 | environment: 7 | sdk: '>=3.0.0 <4.0.0' 8 | flutter: '>=3.24.0' 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | fl_channel: ^1.0.3 14 | 15 | dev_dependencies: 16 | flutter_lints: ^5.0.0 17 | 18 | flutter: 19 | plugin: 20 | platforms: 21 | android: 22 | package: fl.amap.map 23 | pluginClass: AMapMapPlugin 24 | ios: 25 | pluginClass: AMapMapPlugin 26 | -------------------------------------------------------------------------------- /format.sh: -------------------------------------------------------------------------------- 1 | dart format fl_amap/lib 2 | dart format fl_amap/example/lib 3 | dart format fl_amap_map/lib 4 | dart format fl_amap_map/example/lib 5 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: fl_amap 2 | description: AMap plugin for flutter 3 | version: 1.0.0 4 | repository: https://github.com/Wayaer/fl_amap 5 | 6 | environment: 7 | sdk: '>=3.0.0 <4.0.0' 8 | flutter: '>=3.29.0' 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | 14 | dev_dependencies: 15 | flutter_lints: ^5.0.0 16 | --------------------------------------------------------------------------------