Ionic 使用原生定位功能

我们在上一篇已经成功创建并编译了 hello-world 项目。现在增加读取当前坐标的功能。

新增读取当前坐标的功能

  1. 首先要安装 geolocation plugin

    npm install --save @ionic-native/geolocation
  2. 将 geolocation plugin 添加到 app.module.ts 的 providers 中:

    import { Geolocation } from "@ionic-native/geolocation";
    
    @NgModule({
      providers: [
        StatusBar,
        SplashScreen,
        Geolocation,
        { provide: ErrorHandler, useClass: IonicErrorHandler }
      ]
    })
    export class AppModule { }
  3. 在 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);
        });
      }
    }
  4. 按上一篇的方法再次编译 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.”,也就是默认是没有获取定位的权限的。

请求定位权限

  1. 参考官方文档,首先要安装 android-permissions 插件,注意这两个都要装,可不是装一个插件的两种方法!

    ionic cordova plugin add cordova-plugin-android-permissions
    npm install --save @ionic-native/android-permissions
  2. 官方文档漏了必须的一步,要在

    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中可以查到。

  3. 安装之后同样要把它放置到 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 => {
              //申请权限失败:"
            });
        });
      }
    }

相关推荐