精华内容
下载资源
问答
  • 这是我自己做的一个仿滴滴打车的Android出行项目,主要针对滴滴等出行平台一直饱受质疑的“人车不符”问题,以及当前越发火热的或计划和出海战略,给出行项目增加了下面几个功能:1.RFID识别验证功能:在司机证件...

    前言

    这是我自己做的一个仿滴滴打车的Android出行项目,主要针对滴滴等出行平台一直饱受质疑的“人车不符”问题,以及当前越发火热的国际化和出海战略,给出行项目增加了下面几个功能:

    1. RFID识别验证功能:在司机证件或者车内识别硬件里嵌入RFID识别芯片,乘客使用手机读取到芯片信息,并且通过网络(okhttp3)发送到出行平台数据库进行验证(我用NDK加了一个C语言的MD5加密算法对识别到的信息进行了加密)。如果不是合规的“人”或“车”,则不能完成订单并向平台或监管单位汇报当前位置。(为了方便读者测试,可以使用手机读取任何一个加密或非加密RFID芯片,比如银行卡、公交卡等,我在代码中的验证前阶段把芯片信息都换成我自己的司机信息,确保读者测试时可以收到服务器的回复)
    2. 海外版功能:点击切换当前语言。
    3. 司机证件号码识别功能:读取司机证件上的证件号码,也可以用来与出行平台数据库的信息进行核实比对。

    项目源码地址:https://github.com/18601949127
    项目代码都是一行一行自己敲的,在多部手机上调试过确保各项功能能够顺畅运行。GitHub的源码中保留了所有的手机CPU指令集架构,保证在所有手机上能够运行成功。觉得包太大的同学可以自己把不需要的 .so 指令集删掉,主要是做识别的 OpenCV4Android.so 包比较大,其次是百度地图的包。

    地图我使用的是百度地图LBS 版本5.3,海外的话考虑到信息数据多少、性能、包大小、数据源等多方面因素推荐使用mapbox。 感兴趣的读者可以看Trinea 的这篇文章:
    https://blog.csdn.net/weixin_37734988/article/details/92852349

    文章发布以后得到《滴滴国际化项目 Android 端演进》作者滴滴公司技术专家Trinea @trinea 的提点, 告诉我要特别根据海外版的应用场景认真分析国外几款 Map 服务的各项优劣,比较Google地图、 mapbox 、Nutiteq 等,非常感谢。我后面会单独写几篇关于 mapbox使用的文章并且分享出来

    读者如果想到滴滴出行或者其他平台比较实用的功能可以留言或者微信给我(微信:18601949127),我会抽时间把好的 idea 或者功能继续添加到项目里。

    开发环境

    1. Android端: Android Studio 版本3.4, 百度地图LBS 版本5.3 , OpenCV4Android 版本3.2
    2. 服务器端: Apache + PHP + MySQL 用的是我自己租的腾讯云主机做服务器,我会一直开放出这个项目的接口,接受并处理读者发来的测试请求。

    主界面概览

    主界面概览

    界面最上面TitleBar 的位置是主要的功能区,除了中间的醒目logo,两侧分布主要功能选项,最左边的SlidingMenu提供侧滑菜单,给乘客个人信息和软件设置提供入口,右边的证件标志按钮用于导向司机证件号码识别功能,再右边的英语标志按钮是国际化语言切换,最右边的无线标志是RFID识别认证功能的入口。

    主界面的中间部分是地图区域,可以在上边选择不同交通工具,用于展示乘客所在位置,附近车辆或者POI热点,以及路径规划。

    主界面的下方可以提供上划菜单,主要用于上车和目的地地址关键字输入,以及安全提示信息或者广告的入口。

    项目文件结构

    首先介绍一下项目文件结构,方便读者阅读代码:
    项目文件结构

    包名:com.tantuo.didicar

    • Activity 文件夹:有的Activity 相对独立,并不属于某个功能模块,可以放到这个文件夹。

    • adapter 文件夹:相对复杂一点的adapter会从类文件中取出单独保存到 adapter文件夹,比如左侧侧滑菜单中 recycler view的adapter。简单一点的adapter还是会保存在调用的类中。

    • Bean 文件夹: 存放Entity 实体类,比如司机的相关信息会包装成一个DriverBean,每个司机都是一个类对象,使用Gson 传递很方便,用的时候get,set 就可以。

    • DriverLicenseNFC 文件夹:RFID识别验证模块,乘客使用这个功能模块验证司机身份或者车辆信息。

    • DriverLicenseRecognition 文件夹:司机证件号码OCR识别的功能模块。

    • splash 文件夹:app 初始化和引导界面。

    • TabFragment:主界面上方的滑动主题条用来切换交通工具或者服务项目(Tab),不同的交通工具或者服务项目代码都保存在TabFragment 文件夹里。

    • utils 文件夹: 用来保存项目用到的各种工具类,比如DriverRouteOverlay 用来在地图上渲染规划出来的驾车路线,MD5JniUtils 用NDK调用MD5加密算法,保护RFID芯片信息,NfcUtils 用来管理手机的NFC功能,POIOverlay 用来在地图上渲染周围兴趣点(POI)。

      把工具类从Activity 或者 Fragment 中extract 出来放到统一的utils 文件夹,会让你的代码更清晰,可读性更强。

    引导界面

    先看下真机上的效果:
    引导界面

    引导界面最初的logo动画是用我自己用SVG矢量动画做的,路径规划描述在 drawable 的splash_logo.xml 文件里:

    路径规划描述
    还需要资源文件里的animator文件夹下的didi_logo_animator.xml 对路径进行动画描述:

    <objectAnimator
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="3000"
        android:propertyName="trimPathEnd"
        android:repeatCount="0"
        android:valueFrom="0"
        android:valueTo="1"
        android:valueType="floatType"/>
    

    这几秒的时间里可以在下图的位置添加一些初始化代码,比如网络请求,得到后续Activity的素材,地理位置等等。

    初始化代码位置

    出行界面

    通过滑动地图界面上方的主题可以切换不同的项目界面。
    滑动主题条是一个VIewPager的 Indicator,每一个主题对应一个下面的服务项目,放在各自独立的VIewPager里。每个服务项目有各自独立的上划菜单,作为此服务对应的地址关键字输入或者相关信息入口。
    出行界面
    出行界面的UI结构:
    出行界面的UI结构
    注意:乘客的位置信息、当前经纬度、当前街道名字、楼宇名字都是在MainAcitivity做为静态成员变量定义的,原因是在别的Acitivity或者类中,这些变量需要经常使用,直接调用 MainActivity.CurrentLocation就可以了,后面用到的所有当前位置,都是在MainActivity中 MyLocationListener 类得到的。

    MainAcitivity

    上车地址和目的地址的路线规划

    路线规划功能
    不同交通工具(快车,出租车,单车,公交车等等)对应的服务项目都嵌在TItleBar下边的 VIewpager里,一个服务项目对应一个独立的Fragmen文件,由其顶部的的VIewpagerIndicator滑动切换。
    服务项目的主要代码在com.tantuo.didicar 包下 TabFragment 文件夹里。

    底部上滑动菜单

    底部上滑动菜单
    buttonsheet是在布局文件中加入android.support.v4.widget.NestedScrollView类的 app:layout_behavior="@string/bottom_sheet_behavior"
    在这里插入图片描述

    左侧侧滑菜单

    左侧侧滑菜单可以作为个人信息、安全提示、设置信息的入口
    左侧侧滑菜单

    司机证件的号码OCR识别功能

    证件号码识别功能的主要代码在com.tantuo.didicar 包下的 DriverLicenseRecognition 模块。

    证件号码识别代码

    还是先看下真机效果:

    司机证件的号码识别功能

    点击进入司机证件号码识别功能以后,可以选择对证件拍照,为了方便演示,这里是从手机相册选择刚刚拍的照片。同时为了方便读者测试这个功能,我把照片保存在了开发包的asset文件夹里面,这样读者下载我保存在GIthub上https://github.com/18601949127 的版本,点击选择司机证件以后调用的是我保存在assets 文件夹里的司机证件照片,也就是下面图片里的 getDriverLicenseFromMySample() 方法,可以立刻进行测试。想继续从手机相册读取的读者可以执行LicenseMainActivity 下的 LicenseMainActivity 方法。
    调用司机证件
    注意:在程序中,想要在运行中读取司机证件照片,要把照片保存在assets 文件夹下面,使用AssetManager 类读取,而不能试图调取drawable 文件夹下面的照片,因为 \res 文件夹下的资源文件都会被编译到apk里面去,并同时赋予资源 id。感兴趣的同学可以看下代码里面的 copyFilesFassets()方法。

    这里用我以前在国外读书时候的证件作为例子:

    司机证件照片

    1. 首先:要从照片中找到司机证件区域,也就是上证件边缘红色的区域
        /**
         * 找到图像中的证件区域
         * 在RGB色彩空间求取驾驶员证件的图像梯度,之后在此图像上做二值化,从而通过轮廓(contour)发现与面积大小过滤得到证件区域
         * author:Tantuo 86-1860194917
         * @param fileUri
         * @return
         */
        public Mat findLicenseContour(Uri fileUri) {
    
            //首先使用openCV 的 Imgcodecs类得到相机获取的证件图片
            Mat src = Imgcodecs.imread(fileUri.getPath());
            if (src.empty()) {
                return null;
            }
    
            //得到证件照片的x梯度和y梯度
            Mat grad_x = new Mat();
            Mat grad_y = new Mat();
            Mat abs_grad_x = new Mat();
            Mat abs_grad_y = new Mat();
    
            //注意求梯度的时候我们使用的是Scharr算法,sofia算法容易收到图像细节的干扰
            //所谓梯度运算就是对图像中的像素点进行就导数运算,从而得到相邻两个像素点的差异值 by:Tantuo
            Imgproc.Scharr(src, grad_x, CvType.CV_32F, 1, 0);
            Imgproc.Scharr(src, grad_y, CvType.CV_32F, 0, 1);
            //openCV中有32位浮点数的CvType用于保存可能是负值的像素数据值
            Core.convertScaleAbs(grad_x, abs_grad_x);
            Core.convertScaleAbs(grad_y, abs_grad_y);
            //openCV中使用release()释放Mat类图像,使用recycle()释放BitMap类图像
            grad_x.release();
            grad_y.release();
    
    
            //使用openCV的Core.addWeighted方法将x梯度和y梯度合并成一个梯度图像
            Mat grad = new Mat();
            Core.addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad);
            abs_grad_x.release();
            abs_grad_y.release();
    
            //得到梯度图像以后将其二值化,以便更清晰地找到轮廓边缘
            //Imgproc.cvtColor方法将梯度图像转换成binary gray灰度图像
            Mat binary = new Mat();
            Imgproc.cvtColor(grad, binary, Imgproc.COLOR_BGR2GRAY);
            //手动阈值化,threshould阈值定为40
            Imgproc.threshold(binary, binary, 40, 255, Imgproc.THRESH_BINARY);
            grad.release();
    
            //下面对二值图像进行形态学(morphology excution)的去噪声操作,先得到大小为 3*3像素的结构元素
            Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3, 3));
            //然后对结构元素进行 Morph_open开操作。 腐蚀:去除噪声-膨胀:覆盖去除的噪声点
            Imgproc.morphologyEx(binary, binary, Imgproc.MORPH_OPEN, kernel);
    
    
            //接下来使用openCV的Imgproc.findContours()方法,在图像中寻找驾驶员证件的轮廓 contour roi
            List<MatOfPoint> contours = new ArrayList<>();
            Mat hierarchy = new Mat();
            Imgproc.findContours(binary, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE, new Point(0, 0));
            int hw = binary.cols() / 2;
            int hh = binary.rows() / 2;
            Rect roi = new Rect();
            for (int i = 0; i < contours.size(); i++) {
                Rect rect = Imgproc.boundingRect(contours.get(i));
                //如果发现某一个 roi兴趣区域的轮廓宽度超过图片的一半,即可以认为这个轮廓是驾驶员证件的轮廓 contour
                if (rect.width > hw) {
                    roi.x = rect.x;
                    roi.y = rect.y;
                    roi.width = rect.width;
                    roi.height = rect.height;
                    break;
                }
            }
    
            //没找到就返回
            if (roi.width == 0 || roi.height == 0) {
                return null;
            }
    
            //找到证件轮廓区域就将其拷贝到card图片中
            Mat card = new Mat();
            src.submat(roi).copyTo(card);
    
            //拷贝完成以后记得释放资源0
            src.release();
            binary.release();
            return card;
        }
    

    第一步先调用Imgproc.Scharr()方法对司机证件的原始照片进行Scharr梯度运算,所谓梯度运算就是对图像中的像素点进行导数运算,从而得到相邻两个像素点的差异值,像素差异大的地方就是图像内轮廓contour,第二步在此图像上做二值化Binarization,调用 Imgproc.morphologyEx()方法,通过轮廓(contour)发现与面积大小过滤得到证件区域。

    边缘发现以后调用Imgproc.cvtColor()方法得到下面的证件区域:
    识别出的证件区域
    2.识别到证件区域以后我们注意到证件左上角有一个比较醒目的矩形,我们用它作为reference识别到照片下方包含数字的号码区域。在程序中这个过程调用下面的 findCardNumBlock(Mat card) 方法。

        public Mat findCardNumBlock(Mat card) {
            //首先初始化HSV色彩空间(H:hue色相,S:saturation饱和度,V:value明度,亮度)
            Mat hsv = new Mat();
            Mat binary = new Mat();
    
            //从RGB色彩空间转换到hsv色彩空间,使用openCV的 Imgproc函数:Imgproc.COLOR_BGR2HSV
            Imgproc.cvtColor(card, hsv, Imgproc.COLOR_BGR2HSV);
            //inRange函数将hsv彩色图片的根阈值进行过滤,用来过滤掉对识别左上角标志区域帮助不大的颜色
            //并且把滤出的图像保存到 binary里面
            // Scalar()是具有三个参数的结构体,三个参数代表 hsv的色相,饱和度,亮度值
    
            Core.inRange(hsv, new Scalar(30, 40, 45), new Scalar(180, 255, 255), binary);
    
            //以上会得到一个驾驶员证件的二值化图像,但是噪声比较多
            //下面对二值话图像进行形态学的开操作(morphology excution),去除小的 5*5大小的结构元素(噪声)
            Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(5, 5));
            Imgproc.morphologyEx(binary, binary, Imgproc.MORPH_OPEN, kernel);//去除噪声
    
    
            //获取证件标志的轮廓(contours)
            List<MatOfPoint> contours = new ArrayList<>();
            Mat hierarchy = new Mat();
            Imgproc.findContours(binary, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE, new Point(0, 0));
    
            int offsetx = binary.cols() / 3;
            int offsety = binary.rows() / 3;
            Rect numberROI = new Rect();
    
            //对每个ROI寻找外接矩形 contourArea
            for (int i = 0; i < contours.size(); i++) {
                Rect roi = Imgproc.boundingRect(contours.get(i));
    
                //对于识别出来的矩形区域如果太小(面积小于200像素)则忽略
                if (Imgproc.contourArea(contours.get(i)) < 200) {
                    continue;
                }
                //找到标志区域以后,以标志区域为基准,证件号码的位置在标志x坐标 *2 左右,宽度大概在 binary.cols() - roi.x - 100像素
                //证件号码的高度大概是证件标志(基准)的0.7倍 height*0.7 ;
                //如果找到的左上角标志物的轮廓长宽都小于证件的三分之一,则以此标志物作为标准定为号码区域
                if (roi.x < offsetx && roi.y < offsety) {
                    numberROI.x = 3* roi.x + 120;
                    numberROI.y = roi.y + 4 * roi.height - 65;
                    numberROI.width = binary.cols() - roi.x - 390;
                    numberROI.height = (int) (roi.height * 0.9);
                    break;
                }
            }
    
            //如果没有找到就返回null
            if (numberROI.width == 0 || numberROI.height == 0) {
                return null;
            }
    
            //得到证件号码的区域以后就可以截取下来保存到 textimage
            Mat textImage = new Mat();
            card.submat(numberROI).copyTo(textImage);
            //拷贝完成以后记得释放release mat资源
            card.release();
            hsv.release();
            binary.release();
            return textImage;
        }
    

    同样还是先把图像从RGB色彩空间转换成HSV色彩空间,调用OpenCV的 Imgproc类生成一个 Imgproc.COLOR_BGR2HSV 对象。

    Imgproc.cvtColor(card, hsv, Imgproc.COLOR_BGR2HSV);
    

    之后调用下面的Core.inRange()方法得到一个hsv颜色在new Scalar(30, 40, 45)范围内的区域,也就是左上角的reference 矩形。

    Core.inRange(hsv, new Scalar(30, 40, 45), new Scalar(180, 255, 255), binary);
    

    下一步还是形态学操作去噪声。噪声就是二值化图像里面识别出来的一个个小的黑点,形态学的开操作(morphology excution)会把图像中这些小小的黑点用旁边的大区域颜色覆盖掉,目的是为了让处理后的图像更加容易被机器识别。
    比如下面的代码调用OpenCV的Imgproc.morphologyEx()方法可以把大小为 5*5的结构元素(噪声)用周边像素弥补掉

            //下面对二值话图像进行形态学的开操作(morphology excution),去除小的 5*5大小的结构元素(噪声)
            Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(5, 5));
            Imgproc.morphologyEx(binary, binary, Imgproc.MORPH_OPEN, kernel);//去除噪声
    
    

    噪声处理以后开始寻找证件区域内的号码区域 Contour做轮廓发现操作:

            //对每个ROI寻找外接矩形 contourArea
            for (int i = 0; i < contours.size(); i++) {
                Rect roi = Imgproc.boundingRect(contours.get(i));
    
                //对于识别出来的矩形区域如果太小(面积小于200像素)则忽略
                if (Imgproc.contourArea(contours.get(i)) < 200) {
                    continue;
                }
                //找到标志区域以后,以标志区域为基准,证件号码的位置在标志x坐标 *2 左右,宽度大概在 binary.cols() - roi.x - 100像素
                //证件号码的高度大概是证件标志(基准)的0.7倍 height*0.7 ;
                //如果找到的左上角标志物的轮廓长宽都小于证件的三分之一,则以此标志物作为标准定为号码区域
                if (roi.x < offsetx && roi.y < offsety) {
                    numberROI.x = 3* roi.x + 120;
                    numberROI.y = roi.y + 4 * roi.height - 65;
                    numberROI.width = binary.cols() - roi.x - 390;
                    numberROI.height = (int) (roi.height * 0.9);
                    break;
                }
            }
    

    得到证件号码的区域以后就可以截取下来保存到 textimage

        Mat textImage = new Mat();
        card.submat(numberROI).copyTo(textImage);
    

    拷贝完成以后记得释放release mat资源

            card.release();
            hsv.release();
            binary.release();
            return textImage;
    

    完成以上工作以后可以识别到证件号码区域的矩形轮廓:
    识别出的证件号码区域
    识别出了证件中的号码区域,后面就调用 DigitImageProcessor 类对这些数字进行识别,这个过程需要我单独在另外一篇文章介绍,下面仅仅对几个重要方法的功能作介绍:

    • splitNumberBlock(Mat textImage)方法使用二值化方法识别数字区域里的字符轮廓。
    • getSplitLinePos(Mat mtexts) 方法用来对图像中有两个数字粘结起来的情况做分离。
    • extractFeatureData(Mat txtImage) 方法的作用是证件卡号识别的特征提取,获取卡号每个数字的黑色像素点特征,作为每个号码的特征和识别的重要依据。
    • dumpFeature(float[] fv, int textNum) 方法将生成的特征文本文件保存在手机。
    • readFeatureVector(File f) 用来读取保存的特征向量。
    • recognitionChar(Mat charImage) 用来根据特征向量对证件号码进行识别。

    RFID识别验证功能

    RIFD识别验证功能的主要代码在com.tantuo.didicar 包下的DriverLIcenseNFC模块里:

    RFID识别验证功能代码

    还是先看下真机效果:
    RFID识别验证功能

    点击右上角的RFID验证入口以后,会提示乘客使用手机背面像刷公交卡那样感应RFID硬件,比如嵌入芯片的司机证件、固定在车上识别器等。

    使用手机感应RFID芯片
    注意: 某个Activity 要想能够在当前栈顶接收RFID芯片号码,必须在 Manifest.xml 文件中设置intent-filter 拦截TAG_DISCOVERED的Action,这样这个Activity 才能捕获RFID标签信息。并且设置LunchMode 为SingleTop,确保再次捕获RFID标签信息(TAG_DISCOVERED)的时候,始终由处于栈顶的这个Activity 来处理,而不是把他压入栈,调取新的DriverRFIDMainActivity作栈顶。
    有疑惑的同学可以看下 Activity 启动模式和栈管理的相关文章。
    彻底明白Activity启动模式-SingleTop、SingleTask、SingleInstance具体使用场景
     Manifest.xml 文件中的设置
    考虑到用户的手机可能有多个APP或者Activity 可以拦截RFID或者 NFC 芯片信息,所以需要给处于当前栈顶的 DriverRFIDMainActivity 设置前台分发系 enableForegroundDispatch ,可以确保检测到RFID标签时,此活动拥有最高的捕获优先权,而不是由Android Activity 调度机制调出新的有拦截权限的活动。

        @Override
        protected void onResume() {
            super.onResume();
            // 前台分发系统,用于确保检测RFID标签时拥有最高的捕获优先权.
            NfcUtils.mNfcAdapter.enableForegroundDispatch(this, NfcUtils.mPendingIntent, NfcUtils.mIntentFilter, NfcUtils.mTechList);
        }
    
        
        @Override
        protected void onPause() {
            super.onPause();
            //关闭前台调度系统
            NfcUtils.mNfcAdapter.disableForegroundDispatch(this);
        }
    

    手机读取芯片ID这个功能的代码我单独放到NfcUtils工具类里,在utils 文件夹下。
    NfcUtils工具类
    手机读取到芯片信息,会调用NDK编译成C语言的MD5加密算法so 文件(文章最后会讲),连同当时的地理位置经纬度一起发送给平台服务器(我用的 OkHttp3 ),与数据库中注册司机的信息进行比对,并将验证结果和司机信息发送给乘客:
    服务器端返回的验证结果
    服务器端用的是我自己的腾讯云主机 + Apache + PHP+ MySQL , 会一直开放出这个项目的网络接口并持续维护,方便读者测试这个功能。读者只要在验证环节使用手机读取任何一个嵌有RFID加密芯片比如学生证、银行卡、公交卡,程序在发送数据请求之前(下图代码中第二行高亮的部分)都会把读取到的ID信息换成作者本人的,再发送给平台服务器服务器做验证,这样读者测试时使用手机读取任何RFID信息都会接收到从服务器发回来的司机信息。实际项目中把这一行注释掉即可。

    发送验证信息前的代码
    服务器端收到乘客发送过来的验证请求以后,会对比平台司机数据库进行核实,并把核实结果和对应司机、车辆信息发回给乘客。
    下面就是平台服务器端注册司机的注册信息数据库,我用Navicat 做了部分截图,第一行红色部分就是平台验证的结果,也就是作者本人的信息。
    服务器端的司机信息数据库
    服务器端还会对乘客发送过来的数据进行整理和分析,也可以将“人车不符”数据和位置信息发送给合规部门。
    “人车不符”
    下图是“人车不符”情况发生的地区热力图:

    “人车不符”发生频率热力图
    还可以根据乘客的叫车时间,筛选出高峰时段的用车需求热力图,给司机调度部门提供数据支持。
    用车需求热力图
    对服务器端的打车数据进行分析,还可以生成非常漂亮的24小时动态热力图、星云图、蝌蚪迁移图,感兴趣的读者可以研究下Python 、Pandas 、MatplotLib,可以快捷地处理服务器端数据,生成可视化图表。

    使用NDK调用MD5加密算法

    前面提到项目中会把ID号码使用C语言的MD5算法进行加密,关键代码在下图中的cpp 文件夹。
    图中 NDK Components 组件提供了一整套编译C语言动态库(.so )和打包的工具,可以把 *.so 动态库打包到apk中。
    下面的MD5.h 和 MD5.cpp 文件分别是C语言写的算法类头文件和源文件。头文件用来声明源文件要用到的变量、类型、宏定义,源文件则用来描述方法和具体实现,里面会有一个#include "MD5.h" 把头文件导入进来。两者的关系有点像书的目录和内容的关系,目录是对章节和内容进行简单表示,真正的实现实在书里面的。
    NDK相关文件
    上图中MD5 C语言文件下面还有一个native-lib.cpp 文件,是NDK 在 Android studio 里帮助我们生成的。它可以认为是Java方法调用C语言方法的桥梁。
    下面的图可以看到 native-lib 是如何帮助 MD5JniUtils 类的 getMd5 () 方法调用 C语言加密方法的,JNIEXPORT 和 JNICALL 两个宏用来标识函数用途是调用.so 库,就好像 C++可以调用 .dll 动态链接库一样,后面紧跟的是函数名,命名规则很重要:Java_ + 包名 + 调用这个加密算法的Java工具类名 + Java调用方法 ,后面的变量参数是Java中String类型对应的JNI jstring类型,下面在方法体中,就可以使用对传入的加密前字符串进行加密的C语言运算了,并把加密完成的 jstring类型结果返回给java层。
    native-lib.cpp 文件

    结语

    整个项目就大概介绍完了,欢迎读者转载和提问,我看到会尽快回复,如果读者能想到更加实用的功能,我会更新GitHub上的源码加上新的功能。
    我也会尽快抽时间把百度地图换成海外版地图MapBox 或者 Here Map的版本,这样国内的应用拿到国外也可以正常使用。
    感谢滴滴专家吴更新@Trinea的提点和郭霖老师的转载,所有提出好的idea和实用功能的读者在这里都会被实名@感谢。

    项目源码地址:https://github.com/18601949127
    我的博客:https://blog.csdn.net/weixin_37734988

    展开全文
  • 一、高精准IP地址定位 IP地址定位技术,是通过设备的IP地址来确定其地理位置。近年来,IP地址定位技术受到越来越多的关注,随着互联网日新月异的发展,市场中的IP地址定位产品存在数据陈旧、定位颗粒度粗糙(仅...

    一、高精准IP地址定位

     

          IP地址定位技术,是通过设备的IP地址来确定其地理位置。近年来,IP地址定位技术受到越来越多的关注,随着互联网日新月异的发展,市场中的IP地址定位产品存在数据陈旧、定位颗粒度粗糙(仅能达到城市级别)等问题。即使近年来市场中出现了相比城市级别精度有所提升的IP地址定位产品,但仍无法充分满足市场中用户的需求。目前在互联网行业基于位置的服务已经成为趋势,基于地理位置的网络应用层出不穷,IP地址定位已广泛应用于网络安全、在线广告投放、在线安全支付、大数据分析、反欺诈风控、大数据征信等领域。高精准IP地址定位技术在互联网领域中越来越重要。许多研究机构和学者已围绕如何提升IP地址定位技术的定位精度、应用场景等不同问题进行了系统的研究。

     

    1、基于数据挖掘的方式

    ● 基于DNS. Davis等人提出了一种基于DNS的方法。这种方法在资源记录(Resource Record)中增加位置字段。然而,这种方式实施起来仍有一定难度。这是因为管理员对于修改或者更新资源记录缺乏动力。此外,研究人员表明DNS的错误命名是具有普遍性的,这种错误有可能将互联网的拓扑映射毁掉。

    ● 基于Whois. Moore等人指出,地理位置定位也可以通过挖掘Whois数据库获得。然而,正如作者自己指出的那样,大型的机构可以把它们的机器分散在不同地点,但是却把这些机器的地理位置注册在公司的总部位置。举一个例子,许多现有使用此方法的IP地址定位数据库都把Google分布在世界各地的服务器错误的定位到了Mountain View,加州,美国。

    ● 基于主机. 路由器的主机名有时可以暗示出机器的地理信息。Padmanabhan和 Subramanian的GeoTrack首先找到离被探测目标最近的路由器,然后从这个路由器的主机名上来判断出该接入路由器的位置。最终,GeoTrack认为路由器的位置信息即是被探测目标的位置信息。然而,这种方法受到多种因素的影响。第一,并不是所有的机器名称中都包含地理位置信息。其次,管理员可以非常有创意地来命名他们的机器,因此,从技术上来说,解析全部命名格式是十分困难的。再次,由于最后一跳路由器可能和目标主机相差很远,因此用最后一跳路由器的位置来替代目标主机的位置可能带来很大的错误。

    ● 基于Web. Guo等人的Structon,从Web网页中挖掘地理位置信息。尤其是Structon建立了一个地理定位表,并在一个非常大的数据集的每个网页页面上使用正则表达式提取地理位置信息。由于Structon不把他们发掘的基准点与延迟测量向结合,它只实现了较粗颗粒度的定位精度,如城市级别。他们从网页上提取所有与地理位置有关的信息,而不仅仅是邮政地址信息,而且对于一个网站,他们考虑这个网站域名下的所有网页所提供的地理位置信息。事实上,这种办法很容易出错。此外,把一个/24的IP段都考虑为同一个城市忽略了在这一个网段中IP地址的更细颗粒度的特点。由于Hosting即数据中心、网页地址不正确、traceroute经过的路由未知等因素,会有很大一部分IP地址无法定位或者定位错误,该方法要达到一个较高的精准度是很困难的。

    ● 其他来源. Padmanabhan和Subramanian的GeoCluster使用在BGP路由表中IP地址的前缀把IP地址首先聚成集群。此外,通过一些私有的资源,GeoCluster找到集群中部分IP地址的地理位置信息。这些私有资源有很多种,其中一个例子是用户在使用Hotmail服务时,登记自己的地理位置信息。最终,根据这些部分IP地址的地理位置信息,GeoCluster推导出整个群集的所有IP地址的地理位置信息。该方法的正确性高度取决于用户的输入。并且这些私有的位置信息一般情况下是不公开的。

    2、基于延迟测量

    ● GeoPing. Padmanabhan和Subramanian设计了GeoPing。它假设,如果两台机器的延迟向量越是类似的话,那么他们之间越有可能靠的近一些。GeoPing需要使用一组可以发送探测包的探测点。很明显,这种办法取决于可以发送探测包的探测点的数量,而通常这个数量是很少的。

    ● CBG. 之前的研究工作的输出结果多是一些单一的离散的地理位置。Gueye等人提出了基于约束的地理定位方法(Constraint based Geolocation, CBG)。这种方法使用三角测量的方法,提供了一片连续的地理空间范围。特别是,CBG测量从所有基准点到被探测目标点的延迟。然后,它把延迟转化成从基准点到被探测目标点之间的地理距离。最后,它使用三角测量的方法得到一片连续的地理范围。

    值得一提的是,CBG使用最优值(bestline)的限制来弥补互联网中路由的绕路和膨胀问题。然而,由于很难预测从一个探测点到目标节点路由是否绕路,通常情况下,只有在被探测节点离探测点很近时,CBG才行之有效。虽然CBG可以很有效地限制目的地区,但由于它测量的不准确性,因此,从本质上来说,要想实现非常精细的地理位置定位是十分困难的。

    ● TBG. 根据靠近被探测目标的路由器更容易被精确地地理定位这一事实, Katz-Bassett等人提出了基于拓扑结构的地理定位系统(Topology based Geolocation, TBG)。这种方法地理定位目标和到目标的路径中的路由器。TBG的关键贡献在于,它证实了网络的拓扑结构是可以被用来实现更高的地理定位精度。尤其是TBG首先定位到达被探测目标IP路径上路由器的地理位置,然后用这些路由器作为基准点来进一步得到探测目标IP的地理位置。除了使用网络的拓扑信息,一个TBG的变种也使用了一些被动的基准点。当然,这些基准点的位置都是已知的。然而,这样的做法的效果是十分有限的,这是因为这种方法受到基准点个数的限制。

    ● Octant. Wong等人提出了Octant,它也首先定位了到达被探测节点路径上的路由器的地理位置,然后以这些路由器作为基准点来进一步得到探测节点的地理位置。此外,Octant还考虑了一些正约束信息,如从被探测目标到基准点的最大距离,和一些负约束信息,如从被探测目标到基准点的最小距离。除了延迟的制约,Octant还在其系统中使用了一些其他的正约束和负约束限制。例如,从地理和人口统计数据中获得的负约束(海洋和无法居住的地区)。为了达到更高的精准度,Octant(与TBG方法一样)也首先定位了到达被探测节点路径上的路由器的地理位置,然后用这些路由器作为基准点来进一步得到探测节点的地理位置。

          IP地址定位这个领域,已经有了数十年的研究工作。尽管近年来取得了显著改善,但在商业领域中的IP地址定位产品的定位精度及信息完整度仍无法满足市场需求。之前最好的研究结果是Octant系统。该系统的中值误差距离是35公里。虽然这已经是一个很好的结果,但是正如我们看到的,Octant系统仍不足以满足市场的要求。一个高度精确的、无需硬件支持的IP地址定位系统已经变得对互联网越来越重要。

    为了满足市场需求,埃文科技的创始人王永提出了无需硬件支持的、街道级别的IP地理位置定位系统——《Towards Street-Level Client Independent IP Geolocation》(2011年在国际顶级互联网会议NSDI上发表,王永是第一位以第一作者身份在NSDI上发表论文的中国大陆学者)。该系统首次提出利用数据挖掘和网络测量相结合的方式,对IP地址进行定位;同时提出了一个三层的IP地址定位系统,并通过实验说明该系统的定位精准度,比定位效果最好的“Octant”提高了50倍。

     

    二、高精准IP地址定位互联网的影响

     

          虽然精确到城市级别或者区县级别的IP地址定位产品能够在某些领域满足用户需求。但一个更高精确度、更加可靠的IP地址定位产品已被确定为是互联网产业发展的重要需求。

    例如,互联网在线广告行业已经广泛地使用IP地址定位服务,高精准IP地址定位服务能更大程度的提升有效性。根据研究分析,基于位置的营销比无位置的营销转化率能够提升30~300%,并提升30%~50%的溢价。同样,高精准IP地址定位在网络安全、在线广告投放、在线安全支付、大数据分析、反欺诈风控、大数据征信等领域能提升产品性能和增加收益,为互联网行业发展做出贡献。它不仅能改善现有的应用程序的性能,同时将为基于位置服务提供新的支撑,也使以固定网络接入互联网的用户享受更精准的位置服务成为可能。

     

    埃文科技–全球高精准IP地址定位技术领航者

    作为专业从事位置服务的大数据技术科研互联网公司,自2012年成立至今,埃文科技持续推进IP地址定位领域的技术水准。公司专注于网络设备与地理空间位置映射系统的产品研发,拥有12项软件著作权及8项发明专利。

    “全球IP地址定位的领航者,为用户提供更加精准的IP地址定位服务”

    了解,使用IP问问

    展开全文
  • jQuery百度地图API美团外卖配送地址定位代码,省市区得根据自身需求去增加
  • 而传统的IP地址定位产品仅能提供城市或区县级别的定位数据,无法支撑基于位置的服务开展。IP问问可以提供高精准(街道级别)的IP地址定位数据,支持各种基于位置的服务开展。  一、为什么准确度与一致性相加超过...
    研究结果表明,在基于位置的精准营销领域中,通过GPS能够提供的互联网用户位置信息仅占在线广告投放所有位置信息的20%左右,普适性不高。而传统的IP地址定位产品仅能提供城市或区县级别的定位数据,无法支撑基于位置的服务开展。IP问问可以提供高精准(街道级别)的IP地址定位数据,支持各种基于位置的服务开展。
           一、为什么准确度与一致性相加超过8星的数据是优质数据
          为了方便大家使用优质IP地址定位数据,减少使用成本。在《如何验证IP地址定位的准确率?》这篇文章中,埃文科技提出了高质量IP定位数据的判断标准:“使用IP问问时获取的定位数据准确度及一致性两项指标相加大于等于8星即为优质IP地址定位数据,可以直接应用”。
          大家可能会有疑惑,准确度和一致性有什么作用,为什么两项指标相加大于等于8星就是优质IP定位数据?埃文科技将通过数据分析为大家解惑。
          1.什么是准确度和一致性
          IP问问提供的准确度这项指标,是综合了应用场景、定位方式、定位精度、覆盖半径等多种数据判断的。指的是某个IP地址定位结果的准确程度。一共有5个星级的判断标准。
          IP问问提供的一致性这项指标,是综合了定位结果的变化频率及定位结果的抖动性等多种数据判断的。指的是某个IP地址的定位结果的稳定程度和一致性。一共有5个星级的判断标准。
          2.为什么8星以上数据是精准的
          在实际使用过程中,不论是埃文科技进行的内部测试,亦或是客户进行的测试工作。我们均发现优质的IP地址定位数据有一个共性特点,那就是准确度、一致性2项指标相加星级在8~10星。
          以内部测试为例,埃文科技员工手工采集了带有位置信息的IP测试集。在75%的情况下与真实位置的误差距离在6公里左右。在这种情况下IP定位的准确度和一致性两项指标相加为8~10星,IP地址定位数据质量高,可以直接应用在在线广告投放、互联网金融反欺诈、防“羊毛党”等业务中。且根据各个不同阶段的误差距离分析,误差距离越小,2项指标相加得到的星级越高。而随着误差距离的增加,8星以下的数据占比会逐渐增加。高精准的ip地址定位数据在误差距离较小时,保持在8星以上的概率非常高。
     
          二、数据示例与批量分析
          我们为大家展示的是不同星级下IP地址的定位具体情况。
          如图1所示,120.XX.XX.38(为了保护隐私,我们隐去了中间2位数字,全文将统一采取此方法处理。)这个IP地址在福建省厦门市斗西路亚珠大酒店(经度:118.08151,纬度:24.465536。本文坐标系统一采用OSM坐标系),该酒店使用的IP地址类型是企业专线,覆盖半径为135米,与实际位置误差距离在100米范围内。准确度和一致性两项指标相加为10星,是优质的IP地址定位数据。
     
    图片1.jpg
    图1:120.XX.XX.38的准确度和一致性2项指标相加为10星
     
          如图2所示,116.XX.XX.53这个IP地址在深圳市福田区沙嘴村二坊(经度:114.01927,纬度:22.527643。),该互联网使用者的IP类型为住宅用户,覆盖半径为2.6523公里,与实际位置误差距离在2.3178公里范围内。准确度和一致性两项指标相加为9星,是优质的IP地址定位数据。
     
    图片2.jpg 
    图2:116.XX.XX.53的准确度和一致性2项指标相加为9星 
     
          如图3所示,124.XX.XX.214这个IP地址在北京市东城区东直门内大街来福士(经度:116.426059524,纬度:39.9387663751。),该互联网使用者的IP类型为企业专线多区域,覆盖半径分别为541.95米和498.8米,与实际位置误差距离在600米范围内。准确度和一致性两项指标相加为8星,是优质的IP地址定位数据。
     
    图片3.jpg 
    图3:124.XX.XX.214的准确度和一致性2项指标相加为8星
     
          如图4所示,223.XX.XX.253这个IP地址在重庆市北碚区双元大道永辉超市,该互联网使用者的IP类型为移动网络(3G/4G),由于该类型IP在全省分布,故定位精度为省级别,是准确的数据。准确度和一致性两项指标相加为4星,不是街道级IP地址定位数据。
        小贴士:移动终端连接WIFI后,可以通过IP地址定位得到街道级数据。
     
    图片4.jpg
    图4:223.XX.XX.253的准确度和一致性2项指标相加为4
     
          在实际业务开展过程中,由于各个行业对于IP地址定位数据的需求不同,所以在使用过程中,不同行业的用户可以根据自己的需求,选择多种标准作为使用依据。
          以在线广告投放业务为例,在实际投放过程中,DSP公司可以选择不同的覆盖半径或误差距离作为投放的判断依据。按埃文科技内测数据显示,如图5所示。如果以5公里的误差距离作为基于位置的在线广告投放依据,8星以上的数据占总数据量的71.23%,以10星IP地址定位数据为例,10星数据在5公里的误差距离下占全部10星数据的79.01%。(以上数据为内测数据,仅为方法介绍,实际数据占比需要根据大家真实测试反映)
     
    图片5.jpg
    图5:实际位置误差距离对比的准确度和一致性累积分布情况
     
          所以DSP公司在为本地商超、快消品、房地产、4S店等行业的广告主投放时,可以将准确度和一致性2项指标相加大于等于8星的IP定位数据直接用于基于位置的在线广告投放业务。根据以上分析,DSP公司在选择优质IP地址定位数据后,可以通过与需要进行投放的位置(经纬度与覆盖半径)进行匹配,结合用户画像标签数据,选择在该范围内或与该范围相交的IP地址进行广告投放,完成基于位置的精准营销。
          综上,不论是互联网在线广告投放、互联网广告反作弊、互联网交易反欺诈、互联网金融信贷风控或是互联网征信位置核验等业务,均可以根据公司的实际需求选择准确度、一致性2项指标相加在8~10星的IP地址定位数据开展业务。大家在完成测试后,可以用同样的方法进行分析。亦可联系埃文科技,埃文科技能够提供专业的测试分析,为您选择优质数据。
     
    埃文科技–全球高精准IP地址定位技术领航者
    作为专业从事位置服务的大数据技术科研互联网公司,自2012年成立至今,埃文科技持续推进IP地址定位领域的技术水准。公司专注于网络设备与地理空间位置映射系统的产品研发,拥有12项软件著作权及8项发明专利。
    “全球IP地址定位的领航者,为用户提供更加精准的IP地址定位服务”
    展开全文
  • iOS:定位地址和经纬度互转

    千次阅读 2019-04-11 15:16:28
    1.增加定位权限: 打开Info.plist,在<dict>节点增加NSLocationUsageDescription值: <dict> ... <key>NSLocationUsageDescription</key> <string>请求获取位置信息</str...

    一、使用CLLocationManager进行定位:

    1.增加定位权限:

    打开Info.plist,在<dict>节点增加NSLocationUsageDescription值:

    <dict>
    	...
    	<key>NSLocationUsageDescription</key>
    	<string>请求获取位置信息</string>
    </dict>

    2.导入定位相关依赖包,实现CLLocationManagerDelegate,并初始化定位管理器:

    //导入定位相关依赖包
    #import <CoreLocation/CoreLocation.h>
    
    //实现定位代理(接口)
    @interface ViewController () <CLLocationManagerDelegate>
    //定位管理器
    @property (nonatomic, strong) CLLocationManager *localM;
    
    @end
    
    @implementation ViewController
    
    /*
     懒加载初始化定位管理器
     */
    - (CLLocationManager *)clm{
        //如果定位不可用,直接返回
        if(![CLLocationManager locationServicesEnabled]){
            return nil;
        }
        if(_localM == nil){
            //创建定位管理器
            _localM = [[CLLocationManager alloc] init];
            //设置当前类实现定位代理方法
            _localM.delegate = self;
        }
        return _localM;
    }

    3.重写locationManager-didUpdateLocations方法,接收当前实时更新的位置信息:

    /*
     CLLocationManagerDelegate方法:更新定位信息
     */
    - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations{
        //取出位置信息
        CLLocation *location = [locations firstObject];
        
        //获取当前位置经纬度
        CLLocationCoordinate2D coordinate = location.coordinate;
        NSLog(@"latitude: %f, longitude: %f", coordinate.latitude, coordinate.longitude);
        
        //获取当前位置海拔
        CLLocationDistance altitude = location.altitude;
        NSLog(@"海拔: %f", altitude);
        
        //获取当前航向,取值0.0度-359.9度,0.0为真北方向
        CLLocationDirection course = location.course;
        NSLog(@"航向: %f", course);
        
        //获取当前行走速度
        CLLocationSpeed speed = location.speed;
        NSLog(@"航向: %f", speed);
    }

    4.开启实时定位:

    - (void)viewDidLoad {
        [super viewDidLoad];
        
        //开始定位
        [self.localM startUpdatingLocation];
        //停止定位更新
    //    [manager stopUpdatingLocation];
    }

    二、使用CLGeocoder实现地址和经纬度互转:

    1.将地址字符串转为经纬度:

    /*
     自定义方法:将地址转为经纬度
     */
    - (void)adressToCoordinate{
        NSString *adress = @"杭州";
        //编码地址
        [self.geocoder geocodeAddressString:adress completionHandler:^(NSArray<CLPlacemark *> *placemarks, NSError *error) {
            //地址错误
            if(error){
                return;
            }
            //取出首个地址
            CLPlacemark *firstLp = [placemarks firstObject];
            
            /*
             取出地址列表
             */
            for (CLPlacemark *lp in placemarks) {
                //取出位置信息
                CLLocation *location = lp.location;
                //获取位置经纬度
                CLLocationCoordinate2D coordinate = location.coordinate;
                NSLog(@"latitude: %f, longitude: %f, name: %@", coordinate.latitude, coordinate.longitude, lp.name);
                //循环NSDictionary中的地址信息
                [lp.addressDictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
                    NSLog(@"key: %@, value: %@", key, obj);
                }];
            }
        }];
    }

    2.将经纬度转为地址字符串:

    /*
     自定义方法:将经纬度转为地址
     */
    - (void)coordinateToAdress{
        //根据经纬度值创建地址对象
        CLLocation *location = [[CLLocation alloc] initWithLatitude:30.28 longitude:120.15];
        //反编码经纬度为地址
        [self.geocoder reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> *placemarks, NSError *error) {
            //经纬度错误
            if(error){
                return;
            }
            //取出首个地址
            CLPlacemark *firstLp = [placemarks firstObject];
            
            /*
             取出地址列表
             */
            for (CLPlacemark *lp in placemarks) {
                //取出位置信息
                CLLocation *location = lp.location;
                //获取位置经纬度
                CLLocationCoordinate2D coordinate = location.coordinate;
                NSLog(@"latitude: %f, longitude: %f, name: %@", coordinate.latitude, coordinate.longitude, lp.name);
                //循环NSDictionary中的地址信息
                [lp.addressDictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
                    NSLog(@"key: %@, value: %@", key, obj);
                }];
            }
        }];
    }

    三、计算2个位置之间的直线距离:

    /*
     自定义方法:计算2个位置之间的直线距离
     */
    - (void)getDistance{
        //第1个位置经纬度值
        CLLocation *cl1 = [[CLLocation alloc] initWithLatitude:100 longitude:100];
        //第2个位置经纬度值
        CLLocation *cl2 = [[CLLocation alloc] initWithLatitude:200 longitude:200];
        //计算2个位置之间的直线距离
        CLLocationDistance distance = [cl1 distanceFromLocation:cl2];
        NSLog(@"distance : %f", distance);
    }

    四、监控某个地址区域:

    /*
     自定义方法:开始监控某个地址区域
     */
    - (void)monitorLocation{
        CLRegion *region = [[CLRegion alloc] init];
        //开始监控某个区域
        [self.localM startMonitoringForRegion:region];
    }
    /*
     CLLocationManagerDelegate方法:进入区域
     */
    - (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region{
        
    }
    /*
     CLLocationManagerDelegate方法:离开区域
     */
    - (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region{
        
    }

     

    展开全文
  • 关于地址定位

    千次阅读 2013-12-22 17:06:39
     它的主要优点是,无需增加硬件地址变换机构,因而可在一般计算机上实现。 (3)缺点  主要缺点有:  ①要求给每个作业分配一个连续的存储空间,且在作业的整个执行期间不能再移动,因而也就不能实现重新...
  • 一、手机App定位在我看来有三种方法:1.通过Android自带的API:...通过外部接口获取到外网IP,再通过百度API或者聚合数据的API得出地址1、Android自带API,它有三种定位方式可以通过GPS,网络和WIFI定位。1.1步骤:...
  • 通常意义上来说,app 可以读取 mac 地址,但仅限于用户已经阅读了隐私内容,并且隐私内容中也告知了用户,app 会运行期间采集 wlan mac 地址等信息。所以如果没等用户同意隐私政策中的内容,就开始提前读取 mac 地址...
  • 手机定位是指通过特定的定位技术来获取移动手机或终端用户的位置信息(经纬度坐标),在电子地图上标出被定位对象的位置的技术或服务。定位技术有两种,一种是基于GPS的定位,一种是基于移动运营网的基站的定位。...
  • GIS定位

    千次阅读 2019-02-24 01:50:40
    撰写时间:2019年1月16日星期三...地址进行输入查询内容,并在地图上进行定位出来,如果输入的地址在地图找不到将不会显示,建议输入详细的地址: 下面是完成功能的代码: 首先我们要获取点击事件的ID给Click单击事...
  • MAC地址定位技术的大数据警用应用

    千次阅读 2017-04-27 14:35:43
    在传统方式上的电脑定位大致是通过技术手段获取到电脑所在网络出口IP地址,然后通过运营商查询相关IP的登记属性。这种方式步骤繁琐,流程冗长。本文是用于探讨新信息时代的大数据管理方式模型,以提高PC、笔记本等...
  • 简介:基于bootstrap地址选择的功能,加入了简单的封装。 代码地址:https://github.com/shulongfei/demo-manage.git 在线访问:https://shulongfei.github.io/demo-manage/#bootstrap/addrSelect 效果图: ...
  • 在甲方工作的朋友可能会遇到这样的问题,服务器或者系统经常被扫描,...偶然间发现百度地图有高精度IP定位API的接口,通过该接口我们可以通过IP地址定位到具体的地理位置,甚至能精确到门牌号及周围的标志性建筑。
  • Keil C51中变量和函数的绝对地址定位问题: 1. 变量绝对地址定位  1) 在定义变量时使用 _at_ 关键字加上地址就可.  e.g.  unsigned char idata myvar _at_ 0x40;  把变量 myvar 定义在 idata 的 0x40 处
  • 静态重定位和动态重定位

    万次阅读 多人点赞 2018-06-04 18:50:31
    优点:是无需增加硬件地址转换机构,便于实现程序的静态连接。在早期计算机系统中大多采用这种方案。 缺点:内存空间不能移动;各个用户进程很难共享内存中同一程序的副本动态重定位:动态运行的...
  • // 可选,设置是否需要地址信息,默认不需要 option.setOpenGps(true);// 可选,默认false,设置是否使用gps option.setLocationNotify(true);// 可选,默认false,设置是否当gps有效时按照1S1次频率输出GPS...
  • Keil C51中变量和函数的绝对地址定位问题: 1. 变量绝对地址定位  1) 在定义变量时使用 _at_ 关键字加上地址就可.  e.g.  unsigned char idata myvar _at_ 0x40;  把变量 myvar 定义在 idata 的 0x4
  • 这个是我写水印的 http://www.eoeandroid.com/thread-206223-1-1.html 这个是我强制打开GPS http://www.eoeandroid.com/thread-206003-1-1.html 这是今天下班的时候 发的 ... 源码下载地址 :点击打
  • 高德地图API定位失败 浏览器定位 IP定位
  • 本章将涉及更多内存地址定位和编程的方法。 7.1 and 和 or 指令 (1) and指令,逻辑按位与指令 例如: mov al,01100011B and al,00111011B 执行后 al=00100011B  and指令可以用来将某个数的位置为零。 比如我们要
  • *</span> 站点地址: *</span> 经度: *</span> 纬度: ...
  • 前些天做个毕设,使用高德地图API的浏览器和IP定位贼不稳定,之前搜集文献的时候就发现,一直头疼没解决,看百度地图或者高德地图在浏览器上访问也是不稳定,大概原因收集了一下。下图为系统定位图,当在公司网络下...
  • Android的定位策略

    千次阅读 2016-06-17 18:15:48
    为android开发地理位置相关的应用程序,你可以利用GPS或者android的网络定位数据源来获取用户的地理位置。尽管GPS的定位更加精准,但它只适用于户外,并且还会更快的消耗电量,它也不能按用户所期待的及时返回地理...
  • 静态重定位与动态重定位

    千次阅读 2015-07-02 16:49:26
    这种把逻辑地址转变为内存的物理地址的过程叫重定位。 对程序进行重定位的技术按重定位的时机可分为两种:静态重定位和动态重定位。 1.静态重定位 静态重定位是在目标程序装入内存时,由装入程序对目标程序中的...
  • Android定位功能实现

    千次阅读 多人点赞 2020-05-28 18:20:10
    关于Android定位功能如何实现的文章实在...文章目录获取定位权限在AndroidManifest.xml中增加权限配置检查是否有定位权限申请权限判断请求权限结果弹框提醒用户去设置打开(可选)打开权限设置页面检查定位服务开关检查
  • iOS 定位服务

    千次阅读 2013-08-31 10:40:46
    )[-]iOS中有三个定位服务组件iOS地图Web地图iOS中有三个定位服务组件: Wifi定位,通过查询一个Wifi路由器的地理位置的信息。比较省电,iPod touch和iPad也可以采用。 蜂窝基站定位,通过移动运用商基站定位。也...
  • android高德定位使用

    千次阅读 2017-04-11 16:57:01
    一、概念解释 什么是地理围栏? 地理围栏相当于在地图上根据一个规则...1、增加地理围栏; 2、初始化围栏广播接收; 3、初始化定位; 4、获取定位信息; 5、销毁定位和移除地理围栏。 三、代码 public clas
  • 对程序进行重定位的技术按重定位的时机可分为两种:静态重定位和动态重定位。... 优点:是无需增加硬件地址转换机构,便于实现程序的静态连接。在早期计算机系统中大多采用这种方案。 缺点:(1)程序的存储空间只...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 196,963
精华内容 78,785
关键字:

怎么增加定位地址