uniapp适配H5和Android-apk实现获取当前位置经纬度并调用接口

index.vue:

注意:这里的

return 'https://www.******.com/bus_admin_java'

这里是区分 H5和apk调用接口地址的不同而设置的。之后凡是调用接口的方法就使用封装后的request()

复制代码
<template>
  <view class="container">
    <view class="title">实时位置追踪器</view>

    <view
      class="btn"
      :class="{ active: tracking }"
      @click="toggleTracking"
    >
      {{ tracking ? '停止追踪' : '点击开始' }}
    </view>

    <view v-if="latitude !== null && longitude !== null" class="location-info">
      当前经度: {{ longitude }} <br />
      当前纬度: {{ latitude }}
    </view>

    <!-- 雷达扫描效果 -->
    <view class="radar" v-if="tracking">
      <view class="circle circle1"></view>
      <view class="circle circle2"></view>
      <view class="circle circle3"></view>
      <view class="pulse"></view>
    </view>
  </view>
</template>

<script>
	
const BASE_URL = (() => {
  // #ifdef H5
  return '/api'
  // #endif

  // #ifdef APP-PLUS
  return 'https://www.******.com/bus_admin_java'
  // #endif

  return '/api'
})()

function request(options) {
  return new Promise((resolve, reject) => {
    uni.request({
      url: BASE_URL + options.url,
      method: options.method || 'GET',
      data: options.data || {},
      header: {
        'content-type': 'application/json',
        ...(options.header || {})
      },
      timeout: 15000,
      success: (res) => {
        resolve(res)
      },
      fail: (err) => {
        reject(err)
      }
    })
  })
}
	
export default {
  data() {
    return {
      latitude: null,
      longitude: null,
      tracking: false,
      timer: null
    }
  },
  methods: {
    toggleTracking() {
      if (this.tracking) {
        this.tracking = false
        this.stopTracking()
      } else {
        this.startTracking()
      }
    },

    startTracking() {
      this.stopTracking()

      // 先尝试获取一次位置
      this.getLocation(true)
    },

    stopTracking() {
      if (this.timer) {
        clearInterval(this.timer)
        this.timer = null
      }
    },

    getLocation(isFirst = false) {
      uni.getLocation({
        type: 'wgs84',
        success: (res) => {
          this.latitude = res.latitude
          this.longitude = res.longitude

          console.log('当前位置', res)

          uni.showToast({
            title: `经度:${res.longitude.toFixed(4)} 纬度:${res.latitude.toFixed(4)}`,
            icon: 'none',
            duration: 3000
          })

          this.sendPosition(res.longitude, res.latitude)

          // 第一次成功后再开启轮询
          if (isFirst) {
            this.tracking = true
            this.timer = setInterval(() => {
              this.getLocation(false)
            }, 3000)
          }
        },
        fail: (err) => {
          console.error('获取位置失败', err)

          this.tracking = false
          this.stopTracking()

          this.handleLocationFail(err)
        }
      })
    },

    handleLocationFail(err) {
      let content = '获取位置失败,请检查定位服务是否开启'

      // #ifdef APP-PLUS
      content = '请先开启系统定位服务,并允许当前应用使用定位权限,是否前往设置?'
      // #endif

      // #ifdef H5
      content = 'H5 获取定位失败,请确认浏览器已允许定位,并且当前页面运行在 HTTPS 或 localhost 环境下'
      // #endif

      uni.showModal({
        title: '定位失败',
        content,
        success: (res) => {
          if (!res.confirm) return

          // App 端支持打开设置
          // #ifdef APP-PLUS
          uni.openSetting({
            success: (settingRes) => {
              console.log('设置页返回', settingRes)
              uni.showToast({
                title: '请重新点击开始定位',
                icon: 'none'
              })
            },
            fail: (settingErr) => {
              console.error('打开设置失败', settingErr)
              uni.showToast({
                title: '无法打开设置页',
                icon: 'none'
              })
            }
          })
          // #endif

          // H5 没有统一的 openSetting,给提示即可
          // #ifdef H5
          uni.showToast({
            title: '请在浏览器地址栏附近开启定位权限',
            icon: 'none',
            duration: 3000
          })
          // #endif
        }
      })
    },

    sendPosition(longitude, latitude) {
      request({
        url: '/bus/position/save',
        method: 'POST',
        data: {
          longitude: longitude,
          latitude: latitude
        },
        success: (res) => {
          console.log('上传成功', res.data)
        },
        fail: (err) => {
          console.error('上传失败', err)
        }
      })
    }
  },

  beforeDestroy() {
    this.stopTracking()
  },

  onUnload() {
    this.stopTracking()
  }
}
</script>

<style>
.container {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  align-items: center;
  padding: 40px 20px;
  background: radial-gradient(circle at center, #0a0a0a, #001010);
  min-height: 100vh;
  color: #00ffff;
  font-family: "Microsoft YaHei", sans-serif;
}

.title {
  font-size: 22px;
  font-weight: bold;
  margin-bottom: 20px;
}

.location-info {
  margin-top: 20px;
  font-size: 16px;
  text-align: center;
  line-height: 1.8;
}

.btn {
  margin-top: 20px;
  padding: 12px 24px;
  background: #002f2f;
  color: #00ffff;
  border: 1px solid #00ffff;
  border-radius: 8px;
  font-size: 16px;
  text-align: center;
  transition: all 0.3s ease;
}

.btn.active {
  background: #00ffff;
  color: #001010;
  box-shadow: 0 0 10px #00ffff;
}

.btn:active {
  transform: scale(0.96);
}

/* 雷达扫描效果 */
.radar {
  position: relative;
  width: 200px;
  height: 200px;
  margin-top: 40px;
}

.circle {
  position: absolute;
  border: 2px solid rgba(0, 255, 255, 0.3);
  border-radius: 50%;
  animation: pulseScale 3s linear infinite;
}

.circle1 {
  width: 60px;
  height: 60px;
  top: 70px;
  left: 70px;
  animation-delay: 0s;
}

.circle2 {
  width: 120px;
  height: 120px;
  top: 40px;
  left: 40px;
  animation-delay: 1s;
}

.circle3 {
  width: 180px;
  height: 180px;
  top: 10px;
  left: 10px;
  animation-delay: 2s;
}

.pulse {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 255, 255, 0.1);
  border-radius: 50%;
  animation: rotateRadar 4s linear infinite;
}

@keyframes pulseScale {
  0% {
    transform: scale(0.2);
    opacity: 0.5;
  }
  50% {
    transform: scale(1);
    opacity: 0.2;
  }
  100% {
    transform: scale(0.2);
    opacity: 0.5;
  }
}

@keyframes rotateRadar {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}
</style>

main.js:

复制代码
import App from './App.vue'

// #ifndef VUE3
import Vue from 'vue'
import './uni.promisify.adaptor'
Vue.config.productionTip = false
App.mpType = 'app'
const app = new Vue({
  ...App
})
app.$mount()
// #endif

// #ifdef VUE3
import { createSSRApp } from 'vue'
export function createApp() {
  const app = createSSRApp(App)
  return {
    app
  }
}
// #endif

mainifest.json:

复制代码
{
    "name" : "bus_uniapp",
    "appid" : "__UNI__7E751FC",
    "description" : "",
    "versionName" : "1.0.0",
    "versionCode" : "100",
    "transformPx" : false,
    /* 5+App特有相关 */
    "app-plus" : {
        "permissions" : {
            "Location" : {
                "desc" : "用于获取当前位置"
            }
        },
        "usingComponents" : true,
        "nvueStyleCompiler" : "uni-app",
        "compilerVersion" : 3,
        "splashscreen" : {
            "alwaysShowBeforeRender" : true,
            "waiting" : true,
            "autoclose" : true,
            "delay" : 0
        },
        /* 模块配置 */
        "modules" : {},
        /* 应用发布信息 */
        "distribute" : {
            /* android打包配置 */
            "android" : {
                "permissions" : [
					"<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
					"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
                    "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
                    "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
                    "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
                    "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
                    "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
                    "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
                    "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
                    "<uses-permission android:name=\"android.permission.CAMERA\"/>",
                    "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
                    "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
                    "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
                    "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
                    "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
                    "<uses-feature android:name=\"android.hardware.camera\"/>",
                    "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
                ]
            },
            /* ios打包配置 */
            "ios" : {
                "dSYMs" : false
            },
            /* SDK配置 */
            "sdkConfigs" : {}
        }
    },
    /* 快应用特有相关 */
    "quickapp" : {},
    /* 小程序特有相关 */
    "mp-weixin" : {
        "appid" : "",
        "setting" : {
            "urlCheck" : false
        },
        "usingComponents" : true
    },
    "mp-alipay" : {
        "usingComponents" : true
    },
    "mp-baidu" : {
        "usingComponents" : true
    },
    "mp-toutiao" : {
        "usingComponents" : true
    },
    "uniStatistics" : {
        "enable" : false
    },
    "vueVersion" : "3"
}

注意开通:

vite.config.js: (解决H5的跨域的问题)

复制代码
// vite.config.js
import { defineConfig } from 'vite'
import uni from '@dcloudio/vite-plugin-uni'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    uni(),
  ],
  server: {
    // 1. 配置代理规则
    proxy: {
      // 2. '/api' 是你自定义的请求前缀
      '/api': {
        // 3. target 是你的目标后端接口的真实地址
        // target: 'http://localhost:9002',
		target: 'https://www.*****.com/bus_admin_java',
        // 4. 改变请求源头,解决大部分跨域问题,必须为 true
        changeOrigin: true,
        // 5. (可选) 重写路径,移除 '/api' 前缀
        rewrite: (path) => path.replace(/^\/api/, '')
      }
    }
  }
})
相关推荐
宁&沉沦2 小时前
前端开发专用的 Cursor 四大模式「快捷切换 + 指令模板」,直接复制就能用,覆盖 90% 日常场景
前端·编辑器
咚咚王者2 小时前
MySQL 导出脚本
android·mysql·adb
Cloud Traveler2 小时前
用Calibre-Web把NAS上的电子书管起来:部署、配置与远程访问实战
前端
神明不懂浪漫2 小时前
【第一章】HTML(一)——HTML简述及常用标签
前端·javascript·css·html·css3
Fate_I_C2 小时前
Android Navigation的使用说明
android·kotlin·navigation
鹏程十八少2 小时前
5. 2026金三银四 吐血整理!Android高级UI 自定义view面试25题,覆盖90%大厂考点
前端·面试·前端框架
兄弟加油,别颓废了。2 小时前
XSS-Labs 前 5 关 超详细通关全解
前端·xss
telllong2 小时前
深入理解React Fiber架构:从栈调和到时间切片
前端·react.js·架构
英俊潇洒美少年2 小时前
React18 Hooks 项目重构为 Vue3 组合式API的坑
前端·javascript·重构