福州模板做网站,制作荧光字网站,建工网校app,公司网站制作找哪家Android 谷歌地图 前言正文一、设置Google Cloud 项目二、项目配置① 设置SDK② 配置API密钥③ 配置AndroidManifest.xml 三、添加地图四、定位当前① 请求定位权限② 我的位置控件③ 获取当前位置 五、配置地图① xml配置地图② 代码配置地图③ 地图点击事件④ 管理Marker 六、… Android 谷歌地图 前言正文一、设置Google Cloud 项目二、项目配置① 设置SDK② 配置API密钥③ 配置AndroidManifest.xml 三、添加地图四、定位当前① 请求定位权限② 我的位置控件③ 获取当前位置 五、配置地图① xml配置地图② 代码配置地图③ 地图点击事件④ 管理Marker 六、地址位置编码① 坐标转地址② 地址转坐标 七、源码 前言 在国内你选择的SDK可以是高德、百度、腾讯等但在国外你首选肯定是谷歌因此要进行Google地图的开发你首先要解决下面三个问题
VPNGoogle账号信用卡 American Express美国运通卡Discover美国发现卡JCBJapan Credit Bureau日本国际信用卡MasterCard万事达VISA维萨
正文 首先我们进入Google的地图开发平台点击Google Maps进入建议你使用Google Chrome进行访问。 一、设置Google Cloud 项目 点击这里的创建新项目按钮。 输入名字后点击创建。 然后我们进入API和服务然后你就会发现你需要设置账号信息和付款验证信息这一步还挺麻烦的主要是那个卡的信息在前面我已经提过了。 在你通过账号信息验证之后就可以创建API秘钥了创建的API之后需要对应使用应用的包名和SHA1证书指纹一个API秘钥可以增加多个App进行配置只有配置之后的App才能通过此API秘钥访问Google Maps。 在你配置好之后你就会得到一个API密钥这个密钥我们需要在项目中配置好下面进入项目。
二、项目配置 一般情况这里是要进入项目的创建和配置了而因为Google这边比较特殊你可能需要先上架一个应用上去我这边的正式版的你可以试试测试版行不行有应用之后我们就可以通过选择应用使配置的API密钥去生效。 我之前在使用的时候就遇到过一个指纹不对的情况结果发现你的应用有两个指纹你可以理解为测试版和正式版如果你遇到这个情况那么你换一下试试看。
① 设置SDK 首先你要检查一下你的项目是否导入google()、mavenCentral()这两个仓库如果没有的话你就需要导入了有则不用管而根据你所使用的Gradle的不同你配置这两个仓库的地方也不一样如果Gradle是7.4以上的则在settings.gradle文件中配置否则在工程级build.gradle配置我这边就是工程级build.gradle如下所示
repositories {google()mavenCentral()
}然后我们找到需要使用地图的模块例如app模块找到该模块下的build.gradle在里面中dependencies{}闭包中添加如下依赖 // Maps SDK for Androidimplementation com.google.android.gms:play-services-maps:19.0.0同时我们注意配置一下buildFeatures在模块级 build.gradle的 buildFeatures 部分中 或 build.gradle 文件中请添加 BuildConfig 类该类可用于 访问此过程后面部分定义的元数据值
buildFeatures {buildConfig true
}这里你可以先Sync Now同步一下也可以不急在配置了API密钥之后再同步。
② 配置API密钥
基于Google上推荐的配置方式我们这里首先在打开工程的build.gradle在里面添加
buildscript {dependencies {classpath com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:2.0.1}
}这是Android 版 Secret Gradle 插件然后打开app模块下build.gradle在plugins{}闭包中添加如下代码 id com.google.android.libraries.mapsplatform.secrets-gradle-plugin然后我们将build.gradle文件中设置 targetSdk 和 compileSdk 到 34如果不能到34那么你的相关的依赖就需要降低一些版本否则会出现同步失败的情况这是你可以Sync Now同步一下了。 接着我们在功能的根目录下创建一个secrets.properties 文件请注意它和你的工程级build.gradle是同级的在这个文件里面配置如下代码
MAPS_API_KEYYOUR_API_KEY注意将YOUR_API_KEY替换为你实际申请到的API密钥然后保存文件然后同样是这个目录我们再创建一个local.defaults.properties文件里面的代码如下所示
MAPS_API_KEYDEFAULT_API_KEY此文件的作用是为 API 密钥提供备用位置以免在找不到 secrets.properties 文件的情况下构建失败。如果您是从省略 secrets.properties 的版本控制系统中克隆应用而您还没有在本地创建 secrets.properties 文件来提供 API 密钥就可能会出现构建失败。然后保存文件。
接着我们打开 AndroidManifest.xml 文件在application 标签中添加如下代码
meta-dataandroid:namecom.google.android.geo.API_KEYandroid:value${MAPS_API_KEY} /最后我们在app模块下的android{}闭包中增加一个secrets属性如果该属性不存在代码如下所示
secrets {propertiesFileName secrets.propertiesdefaultPropertiesFileName local.defaults.propertiesignoreList.add(keyToIgnore) ignoreList.add(sdk.*)
} 下面再Sync Now同步一下。
③ 配置AndroidManifest.xml 首先配置Google Play 服务版本号在 application标签中添加以下声明。该操作会嵌入编译应用时所用 Google Play 服务的版本代码如下所示
meta-dataandroid:namecom.google.android.gms.versionandroid:valueinteger/google_play_services_version /然后再增加一个Apache HTTP 旧版库代码如下所示
uses-libraryandroid:nameorg.apache.http.legacyandroid:requiredfalse /最后我们再配置一下需要使用到的权限
uses-permission android:nameandroid.permission.ACCESS_FINE_LOCATION/
uses-permission android:nameandroid.permission.ACCESS_COARSE_LOCATION/
uses-permission android:nameandroid.permission.WRITE_EXTERNAL_STORAGE /到此为止配置工作就完成了你可以先不急着添加地图先运行一下试试看有没有报错或者其他的问题如果没有问题再进行下一步。
三、添加地图
首先我们在工程中创建一个map包里面新建一个GoogleMapActivity。
完成创建之后我们用上ViewBinding代码如下所示
class GoogleMapActivity : AppCompatActivity() {private lateinit var binding: ActivityGoogleMapBindingoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)enableEdgeToEdge()binding ActivityGoogleMapBinding.inflate(layoutInflater)setContentView(binding.root)ViewCompat.setOnApplyWindowInsetsListener(binding.main) { v, insets -val systemBars insets.getInsets(WindowInsetsCompat.Type.systemBars())v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)insets}}
}注意自行导包并且设置一个可以进入这个页面的入口比如点击一个按钮跳转到这个页面来。下面我们配置XML打开activity_google_map.xml修改后代码如下所示
?xml version1.0 encodingutf-8?
androidx.constraintlayout.widget.ConstraintLayout xmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:apphttp://schemas.android.com/apk/res-autoxmlns:maphttp://schemas.android.com/apk/res-autoxmlns:toolshttp://schemas.android.com/toolsandroid:idid/mainandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroidx.fragment.app.FragmentContainerViewandroid:idid/mapandroid:namecom.google.android.gms.maps.SupportMapFragmentandroid:layout_width0dpandroid:layout_height0dpapp:layout_constraintBottom_toBottomOfparentapp:layout_constraintEnd_toEndOfparentapp:layout_constraintStart_toStartOfparentapp:layout_constraintTop_toTopOfparent /
/androidx.constraintlayout.widget.ConstraintLayout这里我们以静态方式添加 fragment在用于处理地图的 activity 的布局文件中添加名称声明 xmlns:maphttp://schemas.android.com/apk/res-auto。完成此操作后即可使用 maps 自定义 XML 属性。在后面我们就可以直接在xml中通过map去设置地图的一些属性了。将 android:name 属性设置为com.google.android.gms.maps.SupportMapFragment这是必须要做的事情。
接下来回到GoogleMapActivity首先我们创建一个initView()函数代码如下 /*** 初始化视图*/private fun initView() {val mapFragment supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragmentmapFragment.getMapAsync(this)} 这里获取 fragment 的句柄并注册回调函数GoogleMapActivity需要实现OnMapReadyCallback接口重写里面的onMapReady()函数在这个方法中我们添加一个Marker代码如下所示 /*** 地图就绪*/override fun onMapReady(googleMap: GoogleMap) {googleMap.addMarker(MarkerOptions().position(LatLng(0.0, 0.0)).title(Marker))}最后要在onCreate()函数中调用initView()函数最终代码如下图所示 下面我们运行一下看看 OK你会看到出现了这个Marker就是我们所设置的地方如果你没有加载出这个画面那么检查一下你的控制台看看有没有相关的错误日志再根据日志判断具体问题一般都是配置的问题请根据一、二步骤进行检查。
四、定位当前 上述的内容对你毫无难度我们继续往下走现在地图加载出来了我们最实际的想法就是定位当前所在位置那么要怎么做呢这里分为两种方式无论那种方式我们都需要先获取位置权限。
① 请求定位权限 在Android6.0及以上版本定位权限光在AndroidManifest.xml配置还不够还需要动态请求下面我们在GoogleMapActivity中完成这一代码。 首先声明变量如下所示 private val TAG: String GoogleMapActivity::class.java.simpleName// 权限请求码private val LOCATION_PERMISSION_REQUEST_CODE: Int 9527// 地图private lateinit var map: GoogleMap这里的map我们需要在onMapReady()函数中进行赋值 override fun onMapReady(googleMap: GoogleMap) {map googleMap// 检查权限checkPermission()}通过我们增加一个检查权限的函数也就地图就绪之后我们就检查权限代码如下所示 /*** 检查权限*/private fun checkPermission() {// 检查当前是否拥有精确位置或粗略位置权限if (ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION) PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION) PackageManager.PERMISSION_GRANTED) {// 权限已授予可以进行定位操作Log.d(TAG, checkPermission: 权限已授予)configMap()} else {Log.d(TAG, checkPermission: 请求权限)// 请求权限ActivityCompat.requestPermissions(this,arrayOf(Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION),LOCATION_PERMISSION_REQUEST_CODE)}}这里的代码很常规就是先检查有没有相关权限有就配置地图没有就请求权限。然后写一个配置地图的函数代码如下 /*** 地图配置*/private fun configMap() {Log.d(TAG, configMap: 地图配置)map.addMarker(MarkerOptions().position(LatLng(0.0, 0.0)).title(Marker))}最后重写onRequestPermissionsResult()函数捕获权限请求结果代码如下所示 /*** 权限请求结果*/override fun onRequestPermissionsResult(requestCode: Int, permissions: Arrayout String, grantResults: IntArray) {super.onRequestPermissionsResult(requestCode, permissions, grantResults)when (requestCode) {LOCATION_PERMISSION_REQUEST_CODE - {// 如果请求被取消则结果数组为空if (grantResults.isNotEmpty() grantResults[0] PackageManager.PERMISSION_GRANTED) {// 权限被授予可以进行定位操作Log.d(TAG, onRequestPermissionsResult: 权限被授予)configMap()} else {// 权限被拒绝无法进行定位操作Log.d(TAG, onRequestPermissionsResult: 权限被拒绝)Toast.makeText(this, 拒绝将无法使用定位功能, Toast.LENGTH_SHORT).show()finish()}}}}获取权限则配置地图拒绝权限直接提示一下就退出了下面我们运行一下 再看看控制台日志 OK没有问题现在权限的问题我们就解决了下面进行定位。
② 我的位置控件 要定位到当前位置我们可以使用Google地图中的自带控件修改configMap()函数代码如下所示 /*** 地图配置*/SuppressLint(MissingPermission)private fun configMap() {Log.d(TAG, configMap: 地图配置)map.addMarker(MarkerOptions().position(LatLng(0.0, 0.0)).title(Marker))map.isMyLocationEnabled true// 当前位置图标的点击事件map.setOnMyLocationButtonClickListener {Log.d(TAG, configMap: 点击位置图标)returnsetOnMyLocationButtonClickListener false }// 定位后的蓝点点击事件map.setOnMyLocationClickListener { location -Log.d(TAG, configMap: 点击我的位置 $location)Toast.makeText(this, Current location:\n$location, Toast.LENGTH_LONG).show()}}注意要加上这个SuppressLint(MissingPermission)不然会检查map.isMyLocationEnabled true是否通过权限判断这里我们在地图上启用“我的位置”图层。则地图上就会出现一个定位当前位置的控件出现在右上角setOnMyLocationButtonClickListener 则是这个控件的点击监听这里返回false则点击之后就会移动地图中心到当前设备所在位置setOnMyLocationClickListener 则是定位后的蓝色点的点击事件这里运行之后就会看到。 你会看到右上角的定位按钮点击就可以了控制台如下所示 ③ 获取当前位置
首先声明变量 // 地图private lateinit var map: GoogleMap// Places API 的入口点。private lateinit var placesClient: PlacesClient// 融合位置信息提供程序的入口点。private lateinit var fusedLocationProviderClient: FusedLocationProviderClient// 最后已知位置private var lastKnownLocation: Location? nullcompanion object {private val TAG GoogleMapActivity::class.java.simpleName// 默认缩放private const val DEFAULT_ZOOM 15// 权限请求码private const val LOCATION_PERMISSION_REQUEST_CODE 9527// 未授予位置权限时使用的默认位置澳大利亚悉尼和默认缩放。private val defaultLocation LatLng(-33.8523341, 151.2106085)}在initView()函数中增加如下代码 // 构造 PlacesClientPlaces.initialize(applicationContext, BuildConfig.MAPS_API_KEY)placesClient Places.createClient(this)// 构造 FusedLocationProviderClient。fusedLocationProviderClient LocationServices.getFusedLocationProviderClient(this)添加位置如下图所示 下面我们需要写一个getCurrentLocation()函数获取当前位置代码如下所示 /*** 获取当前位置*/SuppressLint(MissingPermission)private fun getCurrentLocation() {Log.d(TAG, getCurrentLocation: 获取当前位置)fusedLocationProviderClient.lastLocation.addOnCompleteListener { task -// 获取当前位置未成功if (!task.isSuccessful) {Log.d(TAG, Current location is null. Using defaults.)Log.e(TAG, Exception: %s, task.exception)// 设置默认位置changeMapCenter(defaultLocation)returnaddOnCompleteListener}lastKnownLocation task.resultif (lastKnownLocation null) returnaddOnCompleteListener// 移动地图到当前位置changeMapCenter(LatLng(lastKnownLocation!!.latitude, lastKnownLocation!!.longitude))}}这里有一个changeMapCenter()函数用于改变地图中心代码如下所示 /*** 改变地图中心*/private fun changeMapCenter(latLng: LatLng) {map.addMarker(MarkerOptions().title(Marker).position(latLng))// 地图中移动到经纬度处map.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, DEFAULT_ZOOM.toFloat()))}最后我们在configMap()函数中调用getCurrentLocation()函数同时去掉之前的默认Marker如下图所示 下面你运行一下就会自动定位到当前设备所在位置了这个位置不定义完全正确有一些偏差控制台日志如下图所示 五、配置地图
① xml配置地图 完成定位之后我们可以对地图进行一些配置我们可以通过xml去配置。 map:cameraTilt30map:uiRotateGesturestruemap:uiZoomControlstrue cameraTilt 将地图倾斜度设置为 30uiRotateGestures启用旋转手势控件uiZoomControls启用缩放控件
添加位置如下图所示 XML属性还有其他的设置
mapType - 要显示的地图类型。有效值包括none、normal、hybrid、satellite 和 terrain。cameraTargetLat、cameraTargetLng、cameraZoom、cameraBearing、cameraTilt - 镜头的初始位置。uiZoomControls、uiCompass - 用于指定是否显示缩放控件和罗盘。uiZoomGestures、uiScrollGestures、uiRotateGestures、uiTiltGestures - 用于指定是否启用特定手势。zOrderOnTop - 用于指明地图视图的表面是否叠加显示在地图窗口、地图控件和窗口中的任何对象上。useViewLifecycle - 此属性必须与 SupportMapFragment 对象一起使用才有效它用于指定是否应将地图的生命周期与 fragment 的视图或 fragment 本身关联。liteMode - 如果要启用精简模式则为 true否则为 false。
② 代码配置地图
xml可以设置的同样可以通过代码设置。就需要用到GoogleMapOptions 和UiSettings如果你使用的是动态加载的地图那么就使用GoogleMapOptions的方式如果是静态加载的地图就使用UiSettings这里我们使用UiSettings去设置地图修改一下configMap()中的代码如下图所示 /*** 地图配置*/SuppressLint(MissingPermission)private fun configMap() {Log.d(TAG, configMap: 地图配置)map.apply {isMyLocationEnabled true // 地图上启用“我的位置”图层// 当前位置图标的点击事件setOnMyLocationButtonClickListener { Log.d(TAG, configMap: 点击位置图标)returnsetOnMyLocationButtonClickListener false}// 定位后的蓝点点击事件setOnMyLocationClickListener { location - Log.d(TAG, configMap: 点击我的位置 $location)Toast.makeText(thisGoogleMapActivity, Current location:\n$location, Toast.LENGTH_LONG).show()}// 地图设置uiSettings.apply {isZoomControlsEnabled true // 显示缩放按钮isMyLocationButtonEnabled true // 显示定位按钮isCompassEnabled true // 显示指南针isMapToolbarEnabled true // 显示地图工具栏isRotateGesturesEnabled true // 允许旋转手势isScrollGesturesEnabled true // 允许滚动手势isTiltGesturesEnabled true // 允许倾斜手势isZoomGesturesEnabled true // 允许缩放手势isScrollGesturesEnabledDuringRotateOrZoom true // 允许在旋转或缩放时滚动手势isIndoorLevelPickerEnabled true // 显示室内层选择器}}// 获取当前位置getCurrentLocation()}主要是注意uiSettings里面的配置可以自行运行看配置效果。
③ 地图点击事件 关于地图的事件我们主要讲述点击事件比如我们点击哪里就移动地图到哪里这是很常用的一个功能实现起来也很简单在configMap()函数中添加如下代码 // 地图点击事件setOnMapClickListener { latLng -changeMapCenter(latLng)}这里就做到了点击哪里移动到哪里因为在changeMapCenter()函数中对于定位点进行添加Marker所以如果你点击了地图很多次那么可能每一次都会绘制一个Marker有时候你就不知道当前到底在哪里那么为了解决这个问题可以只保留一个Marker。
④ 管理Marker
首先我们声明一个变量 // 标记private var marker: Marker? null然后修改changeMapCenter()函数的代码如下所示 private fun changeMapCenter(latLng: LatLng) {// 移除标点marker?.remove()// 添加标点marker map.addMarker(MarkerOptions().title(Marker).position(latLng))// 地图中移动到经纬度处map.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, DEFAULT_ZOOM.toFloat()))}这里在赋值之前先移除如果不为空就会移除再添加到另外我们还可以在点击当前位置按钮的时候移除代码如下所示 setOnMyLocationButtonClickListener {Log.d(TAG, configMap: 点击位置图标)// 移除标点marker?.remove()marker nullreturnsetOnMyLocationButtonClickListener false}这样Marker就是唯一的一个我们还可以修改Marker的样式。通过MarkerOptions进行设置比如icon图标alpha透明度。 marker map.addMarker(MarkerOptions().title(Marker) // 设置标题.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_YELLOW)) // 设置默认图标颜色为黄色.alpha(0.7f) // 设置透明度.position(latLng) // 设置位置)类似这样修改当然icon还可以设置自定义的图标比如这样
.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_google))这个图标可以设置成自己需要的图标。
六、地址位置编码 地址位置编码分为两种情况通过经纬度获取详细地址通过地址获取经纬度坐标。无论那种方式在国内都有限制。
① 坐标转地址
首先我们来写坐标转地址地址的结果我们通过Address来接收这是一个列表首先我们声明变量 // 地理编码器private var geocoder: Geocoder? null// 地址结果private var addressesLiveData: MutableLiveDataListAddress MutableLiveData()然后在configMap()函数中增加如下代码 // 初始化地理编码器geocoder Geocoder(this)// 编码结果addressesLiveData.observe(this) { addresses -// 获取地址信息if (!addresses.isNullOrEmpty()) {val address addresses[0]Log.d(TAG, Address: ${address.latitude} ${address.longitude} ${address.countryName} ${address.adminArea} ${address.locality} ${address.thoroughfare} ${address.subThoroughfare})}}在观察到数据改变时打印出来。当前的Activity需要实现接口 主要加上这个注解然后重写onGeocode()函数代码如下所示 /*** 地理编码结果经纬度坐标转地址*/override fun onGeocode(addresses: MutableListAddress) {addressesLiveData.postValue(addresses)}然后再增加一个getDetailAddress()函数 /*** 获取详情位置信息获取国内位置会出现异常*/private fun getDetailAddress(latLng: LatLng) {if (Build.VERSION.SDK_INT Build.VERSION_CODES.TIRAMISU) {geocoder?.getFromLocation(latLng.latitude, latLng.longitude, 1, thisGoogleMapActivity)} else {addressesLiveData.postValue(geocoder?.getFromLocation(latLng.latitude, latLng.longitude, 1))}}在这里我们通过geocoder去获取详细的地址信息这里就需要进行版本的判断了1表示返回的最大结果数可以自行修改。最后在changeMapCenter()函数中调用getDetailAddress()函数如下图所示 运行后控制台日志如下图所示 ② 地址转坐标
这里我们只需要写一个getDetailLatLng()函数就可以了代码如下所示 /*** 获取默认经纬度的地址信息*/private fun getDetailLatLng(address: String 悉尼歌剧院) {if (Build.VERSION.SDK_INT Build.VERSION_CODES.TIRAMISU) {geocoder?.getFromLocationName(address, 1, thisGoogleMapActivity)} else {addressesLiveData.postValue(geocoder?.getFromLocationName(address, 1))}}这里我们使用的是默认值悉尼歌剧院看是否能够通过地址名称获取具体的地址信息这里的接口是一样的因此我们在使用的使用要么只用一个要么通过一个变量来判断是坐标转地址还是地址转坐标。这里我只使用一个。 运行看看效果 好的这样就完成了通过这个获取到的数据还不是最准确的通过Google API接口去获取比较准备感兴趣的可以去看看。
七、源码 因为涉及到项目所以这里我就不贴源码只贴上GoogleMapActivity的完整代码
SuppressLint(NewApi)
class GoogleMapActivity : AppCompatActivity(), OnMapReadyCallback, Geocoder.GeocodeListener {private lateinit var binding: ActivityGoogleMapBinding// 地图private lateinit var map: GoogleMap// Places API 的入口点。private lateinit var placesClient: PlacesClient// 融合位置信息提供程序的入口点。private lateinit var fusedLocationProviderClient: FusedLocationProviderClient// 最后已知位置private var lastKnownLocation: Location? null// 标记private var marker: Marker? null// 地理编码器private var geocoder: Geocoder? null// 地址结果private var addressesLiveData: MutableLiveDataListAddress MutableLiveData()companion object {private val TAG GoogleMapActivity::class.java.simpleName// 默认缩放private const val DEFAULT_ZOOM 15// 权限请求码private const val LOCATION_PERMISSION_REQUEST_CODE 9527// 未授予位置权限时使用的默认位置澳大利亚悉尼和默认缩放。private val defaultLocation LatLng(-33.8523341, 151.2106085)}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)enableEdgeToEdge()binding ActivityGoogleMapBinding.inflate(layoutInflater)setContentView(binding.root)ViewCompat.setOnApplyWindowInsetsListener(binding.main) { v, insets -val systemBars insets.getInsets(WindowInsetsCompat.Type.systemBars())v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)insets}initView()}/*** 初始化视图*/private fun initView() {// 构造 PlacesClientPlaces.initialize(applicationContext, BuildConfig.MAPS_API_KEY)placesClient Places.createClient(this)// 构造 FusedLocationProviderClient。fusedLocationProviderClient LocationServices.getFusedLocationProviderClient(this)val mapFragment supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragmentmapFragment.getMapAsync(this)}/*** 检查权限*/private fun checkPermission() {// 检查当前是否拥有精确位置或粗略位置权限if (ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION) PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION) PackageManager.PERMISSION_GRANTED) {// 权限已授予可以进行定位操作Log.d(TAG, checkPermission: 权限已授予)configMap()} else {Log.d(TAG, checkPermission: 请求权限)// 请求权限ActivityCompat.requestPermissions(this,arrayOf(Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION),LOCATION_PERMISSION_REQUEST_CODE)}}/*** 地图就绪*/override fun onMapReady(googleMap: GoogleMap) {map googleMap// 检查权限checkPermission()}/*** 地图配置*/SuppressLint(MissingPermission)private fun configMap() {Log.d(TAG, configMap: 地图配置)// 初始化地理编码器geocoder Geocoder(this)// 编码结果addressesLiveData.observe(this) { addresses -// 获取地址信息if (!addresses.isNullOrEmpty()) {val address addresses[0]Log.d(TAG, Address: ${address.latitude} ${address.longitude} ${address.countryName} ${address.adminArea} ${address.locality} ${address.thoroughfare} ${address.subThoroughfare})}}map.apply {isMyLocationEnabled true // 地图上启用“我的位置”图层// 当前位置图标的点击事件setOnMyLocationButtonClickListener {Log.d(TAG, configMap: 点击位置图标)// 移除标点marker?.remove()marker nullreturnsetOnMyLocationButtonClickListener false}// 定位后的蓝点点击事件setOnMyLocationClickListener { location -Log.d(TAG, configMap: 点击我的位置 $location)Toast.makeText(thisGoogleMapActivity, Current location:\n$location, Toast.LENGTH_LONG).show()}// 地图点击事件setOnMapClickListener { latLng -changeMapCenter(latLng)}// 地图设置uiSettings.apply {isZoomControlsEnabled true // 显示缩放按钮isMyLocationButtonEnabled true // 显示定位按钮isCompassEnabled true // 显示指南针isMapToolbarEnabled true // 显示地图工具栏isRotateGesturesEnabled true // 允许旋转手势isScrollGesturesEnabled true // 允许滚动手势isTiltGesturesEnabled true // 允许倾斜手势isZoomGesturesEnabled true // 允许缩放手势isScrollGesturesEnabledDuringRotateOrZoom true // 允许在旋转或缩放时滚动手势isIndoorLevelPickerEnabled true // 显示室内层选择器}}// 获取当前位置getCurrentLocation()}/*** 获取当前位置*/SuppressLint(MissingPermission)private fun getCurrentLocation() {Log.d(TAG, getCurrentLocation: 获取当前位置)fusedLocationProviderClient.lastLocation.addOnCompleteListener { task -// 获取当前位置未成功if (!task.isSuccessful) {Log.d(TAG, Current location is null. Using defaults.)Log.e(TAG, Exception: %s, task.exception)// 设置默认位置changeMapCenter(defaultLocation)returnaddOnCompleteListener}lastKnownLocation task.resultif (lastKnownLocation null) returnaddOnCompleteListener// 移动地图到当前位置changeMapCenter(LatLng(lastKnownLocation!!.latitude, lastKnownLocation!!.longitude))}}/*** 改变地图中心*/private fun changeMapCenter(latLng: LatLng) {// 移除标点marker?.remove()// 添加标点marker map.addMarker(MarkerOptions().title(Marker) // 设置标题.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_google)) // 设置自定义图标.alpha(0.7f) // 设置透明度.position(latLng) // 设置位置)// 获取详细位置信息// getDetailAddress(latLng)// 获取默认经纬度的地址信息getDetailLatLng()// 地图中移动到经纬度处map.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, DEFAULT_ZOOM.toFloat()))}/*** 获取默认经纬度的地址信息*/private fun getDetailLatLng(address: String 悉尼歌剧院) {if (Build.VERSION.SDK_INT Build.VERSION_CODES.TIRAMISU) {geocoder?.getFromLocationName(address, 1, thisGoogleMapActivity)} else {addressesLiveData.postValue(geocoder?.getFromLocationName(address, 1))}}/*** 获取详情位置信息获取国内位置会出现异常*/private fun getDetailAddress(latLng: LatLng) {if (Build.VERSION.SDK_INT Build.VERSION_CODES.TIRAMISU) {geocoder?.getFromLocation(latLng.latitude, latLng.longitude, 1, thisGoogleMapActivity)} else {addressesLiveData.postValue(geocoder?.getFromLocation(latLng.latitude, latLng.longitude, 1))}}/*** 权限请求结果*/override fun onRequestPermissionsResult(requestCode: Int, permissions: Arrayout String, grantResults: IntArray) {super.onRequestPermissionsResult(requestCode, permissions, grantResults)when (requestCode) {LOCATION_PERMISSION_REQUEST_CODE - {// 如果请求被取消则结果数组为空if (grantResults.isNotEmpty() grantResults[0] PackageManager.PERMISSION_GRANTED) {// 权限被授予可以进行定位操作Log.d(TAG, onRequestPermissionsResult: 权限被授予)configMap()} else {// 权限被拒绝无法进行定位操作Log.d(TAG, onRequestPermissionsResult: 权限被拒绝)Toast.makeText(this, 拒绝将无法使用定位功能, Toast.LENGTH_SHORT).show()finish()}}}}/*** 地理编码结果经纬度坐标转地址*/override fun onGeocode(addresses: MutableListAddress) {addressesLiveData.postValue(addresses)}
}该导包的地方注意导包即可。