mirror of
https://github.com/GLEGram/GLEGram-iOS.git
synced 2026-04-24 20:06:39 +02:00
4647310322
Based on Swiftgram 12.5 (Telegram iOS 12.5). All GLEGram features ported and organized in GLEGram/ folder. Features: Ghost Mode, Saved Deleted Messages, Content Protection Bypass, Font Replacement, Fake Profile, Chat Export, Plugin System, and more. See CHANGELOG_12.5.md for full details.
322 lines
14 KiB
Swift
Executable File
322 lines
14 KiB
Swift
Executable File
import Foundation
|
|
import UIKit
|
|
import CoreLocation
|
|
#if canImport(SGSimpleSettings)
|
|
import SGSimpleSettings
|
|
#endif
|
|
|
|
public final class FakeLocationManager: NSObject {
|
|
public static let shared = FakeLocationManager()
|
|
|
|
private var locationManagers: NSHashTable<CLLocationManager> = NSHashTable.weakObjects()
|
|
private var periodicUpdateTimer: Foundation.Timer?
|
|
private let timerInterval: TimeInterval = 20.0
|
|
|
|
private override init() {
|
|
super.init()
|
|
setupAppLifecycleObservers()
|
|
}
|
|
|
|
private func setupAppLifecycleObservers() {
|
|
NotificationCenter.default.addObserver(
|
|
self,
|
|
selector: #selector(appDidBecomeActive),
|
|
name: UIApplication.didBecomeActiveNotification,
|
|
object: nil
|
|
)
|
|
|
|
NotificationCenter.default.addObserver(
|
|
self,
|
|
selector: #selector(appDidEnterBackground),
|
|
name: UIApplication.didEnterBackgroundNotification,
|
|
object: nil
|
|
)
|
|
}
|
|
|
|
@objc private func appDidBecomeActive() {
|
|
startPeriodicUpdates()
|
|
}
|
|
|
|
@objc private func appDidEnterBackground() {
|
|
stopPeriodicUpdates()
|
|
}
|
|
|
|
private func startPeriodicUpdates() {
|
|
if periodicUpdateTimer != nil {
|
|
return
|
|
}
|
|
|
|
#if canImport(SGSimpleSettings)
|
|
guard SGSimpleSettings.shared.fakeLocationEnabled else {
|
|
return
|
|
}
|
|
|
|
sendFakeLocationToAllManagers()
|
|
|
|
periodicUpdateTimer = Foundation.Timer.scheduledTimer(
|
|
withTimeInterval: timerInterval,
|
|
repeats: true
|
|
) { [weak self] _ in
|
|
self?.sendFakeLocationToAllManagers()
|
|
}
|
|
|
|
if let timer = periodicUpdateTimer {
|
|
RunLoop.current.add(timer, forMode: .common)
|
|
}
|
|
#endif
|
|
}
|
|
|
|
private func stopPeriodicUpdates() {
|
|
periodicUpdateTimer?.invalidate()
|
|
periodicUpdateTimer = nil
|
|
}
|
|
|
|
private func sendFakeLocationToAllManagers() {
|
|
#if canImport(SGSimpleSettings)
|
|
guard SGSimpleSettings.shared.fakeLocationEnabled else {
|
|
stopPeriodicUpdates()
|
|
return
|
|
}
|
|
|
|
let latitude = SGSimpleSettings.shared.fakeLatitude
|
|
let longitude = SGSimpleSettings.shared.fakeLongitude
|
|
|
|
guard latitude != 0.0 && longitude != 0.0 else {
|
|
return
|
|
}
|
|
|
|
for manager in locationManagers.allObjects {
|
|
sendFakeLocationToManager(manager)
|
|
}
|
|
#endif
|
|
}
|
|
|
|
func addLocationManager(_ manager: CLLocationManager) {
|
|
locationManagers.add(manager)
|
|
}
|
|
|
|
func sendFakeLocationToManager(_ manager: CLLocationManager) {
|
|
#if canImport(SGSimpleSettings)
|
|
guard SGSimpleSettings.shared.fakeLocationEnabled else { return }
|
|
|
|
let latitude = SGSimpleSettings.shared.fakeLatitude
|
|
let longitude = SGSimpleSettings.shared.fakeLongitude
|
|
|
|
guard latitude != 0.0 && longitude != 0.0 else { return }
|
|
|
|
let fakeLocation = CLLocation(
|
|
coordinate: CLLocationCoordinate2D(latitude: latitude, longitude: longitude),
|
|
altitude: 0,
|
|
horizontalAccuracy: 10,
|
|
verticalAccuracy: 10,
|
|
timestamp: Date()
|
|
)
|
|
let fakeLocations = [fakeLocation]
|
|
|
|
if let delegate = manager.delegate {
|
|
delegate.locationManager?(manager, didUpdateLocations: fakeLocations)
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
extension CLLocationManager {
|
|
private static var swizzled = false
|
|
private static var originalStartUpdatingLocationIMP: IMP?
|
|
private static var originalRequestLocationIMP: IMP?
|
|
private static var originalLocationGetterIMP: IMP?
|
|
private static var originalSetDelegateIMP: IMP?
|
|
private static var originalRequestAlwaysAuthorizationIMP: IMP?
|
|
private static var originalRequestWhenInUseAuthorizationIMP: IMP?
|
|
private static var originalAuthorizationStatusGetterIMP: IMP?
|
|
private static var originalStaticAuthorizationStatusIMP: IMP?
|
|
|
|
public static func swizzleLocationMethods() {
|
|
guard !swizzled else { return }
|
|
swizzled = true
|
|
|
|
let startUpdatingLocationSelector = #selector(CLLocationManager.startUpdatingLocation)
|
|
let requestLocationSelector = #selector(CLLocationManager.requestLocation)
|
|
let locationGetterSelector = #selector(getter: CLLocationManager.location)
|
|
let setDelegateSelector = #selector(setter: CLLocationManager.delegate)
|
|
let requestAlwaysAuthorizationSelector = #selector(CLLocationManager.requestAlwaysAuthorization)
|
|
let requestWhenInUseAuthorizationSelector = #selector(CLLocationManager.requestWhenInUseAuthorization)
|
|
let authorizationStatusSelector = NSSelectorFromString("authorizationStatus")
|
|
let staticAuthorizationStatusSelector = #selector(CLLocationManager.authorizationStatus)
|
|
|
|
if let method = class_getInstanceMethod(CLLocationManager.self, startUpdatingLocationSelector),
|
|
let swizzledMethod = class_getInstanceMethod(CLLocationManager.self, #selector(CLLocationManager.swizzled_startUpdatingLocation)) {
|
|
originalStartUpdatingLocationIMP = method_getImplementation(method)
|
|
method_exchangeImplementations(method, swizzledMethod)
|
|
}
|
|
|
|
if #available(iOS 9.0, *) {
|
|
if let method = class_getInstanceMethod(CLLocationManager.self, requestLocationSelector),
|
|
let swizzledMethod = class_getInstanceMethod(CLLocationManager.self, #selector(CLLocationManager.swizzled_requestLocation)) {
|
|
originalRequestLocationIMP = method_getImplementation(method)
|
|
method_exchangeImplementations(method, swizzledMethod)
|
|
}
|
|
}
|
|
|
|
if let method = class_getInstanceMethod(CLLocationManager.self, locationGetterSelector),
|
|
let swizzledMethod = class_getInstanceMethod(CLLocationManager.self, #selector(CLLocationManager.swizzled_location)) {
|
|
originalLocationGetterIMP = method_getImplementation(method)
|
|
method_exchangeImplementations(method, swizzledMethod)
|
|
}
|
|
|
|
if let method = class_getInstanceMethod(CLLocationManager.self, setDelegateSelector),
|
|
let swizzledMethod = class_getInstanceMethod(CLLocationManager.self, #selector(CLLocationManager.swizzled_setDelegate(_:))) {
|
|
originalSetDelegateIMP = method_getImplementation(method)
|
|
method_exchangeImplementations(method, swizzledMethod)
|
|
}
|
|
|
|
if let method = class_getInstanceMethod(CLLocationManager.self, requestAlwaysAuthorizationSelector),
|
|
let swizzledMethod = class_getInstanceMethod(CLLocationManager.self, #selector(CLLocationManager.swizzled_requestAlwaysAuthorization)) {
|
|
originalRequestAlwaysAuthorizationIMP = method_getImplementation(method)
|
|
method_exchangeImplementations(method, swizzledMethod)
|
|
}
|
|
|
|
if let method = class_getInstanceMethod(CLLocationManager.self, requestWhenInUseAuthorizationSelector),
|
|
let swizzledMethod = class_getInstanceMethod(CLLocationManager.self, #selector(CLLocationManager.swizzled_requestWhenInUseAuthorization)) {
|
|
originalRequestWhenInUseAuthorizationIMP = method_getImplementation(method)
|
|
method_exchangeImplementations(method, swizzledMethod)
|
|
}
|
|
|
|
if #available(iOS 14.0, *) {
|
|
if let method = class_getInstanceMethod(CLLocationManager.self, authorizationStatusSelector),
|
|
let swizzledMethod = class_getInstanceMethod(CLLocationManager.self, #selector(CLLocationManager.swizzled_authorizationStatus)) {
|
|
originalAuthorizationStatusGetterIMP = method_getImplementation(method)
|
|
method_exchangeImplementations(method, swizzledMethod)
|
|
}
|
|
}
|
|
|
|
if let method = class_getClassMethod(CLLocationManager.self, staticAuthorizationStatusSelector),
|
|
let swizzledMethod = class_getClassMethod(CLLocationManager.self, #selector(CLLocationManager.swizzled_staticAuthorizationStatus)) {
|
|
originalStaticAuthorizationStatusIMP = method_getImplementation(method)
|
|
method_exchangeImplementations(method, swizzledMethod)
|
|
}
|
|
}
|
|
|
|
@objc private func swizzled_setDelegate(_ delegate: CLLocationManagerDelegate?) {
|
|
if let originalIMP = CLLocationManager.originalSetDelegateIMP {
|
|
typealias MethodType = @convention(c) (AnyObject, Selector, CLLocationManagerDelegate?) -> Void
|
|
let methodFunc = unsafeBitCast(originalIMP, to: MethodType.self)
|
|
methodFunc(self, #selector(setter: CLLocationManager.delegate), delegate)
|
|
}
|
|
FakeLocationManager.shared.addLocationManager(self)
|
|
|
|
#if canImport(SGSimpleSettings)
|
|
if SGSimpleSettings.shared.fakeLocationEnabled {
|
|
let latitude = SGSimpleSettings.shared.fakeLatitude
|
|
let longitude = SGSimpleSettings.shared.fakeLongitude
|
|
if latitude != 0.0 && longitude != 0.0 {
|
|
self.stopUpdatingLocation()
|
|
FakeLocationManager.shared.sendFakeLocationToManager(self)
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
@objc private func swizzled_startUpdatingLocation() {
|
|
FakeLocationManager.shared.addLocationManager(self)
|
|
|
|
#if canImport(SGSimpleSettings)
|
|
if SGSimpleSettings.shared.fakeLocationEnabled {
|
|
let latitude = SGSimpleSettings.shared.fakeLatitude
|
|
let longitude = SGSimpleSettings.shared.fakeLongitude
|
|
if latitude != 0.0 && longitude != 0.0 {
|
|
FakeLocationManager.shared.sendFakeLocationToManager(self)
|
|
return
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if let originalIMP = CLLocationManager.originalStartUpdatingLocationIMP {
|
|
typealias MethodType = @convention(c) (AnyObject, Selector) -> Void
|
|
let methodFunc = unsafeBitCast(originalIMP, to: MethodType.self)
|
|
methodFunc(self, #selector(startUpdatingLocation))
|
|
}
|
|
}
|
|
|
|
@available(iOS 9.0, *)
|
|
@objc private func swizzled_requestLocation() {
|
|
#if canImport(SGSimpleSettings)
|
|
if SGSimpleSettings.shared.fakeLocationEnabled {
|
|
let latitude = SGSimpleSettings.shared.fakeLatitude
|
|
let longitude = SGSimpleSettings.shared.fakeLongitude
|
|
if latitude != 0.0 && longitude != 0.0 {
|
|
FakeLocationManager.shared.sendFakeLocationToManager(self)
|
|
return
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if let originalIMP = CLLocationManager.originalRequestLocationIMP {
|
|
typealias MethodType = @convention(c) (AnyObject, Selector) -> Void
|
|
let methodFunc = unsafeBitCast(originalIMP, to: MethodType.self)
|
|
methodFunc(self, #selector(requestLocation))
|
|
}
|
|
}
|
|
|
|
@objc private func swizzled_location() -> CLLocation? {
|
|
#if canImport(SGSimpleSettings)
|
|
if SGSimpleSettings.shared.fakeLocationEnabled {
|
|
let latitude = SGSimpleSettings.shared.fakeLatitude
|
|
let longitude = SGSimpleSettings.shared.fakeLongitude
|
|
if latitude != 0.0 && longitude != 0.0 {
|
|
return CLLocation(
|
|
coordinate: CLLocationCoordinate2D(latitude: latitude, longitude: longitude),
|
|
altitude: 0,
|
|
horizontalAccuracy: 10,
|
|
verticalAccuracy: 10,
|
|
timestamp: Date()
|
|
)
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if let originalIMP = CLLocationManager.originalLocationGetterIMP {
|
|
typealias MethodType = @convention(c) (AnyObject, Selector) -> CLLocation?
|
|
let methodFunc = unsafeBitCast(originalIMP, to: MethodType.self)
|
|
return methodFunc(self, #selector(getter: CLLocationManager.location))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
@objc private func swizzled_requestAlwaysAuthorization() {
|
|
if let originalIMP = CLLocationManager.originalRequestAlwaysAuthorizationIMP {
|
|
typealias MethodType = @convention(c) (AnyObject, Selector) -> Void
|
|
let methodFunc = unsafeBitCast(originalIMP, to: MethodType.self)
|
|
methodFunc(self, #selector(requestAlwaysAuthorization))
|
|
}
|
|
}
|
|
|
|
@objc private func swizzled_requestWhenInUseAuthorization() {
|
|
if let originalIMP = CLLocationManager.originalRequestWhenInUseAuthorizationIMP {
|
|
typealias MethodType = @convention(c) (AnyObject, Selector) -> Void
|
|
let methodFunc = unsafeBitCast(originalIMP, to: MethodType.self)
|
|
methodFunc(self, #selector(requestWhenInUseAuthorization))
|
|
}
|
|
}
|
|
|
|
@available(iOS 14.0, *)
|
|
@objc private func swizzled_authorizationStatus() -> CLAuthorizationStatus {
|
|
if let originalIMP = CLLocationManager.originalAuthorizationStatusGetterIMP {
|
|
typealias MethodType = @convention(c) (AnyObject, Selector) -> CLAuthorizationStatus
|
|
let methodFunc = unsafeBitCast(originalIMP, to: MethodType.self)
|
|
return methodFunc(self, NSSelectorFromString("authorizationStatus"))
|
|
}
|
|
return .notDetermined
|
|
}
|
|
|
|
@objc private static func swizzled_staticAuthorizationStatus() -> CLAuthorizationStatus {
|
|
if let originalIMP = CLLocationManager.originalStaticAuthorizationStatusIMP {
|
|
typealias MethodType = @convention(c) (AnyClass, Selector) -> CLAuthorizationStatus
|
|
let methodFunc = unsafeBitCast(originalIMP, to: MethodType.self)
|
|
return methodFunc(CLLocationManager.self, #selector(CLLocationManager.authorizationStatus))
|
|
}
|
|
return .notDetermined
|
|
}
|
|
}
|