链接:https://pan.baidu.com/s/1nRgTENCBDTz1Y4RLJ1tMNw
提取码:vrnh
郑重声明:
虚拟定位仅提供开发人员测试使用
禁止用于任何违法行为与商业行为
滥用软件导致的一切影响本人概不负责
1.地图上点哪飞哪
2.地图搜索后点击悬浮的按钮飞
3.唤出悬浮皮卡丘(以下简称皮卡丘)按钮,双击后可移动位置
4.长按皮卡丘可保存当前定位,用于自动循环飞行,或在记录定位中手动飞行。
5.点击历史定位或保存定位点可定点飞。
6.考虑到手机分辨率,皮卡丘的大小以及移动范围、移速等均可在设置中设置。
软件只是个人兴趣作安卓开发学习,如有侵权,联系删除。
使用方式请往下翻。
虚拟定位下的摇杆行走功能实现
主要用于安卓虚拟定位摇杆行走
1.打开安卓开发者模式(打开系统,关于手机,版本号连按7下打开) 勾选模拟位置信息应用选项。
2.需要授权
3.启动管理设置软件自启动,不然来回切屏会导致定位飘移
4.如果有需要自由移动的,选择小粉球显示方向盘。
皮卡丘双击按钮拖动
P:移动方位以朝北为准,所以游戏中也需要将指南针面向朝北,当然这里做了以当前方向为参考的移动方式,实测不好用,所以还是建议用方向盘。
5.如果出现地图网格加载失败的开关流量及wifi。
1.建立安卓界面,整合百度地图,实现百度地图的搜索及地图点击功能。
2.获取搜索到的POI或点击的坐标实现虚拟定位。
3.借助全局性悬浮窗并监听其移动的角度对虚拟坐标进行修改达到全局性的任意方向移动。
4.调用接口获取服务器数据限制权限,避免软件的滥用。
5.借助服务器实现新版本的更新。
参考博客:
https://blog.csdn.net/Hilavergil/article/details/81907548 虚拟定位
https://blog.csdn.net/Imshuyuan/article/details/62886741 安卓更新
百度地图详见百度APK使用
开始参考了网上许多的资料均失败,后参考自
https://blog.csdn.net/Hilavergil/article/details/81907548
原理就是一个虚假的提供者一直发送虚假的信息,开放开发者模式的模拟位置应用即可。
有以下的问题:
尝试多次后回来仔细看博客,发现上述博客的最后提到了,百度地图的经纬度标准和国际的GPS标准是不一致的,但是提供了方法但没写明怎么使用。
这里我的用法是,点击百度地图的点获取到一个百度的经纬度,再使用他提供的方法将这个经纬度转成国际标准进行虚拟定位。
//上文博客作者提供的解密方法
double[] doubles = CoordinateUtil.bd2wgs(virtualLon, virtualLat);
latLng = new LatLng(doubles[1], doubles[0]);
locationManager.setTestProviderLocation(providerStr, generateLocation(latLng));
转换后的定位经纬度和实际坐标基本一致。
这条是上文作者的开源APP中存在的问题,按他的代码嵌入自己的代码后虽然能实现虚拟定位但是会在真实地址和虚拟地址间不断的来回,这种不稳定也让我一度怀疑是不是这样的虚拟定位方式本来就不可取。
仔细观察代码发现百度地图是会自己获取定位的,地址监听器中即便不发送虚拟信号也会一直获取当前地址,所以我第一步先禁用了他的自动获取。
百度地图有一条配置:
option.setScanSpan(0);//可选,默认0,即仅定位一次,设置发起定位请求的间隔需要大于等于1000ms才是有效的
也就是定位间隔最短1000,为0时只定位一次,然后需要主动发起请求地址监听器才会工作。
然后在多次尝试后,发现模拟定位的方法如下图代码的时候,定位基本没有来回飘移过。
locationManager.setTestProviderStatus(LocationManager.GPS_PROVIDER, 100, null, System.currentTimeMillis());
locationManager.setTestProviderLocation(providerName, generateLocation(latLng));
mLocationClient.requestLocation();
这个是百度地图开发者的AK配置错误,然后就是AndroidManifest.xml中权限没开,以及手机自身的权限没赋予。网上的获取SHA1及百度开发者AK的配置资料很多。
我也比较懒,SHA1的获取有点麻烦又容易出错,所以我不知道从哪里下了一个安全码校验的工具,应用安装后,直接获取然后拿这个SHA1配置到百度开发者中,也能保证不出错。
一开始做了一个悬浮球,就是上图的粉色小圆圈,原理是第三方的FloatingActionButton,结果只能在本应用生效,于是保留作为功能菜单使用。
多次尝试后(不得不吐槽网上的十个博客八个复制九个没用)得到了正解。
主要是使用WindowManager来悬浮自定义的ImageView,需要开启悬浮的权限。
wm = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = getResources().getDisplayMetrics();
int widthPixels = dm.widthPixels;
int heightPixels = dm.heightPixels;
wmParams = ((MyApplication) getApplication()).getMywmParams();
//只有这样才能弹框
if (Build.VERSION.SDK_INT >= 26) {//8.0新特性
wmParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
wmParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
}
wmParams.format = PixelFormat.RGBA_8888;//设置背景图片
wmParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;//
wmParams.gravity = Gravity.LEFT | Gravity.TOP;//
/* wmParams.x = widthPixels - 550; //设置位置像素
wmParams.y = heightPixels - 510;*/
// 圆心位置就在800,2000
wmParams.x = 700;
wmParams.y = 1900;
wmParams.width = 200; //设置图片大小
wmParams.height = 200;
customeMovebutton = new CustomeMovebutton(getApplicationContext());
customeMovebutton.setImageResource(R.drawable.circle);
wm.addView(customeMovebutton, wmParams);
customeMovebutton.setOnSpeakListener(new CustomeMovebutton.OnSpeakListener() {
@Override
public void onSpeakListener(double sin, double cos) {
speedLat = -speed * sin;
speedLon = speed * cos;
}
});
悬浮的customeMovebutton就是一个普通的ImageView,其中重写了onTouchEvent来获取对悬浮球的操作
通过自定义了一个回调函数来获得悬浮球的移动,再回调了一个移动角度回来,在模拟定位的线程对模拟坐标修改,就达到了悬浮球修改坐标。
/**
* 设置点击回调接口
*/
public interface OnSpeakListener {
void onSpeakListener(double sin, double cos);
}
public void setOnSpeakListener(OnSpeakListener listener) {
this.listener = listener;
}
悬浮球回调sin与cos给Activity
if (getDistance(x, mStartX, y, mStartY) < moveRange) {
updateViewPosition();
} else {
//斜率
float k = (y - mStartY) / (x - mStartX);
double rx;
double ry;
rx = Math.sqrt(moveRange * moveRange / (k * k + 1));
if ((x - mStartX) < 0) {
rx = -rx;
}
ry = k * rx;
wmParams.x = (int) (rx + 700);
wmParams.y = (int) (ry + 1900);
//回调sin,cos
listener.onSpeakListener(ry / radius, rx / radius);
wm.updateViewLayout(this, wmParams); //刷新显示
}
Activity接收参数
customeMovebutton.setOnSpeakListener(new CustomeMovebutton.OnSpeakListener() {
@Override
public void onSpeakListener(double sin, double cos) {
speedLat = -speed * sin;
speedLon = speed * cos;
}
});
参考自
https://blog.csdn.net/Imshuyuan/article/details/62886741
下载的URL就是我们在服务器中的常规文件下载方法,就是一些InputStrem与OutputStream的应用。
下载的文件可以直接镶入自己的程序用,但是有动态权限的问题,在版本大于24的情况下要使用fileProvide来授予文件的临时访问权限,URI.fromFile()这一段要根据网上的资料修改一下才能适配新版本。然后需要授予应用内安装其他应用的权限。
最后碰到的问题是打开后提示解析包出现问题,多次尝试后,发现打开的APP的签名和更新的软件签名一致的情况下可以安装,其余不一致情况均失败。