虚拟定位钉钉打卡签到和迟到说拜拜

苦于钉钉打卡,在土司群内和各位大佬求助,很快的到了大佬们的回复,思路都很棒。下面整理下两位大佬的两个方法。

方法一、需用电脑(By:清水川崎)
以下为转载

原文链接: https://qiita.com/shimizukawasaki/items/429c6175e8797ef1ab51

本文将带你脱离苦海.(安卓用户请自行离开,去买一部几百块的二手iPhone拿来专门打卡吧)

Win用户

Win用户步骤简单粗暴,直接安装爱思助手,连接iPhone到手机等待爱思助手连接到iPhone

点击工具箱,找到虚拟定位

输入坐标系或点击你要的定位,点击蓝色的修改虚拟定位即可

使用百度地图做下检测

Mac用户

对于Mac用户来说,可以使用Apple官方开发工具Xcode进行实现。

1.进入Mac App Store安装Xcode

2.安装好以后打开它,并登陆

  • 3.访问Apple开发者注册为开发者

https://developer.apple.com/

登陆以后进行注册开发者步骤,一直到最后一步要求付款688人民币界面关闭即可,无需付款

  • 4.新建Xcode工程
  • 5.随后你新建一个飘逸算法的文件

取名叫

LocationTransform

文件内容如下:


//
//  LocationTransform.swift
//  SimulateLocation
//
//  Created by 清水川崎 on 2017/3/14.
//  Copyright © 2017年 清水川崎. All rights reserved.
//

import Foundation

/**
 *  Struct transform coordinate between earth(WGS-84) and mars in china(GCJ-02).
 */
public struct LocationTransform {

    static let EARTH_R: Double = 6378137.0

    static func isOutOfChina(lat: Double, lng: Double) -> Bool {

        if lng < 72.004 || lng > 137.8347 {
            return true
        }
        if lat < 0.8293 || lat > 55.8271 {
            return true
        }
        return false
    }

    static func transform(x: Double, y: Double) -> (lat: Double, lng: Double) {

        let xy = x * y
        let absX = sqrt(fabs(x))
        let xPi = x * Double.pi
        let yPi = y * Double.pi
        let d = 20.0 * sin(6.0 * xPi) + 20.0 * sin(2.0 * xPi)

        var lat = d
        var lng = d

        lat += 20.0 * sin(yPi) + 40.0 * sin(yPi / 3.0)
        lng += 20.0 * sin(xPi) + 40.0 * sin(xPi / 3.0)

        lat += 160.0 * sin(yPi / 12.0) + 320 * sin(yPi / 30.0)
        lng += 150.0 * sin(xPi / 12.0) + 300 * sin(xPi / 30.0)

        lat *= 2.0 / 3.0
        lng *= 2.0 / 3.0

        lat += -100 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * xy + 0.2 * absX
        lng += 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * xy + 0.1 * absX

        return (lat, lng)
    }

    static func delta(lat: Double, lng: Double) -> (dLat: Double,  dLng: Double) {
        let ee = 0.00669342162296594323
        let radLat = lat / 180.0 * Double.pi
        var magic = sin(radLat)
        magic = 1 - ee * magic * magic
        let sqrtMagic = sqrt(magic)
        var (dLat, dLng) = transform(x: lng - 105.0, y: lat - 35.0)
        dLat = (dLat * 180.0) / ((EARTH_R * (1 - ee)) / (magic * sqrtMagic) * Double.pi)
        dLng = (dLng * 180.0) / (EARTH_R / sqrtMagic * cos(radLat) * Double.pi)
        return (dLat, dLng)
    }

    /**
     *  wgs2gcj convert WGS-84 coordinate(wgsLat, wgsLng) to GCJ-02 coordinate(gcjLat, gcjLng).
     */
    public static func wgs2gcj(wgsLat: Double, wgsLng: Double) -> (gcjLat: Double, gcjLng: Double) {
        if isOutOfChina(lat: wgsLat, lng: wgsLng) {
            return (wgsLat, wgsLng)
        }
        let (dLat, dLng) = delta(lat: wgsLat, lng: wgsLng)
        return (wgsLat + dLat, wgsLng + dLng)
    }

    /**
     *  gcj2wgs convert GCJ-02 coordinate(gcjLat, gcjLng) to WGS-84 coordinate(wgsLat, wgsLng).
     *  The output WGS-84 coordinate's accuracy is 1m to 2m. If you want more exactly result, use gcj2wgs_exact.
     */
    public static func gcj2wgs(gcjLat: Double, gcjLng: Double) -> (wgsLat: Double, wgsLng: Double) {
        if isOutOfChina(lat: gcjLat, lng: gcjLng) {
            return (gcjLat, gcjLng)
        }
        let (dLat, dLng) = delta(lat: gcjLat, lng: gcjLng)
        return (gcjLat - dLat, gcjLng - dLng)
    }

    /**
     *  gcj2wgs_exact convert GCJ-02 coordinate(gcjLat, gcjLng) to WGS-84 coordinate(wgsLat, wgsLng).
     *  The output WGS-84 coordinate's accuracy is less than 0.5m, but much slower than gcj2wgs.
     */
    public static func gcj2wgs_exact(gcjLat: Double, gcjLng: Double) -> (wgsLat: Double, wgsLng: Double) {
        let initDelta = 0.01, threshold = 0.000001
        var (dLat, dLng) = (initDelta, initDelta)
        var (mLat, mLng) = (gcjLat - dLat, gcjLng - dLng)
        var (pLat, pLng) = (gcjLat + dLat, gcjLng + dLng)
        var (wgsLat, wgsLng) = (gcjLat, gcjLng)
        for _ in 0 ..< 30 {
            (wgsLat, wgsLng) = ((mLat + pLat) / 2, (mLng + pLng) / 2)
            let (tmpLat, tmpLng) = wgs2gcj(wgsLat: wgsLat, wgsLng: wgsLng)
            (dLat, dLng) = (tmpLat - gcjLat, tmpLng - gcjLng)
            if (fabs(dLat) < threshold) && (fabs(dLng) < threshold) {
                return (wgsLat, wgsLng)
            }
            if dLat > 0 {
                pLat = wgsLat
            } else {
                mLat = wgsLat
            }
            if dLng > 0 {
                pLng = wgsLng
            } else {
                mLng = wgsLng
            }
        }
        return (wgsLat, wgsLng)
    }

    /**
     *  Distance calculate the distance between point(latA, lngA) and point(latB, lngB), unit in meter.
     */
    public static func Distance(latA: Double, lngA: Double, latB: Double, lngB: Double) -> Double {
        let arcLatA = latA * Double.pi / 180
        let arcLatB = latB * Double.pi / 180
        let x = cos(arcLatA) * cos(arcLatB) * cos((lngA-lngB) * Double.pi/180)
        let y = sin(arcLatA) * sin(arcLatB)
        var s = x + y
        if s > 1 {
            s = 1
        }
        if s < -1 {
            s = -1
        }
        let alpha = acos(s)
        let distance = alpha * EARTH_R
        return distance
    }
}

extension LocationTransform {

    public static func gcj2bd(gcjLat: Double, gcjLng: Double) -> (bdLat: Double, bdLng: Double) {
        if isOutOfChina(lat: gcjLat, lng: gcjLng) {
            return (gcjLat, gcjLng)
        }
        let x = gcjLng, y = gcjLat
        let z = sqrt(x * x + y * y) + 0.00002 * sin(y * Double.pi)
        let theta = atan2(y, x) + 0.000003 * cos(x * Double.pi)
        let bdLng = z * cos(theta) + 0.0065
        let bdLat = z * sin(theta) + 0.006
        return (bdLat, bdLng)
    }

    public static func bd2gcj(bdLat: Double, bdLng: Double) -> (gcjLat: Double, gcjLng: Double) {
        if isOutOfChina(lat: bdLat, lng: bdLng) {
            return (bdLat, bdLng)
        }
        let x = bdLng - 0.0065, y = bdLat - 0.006
        let z = sqrt(x * x + y * y) - 0.00002 * sin(y * Double.pi)
        let theta = atan2(y, x) - 0.000003 * cos(x * Double.pi)
        let gcjLng = z * cos(theta)
        let gcjLat = z * sin(theta)
        return (gcjLat, gcjLng)
    }

    public static func wgs2bd(wgsLat: Double, wgsLng: Double) -> (bdLat: Double, bdLng: Double) {
        let (gcjLat, gcjLng) = wgs2gcj(wgsLat: wgsLat, wgsLng: wgsLng)
        return gcj2bd(gcjLat: gcjLat, gcjLng: gcjLng)
    }

    public static func bd2wgs(bdLat: Double, bdLng: Double) -> (wgsLat: Double, wgsLng: Double) {
        let (gcjLat, gcjLng) = bd2gcj(bdLat: bdLat, bdLng: bdLng)
        return gcj2wgs(gcjLat: gcjLat, gcjLng: gcjLng)
    }
}

修改

AppDelegate.swift
内容为如下:


//
//  AppDelegate.swift
//  lat
//
//  Created by xue on 11/4/2019.
//  Copyright © 2019 清水川崎. All rights reserved.
//

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        let location = LocationTransform.gcj2wgs(gcjLat:LAT, gcjLng:LON)
        print(location)
        return true
    }

    func applicationWillResignActive(_ application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    }

    func applicationWillTerminate(_ application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    }


}

在新建一个GPX文件,随便取名(不能有中文)

修改GPX文件为如下内容


<?xml version="1.0" encoding="UTF-8" ?>
<gpx version="1.1"
    creator="GMapToGPX 6.4j - http://www.elsewhere.org/GMapToGPX/"
    xmlns="http://www.topografix.com/GPX/1/1"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">

<wpt lat="lat" lon="lon">

    </wpt>
</gpx>

随后连接iPhone和电脑(信任,允许都选是,联网等待大概15分钟安装开发者模式文件),修改运行加载文件设置

随后选择你的gpx文件

  • 6.获取想要修改定位地点的坐标系

访问高德控制台API(钉钉、高德都是阿里系的app)

https://lbs.amap.com/console/show/picker

输入你想要定位的地方,例如香港轩尼诗道

随后获得坐标系为

114.172914,22.275128

进入Xcode工程中AppDelegate,用22.275128替换LON,114.172914替换LAT

随后点击三角进行调试

PS:第一次调试可能耗时较长,且可能遇到无法信任app问题,解决以后再调试一次即可

无法信任app问题请参考:https://jingyan.baidu.com/article/0964eca2487f928285f536fe.html

随后控制台会返回真实坐标系(由于某些原因我国默认坐标系为加密坐标系)

拿着真实坐标系,到gpx文件中进行替换坐标

再次调试工程,即可更换坐标为香港轩尼诗道

使用WeChat\百度地图\Find My iPhone(iCloud)等日常app做一次测试

连Apple自己的App都骗过了,害怕绕不过钉钉?再牛逼的app也是基于iOS SDK下面的几个Kit,例如UIKit、MapKit等

以上两种方法,尤其是苹果的100%不会被钉钉后台检测到,也不需要越狱,WIN爱思助手方式朋友使用至今没有收到任何钉钉后台告警

如果你要还原真实坐标系,重启你的iPhone即可.那么可以尝试购买一部二手iPhone专门用于打卡,反正只需几百块而已.虚拟定位第一种方式我使用至今,几乎一周自动还原一次真实坐标系.使用超过两年,从未被后台警告过.完全可以bypass任何定位打卡设备.而WI-FI定位识别的朋友,可以使用openwrt固件的路由模拟公司路由Mac地址,修改WI-FI名称为公司的WI-FI名称即可破解,过程这里不再赘述.

方法二、不用电脑(By:googler)

ipa下载地址
链接: https://pan.baidu.com/s/1w1f-OwHyrf5H7HB-fcXmpQ 提取码: tay8

9
0