Ionic 使用原生定位功能
我们在上一篇已经成功创建并编译了 hello-world 项目。现在增加读取当前坐标的功能。
新增读取当前坐标的功能
首先要安装 geolocation plugin
npm install --save @ionic-native/geolocation
将 geolocation plugin 添加到 app.module.ts 的 providers 中:
import { Geolocation } from "@ionic-native/geolocation"; @NgModule({ providers: [ StatusBar, SplashScreen, Geolocation, { provide: ErrorHandler, useClass: IonicErrorHandler } ] }) export class AppModule { }
在 home.html 中增加一个按钮,在按钮的 click 事件中调用 gps 插件获取当前坐标点并显示在 home.html 中:
import { Geolocation } from '@ionic-native/geolocation'; @Component({ selector: 'page-home', templateUrl: 'home.html' }) export class HomePage { constructor( public navCtrl: NavController, private geolocation: Geolocation ) { } position = "()"; ngOnInit() { this.isLoading = "加载完毕"; } getPosition() { this.geolocation.getCurrentPosition().then((resp) => { this.position = `(${resp.coords.latitude}, ${resp.coords.longitude})`; }).catch((error) => { this.position = 'error:' + error.message; console.log('Error getting location', error); }); } }
按上一篇的方法再次编译 apk。注意编译之前要把之前生成过的 apk 全部删除先。因为今后要经常进行编译 apk 的工作,建议把压缩未签名 apk、签名 apk、验证签名这 3 项工作放进一个叫做 “sign.bat” 的批处理文件并放置在项目根目录下,然后编写 npm scripts 如下:
"scripts": { "prebuild": "del /F /Q C:\\projects\\ionic\\hello-world\\platforms\\android\\app\\build\\outputs\\apk\\release\\*.*", "build": "ionic cordova build android --prod --release", "postbuild": "sign" }
这样今后只要执行“npm run build”就会先执行 prebuild 里面的脚本删除旧的 apk,然后编译出新的 apk,再执行签名脚本。
在手机上安装新版 apk 之后会发现获取不到当前坐标,错误信息为“application does not have sufficient geolocation permissions.”,也就是默认是没有获取定位的权限的。
请求定位权限
参考官方文档,首先要安装 android-permissions 插件,注意这两个都要装,可不是装一个插件的两种方法!:
ionic cordova plugin add cordova-plugin-android-permissions npm install --save @ionic-native/android-permissions
官方文档漏了必须的一步,要在
C:\projects\ionic\hello-world\platforms\android\app\src\main\AndroidManifest.xml
中添加要申请的权限:ACCESS_COARSE_LOCATION、ACCESS_FINE_LOCATION 和 ACCESS_LOCATION_EXTRA_COMMANDS:
<?xml version='1.0' encoding='utf-8'?> <manifest android:hardwareAccelerated="true" android:versionCode="1" android:versionName="0.0.1" package="io.ionic.starter" xmlns:android="http://schemas.android.com/apk/res/android"> <supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:resizeable="true" android:smallScreens="true" android:xlargeScreens="true" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" /> <application android:hardwareAccelerated="true" android:icon="@mipmap/icon" android:label="@string/app_name" android:supportsRtl="true"> <activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale" android:label="@string/activity_name" android:launchMode="singleTop" android:name="MainActivity" android:theme="@android:style/Theme.DeviceDefault.NoActionBar" android:windowSoftInputMode="adjustResize"> <intent-filter android:label="@string/launcher_name"> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="26" /> </manifest>
否则根本不会弹出权限请求系统对话框。
其中权限字符串列表在Manifest.permission.html中可以查到。安装之后同样要把它放置到 app.module.ts 的 providers 中,并在 home.ts 中添加请求权限的代码。值得注意的是 Android 26 以上要求在请求权限之前要有使用该权限的代码,否则同样不会弹出权限申请系统对话框,所以 home.ts 代码像这样:
import { Geolocation } from '@ionic-native/geolocation'; import { AndroidPermissions } from '@ionic-native/android-permissions'; @Component({ selector: 'page-home', templateUrl: 'home.html' }) export class HomePage { constructor( public navCtrl: NavController, private geolocation: Geolocation, private androidPermissions: AndroidPermissions ) { } position = "()"; getPosition() { this.geolocation.getCurrentPosition().then((resp) => { this.position = `(${resp.coords.latitude}, ${resp.coords.longitude})`; }).catch((error) => { this.androidPermissions.requestPermissions([ this.androidPermissions.PERMISSION.ACCESS_COARSE_LOCATION, this.androidPermissions.PERMISSION.ACCESS_FINE_LOCATION, this.androidPermissions.PERMISSION.ACCESS_LOCATION_EXTRA_COMMANDS]).then(r => { // 申请权限成功 this.geolocation.getCurrentPosition().then((resp) => { this.position = `(${resp.coords.latitude}, ${resp.coords.longitude})`; }); }).catch(err => { //申请权限失败:" }); }); } }