iOS Geofence in progress

geofencing_wifi
Zohaib Kambrani 4 years ago
parent 8457972fda
commit 67f4b4e167

@ -1 +1 @@
3f3d14a0ae775b56806906c2cb14a1f0
067d482a9455eae7d109c3ac5a36de46

@ -2,16 +2,47 @@ import UIKit
import Flutter
import GoogleMaps
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
let locationManager = CLLocationManager()
override func application( _ application: UIApplication,didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// initLocationManager()
GMSServices.provideAPIKey("AIzaSyCiiJiHkocPbcziHt9O8rGWavDrxHRQys8")
GeneratedPluginRegistrant.register(with: self)
if let mainViewController = window.rootViewController as? MainFlutterVC{
HMGPlatformBridge.initialize(flutterViewController: mainViewController)
}
HMG_Geofence.initGeofencing()
if let _ = launchOptions?[.location] {
HMG_Geofence().wakeup()
}
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
extension AppDelegate: CLLocationManagerDelegate {
func initLocationManager(){
locationManager.allowsBackgroundLocationUpdates = true
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.activityType = .other
locationManager.delegate = self
locationManager.requestAlwaysAuthorization()
}
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
if region is CLCircularRegion {
}
}
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
if region is CLCircularRegion {
}
}
}

@ -10,34 +10,32 @@ import Flutter
import NetworkExtension
import SystemConfiguration.CaptiveNetwork
var flutterMethodChannel:FlutterMethodChannel? = nil
class MainFlutterVC: FlutterViewController {
override func viewDidLoad() {
super.viewDidLoad()
flutterMethodChannel = FlutterMethodChannel(name: "HMG-Platform-Bridge",binaryMessenger: binaryMessenger)
flutterMethodChannel?.setMethodCallHandler { (methodCall, result) in
if methodCall.method == "connectHMGInternetWifi"{
self.connectHMGInternetWifi(methodCall:methodCall, result: result)
}else if methodCall.method == "connectHMGGuestWifi"{
self.connectHMGGuestWifi(methodCall:methodCall, result: result)
}else if methodCall.method == "isHMGNetworkAvailable"{
self.isHMGNetworkAvailable(methodCall:methodCall, result: result)
}else if methodCall.method == "registerHmgGeofences"{
self.registerHmgGeofences(result: result)
}
print("")
}
FlutterText.with(key: "errorConnectingHmgNetwork") { (localized) in
print(localized)
}
// flutterMethodChannel?.setMethodCallHandler { (methodCall, result) in
//
// if methodCall.method == "connectHMGInternetWifi"{
// self.connectHMGInternetWifi(methodCall:methodCall, result: result)
//
// }else if methodCall.method == "connectHMGGuestWifi"{
// self.connectHMGGuestWifi(methodCall:methodCall, result: result)
//
// }else if methodCall.method == "isHMGNetworkAvailable"{
// self.isHMGNetworkAvailable(methodCall:methodCall, result: result)
//
// }else if methodCall.method == "registerHmgGeofences"{
// self.registerHmgGeofences(result: result)
// }
//
// print("")
// }
//
// FlutterText.with(key: "errorConnectingHmgNetwork") { (localized) in
// print(localized)
// }
}

@ -12,6 +12,10 @@ extension String{
func toUrl() -> URL?{
return URL(string: self)
}
func removeSpace() -> String?{
return self.replacingOccurrences(of: " ", with: "")
}
}
extension Bundle {

@ -27,6 +27,8 @@ func httpPostRequest(urlString:String, jsonBody:[String:Any], completion:((Bool,
// create post request
let url = URL(string: urlString)!
var request = URLRequest(url: url)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("*/*", forHTTPHeaderField: "Accept")
request.httpMethod = "POST"
request.httpBody = jsonData

@ -0,0 +1,128 @@
//
// HMGPlatformBridge.swift
// Runner
//
// Created by ZiKambrani on 14/12/2020.
//
import UIKit
import NetworkExtension
import SystemConfiguration.CaptiveNetwork
var flutterMethodChannel:FlutterMethodChannel? = nil
var mainViewController:MainFlutterVC!
class HMGPlatformBridge{
private let channelName = "HMG-Platform-Bridge"
private static var shared_:HMGPlatformBridge?
class func initialize(flutterViewController:MainFlutterVC){
shared_ = HMGPlatformBridge()
mainViewController = flutterViewController
shared_?.openChannel()
}
func shared() -> HMGPlatformBridge{
assert((HMGPlatformBridge.shared_ != nil), "HMGPlatformBridge is not initialized, call initialize(mainViewController:MainFlutterVC) function first.")
return HMGPlatformBridge.shared_!
}
private func openChannel(){
flutterMethodChannel = FlutterMethodChannel(name: channelName, binaryMessenger: mainViewController.binaryMessenger)
flutterMethodChannel?.setMethodCallHandler { (methodCall, result) in
print("Called function \(methodCall.method)")
if methodCall.method == "connectHMGInternetWifi"{
self.connectHMGInternetWifi(methodCall:methodCall, result: result)
}else if methodCall.method == "connectHMGGuestWifi"{
self.connectHMGGuestWifi(methodCall:methodCall, result: result)
}else if methodCall.method == "isHMGNetworkAvailable"{
self.isHMGNetworkAvailable(methodCall:methodCall, result: result)
}else if methodCall.method == "registerHmgGeofences"{
self.registerHmgGeofences(result: result)
}
print("")
}
}
// Connect HMG Wifi and Internet
func connectHMGInternetWifi(methodCall:FlutterMethodCall ,result: @escaping FlutterResult){
guard let pateintId = (methodCall.arguments as? [Any])?.first as? String
else { return assert(true, "Missing or invalid arguments (Must have one argument 'String at 0'") }
HMG_Internet.shared.connect(patientId: pateintId) { (status, message) in
result(status ? 1 : 0)
if status{
self.showMessage(title:"Congratulations", message:message)
}else{
self.showMessage(title:"Ooops,", message:message)
}
}
}
// Connect HMG-Guest for App Access
func connectHMGGuestWifi(methodCall:FlutterMethodCall ,result: @escaping FlutterResult){
HMG_GUEST.shared.connect() { (status, message) in
result(status ? 1 : 0)
if status{
self.showMessage(title:"Congratulations", message:message)
}else{
self.showMessage(title:"Ooops,", message:message)
}
}
}
func isHMGNetworkAvailable(methodCall:FlutterMethodCall ,result: @escaping FlutterResult) -> Bool{
guard let ssid = methodCall.arguments as? String else {
assert(true, "Missing or invalid arguments (Must have one argument 'String at 0'")
return false
}
let queue = DispatchQueue.init(label: "com.hmg.wifilist")
NEHotspotHelper.register(options: nil, queue: queue) { (command) in
print(command)
if(command.commandType == NEHotspotHelperCommandType.filterScanList) {
if let networkList = command.networkList{
for network in networkList{
print(network.ssid)
}
}
}
}
return false
}
// Message Dailog
func showMessage(title:String, message:String){
DispatchQueue.main.async {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert )
alert.addAction(UIAlertAction(title: "OK", style: .destructive, handler: nil))
mainViewController.present(alert, animated: true) {
}
}
}
// Register Geofence
func registerHmgGeofences(result: @escaping FlutterResult){
flutterMethodChannel?.invokeMethod("getGeoZones", arguments: nil){ geoFencesJsonString in
if let jsonString = geoFencesJsonString as? String{
let allZones = GeoZoneModel.list(from: jsonString)
HMG_Geofence.shared().register(geoZones: allZones)
}else{
}
}
}
}

@ -14,41 +14,58 @@ fileprivate var transition = ""
enum Transition:Int {
case entry = 1
case exit = 2
func name() -> String{
return self.rawValue == 1 ? "Enter" : "Exit"
}
}
class HMG_Geofence:NSObject{
var geoZones:[GeoZoneModel]?
var locationManager = CLLocationManager()
var locationManager:CLLocationManager!{
didSet{
// https://developer.apple.com/documentation/corelocation/cllocationmanager/1423531-startmonitoringsignificantlocati
locationManager.allowsBackgroundLocationUpdates = true
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.activityType = .other
locationManager.delegate = self
locationManager.requestAlwaysAuthorization()
// locationManager.distanceFilter = 500
// locationManager.startMonitoringSignificantLocationChanges()
}
}
func initLocationManager(){
locationManager.delegate = self
locationManager.allowsBackgroundLocationUpdates = true
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.activityType = .other
locationManager.requestAlwaysAuthorization()
private static var shared_:HMG_Geofence?
class func shared() -> HMG_Geofence{
assert(shared_ != nil, "HMG_Geofence is not initialized, call initGeofencing() function first.")
return shared_!
}
class func initGeofencing(){
shared_ = HMG_Geofence()
shared_?.locationManager = CLLocationManager()
}
func register(geoZones:[GeoZoneModel]){
self.geoZones = geoZones
self.geoZones?.forEach({ (zone) in
startMonitoring(zone: zone)
})
// self.geoZones?.forEach({ (zone) in
// startMonitoring(zone: zone)
// })
let z = geoZones[14]
if monitoredRegions().filter { $0.identifier == z.identifier()}.isEmpty{
startMonitoring(zone: z)
}
}
func wakeup(){
initLocationManager()
}
func monitoredRegions() -> Set<CLRegion>{
return locationManager.monitoredRegions
}
}
// CLLocationManager Delegates
extension HMG_Geofence : CLLocationManagerDelegate{
@ -68,21 +85,34 @@ extension HMG_Geofence : CLLocationManagerDelegate{
if let fenceRegion = region(with: zone){
locationManager.startMonitoring(for: fenceRegion)
locationManager.requestState(for: fenceRegion)
debugPrint("Monitering region: \(fenceRegion.center) | \(fenceRegion.identifier)")
}else{
debugPrint("Invalid region: \(zone.latitude ?? ""),\(zone.longitude ?? ""),r\(zone.radius ?? 0) | \(zone.identifier())")
}
}
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
debugPrint("didEnterRegion: \(region)")
if region is CLCircularRegion {
handleEvent(for: region,transition: .entry, location: manager.location)
}
}
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
debugPrint("didExitRegion: \(region)")
if region is CLCircularRegion {
handleEvent(for: region,transition: .exit, location: manager.location)
}
}
func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
debugPrint("didDetermineState: \(state)")
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
debugPrint("didUpdateLocations: \(locations)")
}
}
@ -91,15 +121,15 @@ extension HMG_Geofence{
func handleEvent(for region: CLRegion!, transition:Transition, location:CLLocation?) {
if let zone = geoZone(by: region.identifier){
notifyUser(forZone: zone, transiotion: transition, location: locationManager.location)
notifyServer(forZone: zone, transiotion: transition, location: locationManager.location)
notifyUser(forZone: zone, transition: transition, location: locationManager.location)
notifyServer(forZone: zone, transition: transition, location: locationManager.location)
}
}
func region(with geoZone: GeoZoneModel) -> CLCircularRegion? {
if !geoZone.identifier().isEmpty,
let radius = geoZone.radius, let lat = geoZone.latitude, let long = geoZone.longitude,
let radius = geoZone.radius, let lat = geoZone.latitude?.removeSpace(), let long = geoZone.longitude?.removeSpace(),
let radius_d = Double("\(radius)"), let lat_d = Double(lat), let long_d = Double(long){
let coordinate = CLLocationCoordinate2D(latitude: lat_d, longitude: long_d)
@ -119,32 +149,36 @@ extension HMG_Geofence{
}
func notifyUser(forZone:GeoZoneModel, transiotion:Transition, location:CLLocation?){
func notifyUser(forZone:GeoZoneModel, transition:Transition, location:CLLocation?){
if UIApplication.shared.applicationState == .active {
mainViewController.showAlert(withTitle: transition.name(), message: forZone.identifier())
} else {
let notificationContent = UNMutableNotificationContent()
notificationContent.title = transition.name()
notificationContent.body = forZone.identifier()
notificationContent.sound = UNNotificationSound.default
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
let request = UNNotificationRequest(identifier: "\(Date().timeIntervalSinceNow)",
content: notificationContent,
trigger: trigger)
UNUserNotificationCenter.current().add(request) { error in
if let error = error {
print("Error: \(error)")
}
}
}
}
func notifyServer(forZone:GeoZoneModel, transiotion:Transition, location:CLLocation?){
func notifyServer(forZone:GeoZoneModel, transition:Transition, location:CLLocation?){
flutterMethodChannel?.invokeMethod("getLogGeofenceFullUrl", arguments: nil){ fullUrlString in
if let url = fullUrlString as? String{
let body:[String : Any?] = [
"PointsID":forZone.geofenceId,
"GeoType":transiotion.rawValue,
"PatientID":"1231755",
"ZipCode": "966",
"VersionID": 5.6,
"Channel": 3,
"LanguageID": UserDefaults.standard.string(forKey: "language") ?? "ar",
"IPAdress": "10.20.10.20",
"generalid": "Cs2020@2016$2958",
"PatientOutSA": 0,
"isDentalAllowedBackend": false,
"TokenID": "27v/qqXC/UGS2bgJfRBHYw==",
"DeviceTypeID": 2
]
httpPostRequest(urlString: url, jsonBody: body){ (status,json) in
if let json_ = json , status{
}else{
flutterMethodChannel?.invokeMethod("getDefaultHttpParameters", arguments: nil){ params in
if let body = params as? [String : Any]{
httpPostRequest(urlString: url, jsonBody: body){ (status,json) in
if let json_ = json , status{
}else{
}
}
}
}
}

@ -2,10 +2,6 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSCalendarsUsageDescription</key>
<string>We need access to record you event in to calender.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>This app will use your location to show cool stuffs near you.</string>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
@ -26,10 +22,14 @@
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSCalendarsUsageDescription</key>
<string>We need access to record you event in to calender.</string>
<key>NSCameraUsageDescription</key>
<string>Need camera access for uploading images</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This app will use your location to show cool stuffs near you.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>This app will use your location to show cool stuffs near you.</string>
<key>NSLocationUsageDescription</key>
<string>Need location access for updating nearby friends</string>
<key>NSLocationWhenInUseUsageDescription</key>
@ -40,12 +40,20 @@
<string>Need photo library access for uploading images</string>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>location</string>
<string>processing</string>
</array>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>location-services</string>
<string>gps</string>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
@ -63,11 +71,5 @@
<false/>
<key>io.flutter.embedded_views_preview</key>
<true/>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>location-services</string>
<string>gps</string>
<string>armv7</string>
</array>
</dict>
</plist>

@ -4,7 +4,8 @@ class GeoZonesRequestModel {
GeoZonesRequestModel({this.PatientID});
Map<String, dynamic> toFlatMap() {
if()
if (PatientID == null) return {};
return {"PatientID": PatientID.toString()};
}
}

@ -210,4 +210,25 @@ class BaseAppClient {
///return id.replaceAll(RegExp('/[^\w\s]/'), '');
// return id.replaceAll(RegExp('/[^a-zA-Z ]'), '');
}
static defaultHttpParameters() async {
String token = await sharedPref.getString(TOKEN);
var languageID = await sharedPref.getStringWithDefaultValue(APP_LANGUAGE, 'ar');
var user = await sharedPref.getObject(USER_PROFILE);
var params = {};
if (user != null) {
params['TokenID'] = token;
params['PatientID'] = user['PatientID'];
params['PatientOutSA'] = user['OutSA'];
params['SessionID'] = SESSION_ID; //getSessionId(token);
}
params['IPAdress'] = IP_ADDRESS;
params['generalid'] = GENERAL_ID;
params['VersionID'] = VERSION_ID;
params['Channel'] = CHANNEL;
params['LanguageID'] = languageID == 'ar' ? 1 : 2;
return params;
}
}

@ -10,11 +10,13 @@ import 'package:diplomaticquarterapp/core/model/geofencing/responses/LogGeoZoneR
import 'package:diplomaticquarterapp/core/service/base_service.dart';
import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import '../../../locator.dart';
class GeofencingServices extends BaseService {
List<GeoZonesResponseModel> geoZones = List();
bool testZones = true;
Future<List<GeoZonesResponseModel>> getAllGeoZones(GeoZonesRequestModel request) async {
hasError = false;
@ -24,6 +26,8 @@ class GeofencingServices extends BaseService {
geoZones.add(GeoZonesResponseModel().fromJson(json));
});
if (kDebugMode || testZones) addTestingGeoZones(zones);
var zonesJsonString = json.encode(zones);
AppSharedPreferences().setString(HMG_GEOFENCES, zonesJsonString);
debugPrint("GEO ZONES saved to AppPreferences with key '$HMG_GEOFENCES'");
@ -45,4 +49,10 @@ class GeofencingServices extends BaseService {
}, body: request.toFlatMap());
return logResponse;
}
addTestingGeoZones(List zones) {
zones.add({"GEOF_ID": 100, "zkH": "", "Latitude": "24.691136", "Longitude": "46.650116", "Radius": 100, "Type": 1});
zones.add({"GEOF_ID": 101, "csO": "", "Latitude": "24.7087913", "Longitude": "46.6656461", "Radius": 100, "Type": 1});
zones.add({"GEOF_ID": 102, "msH": "", "Latitude": "24.777577", "Longitude": "46.652675", "Radius": 100, "Type": 1});
}
}

@ -37,14 +37,15 @@ class PlatformBridge {
String key = methodCall.arguments.toString();
return localizedValue(key);
case 'getGeofencePreferenceKey':
return getGeofencePreferenceKey();
case 'getGeoZones':
return getGeoZones();
case 'getLogGeofenceFullUrl':
return getLogGeofenceFullUrl();
case 'test':
return 123.0;
case 'getDefaultHttpParameters':
return getDefaultHttpParameters();
default:
throw MissingPluginException('notImplemented');
}
@ -62,7 +63,7 @@ class PlatformBridge {
return (localized != null || (localized is String)) ? localized : forKey;
}
static Future<String> getGeofencePreferenceKey() async {
static Future<String> getGeoZones() async {
var res = await sharedPref.getStringWithDefaultValue(HMG_GEOFENCES, "[]");
return res;
}
@ -72,6 +73,10 @@ class PlatformBridge {
return res;
}
static Future getDefaultHttpParameters() async {
return BaseAppClient.defaultHttpParameters();
}
//--//--//--//--//--//--//--//--//--//--//--//--//--//--//--//--//--//--//--//--//--//--//--//
//--//--//--//--//--//--//--//--//--//--//--//--//--//--//--//--//--//--//--//--//--//--//--//

Loading…
Cancel
Save