qt on android之GPS信号的获取

敢说敢作敢为, 无怨无恨无悔。这篇文章主要讲述qt on android之GPS信号的获取相关的知识,希望能为你提供帮助。
0.       写在最前面

本人參考安晓辉大侠的一篇博文后。做了Qt on android的GSP相关的实验。为了后面不时之需。故而记录下来。


1.            Qt on Android GPS系统流程

qt on android之GPS信号的获取

文章图片



图1. 系统流程图

如图1所看到的,系统含两个层面:其一为基于QT的UI。提供启动GPS的button(QPushButton)。以及显示GPS信号的文本域(QTextBrowser)。其二为基于Activity的GPS服务,提供GPS的启动,GPS信号上报等服务。两个层面的交互及C++与java的交互通过JNI来实现。

系统的总体线索如箭头方式所看到的:在QT层,button被点击后。槽函数startGps被触发。该函数调用Activity层的方法calledByCpp,而calledByCpp方法发送消息到mes handle,消息类型为MSG_STR_GPS_LOC。handle收到消息后。调用函数startAmap启动GPS的定位。GPS启动后,位置的实时信息在函数onLocationChanged()函数中公布,该函数把位置信息通过消息发送给msg handle,当中消息类型为MSG_RPT_GSP_INF。handle再调用native方法reportGpsInfo,就能够把消息发送给QT层。


2.            创建Androidproject
qt on android之GPS信号的获取

文章图片

图2 创建project

project命名为QtAndroidGps,且其路径为E:\work\c++\qt。project创建之后。文件夹结构例如以下:
qt on android之GPS信号的获取

文章图片

图3. project初始文件

在上述自己主动生成文件夹下增加文件夹android:
qt on android之GPS信号的获取

文章图片


图4. 增加目录android后
目录android里面包括例如以下内容:

qt on android之GPS信号的获取

文章图片


图5. 目录android的内容

能够看出,文件夹结构与通过eclipse生成的android工程类似,少了assets。bin,gen,res等文件夹,以及project.properties等文件。
本project可採用百度与高德的库来定位。其相关的jar包分别为BaiduLBS_Android.jar与Android_Location_V1.1.2.jar。这两个包均放入到e:\work\c++\qt\QtAndroid\android\libs。
同一时候。在构建projectQtAndroidGps之后,qt会在路径e:\work\c++\qt\之下自己主动生成文件夹:
E:\work\c++\qt\build-QtAndroidGps-Android_for_armeabi_v7a_GCC_4_8_Qt_5_4_0-Debug,该文件夹包括下面文件:
qt on android之GPS信号的获取

文章图片


图6. qt构建project后生成的project文件夹

当中,android-build文件夹包括qt构建出来的androidproject,该project即为完整的androidproject:
qt on android之GPS信号的获取

文章图片


图7. qt构建project后生成的androidproject文件夹


能够发现,之前我们人为创建的projecte:\work\c++\qt\QtAndroid\android\里面的文件除了AnroidManifest.xml被整合外,其它文件包含jar包和java文件都被拷贝入:
build-QtAndroidGps-Android_for_armeabi_v7a_GCC_4_8_Qt_5_4_0-Debug。
3.            project文件清单
3.1 E:\work\c++\qt\QtAndroidGps\android\AndroidManifest.xml
qt on android之GPS信号的获取

文章图片


......
qt on android之GPS信号的获取

文章图片


图8.  AndroidManifest.xml
该文件有如上图标注的4个重要点:
①  -> 与E:\work\c++\qt\QtAndroidGps\android\src中java文件的包路径相应
②  -> 要把百度与高德的包用起来。必须增加Api-key
③  -> 相应Activity的类名
④  -> 须要开启GPS定位相关的权限
3.2.1  E:\work\c++\qt\QtAndroidGps\mainwindow.h

#ifndef MAINWINDOW_H #define MAINWINDOW_H#include < QMainWindow> #include < QPushButton> namespace Ui { class MainWindow; }class MainWindow : public QMainWindow { Q_OBJECTpublic: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); protected: bool event(QEvent *e); private: Ui::MainWindow *ui; QPushButton *btn; // 点击启动GPSprivate slots: void startGps(); // btn相应的点击槽函数}; #endif // MAINWINDOW_H

3.2.2  E:\work\c++\qt\QtAndroidGps\mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" #include < QAndroidJniObject> #include "CustomEvent.h"MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui-> setupUi(this); btn = new QPushButton("start", this); btn-> setGeometry(QRect(10, 10, 100, 50)); connect(btn, SIGNAL(clicked()), this, SLOT(startGps())); }MainWindow::~MainWindow() { delete ui; }void MainWindow::startGps() { //QAndroidJniObject javaAction = QAndroidJniObject::fromString(url); QAndroidJniObject::callStaticMethod< void> ( /* 调用java方法,具体情况请參考qt的帮助文档 */ "com/mtn/mes/GpsService", "calledByCpp", "()V"); }bool MainWindow::event(QEvent *e) { if(e-> type() == CustomEvent::eventType()){ /* 匹配上自己定义事件类型 */ e-> accept(); CustomEvent *sce = (CustomEvent*)e; //_resultView-> setText(sce-> m_arg2); ui-> textBrowser-> setText(sce-> m_arg2); /* 显示GPS信息 */ return true; } return QWidget::event(e); }



3.3.1  E:\work\c++\qt\QtAndroidGps\CustomEvent.h

#ifndef CUSTOMEVENT_H #define CUSTOMEVENT_H #include < QEvent> #include < QString> class CustomEvent : public QEvent { public: CustomEvent(int arg1 = 0, const QString & arg2 = QString()); ~CustomEvent(); static Type eventType(); int m_arg1; QString m_arg2; private: static Type m_evType; }; #endif // CUSTOMEVENT_H

3.3.2  E:\work\c++\qt\QtAndroidGps\CustomEvent.cpp

#include "CustomEvent.h"QEvent::Type CustomEvent::m_evType = (QEvent::Type)QEvent::None; CustomEvent::CustomEvent(int arg1, const QString & arg2) : QEvent(eventType()), m_arg1(arg1), m_arg2(arg2) {}CustomEvent::~CustomEvent() {}QEvent::Type CustomEvent::eventType() { if(m_evType == QEvent::None) { m_evType = (QEvent::Type)registerEventType(); /* 注冊自己定义事件,返回m_evType值为qt分配的自己定义事件类型 */ } return m_evType; }

3.4  E:\work\c++\qt\QtAndroidGps\CustomEvent.cpp
#include "mainwindow.h" #include < QApplication> #include < QDebug> #include < jni.h> #include < QAndroidJniEnvironment> #include < QAndroidJniObject> #include "CustomEvent.h"QObject *main_window = 0; /* 该函数被java的本地方法调用 */ static void reportGpsInfo(JNIEnv *env, jobject thiz,int result, jstring data) { QString qstrData; const char *nativeString = env-> GetStringUTFChars(data, 0); qstrData = https://www.songbingjia.com/android/nativeString; env-> ReleaseStringUTFChars(data, nativeString); QCoreApplication::postEvent(main_window, new CustomEvent(result, qstrData)); /* 发送事件(携带GPS信息)给主窗体。自己定义事件类型 */ qDebug() < < qstrData; }bool registerNativeMethods() { JNINativeMethod methods[] { {"reportGpsInfo", "(ILjava/lang/String; )V", (void*)reportGpsInfo} /* 注冊本地方法,java方可调用,具体信息见qt帮助文档 */ }; const char *classname = "com/mtn/mes/ExtendsQtNative"; jclass clazz; QAndroidJniEnvironment env; QAndroidJniObject javaClass(classname); clazz = env-> GetObjectClass(javaClass.object< jobject> ()); qDebug() < < "find ExtendsQtNative - " < < clazz; bool result = false; if(clazz) { jint ret = env-> RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0])); env-> DeleteLocalRef(clazz); qDebug() < < "RegisterNatives return - " < < ret; result = ret > = 0; } if(env-> ExceptionCheck()) env-> ExceptionClear(); return result; }int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; CustomEvent::eventType(); // 注冊自己定义事件,生成自己定义事件类型 registerNativeMethods(); // 注冊本地方法 w.show(); main_window = qobject_cast< QObject*> (& w); return a.exec(); }

3.5  E:\work\c++\qt\QtAndroidGps\android\src\com\mtn\mes\ExtendsQtNative.java

package com.mtn.mes; import java.lang.String; public class ExtendsQtNative { public native void reportGpsInfo(int result, String content); }

3.6  E:\work\c++\qt\QtAndroidGps\android\src\com\mtn\mes\GpsService.java

package com.mtn.mes; import java.lang.String; import android.content.Context; import android.content.Intent; import android.app.PendingIntent; import android.os.Handler; import android.os.Message; import android.util.Log; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.Uri; import android.location.Criteria; import android.provider.Settings; import android.os.Bundle; import android.os.Environment; import java.io.File; import com.loopj.android.http.AsyncHttpClient; import com.loopj.android.http.AsyncHttpResponseHandler; import android.widget.Toast; import java.util.Date; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import com.amap.api.location.AMapLocation; import com.amap.api.location.AMapLocationListener; import com.amap.api.location.LocationManagerProxy; import com.amap.api.location.LocationProviderProxy; import com.baidu.location.BDLocation; import com.baidu.location.BDLocationListener; import com.baidu.location.LocationClient; import com.baidu.location.LocationClientOption; import com.baidu.location.LocationClientOption.LocationMode; public class GpsService extends org.qtproject.qt5.android.bindings.QtActivity { private static GpsService m_instance; private final static String TAG = "GpsService"; private final static int MSG_STR_GPS_LOC = 0; private final static int MSG_RPT_GPS_INF = 1; //////////////////////////////////////////////////////////////// //定位相关 //////////////////////////////////////////////////////////////// private LocationManagerProxy aMapManager; public GpsService(){ m_instance = this; }public static void calledByCpp() { System.out.println("[0]hello world!"); Message msg = new Message(); msg.what = MSG_STR_GPS_LOC; m_instance.handler.sendMessage(msg); // 消息触发,启动GPS定位 //m_instance.handler.sendEmptyMessage(0); // 消息触发。启动GPS定位 }public static void calledByCpp(int arg0) { System.out.println("[1]hello world!"); }private void startAmap() { aMapManager = LocationManagerProxy.getInstance(this); /* * mAMapLocManager.setGpsEnable(false); * 1.0.2版本号新增方法,设置true表示混合定位中包括gps定位,false表示纯网络定位,默认是true Location * API定位採用GPS和网络混合定位方式 * ,第一个參数是定位provider,第二个參数时间最短是2000毫秒,第三个參数距离间隔单位是米,第四个參数是定位监听者 */ aMapManager.requestLocationUpdates(LocationProviderProxy.AMapNetwork, 2000, 10, mAMapLocationListener); }private AMapLocationListener mAMapLocationListener = new AMapLocationListener() {@Override public void onStatusChanged(String provider, int status, Bundle extras) {}@Override public void onProviderEnabled(String provider) {}@Override public void onProviderDisabled(String provider) {}@Override public void onLocationChanged(Location location) {}@Override public void onLocationChanged(AMapLocation location) { if (location != null) { Double geoLat = location.getLatitude(); Double geoLng = location.getLongitude(); String cityCode = ""; String desc = ""; Bundle locBundle = location.getExtras(); if (locBundle != null) { cityCode = locBundle.getString("citycode"); desc = locBundle.getString("desc"); }String str = ( "location ok:(" + geoLng + "," + geoLat + ")"+ "\nAccuracy:" + location.getAccuracy() + "Meter" + "\nPositioning:" + location.getProvider() + "\nPositioning time:" + new Date(location.getTime()).toLocaleString() + "\nCity coding :" + cityCode + "\nLocation Description:" + desc + "\nProvince:" + location.getProvince() + "\nCity:" + location.getCity() + "\nDistrict (county):" + location.getDistrict() + "\nRegional Coding:" + location.getAdCode()); //Toast.makeText(getApplicationContext(), "高德定位\n" + str, Toast.LENGTH_SHORT).show(); // 发送位置信息到handler, hander处再转发给Qt Message msg = new Message(); Bundle data = https://www.songbingjia.com/android/new Bundle(); data.putString("value", str); msg.setData(data); msg.what = MSG_RPT_GPS_INF; handler.sendMessage(msg); } } }; private Handler handler = new Handler() {@Override public void handleMessage(Message msg) { switch(msg.what) { case MSG_STR_GPS_LOC: // 消息类型为启动GPS定位 m_instance.startAmap(); break; case MSG_RPT_GPS_INF: // 消息类型为上送GSP信息 ExtendsQtNativem_nativeNotify = new ExtendsQtNative(); Bundle data = https://www.songbingjia.com/android/msg.getData(); System.out.println(data.getString("value")); m_nativeNotify.reportGpsInfo(0, data.getString("value")); // 掉用c++方法 break; default: System.out.println("msg type error!"); break; } } }; }

【qt on android之GPS信号的获取】点击下载源代码














    推荐阅读