diff --git a/CHANGELOG.md b/CHANGELOG.md index c81afbe..de2ded1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# 3.10.0-beta.3 + +- Bump iOS version from 3.9.14 to 3.16.1-beta.1 +- Bump Android version from 3.9.8 to 3.16.1-beta.1 + # 3.9.1 - Bump iOS version from 3.9.7 to 3.9.14 diff --git a/android/build.gradle b/android/build.gradle index 11eef99..ef9cfbb 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -34,7 +34,7 @@ android { } dependencies { - implementation 'io.radar:sdk:3.9.8' + implementation 'io.radar:sdk:3.16.1-beta.1' implementation 'com.google.android.gms:play-services-location:21.0.1' implementation 'com.google.code.gson:gson:2.8.6' } diff --git a/android/src/main/java/io/radar/flutter/RadarFlutterPlugin.java b/android/src/main/java/io/radar/flutter/RadarFlutterPlugin.java index 0ab9c9f..baef92d 100644 --- a/android/src/main/java/io/radar/flutter/RadarFlutterPlugin.java +++ b/android/src/main/java/io/radar/flutter/RadarFlutterPlugin.java @@ -21,6 +21,7 @@ import org.json.JSONObject; import org.jetbrains.annotations.Nullable; +import java.lang.reflect.Array; import java.util.ArrayList; import java.util.EnumSet; import java.util.HashMap; @@ -58,6 +59,7 @@ import io.radar.sdk.model.RadarTrip; import io.radar.sdk.model.RadarRouteMatrix; import io.radar.sdk.RadarTrackingOptions.RadarTrackingOptionsForegroundService; +import io.radar.sdk.model.RadarVerifiedLocationToken; import io.flutter.embedding.engine.dart.DartExecutor; import io.flutter.embedding.engine.dart.DartExecutor.DartCallback; @@ -66,7 +68,8 @@ import io.flutter.view.FlutterRunArguments; import io.flutter.view.FlutterCallbackInformation; -public class RadarFlutterPlugin implements FlutterPlugin, MethodCallHandler, ActivityAware, RequestPermissionsResultListener { +public class RadarFlutterPlugin + implements FlutterPlugin, MethodCallHandler, ActivityAware, RequestPermissionsResultListener { private static FlutterEngine sBackgroundFlutterEngine; @@ -76,40 +79,19 @@ public class RadarFlutterPlugin implements FlutterPlugin, MethodCallHandler, Act private static final String TAG = "RadarFlutterPlugin"; private static final String CALLBACK_DISPATCHER_HANDLE_KEY = "callbackDispatcherHandle"; private static MethodChannel sBackgroundChannel; + private MethodChannel channel; private static final Object lock = new Object(); private static final int PERMISSIONS_REQUEST_CODE = 20160525; private Result mPermissionsRequestResult; - - private static void initializeBackgroundEngine(Context context) { - synchronized(lock) { - if (sBackgroundFlutterEngine == null) { - FlutterMain.startInitialization(context.getApplicationContext()); - FlutterMain.ensureInitializationComplete(context.getApplicationContext(), null); - - SharedPreferences sharedPrefs = context.getSharedPreferences(TAG, Context.MODE_PRIVATE); - long callbackDispatcherHandle = sharedPrefs.getLong(CALLBACK_DISPATCHER_HANDLE_KEY, 0); - if (callbackDispatcherHandle == 0) { - Log.e(TAG, "Error looking up callback dispatcher handle"); - return; - } - - FlutterCallbackInformation callbackInfo = FlutterCallbackInformation.lookupCallbackInformation(callbackDispatcherHandle); - sBackgroundFlutterEngine = new FlutterEngine(context.getApplicationContext()); - DartCallback callback = new DartCallback(context.getAssets(), FlutterMain.findAppBundlePath(context), callbackInfo); - sBackgroundFlutterEngine.getDartExecutor().executeDartCallback(callback); - sBackgroundChannel = new MethodChannel(sBackgroundFlutterEngine.getDartExecutor().getBinaryMessenger(), "flutter_radar_background"); - } - } - } - @Override public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) { - Radar.setReceiver(new RadarFlutterReceiver()); mContext = binding.getApplicationContext(); - MethodChannel channel = new MethodChannel(binding.getFlutterEngine().getDartExecutor(), "flutter_radar"); + channel = new MethodChannel(binding.getFlutterEngine().getDartExecutor(), "flutter_radar"); + Radar.setReceiver(new RadarFlutterReceiver(channel)); + Radar.setVerifiedReceiver(new RadarFlutterVerifiedReceiver(channel)); channel.setMethodCallHandler(this); } @@ -215,6 +197,9 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result) case "startTrackingVerified": startTrackingVerified(call, result); break; + case "stopTrackingVerified": + stopTrackingVerified(call, result); + break; case "stopTracking": stopTracking(result); break; @@ -245,6 +230,12 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result) case "cancelTrip": cancelTrip(result); break; + case "acceptEvent": + acceptEvent(call, result); + break; + case "rejectEvent": + rejectEvent(call, result); + break; case "getContext": getContext(call, result); break; @@ -256,7 +247,7 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result) break; case "autocomplete": autocomplete(call, result); - break; + break; case "forwardGeocode": geocode(call, result); break; @@ -293,24 +284,9 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result) case "trackVerified": trackVerified(call, result); break; - case "trackVerifiedToken": - trackVerifiedToken(call, result); - break; case "validateAddress": validateAddress(call, result); break; - case "attachListeners": - attachListeners(call, result); - break; - case "detachListeners": - detachListeners(call, result); - break; - case "on": - on(call, result); - break; - case "off": - off(call, result); - break; default: result.notImplemented(); break; @@ -320,18 +296,104 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result) } } + private String getStringFromMethodCall(MethodCall call, String key) { + try { + final Map arguments = call.arguments(); + if (arguments.containsKey(key)) { + Object value = arguments.get(key); + if (value instanceof String) { + return (String) value; // Return the string value if it exists and is a string + } + } + } catch (Exception e) { + Log.e(TAG, e.getMessage()); + } + return null; // Return null if the key does not exist or is not a string + } + + private boolean getBooleanFromMethodCall(MethodCall call, String key, boolean defaultValue) { + try { + final Map arguments = call.arguments(); + if (arguments.containsKey(key)) { + Object value = arguments.get(key); + if (value instanceof Boolean) { + return (Boolean) value; + } + } + } catch (Exception e) { + Log.e(TAG, e.getMessage()); + } + return defaultValue; + } + + private HashMap getHashMapFromMethodCall(MethodCall call, String key) { + try { + final Map arguments = call.arguments(); + if (arguments.containsKey(key)) { + Object value = arguments.get(key); + if (value instanceof HashMap) { + return (HashMap) value; + } + } + } catch (Exception e) { + Log.e(TAG, e.getMessage()); + } + return null; + } + + private int getIntFromMethodCall(MethodCall call, String key, int defaultValue) { + try { + final Map arguments = call.arguments(); + if (arguments.containsKey(key)) { + Object value = arguments.get(key); + if (value instanceof Integer) { + return (Integer) value; + } + } + } catch (Exception e) { + Log.e(TAG, e.getMessage()); + } + return defaultValue; + } + + private ArrayList getArrayListFromMethodCall(MethodCall call, String key) { + try { + final Map arguments = call.arguments(); + if (arguments.containsKey(key)) { + Object value = arguments.get(key); + if (value instanceof ArrayList) { + return (ArrayList) value; + } + } + } catch (Exception e) { + Log.e(TAG, e.getMessage()); + } + return null; + } + + private String[] getStringArrayFromMethodCall(MethodCall call, String key) { + ArrayList list = getArrayListFromMethodCall(call, key); + if (list != null) { + return list.toArray(new String[0]); + } + return null; + } + private void initialize(MethodCall call, Result result) { - String publishableKey = call.argument("publishableKey"); + String publishableKey = getStringFromMethodCall(call, "publishableKey"); + boolean fraud = getBooleanFromMethodCall(call, "fraud", false); SharedPreferences.Editor editor = mContext.getSharedPreferences("RadarSDK", Context.MODE_PRIVATE).edit(); editor.putString("x_platform_sdk_type", "Flutter"); - editor.putString("x_platform_sdk_version", "3.9.1"); + editor.putString("x_platform_sdk_version", "3.10.0-beta.3"); editor.apply(); - Radar.initialize(mContext, publishableKey); + Radar.initialize(mContext, publishableKey, null, Radar.RadarLocationServicesProvider.GOOGLE, fraud); + Radar.setReceiver(new RadarFlutterReceiver(channel)); + Radar.setVerifiedReceiver(new RadarFlutterVerifiedReceiver(channel)); result.success(true); } private void setNotificationOptions(MethodCall call, Result result) { - HashMap notificationOptionsMap = (HashMap)call.arguments; + HashMap notificationOptionsMap = (HashMap) call.arguments; JSONObject notificationOptionsJson = new JSONObject(notificationOptionsMap); RadarNotificationOptions options = RadarNotificationOptions.fromJson(notificationOptionsJson); Radar.setNotificationOptions(options); @@ -339,15 +401,16 @@ private void setNotificationOptions(MethodCall call, Result result) { } private void setForegroundServiceOptions(MethodCall call, Result result) { - HashMap foregroundServiceOptionsMap = (HashMap)call.arguments; + HashMap foregroundServiceOptionsMap = (HashMap) call.arguments; JSONObject foregroundServiceOptionsJson = new JSONObject(foregroundServiceOptionsMap); - RadarTrackingOptionsForegroundService options = RadarTrackingOptionsForegroundService.fromJson(foregroundServiceOptionsJson); + RadarTrackingOptionsForegroundService options = RadarTrackingOptionsForegroundService + .fromJson(foregroundServiceOptionsJson); Radar.setForegroundServiceOptions(options); result.success(true); } private void setLogLevel(MethodCall call, Result result) { - String logLevel = call.argument("logLevel"); + String logLevel = getStringFromMethodCall(call, "logLevel"); if (logLevel == null) { Radar.setLogLevel(Radar.RadarLogLevel.NONE); } else if (logLevel.equals("debug")) { @@ -364,20 +427,21 @@ private void setLogLevel(MethodCall call, Result result) { result.success(true); } - private void getPermissionStatus(Result result) { String status = "NOT_DETERMINED"; - + if (mActivity == null || result == null) { result.success(status); return; } - boolean foreground = ActivityCompat.checkSelfPermission(mActivity, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED; + boolean foreground = ActivityCompat.checkSelfPermission(mActivity, + Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED; if (Build.VERSION.SDK_INT >= 29) { if (foreground) { - boolean background = ActivityCompat.checkSelfPermission(mActivity, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED; + boolean background = ActivityCompat.checkSelfPermission(mActivity, + Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED; status = background ? "GRANTED_BACKGROUND" : "GRANTED_FOREGROUND"; } else { status = "DENIED"; @@ -390,21 +454,27 @@ private void getPermissionStatus(Result result) { } private void requestPermissions(MethodCall call, Result result) { - boolean background = call.argument("background"); + boolean background = getBooleanFromMethodCall(call, "background", false); mPermissionsRequestResult = result; if (mActivity != null) { if (Build.VERSION.SDK_INT >= 23) { if (background && Build.VERSION.SDK_INT >= 29) { - ActivityCompat.requestPermissions(mActivity, new String[] { Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION }, PERMISSIONS_REQUEST_CODE); + ActivityCompat.requestPermissions(mActivity, + new String[] { Manifest.permission.ACCESS_COARSE_LOCATION, + Manifest.permission.ACCESS_FINE_LOCATION, + Manifest.permission.ACCESS_BACKGROUND_LOCATION }, + PERMISSIONS_REQUEST_CODE); } else { - ActivityCompat.requestPermissions(mActivity, new String[] { Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION }, PERMISSIONS_REQUEST_CODE); + ActivityCompat.requestPermissions(mActivity, new String[] { + Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION }, + PERMISSIONS_REQUEST_CODE); } } } } private void setUserId(MethodCall call, Result result) { - String userId = call.argument("userId"); + String userId = getStringFromMethodCall(call, "userId"); Radar.setUserId(userId); result.success(true); } @@ -415,7 +485,7 @@ private void getUserId(Result result) { } private void setDescription(MethodCall call, Result result) { - String description = call.argument("description"); + String description = getStringFromMethodCall(call, "description"); Radar.setDescription(description); result.success(true); } @@ -426,7 +496,7 @@ private void getDescription(Result result) { } private void setMetadata(MethodCall call, Result result) { - HashMap metadataMap = (HashMap)call.arguments; + HashMap metadataMap = (HashMap) call.arguments; JSONObject metadata = new JSONObject(metadataMap); Radar.setMetadata(metadata); result.success(true); @@ -436,13 +506,13 @@ private void getMetadata(Result result) { JSONObject metadata = Radar.getMetadata(); HashMap metadataMap = null; if (metadata != null) { - metadataMap = new Gson().fromJson(metadata.toString(), HashMap.class); + metadataMap = new Gson().fromJson(metadata.toString(), HashMap.class); } result.success(metadataMap); } private void setAnonymousTrackingEnabled(MethodCall call, Result result) { - boolean enabled = call.argument("enabled"); + boolean enabled = getBooleanFromMethodCall(call, "enabled", false); Radar.setAnonymousTrackingEnabled(enabled); result.success(true); } @@ -472,7 +542,7 @@ public void run() { } }; - String accuracy = call.argument("accuracy"); + String accuracy = getStringFromMethodCall(call, "accuracy"); if (accuracy == null) { Radar.getLocation(callback); } else if (accuracy.equals("high")) { @@ -489,7 +559,8 @@ public void run() { private void trackOnce(MethodCall call, final Result result) { Radar.RadarTrackCallback callback = new Radar.RadarTrackCallback() { @Override - public void onComplete(final Radar.RadarStatus status, final Location location, final RadarEvent[] events, final RadarUser user) { + public void onComplete(final Radar.RadarStatus status, final Location location, final RadarEvent[] events, + final RadarUser user) { runOnMainThread(new Runnable() { @Override public void run() { @@ -505,7 +576,7 @@ public void run() { if (user != null) { obj.put("user", user.toJson()); } - + HashMap map = new Gson().fromJson(obj.toString(), HashMap.class); result.success(map); } catch (Exception e) { @@ -515,17 +586,17 @@ public void run() { }); } }; - - if (call.hasArgument("location") && call.argument("location") != null) { - HashMap locationMap = (HashMap)call.argument("location"); + + HashMap locationMap = getHashMapFromMethodCall(call, "location"); + if (locationMap != null) { Location location = locationForMap(locationMap); Radar.trackOnce(location, callback); } else { RadarTrackingOptions.RadarTrackingOptionsDesiredAccuracy accuracyLevel = RadarTrackingOptions.RadarTrackingOptionsDesiredAccuracy.MEDIUM; - boolean beaconsTrackingOption = false; - - if (call.hasArgument("desiredAccuracy") && call.argument("desiredAccuracy") != null) { - String desiredAccuracy = ((String)call.argument("desiredAccuracy")).toLowerCase(); + boolean beaconsTrackingOption = getBooleanFromMethodCall(call, "beacons", false); + String desiredAccuracy = (getStringFromMethodCall(call, "desiredAccuracy")); + if (desiredAccuracy != null){ + desiredAccuracy = desiredAccuracy.toLowerCase(); if (desiredAccuracy.equals("none")) { accuracyLevel = RadarTrackingOptions.RadarTrackingOptionsDesiredAccuracy.NONE; } else if (desiredAccuracy.equals("low")) { @@ -536,16 +607,13 @@ public void run() { accuracyLevel = RadarTrackingOptions.RadarTrackingOptionsDesiredAccuracy.HIGH; } } - if (call.hasArgument("beacons") && call.argument("beacons") != null) { - beaconsTrackingOption = call.argument("beacons"); - } - + Radar.trackOnce(accuracyLevel, beaconsTrackingOption, callback); } - } + } private void startTracking(MethodCall call, Result result) { - String preset = call.argument("preset"); + String preset = getStringFromMethodCall(call, "preset"); if (preset == null) { Radar.startTracking(RadarTrackingOptions.RESPONSIVE); } else if (preset.equals("continuous")) { @@ -561,7 +629,7 @@ private void startTracking(MethodCall call, Result result) { } private void startTrackingCustom(MethodCall call, Result result) { - HashMap optionsMap = (HashMap)call.arguments; + HashMap optionsMap = (HashMap) call.arguments; JSONObject optionsJson = new JSONObject(optionsMap); RadarTrackingOptions options = RadarTrackingOptions.fromJson(optionsJson); Radar.startTracking(options); @@ -569,34 +637,41 @@ private void startTrackingCustom(MethodCall call, Result result) { } private void startTrackingVerified(MethodCall call, Result result) { - Boolean token = call.hasArgument("token") ? call.argument("token") : false; - int interval = call.hasArgument("interval") && call.argument("interval") != null ? (int)call.argument("interval") : 1; - Boolean beacons = call.hasArgument("beacons") ? call.argument("beacons") : false; - Radar.startTrackingVerified(token, interval, beacons); + int interval = getIntFromMethodCall(call, "interval", 1); + Boolean beacons = getBooleanFromMethodCall(call, "beacons", false); + Radar.startTrackingVerified(interval, beacons); + result.success(true); + } + + private void stopTrackingVerified(MethodCall call, Result result) { + Radar.stopTrackingVerified(); result.success(true); } public void mockTracking(MethodCall call, final Result result) { - HashMap originMap = (HashMap)call.argument("origin"); + HashMap originMap = getHashMapFromMethodCall(call, "origin"); Location origin = locationForMap(originMap); - HashMap destinationMap = (HashMap)call.argument("destination"); + HashMap destinationMap = getHashMapFromMethodCall(call, "destination"); Location destination = locationForMap(destinationMap); - String modeStr = call.argument("mode"); + String modeStr = getStringFromMethodCall(call, "mode"); Radar.RadarRouteMode mode = Radar.RadarRouteMode.CAR; - if (modeStr.equals("FOOT") || modeStr.equals("foot")) { - mode = Radar.RadarRouteMode.FOOT; - } else if (modeStr.equals("BIKE") || modeStr.equals("bike")) { - mode = Radar.RadarRouteMode.BIKE; - } else if (modeStr.equals("CAR") || modeStr.equals("car")) { - mode = Radar.RadarRouteMode.CAR; + if (modeStr != null) { + if (modeStr.equals("FOOT") || modeStr.equals("foot")) { + mode = Radar.RadarRouteMode.FOOT; + } else if (modeStr.equals("BIKE") || modeStr.equals("bike")) { + mode = Radar.RadarRouteMode.BIKE; + } else if (modeStr.equals("CAR") || modeStr.equals("car")) { + mode = Radar.RadarRouteMode.CAR; + } } - int steps = call.hasArgument("steps") ? (int)call.argument("steps") : 10; - int interval = call.hasArgument("interval") ? (int)call.argument("interval") : 1; + + int steps = getIntFromMethodCall(call, "steps", 10); + int interval = getIntFromMethodCall(call, "interval", 1); Radar.mockTracking(origin, destination, mode, steps, interval, new Radar.RadarTrackCallback() { @Override public void onComplete(Radar.RadarStatus status, Location location, RadarEvent[] events, RadarUser user) { - + } }); } @@ -611,21 +686,21 @@ private void isTracking(Result result) { result.success(isTracking); } - private void getTrackingOptions(Result result) throws JSONException { - RadarTrackingOptions options = Radar.getTrackingOptions(); + private void getTrackingOptions(Result result) throws JSONException { + RadarTrackingOptions options = Radar.getTrackingOptions(); JSONObject optionsJson = options.toJson(); HashMap optionsMap = null; if (optionsJson != null) { - optionsMap = new Gson().fromJson(optionsJson.toString(), HashMap.class); + optionsMap = new Gson().fromJson(optionsJson.toString(), HashMap.class); } result.success(optionsMap); } public void startTrip(MethodCall call, Result result) throws JSONException { - HashMap tripOptionsMap = (HashMap)call.argument("tripOptions"); + HashMap tripOptionsMap = getHashMapFromMethodCall(call, "tripOptions"); JSONObject tripOptionsJson = jsonForMap(tripOptionsMap); RadarTripOptions tripOptions = RadarTripOptions.fromJson(tripOptionsJson); - HashMap trackingOptionsMap = (HashMap)call.argument("trackingOptions"); + HashMap trackingOptionsMap = getHashMapFromMethodCall(call, "trackingOptions"); JSONObject trackingOptionsJson = jsonForMap(trackingOptionsMap); RadarTrackingOptions trackingOptions = null; if (trackingOptionsJson != null) { @@ -634,8 +709,8 @@ public void startTrip(MethodCall call, Result result) throws JSONException { Radar.startTrip(tripOptions, trackingOptions, new Radar.RadarTripCallback() { @Override public void onComplete(@NonNull Radar.RadarStatus status, - @Nullable RadarTrip trip, - @Nullable RadarEvent[] events) { + @Nullable RadarTrip trip, + @Nullable RadarEvent[] events) { runOnMainThread(new Runnable() { @Override public void run() { @@ -661,29 +736,31 @@ public void run() { } public void updateTrip(MethodCall call, Result result) throws JSONException { - HashMap tripOptionsMap = (HashMap)call.argument("tripOptions"); + HashMap tripOptionsMap = getHashMapFromMethodCall(call, "tripOptions"); JSONObject tripOptionsJson = jsonForMap(tripOptionsMap); RadarTripOptions tripOptions = RadarTripOptions.fromJson(tripOptionsJson); - String statusStr = call.argument("status"); + String statusStr = getStringFromMethodCall(call, "status"); RadarTrip.RadarTripStatus status = RadarTrip.RadarTripStatus.UNKNOWN; - statusStr = statusStr.toLowerCase(); - if (statusStr.equals("started")) { - status = RadarTrip.RadarTripStatus.STARTED; - } else if (statusStr.equals("approaching")) { - status = RadarTrip.RadarTripStatus.APPROACHING; - } else if (statusStr.equals("arrived")) { - status = RadarTrip.RadarTripStatus.ARRIVED; - } else if (statusStr.equals("completed")) { - status = RadarTrip.RadarTripStatus.COMPLETED; - } else if (statusStr.equals("canceled")) { - status = RadarTrip.RadarTripStatus.CANCELED; + if (statusStr != null){ + statusStr = statusStr.toLowerCase(); + if (statusStr.equals("started")) { + status = RadarTrip.RadarTripStatus.STARTED; + } else if (statusStr.equals("approaching")) { + status = RadarTrip.RadarTripStatus.APPROACHING; + } else if (statusStr.equals("arrived")) { + status = RadarTrip.RadarTripStatus.ARRIVED; + } else if (statusStr.equals("completed")) { + status = RadarTrip.RadarTripStatus.COMPLETED; + } else if (statusStr.equals("canceled")) { + status = RadarTrip.RadarTripStatus.CANCELED; + } } - + Radar.updateTrip(tripOptions, status, new Radar.RadarTripCallback() { @Override public void onComplete(@NonNull Radar.RadarStatus status, - @Nullable RadarTrip trip, - @Nullable RadarEvent[] events) { + @Nullable RadarTrip trip, + @Nullable RadarEvent[] events) { runOnMainThread(new Runnable() { @Override public void run() { @@ -710,7 +787,7 @@ public void run() { public void getTripOptions(Result result) { RadarTripOptions tripOptions = Radar.getTripOptions(); - HashMap map = new Gson().fromJson(tripOptions.toJson().toString(), HashMap.class); + HashMap map = new Gson().fromJson(tripOptions.toJson().toString(), HashMap.class); result.success(map); } @@ -718,8 +795,8 @@ public void completeTrip(Result result) { Radar.completeTrip(new Radar.RadarTripCallback() { @Override public void onComplete(@NonNull Radar.RadarStatus status, - @Nullable RadarTrip trip, - @Nullable RadarEvent[] events) { + @Nullable RadarTrip trip, + @Nullable RadarEvent[] events) { runOnMainThread(new Runnable() { @Override public void run() { @@ -748,8 +825,8 @@ public void cancelTrip(Result result) { Radar.cancelTrip(new Radar.RadarTripCallback() { @Override public void onComplete(@NonNull Radar.RadarStatus status, - @Nullable RadarTrip trip, - @Nullable RadarEvent[] events) { + @Nullable RadarTrip trip, + @Nullable RadarEvent[] events) { runOnMainThread(new Runnable() { @Override public void run() { @@ -774,10 +851,24 @@ public void run() { }); } + public void acceptEvent(MethodCall call, Result result) { + String eventId = getStringFromMethodCall(call, "eventId"); + String verifiedPlaceId = getStringFromMethodCall(call, "verifiedPlaceId"); + Radar.acceptEvent(eventId, verifiedPlaceId); + result.success(true); + } + + public void rejectEvent(MethodCall call, Result result) { + String eventId = getStringFromMethodCall(call, "eventId"); + Radar.rejectEvent(eventId); + result.success(true); + } + public void getContext(MethodCall call, final Result result) { Radar.RadarContextCallback callback = new Radar.RadarContextCallback() { @Override - public void onComplete(final Radar.RadarStatus status, final Location location, final RadarContext context) { + public void onComplete(final Radar.RadarStatus status, final Location location, + final RadarContext context) { runOnMainThread(new Runnable() { @Override public void run() { @@ -800,9 +891,8 @@ public void run() { }); } }; - - if (call.hasArgument("location")) { - HashMap locationMap = (HashMap)call.argument("location"); + HashMap locationMap = getHashMapFromMethodCall(call, "location"); + if (locationMap != null) { Location location = locationForMap(locationMap); Radar.getContext(location, callback); } else { @@ -813,7 +903,8 @@ public void run() { private void searchGeofences(MethodCall call, final Result result) throws JSONException { Radar.RadarSearchGeofencesCallback callback = new Radar.RadarSearchGeofencesCallback() { @Override - public void onComplete(final Radar.RadarStatus status, final Location location, final RadarGeofence[] geofences) { + public void onComplete(final Radar.RadarStatus status, final Location location, + final RadarGeofence[] geofences) { runOnMainThread(new Runnable() { @Override public void run() { @@ -838,21 +929,22 @@ public void run() { }; Location near = null; - if (call.hasArgument("near")) { - HashMap nearMap = (HashMap)call.argument("near"); + HashMap nearMap = getHashMapFromMethodCall(call, "near"); + if (nearMap != null) { near = locationForMap(nearMap); } - int radius = call.hasArgument("radius") ? (int)call.argument("radius") : 1000; - ArrayList tagsList = (ArrayList)call.argument("tags"); - String[] tags = (String[])tagsList.toArray(new String[0]); - HashMap metadataMap = (HashMap)call.argument("metadata"); + int radius = getIntFromMethodCall(call, "radius", 1000); + + String[] tags = getStringArrayFromMethodCall(call, "tags"); + HashMap metadataMap = getHashMapFromMethodCall(call, "metadata"); JSONObject metadata = jsonForMap(metadataMap); - int limit = call.hasArgument("limit") ? (int)call.argument("limit") : 10; + int limit = getIntFromMethodCall(call, "limit", 10); + boolean includeGeometry = getBooleanFromMethodCall(call, "includeGeometry", false); if (near != null) { - Radar.searchGeofences(near, radius, tags, metadata, limit, callback); + Radar.searchGeofences(near, radius, tags, metadata, limit, includeGeometry, callback); } else { - Radar.searchGeofences(radius, tags, metadata, limit, callback); + Radar.searchGeofences(radius, tags, metadata, limit, includeGeometry, callback); } } @@ -884,19 +976,16 @@ public void run() { }; Location near = null; - if (call.hasArgument("near")) { - HashMap nearMap = (HashMap)call.argument("near"); + HashMap nearMap = getHashMapFromMethodCall(call, "near"); + if (nearMap != null) { near = locationForMap(nearMap); } - int radius = call.hasArgument("radius") ? (int)call.argument("radius") : 1000; - ArrayList chainsList = (ArrayList)call.argument("chains"); - String[] chains = (String[])chainsList.toArray(new String[0]); - Map chainMetadata = (Map)call.argument("chainMetadata"); - ArrayList categoriesList = (ArrayList)call.argument("categories"); - String[] categories = categoriesList != null ? (String[])categoriesList.toArray(new String[0]) : new String[0]; - ArrayList groupsList = (ArrayList)call.argument("groups"); - String[] groups = groupsList != null ? (String[])groupsList.toArray(new String[0]) : new String[0]; - int limit = call.hasArgument("limit") ? (int)call.argument("limit") : 10; + int radius = getIntFromMethodCall(call, "radius", 1000); + String[] chains = getStringArrayFromMethodCall(call, "chains"); + Map chainMetadata = (Map) call.argument("chainMetadata"); + String[] categories = getStringArrayFromMethodCall(call, "categories"); + String[] groups = getStringArrayFromMethodCall(call, "groups"); + int limit = getIntFromMethodCall(call, "limit", 10); if (near != null) { Radar.searchPlaces(near, radius, chains, chainMetadata, categories, groups, limit, callback); @@ -906,14 +995,13 @@ public void run() { } public void autocomplete(MethodCall call, final Result result) { - String query = call.argument("query"); - HashMap nearMap = (HashMap)call.argument("near"); + String query = getStringFromMethodCall(call, "query"); + HashMap nearMap = getHashMapFromMethodCall(call, "near"); Location near = locationForMap(nearMap); - int limit = call.hasArgument("limit") ? (int)call.argument("limit") : 10; - String country = call.argument("country"); - ArrayList layersList = (ArrayList)call.argument("layers"); - String[] layers = layersList != null ? (String[])layersList.toArray(new String[0]) : new String[0]; - Boolean mailable = call.argument("mailable"); + int limit = getIntFromMethodCall(call, "limit", 10); + String country = getStringFromMethodCall(call, "country"); + String[] layers = getStringArrayFromMethodCall(call, "layers"); + Boolean mailable = getBooleanFromMethodCall(call, "mailable", false); Radar.autocomplete(query, near, layers, limit, country, true, mailable, new Radar.RadarGeocodeCallback() { @Override @@ -940,9 +1028,9 @@ public void run() { } public void geocode(MethodCall call, final Result result) { - String query = call.argument("query"); + String query = getStringFromMethodCall(call, "query"); - Radar.geocode(query, new Radar.RadarGeocodeCallback() { + Radar.geocode(query, null, null, new Radar.RadarGeocodeCallback() { @Override public void onComplete(final Radar.RadarStatus status, final RadarAddress[] addresses) { runOnMainThread(new Runnable() { @@ -954,7 +1042,7 @@ public void run() { if (addresses != null) { obj.put("addresses", RadarAddress.toJson(addresses)); } - + HashMap map = new Gson().fromJson(obj.toString(), HashMap.class); result.success(map); } catch (Exception e) { @@ -990,12 +1078,13 @@ public void run() { } }; - if (call.hasArgument("location")) { - HashMap locationMap = (HashMap)call.argument("location"); + String[] layers = getStringArrayFromMethodCall(call, "layers"); + HashMap locationMap = getHashMapFromMethodCall(call, "location"); + if (locationMap != null) { Location location = locationForMap(locationMap); - Radar.reverseGeocode(location, callback); + Radar.reverseGeocode(location, layers, callback); } else { - Radar.reverseGeocode(callback); + Radar.reverseGeocode(layers, callback); } } @@ -1050,15 +1139,14 @@ public void run() { }; Location origin = null; - if (call.hasArgument("origin")) { - HashMap originMap = (HashMap)call.argument("origin"); + HashMap originMap = getHashMapFromMethodCall(call, "origin"); + if (originMap != null) { origin = locationForMap(originMap); } - HashMap destinationMap = (HashMap)call.argument("destination"); + HashMap destinationMap = getHashMapFromMethodCall(call, "destination"); Location destination = locationForMap(destinationMap); EnumSet modes = EnumSet.noneOf(Radar.RadarRouteMode.class); - ArrayList modesList = call.argument("modes"); - String[] modesArr = (String[])(new String[0]); + String[] modesArr = getStringArrayFromMethodCall(call, "modes"); for (String modeStr : modesArr) { if (modeStr.equals("FOOT") || modeStr.equals("foot")) { modes.add(Radar.RadarRouteMode.FOOT); @@ -1070,8 +1158,10 @@ public void run() { modes.add(Radar.RadarRouteMode.CAR); } } - String unitsStr = call.argument("units"); - Radar.RadarRouteUnits units = unitsStr.equals("METRIC") || unitsStr.equals("metric") ? Radar.RadarRouteUnits.METRIC : Radar.RadarRouteUnits.IMPERIAL; + String unitsStr = getStringFromMethodCall(call, "units"); + Radar.RadarRouteUnits units = unitsStr.equals("METRIC") || unitsStr.equals("metric") + ? Radar.RadarRouteUnits.METRIC + : Radar.RadarRouteUnits.IMPERIAL; if (origin != null) { Radar.getDistance(origin, destination, modes, units, callback); @@ -1080,7 +1170,7 @@ public void run() { } } - public void logConversion(MethodCall call, final Result result) throws JSONException { + public void logConversion(MethodCall call, final Result result) throws JSONException { Radar.RadarLogConversionCallback callback = new Radar.RadarLogConversionCallback() { @Override public void onComplete(@NonNull Radar.RadarStatus status, @Nullable RadarEvent event) { @@ -1093,7 +1183,7 @@ public void run() { if (event != null) { obj.put("event", event.toJson()); } - + HashMap map = new Gson().fromJson(obj.toString(), HashMap.class); result.success(map); } catch (Exception e) { @@ -1104,11 +1194,14 @@ public void run() { } }; - String name = call.argument("name"); - HashMap metadataMap= call.argument("metadata"); - JSONObject metadataJson = jsonForMap(metadataMap); + String name = getStringFromMethodCall(call, "name"); + JSONObject metadataJson = null; + HashMap metadataMap = getHashMapFromMethodCall(call, "metadata"); + if (metadataMap == null) { + metadataJson = jsonForMap(metadataMap); + } if (call.hasArgument("revenue") && call.argument("revenue") != null) { - double revenue = (Double)call.argument("revenue"); + double revenue = (Double) call.argument("revenue"); Radar.logConversion(name, revenue, metadataJson, callback); } else { Radar.logConversion(name, metadataJson, callback); @@ -1126,7 +1219,7 @@ public void logResigningActive(Result result) { } public void getMatrix(MethodCall call, final Result result) throws JSONException { - ArrayList originsArr = call.argument("origins"); + ArrayList originsArr = call.argument("origins"); Location[] origins = new Location[originsArr.size()]; for (int i = 0; i < originsArr.size(); i++) { origins[i] = locationForMap(originsArr.get(i)); @@ -1136,11 +1229,11 @@ public void getMatrix(MethodCall call, final Result result) throws JSONException for (int i = 0; i < destinationsArr.size(); i++) { destinations[i] = locationForMap(destinationsArr.get(i)); } - String modeStr = call.argument("mode"); + String modeStr = getStringFromMethodCall(call, "mode"); Radar.RadarRouteMode mode = Radar.RadarRouteMode.CAR; if (modeStr != null) { modeStr = modeStr.toLowerCase(); - if ( modeStr.equals("foot")) { + if (modeStr.equals("foot")) { mode = Radar.RadarRouteMode.FOOT; } else if (modeStr.equals("bike")) { mode = Radar.RadarRouteMode.BIKE; @@ -1152,8 +1245,10 @@ public void getMatrix(MethodCall call, final Result result) throws JSONException mode = Radar.RadarRouteMode.MOTORBIKE; } } - String unitsStr = call.argument("units"); - Radar.RadarRouteUnits units = unitsStr != null && unitsStr.toLowerCase().equals("metric") ? Radar.RadarRouteUnits.METRIC : Radar.RadarRouteUnits.IMPERIAL; + String unitsStr = getStringFromMethodCall(call, "units"); + Radar.RadarRouteUnits units = unitsStr != null && unitsStr.toLowerCase().equals("metric") + ? Radar.RadarRouteUnits.METRIC + : Radar.RadarRouteUnits.IMPERIAL; Radar.getMatrix(origins, destinations, mode, units, new Radar.RadarMatrixCallback() { @Override @@ -1180,24 +1275,18 @@ public void run() { } public void trackVerified(MethodCall call, final Result result) { - Boolean beacons = call.hasArgument("beacons") ? call.argument("beacons") : false; + Boolean beacons = getBooleanFromMethodCall(call, "beacons", false); - Radar.RadarTrackCallback callback = new Radar.RadarTrackCallback() { + Radar.RadarTrackVerifiedCallback callback = new Radar.RadarTrackVerifiedCallback() { @Override - public void onComplete(final Radar.RadarStatus status, final Location location, final RadarEvent[] events, final RadarUser user) { + public void onComplete(final Radar.RadarStatus status, final RadarVerifiedLocationToken token) { runOnMainThread(new Runnable() { @Override public void run() { try { JSONObject obj = new JSONObject(); obj.put("status", status.toString()); - if (location != null) { - obj.put("location", Radar.jsonForLocation(location)); - } - obj.put("events", RadarEvent.toJson(events)); - if ( user != null) { - obj.put("user", user.toJson()); - } + obj.put("token", token.toJson()); HashMap map = new Gson().fromJson(obj.toString(), HashMap.class); result.success(map); @@ -1212,33 +1301,6 @@ public void run() { Radar.trackVerified(beacons, callback); } - public void trackVerifiedToken(MethodCall call, final Result result) { - Boolean beacons = call.hasArgument("beacons") ? call.argument("beacons") : false; - - Radar.RadarTrackTokenCallback callback = new Radar.RadarTrackTokenCallback() { - @Override - public void onComplete(final Radar.RadarStatus status, final String token) { - runOnMainThread(new Runnable() { - @Override - public void run() { - try { - JSONObject obj = new JSONObject(); - obj.put("status", status.toString()); - obj.put("token", token); - - HashMap map = new Gson().fromJson(obj.toString(), HashMap.class); - result.success(map); - } catch (Exception e) { - result.error(e.toString(), e.getMessage(), e.getMessage()); - } - } - }); - } - }; - - Radar.trackVerifiedToken(beacons, callback); - } - private void isUsingRemoteTrackingOptions(Result result) { Boolean isRemoteTracking = Radar.isUsingRemoteTrackingOptions(); result.success(isRemoteTracking); @@ -1247,7 +1309,8 @@ private void isUsingRemoteTrackingOptions(Result result) { public void validateAddress(MethodCall call, final Result result) throws JSONException { Radar.RadarValidateAddressCallback callback = new Radar.RadarValidateAddressCallback() { @Override - public void onComplete(final Radar.RadarStatus status, final RadarAddress address, final Radar.RadarAddressVerificationStatus verificationStatus) { + public void onComplete(final Radar.RadarStatus status, final RadarAddress address, + final Radar.RadarAddressVerificationStatus verificationStatus) { runOnMainThread(new Runnable() { @Override public void run() { @@ -1271,21 +1334,21 @@ public void run() { } }; - HashMap addressMap= call.argument("address"); + HashMap addressMap = getHashMapFromMethodCall(call, "address"); JSONObject addressJSON = jsonForMap(addressMap); RadarAddress address = RadarAddress.fromJson(addressJSON); Radar.validateAddress(address, callback); } private Location locationForMap(HashMap locationMap) { - double latitude = (Double)locationMap.get("latitude"); - double longitude = (Double)locationMap.get("longitude"); + double latitude = (Double) locationMap.get("latitude"); + double longitude = (Double) locationMap.get("longitude"); Location location = new Location("RadarSDK"); location.setLatitude(latitude); location.setLongitude(longitude); if (locationMap.containsKey("accuracy")) { - double accuracyDouble = (Double)locationMap.get("accuracy"); - float accuracy = (float)accuracyDouble; + double accuracyDouble = (Double) locationMap.get("accuracy"); + float accuracy = (float) accuracyDouble; location.setAccuracy(accuracy); } return location; @@ -1307,31 +1370,28 @@ private JSONObject jsonForMap(HashMap map) throws JSONException { public static class RadarFlutterReceiver extends RadarReceiver { + private MethodChannel channel; + + RadarFlutterReceiver(MethodChannel channel) { + this.channel = channel; + } + @Override public void onEventsReceived(Context context, RadarEvent[] events, RadarUser user) { try { - SharedPreferences sharedPrefs = context.getSharedPreferences(TAG, Context.MODE_PRIVATE); - long callbackHandle = sharedPrefs.getLong("events", 0L); - - if (callbackHandle == 0L) { - return; - } - - RadarFlutterPlugin.initializeBackgroundEngine(context); - JSONObject obj = new JSONObject(); obj.put("events", RadarEvent.toJson(events)); obj.put("user", user.toJson()); HashMap res = new Gson().fromJson(obj.toString(), HashMap.class); + final ArrayList eventsArgs = new ArrayList(); + eventsArgs.add(0); + eventsArgs.add(res); synchronized(lock) { - final ArrayList args = new ArrayList(); - args.add(callbackHandle); - args.add(res); runOnMainThread(new Runnable() { @Override public void run() { - sBackgroundChannel.invokeMethod("", args); + channel.invokeMethod("events", eventsArgs); } }); } @@ -1339,33 +1399,24 @@ public void run() { Log.e(TAG, e.toString()); } } - + @Override public void onLocationUpdated(Context context, Location location, RadarUser user) { try { - SharedPreferences sharedPrefs = context.getSharedPreferences(TAG, Context.MODE_PRIVATE); - long callbackHandle = sharedPrefs.getLong("location", 0L); - - if (callbackHandle == 0L) { - Log.e(TAG, "callback handle is empty"); - return; - } - - RadarFlutterPlugin.initializeBackgroundEngine(context); - JSONObject obj = new JSONObject(); obj.put("location", Radar.jsonForLocation(location)); obj.put("user", user.toJson()); HashMap res = new Gson().fromJson(obj.toString(), HashMap.class); + + final ArrayList locationArgs = new ArrayList(); + locationArgs.add(0); + locationArgs.add(res); synchronized(lock) { - final ArrayList args = new ArrayList(); - args.add(callbackHandle); - args.add(res); runOnMainThread(new Runnable() { @Override public void run() { - sBackgroundChannel.invokeMethod("", args); + channel.invokeMethod("location", locationArgs); } }); } @@ -1374,31 +1425,23 @@ public void run() { } } - public void onClientLocationUpdated(Context context, Location location, boolean stopped, Radar.RadarLocationSource source) { + public void onClientLocationUpdated(Context context, Location location, boolean stopped, + Radar.RadarLocationSource source) { try { - SharedPreferences sharedPrefs = context.getSharedPreferences(TAG, Context.MODE_PRIVATE); - long callbackHandle = sharedPrefs.getLong("clientLocation", 0L); - - if (callbackHandle == 0L) { - return; - } - - RadarFlutterPlugin.initializeBackgroundEngine(context); - JSONObject obj = new JSONObject(); obj.put("location", Radar.jsonForLocation(location)); obj.put("stopped", stopped); obj.put("source", source.toString()); HashMap res = new Gson().fromJson(obj.toString(), HashMap.class); - synchronized(lock) { - final ArrayList args = new ArrayList(); - args.add(callbackHandle); - args.add(res); + final ArrayList clientLocationArgs = new ArrayList(); + clientLocationArgs.add(0); + clientLocationArgs.add(res); + synchronized(lock){ runOnMainThread(new Runnable() { @Override public void run() { - sBackgroundChannel.invokeMethod("", args); + channel.invokeMethod("clientLocation", clientLocationArgs); } }); } @@ -1406,31 +1449,22 @@ public void run() { Log.e(TAG, e.toString()); } } - + @Override public void onError(Context context, Radar.RadarStatus status) { try { - SharedPreferences sharedPrefs = context.getSharedPreferences(TAG, Context.MODE_PRIVATE); - long callbackHandle = sharedPrefs.getLong("error", 0L); - - if (callbackHandle == 0L) { - return; - } - - RadarFlutterPlugin.initializeBackgroundEngine(context); - JSONObject obj = new JSONObject(); obj.put("status", status.toString()); HashMap res = new Gson().fromJson(obj.toString(), HashMap.class); - synchronized(lock) { - final ArrayList args = new ArrayList(); - args.add(callbackHandle); - args.add(res); + final ArrayList errorArgs = new ArrayList(); + errorArgs.add(0); + errorArgs.add(res); + synchronized(lock){ runOnMainThread(new Runnable() { @Override public void run() { - sBackgroundChannel.invokeMethod("", args); + channel.invokeMethod("error", errorArgs); } }); } @@ -1438,31 +1472,22 @@ public void run() { Log.e(TAG, e.toString()); } } - + @Override public void onLog(Context context, String message) { try { - SharedPreferences sharedPrefs = context.getSharedPreferences(TAG, Context.MODE_PRIVATE); - long callbackHandle = sharedPrefs.getLong("log", 0L); - - if (callbackHandle == 0L) { - return; - } - - RadarFlutterPlugin.initializeBackgroundEngine(context); - JSONObject obj = new JSONObject(); obj.put("message", message); HashMap res = new Gson().fromJson(obj.toString(), HashMap.class); + final ArrayList logArgs = new ArrayList(); + logArgs.add(0); + logArgs.add(res); synchronized(lock) { - final ArrayList args = new ArrayList(); - args.add(callbackHandle); - args.add(res); runOnMainThread(new Runnable() { @Override public void run() { - sBackgroundChannel.invokeMethod("", args); + channel.invokeMethod("log", logArgs); } }); } @@ -1470,72 +1495,39 @@ public void run() { Log.e(TAG, e.toString()); } } - } public static class RadarFlutterVerifiedReceiver extends RadarVerifiedReceiver { - @Override - public void onTokenUpdated(Context context, String token) { - try { - SharedPreferences sharedPrefs = context.getSharedPreferences(TAG, Context.MODE_PRIVATE); - long callbackHandle = sharedPrefs.getLong("token", 0L); + private MethodChannel channel; - if (callbackHandle == 0L) { - return; - } + RadarFlutterVerifiedReceiver(MethodChannel channel) { + this.channel = channel; + } - RadarFlutterPlugin.initializeBackgroundEngine(context); - + @Override + public void onTokenUpdated(Context context, RadarVerifiedLocationToken token) { + try { JSONObject obj = new JSONObject(); - obj.put("token", token); + obj.put("token", token.toJson()); HashMap res = new Gson().fromJson(obj.toString(), HashMap.class); + final ArrayList tokenArgs = new ArrayList(); + tokenArgs.add(0); + tokenArgs.add(res); synchronized(lock) { - final ArrayList args = new ArrayList(); - args.add(callbackHandle); - args.add(res); runOnMainThread(new Runnable() { @Override public void run() { - sBackgroundChannel.invokeMethod("", args); + channel.invokeMethod("token", tokenArgs); } }); } + } catch (Exception e) { Log.e(TAG, e.toString()); } } } - - public void attachListeners(MethodCall call, Result result) { - SharedPreferences sharedPrefs = mContext.getSharedPreferences(TAG, Context.MODE_PRIVATE); - long callbackDispatcherHandle = ((Number)call.argument("callbackDispatcherHandle")).longValue(); - sharedPrefs.edit().putLong(CALLBACK_DISPATCHER_HANDLE_KEY, callbackDispatcherHandle).commit(); - result.success(true); - } - - public void detachListeners(MethodCall call, Result result) { - SharedPreferences sharedPrefs = mContext.getSharedPreferences(TAG, Context.MODE_PRIVATE); - long callbackDispatcherHandle = call.argument("callbackDispatcherHandle"); - sharedPrefs.edit().putLong(CALLBACK_DISPATCHER_HANDLE_KEY, 0L).commit(); - result.success(true); - } - - public void on(MethodCall call, Result result) { - SharedPreferences sharedPrefs = mContext.getSharedPreferences(TAG, Context.MODE_PRIVATE); - String listener = call.argument("listener"); - long callbackHandle = ((Number)call.argument("callbackHandle")).longValue(); - sharedPrefs.edit().putLong(listener, callbackHandle).commit(); - result.success(true); - } - - public void off(MethodCall call, Result result) { - SharedPreferences sharedPrefs = mContext.getSharedPreferences(TAG, Context.MODE_PRIVATE); - String listener = call.argument("listener"); - sharedPrefs.edit().putLong(listener, 0L).commit(); - result.success(true); - } - }; diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index fb4140f..753b4d0 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -34,7 +34,7 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "io.radar.example" - minSdkVersion 16 + minSdkVersion flutter.minSdkVersion targetSdkVersion 29 versionCode flutterVersionCode.toInteger() versionName flutterVersionName @@ -49,7 +49,7 @@ android { } dependencies { - implementation 'io.radar:sdk:3.9.8' + implementation 'io.radar:sdk:3.16.1-beta.1' implementation "com.google.android.play:integrity:1.2.0" } } diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index e97e15c..142a98c 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -52,4 +52,6 @@ + + diff --git a/example/android/build.gradle b/example/android/build.gradle index 21d7749..9881192 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -24,6 +24,6 @@ subprojects { project.evaluationDependsOn(':app') } -task clean(type: Delete) { +tasks.register("clean", Delete) { delete rootProject.buildDir } diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist index 4f8d4d2..8c6e561 100644 --- a/example/ios/Flutter/AppFrameworkInfo.plist +++ b/example/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 11.0 + 12.0 diff --git a/example/ios/Podfile b/example/ios/Podfile index bfd60c4..b331c7b 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -platform :ios, '11.0' +platform :ios, '12.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 3c16ff9..6f58db5 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -149,6 +149,7 @@ 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 717FBB0054865DEA34CA9827 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -165,7 +166,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -208,10 +209,12 @@ /* Begin PBXShellScriptBuildPhase section */ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( @@ -220,6 +223,23 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin\n"; }; + 717FBB0054865DEA34CA9827 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; 8AED107CD2EAE06C6755A899 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -244,6 +264,7 @@ }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -347,7 +368,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = U6493D9J45; + DEVELOPMENT_TEAM = 96GHH65B9D; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -480,7 +501,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = U6493D9J45; + DEVELOPMENT_TEAM = 96GHH65B9D; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -508,7 +529,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = U6493D9J45; + DEVELOPMENT_TEAM = 96GHH65B9D; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 3db53b6..e67b280 100644 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ Your iOS 10 and lower background location usage description goes here. e.g., "This app uses your location in the background to recommend places nearby." NSLocationWhenInUseUsageDescription Your foreground location usage description goes here. e.g., "This app uses your location in the foreground to recommend places nearby." + NSMotionUsageDescription + Your motion usage description goes here. UIBackgroundModes fetch @@ -78,5 +80,7 @@ + UIApplicationSupportsIndirectInputEvents + diff --git a/example/lib/main.dart b/example/lib/main.dart index 4cbeaaa..9634308 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,11 +1,10 @@ import 'package:flutter/material.dart'; import 'dart:async'; import 'package:flutter_radar/flutter_radar.dart'; +import 'package:permission_handler/permission_handler.dart'; void main() => runApp(MyApp()); - - class MyApp extends StatefulWidget { @override _MyAppState createState() => _MyAppState(); @@ -68,14 +67,13 @@ class _MyAppState extends State with WidgetsBindingObserver { } Future initRadar() async { - Radar.initialize('prj_test_pk_0000000000000000000000000000000000000000'); - Radar.setUserId('flutter'); - Radar.setDescription('Flutter'); - Radar.setMetadata({'foo': 'bar', 'bax': true, 'qux': 1}); - Radar.setLogLevel('info'); - Radar.setAnonymousTrackingEnabled(false); - - Radar.attachListeners(); + Radar.initialize( + publishableKey: 'prj_test_pk_0000000000000000000000000000000000000000'); + Radar.setUserId(userId: 'flutter'); + Radar.setDescription(description: 'Flutter'); + Radar.setMetadata(metadata: {'foo': 'bar', 'bax': true, 'qux': 1}); + Radar.setLogLevel(logLevel: 'info'); + Radar.setAnonymousTrackingEnabled(enabled: false); Radar.onLocation(onLocation); Radar.onClientLocation(onClientLocation); @@ -84,13 +82,13 @@ class _MyAppState extends State with WidgetsBindingObserver { Radar.onLog(onLog); Radar.onToken(onToken); - await Radar.requestPermissions(false); - - await Radar.requestPermissions(true); + await Radar.requestPermissions(background: false); + + await Radar.requestPermissions(background: true); var permissionStatus = await Radar.getPermissionsStatus(); if (permissionStatus != "DENIED") { - var b = await Radar.startTrackingCustom({ - ... Radar.presetResponsive, + var b = await Radar.startTrackingCustom(options: { + ...Radar.presetResponsive, "showBlueBar": true, }); //Radar.startTracking('continuous'); @@ -102,316 +100,396 @@ class _MyAppState extends State with WidgetsBindingObserver { @override Widget build(BuildContext context) { - return MaterialApp( home: Scaffold( appBar: AppBar( title: const Text('flutter_radar_example'), ), body: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: Container( - child: Column(children: [ - Permissions(), - TrackOnce(), - ElevatedButton( - style: raisedButtonStyle, - onPressed: () async { - var status = await Radar.requestPermissions(false); - print(status); - if (status == 'GRANTED_FOREGROUND') { - status = await Radar.requestPermissions(true); + scrollDirection: Axis.vertical, + child: Container( + child: Column(children: [ + Permissions(), + TrackOnce(), + ElevatedButton( + style: raisedButtonStyle, + onPressed: () async { + var status = + await Radar.requestPermissions(background: false); print(status); - } - }, - child: Text('requestPermissions()'), - ), - ElevatedButton( - style: raisedButtonStyle, - onPressed: () async { - Radar.setForegroundServiceOptions({ - 'title': 'Tracking', - 'text': 'Trip tracking started', - 'icon': 2131165271, - 'importance': 2, - 'updatesOnly': false, - 'activity': 'io.radar.example.MainActivity' - }); - var resp = await Radar.startTrip( - tripOptions: { + if (status == 'GRANTED_FOREGROUND') { + status = await Radar.requestPermissions(background: true); + print(status); + } + }, + child: Text('requestPermissions()'), + ), + ElevatedButton( + style: raisedButtonStyle, + onPressed: () async { + Radar.setForegroundServiceOptions(foregroundServiceOptions: { + 'title': 'Tracking', + 'text': 'Trip tracking started', + 'icon': 2131165271, + 'importance': 2, + 'updatesOnly': false, + 'activity': 'io.radar.example.MainActivity' + }); + var resp = await Radar.startTrip(tripOptions: { "externalId": '299', "destinationGeofenceTag": 'store', "destinationGeofenceExternalId": '123', "mode": 'car', "scheduledArrivalAt": "2020-08-20T10:30:55.837Z", "metadata": {"test": 123} - }, - trackingOptions: { - "desiredStoppedUpdateInterval": 30, - "fastestStoppedUpdateInterval": 30, - "desiredMovingUpdateInterval": 30, - "fastestMovingUpdateInterval": 30, - "desiredSyncInterval": 20, - "desiredAccuracy": "high", - "stopDuration": 0, - "stopDistance": 0, - "replay": "none", - "sync": "all", - "showBlueBar": true, - "useStoppedGeofence": false, - "stoppedGeofenceRadius": 0, - "useMovingGeofence": false, - "movingGeofenceRadius": 0, - "syncGeofences": false, - "syncGeofencesLimit": 0, - "beacons": false, - "foregroundServiceEnabled": true - } - ); - print("startTrip: $resp"); - }, - child: Text('startTrip'), - ), - ElevatedButton( - style: raisedButtonStyle, - onPressed: () async { - var resp = await Radar.completeTrip(); - print("completeTrip: $resp"); - }, - child: Text('completeTrip'), - ), - ElevatedButton( - style: raisedButtonStyle, - onPressed: () async { - var resp = await Radar.cancelTrip(); - print("cancelTrip: $resp"); - }, - child: Text('cancelTrip'), - ), - ElevatedButton( - style: raisedButtonStyle, - onPressed: () async { - var resp = await Radar.getTrackingOptions(); - print("getTrackingOptions: $resp"); - }, - child: Text('getTrackingOptions'), - ), - ElevatedButton( - style: raisedButtonStyle, - onPressed: () async { - var resp = await Radar.updateTrip( - status:'arrived', - options: { - "externalId": '299', - "metadata": { - "parkingSpot": '5' - } + }, trackingOptions: { + "desiredStoppedUpdateInterval": 30, + "fastestStoppedUpdateInterval": 30, + "desiredMovingUpdateInterval": 30, + "fastestMovingUpdateInterval": 30, + "desiredSyncInterval": 20, + "desiredAccuracy": "high", + "stopDuration": 0, + "stopDistance": 0, + "replay": "none", + "sync": "all", + "showBlueBar": true, + "useStoppedGeofence": false, + "stoppedGeofenceRadius": 0, + "useMovingGeofence": false, + "movingGeofenceRadius": 0, + "syncGeofences": false, + "syncGeofencesLimit": 0, + "beacons": false, + "foregroundServiceEnabled": true + }); + print("startTrip: $resp"); + }, + child: Text('startTrip'), + ), + ElevatedButton( + style: raisedButtonStyle, + onPressed: () async { + var resp = await Radar.completeTrip(); + print("completeTrip: $resp"); + }, + child: Text('completeTrip'), + ), + ElevatedButton( + style: raisedButtonStyle, + onPressed: () async { + PermissionStatus status = + await Permission.activityRecognition.request(); + if (status.isGranted) { + print('Permission granted'); + } else { + print('Permission denied'); } - ); - print("updateTrip: $resp"); - }, - child: Text('updateTrip'), - ), - ElevatedButton( - style: raisedButtonStyle, - onPressed: () async { - var resp = await Radar.logConversion( - name: "in_app_purchase", - revenue: 0.2, - metadata: {"price": "150USD"}); - print("logConversion: $resp"); - }, - child: Text('logConversion'), - ), - ElevatedButton( - style: raisedButtonStyle, - onPressed: () async { - await Radar.setNotificationOptions({ - 'iconString': 'icon' - }); - }, - child: Text('setNotificationOptions'), - ), - ElevatedButton( - style: raisedButtonStyle, - onPressed: () async { - var resp = await Radar.searchPlaces( - near: { - 'latitude': 40.783826, - 'longitude': -73.975363, - }, - radius: 1000, - chains: ["starbucks"], - chainMetadata: { - "customFlag": "true" - }, - limit: 10, - ); - print("searchPlaces: $resp"); - }, - child: Text('searchPlaces'), - ), - ElevatedButton( - style: raisedButtonStyle, - onPressed: () async { - var resp = await Radar.autocomplete( - query: 'brooklyn roasting', - near: { - 'latitude': 40.783826, - 'longitude': -73.975363, - }, - limit: 10, - layers: ['address', 'street'], - country: 'US', - mailable: false - ); - print("autocomplete: $resp"); - }, - child: Text('autocomplete'), - ), - ElevatedButton( - style: raisedButtonStyle, - onPressed: () async { - var resp = await Radar.getMatrix( - origins: [ - { - 'latitude': 40.78382, - 'longitude': -73.97536, - }, - { - 'latitude': 40.70390, - 'longitude': -73.98670, - }, - ], - destinations: [ - { - 'latitude': 40.64189, - 'longitude': -73.78779, + }, + child: Text('request activity permissions'), + ), + ElevatedButton( + style: raisedButtonStyle, + onPressed: () async { + var resp = await Radar.cancelTrip(); + print("cancelTrip: $resp"); + }, + child: Text('cancelTrip'), + ), + ElevatedButton( + style: raisedButtonStyle, + onPressed: () async { + var resp = await Radar.getTrackingOptions(); + print("getTrackingOptions: $resp"); + }, + child: Text('getTrackingOptions'), + ), + ElevatedButton( + style: raisedButtonStyle, + onPressed: () async { + var resp = + await Radar.updateTrip(status: 'arrived', options: { + "externalId": '299', + "metadata": {"parkingSpot": '5'} + }); + print("updateTrip: $resp"); + }, + child: Text('updateTrip'), + ), + ElevatedButton( + style: raisedButtonStyle, + onPressed: () async { + var resp = await Radar.logConversion( + name: "in_app_purchase", + revenue: 0.2, + metadata: {"price": "150USD"}); + print("logConversion: $resp"); + }, + child: Text('logConversion'), + ), + ElevatedButton( + style: raisedButtonStyle, + onPressed: () async { + await Radar.setNotificationOptions( + notificationOptions: {'iconString': 'icon'}); + }, + child: Text('setNotificationOptions'), + ), + ElevatedButton( + style: raisedButtonStyle, + onPressed: () async { + var resp = await Radar.searchPlaces( + radius: 1000, + limit: 10, + near: { + 'latitude': 40.783826, + 'longitude': -73.975363, }, - { - 'latitude': 35.99801, - 'longitude': -78.94294, + chains: ["starbucks"], + chainMetadata: {"customFlag": "true"}, + ); + print("searchPlaces: $resp"); + }, + child: Text('searchPlaces()'), + ), + ElevatedButton( + style: raisedButtonStyle, + onPressed: () async { + var resp = await Radar.searchGeofences( + near: { + 'latitude': 40.783826, + 'longitude': -73.975363, }, - ], - mode: 'car', - units: 'imperial', - ); - print("getMatrix: $resp"); - }, - child: Text('getMatrix'), - ), - ElevatedButton( - style: raisedButtonStyle, - onPressed: () { - Radar.startTracking('responsive'); - }, - child: Text('startTracking(\'responsive\')'), - ), - ElevatedButton( - style: raisedButtonStyle, - onPressed: () { - - Radar.setForegroundServiceOptions({ - 'title': 'Tracking', - 'text': 'Continuous tracking started', - 'icon': 2131165271, - 'importance': 2, - 'updatesOnly': false, - 'activity': 'io.radar.example.MainActivity' - }); - Radar.startTrackingCustom({ - 'desiredStoppedUpdateInterval': 120, - 'fastestStoppedUpdateInterval': 120, - 'desiredMovingUpdateInterval': 30, - 'fastestMovingUpdateInterval': 30, - 'desiredSyncInterval': 20, - 'desiredAccuracy': 'high', - 'stopDuration': 140, - 'stopDistance': 70, - 'sync': 'all', - 'replay': 'none', - 'showBlueBar': true, - 'foregroundServiceEnabled': true - }); - }, - child: Text('startTrackingCustom()'), - ), - ElevatedButton( - style: raisedButtonStyle, - onPressed: () { - Radar.startTrackingVerified(token: true); - }, - child: Text('startTrackingVerified(token: true)'), - ), - ElevatedButton( - style: raisedButtonStyle, - onPressed: () { - Radar.stopTracking(); - }, - child: Text('stopTracking()'), - ), - ElevatedButton( - style: raisedButtonStyle, - onPressed: () { - Radar.mockTracking( - origin: {'latitude': 40.78382, 'longitude': -73.97536}, - destination: {'latitude': 40.70390, 'longitude': -73.98670}, + radius: 1000, + limit: 10, + includeGeometry: true, + tags: List.empty(), + metadata: {}, + ); + print("searchGeofences: $resp"); + }, + child: Text('searchGeofences()'), + ), + ElevatedButton( + style: raisedButtonStyle, + onPressed: () async { + var resp = await Radar.geocode( + query: '20 jay st brooklyn', + ); + print("geocode: $resp"); + }, + child: Text('geocode()'), + ), + ElevatedButton( + style: raisedButtonStyle, + onPressed: () async { + var resp = await Radar.reverseGeocode(); + print("reverseGeocode: $resp"); + }, + child: Text('reverseGeocode()'), + ), + ElevatedButton( + style: raisedButtonStyle, + onPressed: () async { + var resp = await Radar.autocomplete( + query: 'brooklyn roasting', + limit: 10, + near: { + 'latitude': 40.783826, + 'longitude': -73.975363, + }, + layers: ['address', 'street'], + country: 'US', + mailable: false); + print("autocomplete: $resp"); + }, + child: Text('autocomplete'), + ), + ElevatedButton( + style: raisedButtonStyle, + onPressed: () async { + var resp = await Radar.getMatrix( + origins: [ + { + 'latitude': 40.78382, + 'longitude': -73.97536, + }, + { + 'latitude': 40.70390, + 'longitude': -73.98670, + }, + ], + destinations: [ + { + 'latitude': 40.64189, + 'longitude': -73.78779, + }, + { + 'latitude': 35.99801, + 'longitude': -78.94294, + }, + ], mode: 'car', - steps: 3, - interval: 3); - }, - child: Text('mockTracking()'), - ), - ElevatedButton( - style: raisedButtonStyle, - onPressed: () async { - Map? location = await Radar.getLocation('high'); - print(location); - }, - child: Text('getLocation()'), - ), - ElevatedButton( - style: raisedButtonStyle, - onPressed: () async { - Map? resp = await Radar.trackVerified(); - print("trackVerified: $resp"); - }, - child: Text('trackVerified'), - ), - ElevatedButton( - style: raisedButtonStyle, - onPressed: () async { - Map? resp = await Radar.trackVerifiedToken(); - print("trackVerifiedToken: $resp"); - }, - child: Text('trackVerifiedToken'), - ), - ElevatedButton( - style: raisedButtonStyle, - onPressed: () async { - bool? resp = await Radar.isUsingRemoteTrackingOptions(); - print("isUsingRemoteTrackingOptions: $resp"); - }, - child: Text('isUsingRemoteTrackingOptions'), - ), - ElevatedButton( - style: raisedButtonStyle, - onPressed: () async { - Map? resp = await Radar.validateAddress({ - "city": "NEW YORK", - "stateCode": "NY", - "postalCode": "10003", - "countryCode": "US", - "street": "BROADWAY", - "number": "841", - }); - print("validateAddress: $resp"); - }, - child: Text('validateAddress'), - ), - ]), - ) - ), + units: 'imperial', + ); + print("getMatrix: $resp"); + }, + child: Text('getMatrix'), + ), + ElevatedButton( + style: raisedButtonStyle, + onPressed: () { + Radar.startTracking(preset: 'responsive'); + }, + child: Text('startTracking(\'responsive\')'), + ), + ElevatedButton( + style: raisedButtonStyle, + onPressed: () { + Radar.setForegroundServiceOptions(foregroundServiceOptions: { + 'title': 'Tracking', + 'text': 'Continuous tracking started', + 'icon': 2131165271, + 'importance': 2, + 'updatesOnly': false, + 'activity': 'io.radar.example.MainActivity' + }); + Radar.startTrackingCustom(options: { + 'desiredStoppedUpdateInterval': 120, + 'fastestStoppedUpdateInterval': 120, + 'desiredMovingUpdateInterval': 30, + 'fastestMovingUpdateInterval': 30, + 'desiredSyncInterval': 20, + 'desiredAccuracy': 'high', + 'stopDuration': 140, + 'stopDistance': 70, + 'sync': 'all', + 'replay': 'none', + 'showBlueBar': true, + 'foregroundServiceEnabled': true + }); + }, + child: Text('startTrackingCustom()'), + ), + ElevatedButton( + style: raisedButtonStyle, + onPressed: () { + Radar.startTrackingVerified(interval: 30, beacons: false); + }, + child: Text('startTrackingVerified()'), + ), + ElevatedButton( + style: raisedButtonStyle, + onPressed: () { + Radar.stopTrackingVerified(); + }, + child: Text('stopTrackingVerified()'), + ), + ElevatedButton( + style: raisedButtonStyle, + onPressed: () { + Radar.stopTracking(); + }, + child: Text('stopTracking()'), + ), + ElevatedButton( + style: raisedButtonStyle, + onPressed: () { + Radar.mockTracking(origin: { + 'latitude': 40.78382, + 'longitude': -73.97536 + }, destination: { + 'latitude': 40.70390, + 'longitude': -73.98670 + }, mode: 'car', steps: 3, interval: 3); + }, + child: Text('mockTracking()'), + ), + ElevatedButton( + style: raisedButtonStyle, + onPressed: () async { + Map? location = await Radar.getLocation(accuracy: 'high'); + print(location); + }, + child: Text('getLocation()'), + ), + ElevatedButton( + style: raisedButtonStyle, + onPressed: () async { + Map? resp = await Radar.trackVerified(); + print("trackVerified: $resp"); + }, + child: Text('trackVerified()'), + ), + ElevatedButton( + style: raisedButtonStyle, + onPressed: () async { + bool? resp = await Radar.isUsingRemoteTrackingOptions(); + print("isUsingRemoteTrackingOptions: $resp"); + }, + child: Text('isUsingRemoteTrackingOptions'), + ), + ElevatedButton( + style: raisedButtonStyle, + onPressed: () async { + Map? resp = await Radar.validateAddress(address: { + "city": "NEW YORK", + "stateCode": "NY", + "postalCode": "10003", + "countryCode": "US", + "street": "BROADWAY", + "number": "841", + }); + print("validateAddress: $resp"); + }, + child: Text('validateAddress'), + ), + ElevatedButton( + style: raisedButtonStyle, + onPressed: () async { + await Radar.acceptEvent( + eventId: 'event-id', + VerifiedPlaceId: 'verified-place-id'); + ; + print("accept event"); + }, + child: Text('acceptEvent'), + ), + ElevatedButton( + style: raisedButtonStyle, + onPressed: () async { + await Radar.rejectEvent(eventId: 'event-id'); + ; + print("reject event"); + }, + child: Text('rejectEvent'), + ), + ElevatedButton( + style: raisedButtonStyle, + onPressed: () async { + Map? res = await Radar.getContext( + location: {'latitude': 40.78382, 'longitude': -73.97536}); + ; + print("getContext: $res"); + }, + child: Text('getContext'), + ), + ElevatedButton( + style: raisedButtonStyle, + onPressed: () async { + Map? res = await Radar.getDistance(destination: { + 'latitude': 40.78382, + 'longitude': -73.97536 + }, modes: [ + 'car' + ], units: 'imperial'); + ; + print("getDistance: $res"); + }, + child: Text('getDistance'), + ), + ]), + )), )); } } @@ -462,6 +540,7 @@ class _PermissionsState extends State { setState(() { _status = status; }); + print('Permissions status: $status'); } } diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 63b0bc9..09a7e05 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -24,6 +24,8 @@ dependencies: # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.5 + permission_handler: ^10.2.0 + dev_dependencies: flutter_test: sdk: flutter diff --git a/ios/Classes/RadarFlutterPlugin.m b/ios/Classes/RadarFlutterPlugin.m index 487b8fe..1c6785e 100644 --- a/ios/Classes/RadarFlutterPlugin.m +++ b/ios/Classes/RadarFlutterPlugin.m @@ -74,6 +74,8 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { [self startTrackingCustom:call withResult:result]; } else if ([@"startTrackingVerified" isEqualToString:call.method]) { [self startTrackingVerified:call withResult:result]; + } else if ([@"stopTrackingVerified" isEqualToString:call.method]) { + [self stopTrackingVerified:call withResult:result]; } else if ([@"stopTracking" isEqualToString:call.method]) { [self stopTracking:call withResult:result]; } else if ([@"isTracking" isEqualToString:call.method]) { @@ -92,6 +94,10 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { [self completeTrip:call withResult:result]; } else if ([@"cancelTrip" isEqualToString:call.method]) { [self cancelTrip:call withResult:result]; + } else if ([@"acceptEvent" isEqualToString:call.method]) { + [self acceptEvent:call withResult:result]; + } else if ([@"rejectEvent" isEqualToString:call.method]) { + [self rejectEvent:call withResult:result]; } else if ([@"getContext" isEqualToString:call.method]) { [self getContext:call withResult:result]; } else if ([@"searchGeofences" isEqualToString:call.method]) { @@ -124,31 +130,67 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { // do nothing } else if ([@"trackVerified" isEqualToString:call.method]) { [self trackVerified:call withResult:result]; - } else if ([@"trackVerifiedToken" isEqualToString:call.method]) { - [self trackVerifiedToken:call withResult:result]; } else if ([@"isUsingRemoteTrackingOptions" isEqualToString:call.method]) { [self isUsingRemoteTrackingOptions:call withResult:result]; } else if ([@"validateAddress" isEqualToString:call.method]) { [self validateAddress:call withResult:result]; - } else if ([@"attachListeners" isEqualToString:call.method]) { - [self attachListeners:call withResult:result]; - } else if ([@"detachListeners" isEqualToString:call.method]) { - [self detachListeners:call withResult:result]; - } else if ([@"on" isEqualToString:call.method]) { - [self on:call withResult:result]; - } else if ([@"off" isEqualToString:call.method]) { - [self off:call withResult:result]; } else { result(FlutterMethodNotImplemented); } } +- (NSString *)getStringValueForKey:(NSDictionary *)dictionary key:(NSString *)key { + id value = [dictionary objectForKey:key]; + + if (value && [value isKindOfClass:[NSString class]]) { + return (NSString *)value; + } + + return nil; +} + +- (BOOL)getBoolValueForKey:(NSDictionary *)dictionary key:(NSString *)key defaultValue:(BOOL)defaultValue { + id value = [dictionary objectForKey:key]; + if (value && [value isKindOfClass:[NSNumber class]]) { + return [(NSNumber *)value boolValue]; + } + + return defaultValue; +} + +- (NSDictionary *)getDictionaryValueForKey:(NSDictionary *)dictionary key:(NSString *)key { + id value = [dictionary objectForKey:key]; + if (value && [value isKindOfClass:[NSDictionary class]]) { + return (NSDictionary *)value; + } + + return nil; +} + +- (NSArray *)getArrayValueForKey:(NSDictionary *)dictionary key:(NSString *)key { + id value = [dictionary objectForKey:key]; + if (value && [value isKindOfClass:[NSArray class]]) { + return (NSArray *)value; + } + + return nil; +} + +- (int)getIntegerValueForKey:(NSDictionary *)dictionary key:(NSString *)key defaultValue:(int)defaultValue { + id value = [dictionary objectForKey:key]; + if (value && [value isKindOfClass:[NSNumber class]]) { + return [(NSNumber *)value intValue]; + } + + return defaultValue; +} + - (void)initialize:(FlutterMethodCall *)call withResult:(FlutterResult)result { NSDictionary *argsDict = call.arguments; - NSString *publishableKey = argsDict[@"publishableKey"]; + NSString *publishableKey = [self getStringValueForKey:argsDict key:@"publishableKey"]; [[NSUserDefaults standardUserDefaults] setObject:@"Flutter" forKey:@"radar-xPlatformSDKType"]; - [[NSUserDefaults standardUserDefaults] setObject:@"3.9.1" forKey:@"radar-xPlatformSDKVersion"]; + [[NSUserDefaults standardUserDefaults] setObject:@"3.10.0-beta.3" forKey:@"radar-xPlatformSDKVersion"]; [Radar initializeWithPublishableKey:publishableKey]; result(nil); } @@ -156,7 +198,7 @@ - (void)initialize:(FlutterMethodCall *)call withResult:(FlutterResult)result { - (void)setLogLevel:(FlutterMethodCall *)call withResult:(FlutterResult)result { NSDictionary *argsDict = call.arguments; - NSString *logLevel = argsDict[@"logLevel"]; + NSString *logLevel = [self getStringValueForKey:argsDict key:@"logLevel"]; if (!logLevel) { [Radar setLogLevel:RadarLogLevelNone]; } else if ([logLevel isEqualToString:@"debug"]) { @@ -207,9 +249,8 @@ - (void)requestPermissions:(FlutterMethodCall *)call withResult:(FlutterResult)r self.permissionsRequestResult = result; NSDictionary *argsDict = call.arguments; + BOOL background = [self getBoolValueForKey:argsDict key:@"background" defaultValue:NO]; - NSNumber *backgroundNumber = argsDict[@"background"]; - BOOL background = [backgroundNumber boolValue]; CLAuthorizationStatus status = [CLLocationManager authorizationStatus]; if (background && status == kCLAuthorizationStatusAuthorizedWhenInUse) { [self.locationManager requestAlwaysAuthorization]; @@ -223,7 +264,7 @@ - (void)requestPermissions:(FlutterMethodCall *)call withResult:(FlutterResult)r - (void)setUserId:(FlutterMethodCall *)call withResult:(FlutterResult)result { NSDictionary *argsDict = call.arguments; - NSString *userId = argsDict[@"userId"]; + NSString *userId = [self getStringValueForKey:argsDict key:@"userId"]; [Radar setUserId:userId]; result(nil); } @@ -236,7 +277,7 @@ - (void)getUserId:(FlutterMethodCall *)call withResult:(FlutterResult)result { - (void)setDescription:(FlutterMethodCall *)call withResult:(FlutterResult)result { NSDictionary *argsDict = call.arguments; - NSString *description = argsDict[@"description"]; + NSString *description = [self getStringValueForKey:argsDict key:@"description"]; [Radar setDescription:description]; result(nil); } @@ -260,8 +301,7 @@ - (void)getMetadata:(FlutterMethodCall *)call withResult:(FlutterResult)result { - (void)setAnonymousTrackingEnabled:(FlutterMethodCall *)call withResult:(FlutterResult)result { NSDictionary *argsDict = call.arguments; - NSNumber* enabledNumber = argsDict[@"enabled"]; - BOOL enabled = [enabledNumber boolValue]; + BOOL enabled = [self getBoolValueForKey:argsDict key:@"enabled" defaultValue:NO]; [Radar setAnonymousTrackingEnabled:enabled]; result(nil); } @@ -280,7 +320,7 @@ - (void)getLocation:(FlutterMethodCall *)call withResult:(FlutterResult)result { NSDictionary *argsDict = call.arguments; - NSString *accuracy = argsDict[@"accuracy"]; + NSString *accuracy = [self getStringValueForKey:argsDict key:@"accuracy"]; if (!accuracy) { [Radar getLocationWithCompletionHandler:completionHandler]; } else if ([accuracy isEqualToString:@"high"]) { @@ -314,8 +354,8 @@ - (void)trackOnce:(FlutterMethodCall *)call withResult:(FlutterResult)result { NSDictionary *argsDict = call.arguments; - NSDictionary *locationDict = argsDict[@"location"]; - if (locationDict != nil && [locationDict isKindOfClass:[NSDictionary class]]) { + NSDictionary *locationDict = [self getDictionaryValueForKey:argsDict key:@"location"]; + if (locationDict != nil) { NSNumber *latitudeNumber = locationDict[@"latitude"]; NSNumber *longitudeNumber = locationDict[@"longitude"]; NSNumber *accuracyNumber = locationDict[@"accuracy"]; @@ -326,11 +366,11 @@ - (void)trackOnce:(FlutterMethodCall *)call withResult:(FlutterResult)result { [Radar trackOnceWithLocation:location completionHandler:completionHandler]; } else { RadarTrackingOptionsDesiredAccuracy desiredAccuracy = RadarTrackingOptionsDesiredAccuracyMedium; - BOOL beaconsTrackingOption = NO; + BOOL beaconsTrackingOption = [self getBoolValueForKey:argsDict key:@"beacons" defaultValue:NO]; - NSString *accuracy = argsDict[@"desiredAccuracy"]; + NSString *accuracy =[self getStringValueForKey:argsDict key:@"desiredAccuracy"]; - if (accuracy != nil && [accuracy isKindOfClass:[NSString class]]) { + if (accuracy != nil) { NSString *lowerAccuracy = [accuracy lowercaseString]; if ([lowerAccuracy isEqualToString:@"high"]) { desiredAccuracy = RadarTrackingOptionsDesiredAccuracyHigh; @@ -340,13 +380,7 @@ - (void)trackOnce:(FlutterMethodCall *)call withResult:(FlutterResult)result { desiredAccuracy = RadarTrackingOptionsDesiredAccuracyLow; } } - - BOOL beacons = argsDict[@"beacons"]; - - if (beacons) { - beaconsTrackingOption = beacons; - } - + [Radar trackOnceWithDesiredAccuracy:desiredAccuracy beacons:beaconsTrackingOption completionHandler:completionHandler]; } } @@ -354,7 +388,7 @@ - (void)trackOnce:(FlutterMethodCall *)call withResult:(FlutterResult)result { - (void)startTracking:(FlutterMethodCall *)call withResult:(FlutterResult)result { NSDictionary *argsDict = call.arguments; - NSString *preset = argsDict[@"preset"]; + NSString *preset = [self getStringValueForKey:argsDict key:@"preset"]; if (!preset) { [Radar startTrackingWithOptions:RadarTrackingOptions.presetResponsive]; } else if ([preset isEqualToString:@"continuous"]) { @@ -379,25 +413,16 @@ - (void)startTrackingCustom:(FlutterMethodCall *)call withResult:(FlutterResult) - (void)startTrackingVerified:(FlutterMethodCall *)call withResult:(FlutterResult)result { NSDictionary *argsDict = call.arguments; - BOOL token = NO; - NSNumber *tokenNumber = argsDict[@"token"]; - if (tokenNumber != nil && [tokenNumber isKindOfClass:[NSNumber class]]) { - token = [tokenNumber boolValue]; - } + BOOL beacons = [self getBoolValueForKey:argsDict key:@"beacons" defaultValue:NO]; - BOOL beacons = NO; - NSNumber *beaconsNumber = argsDict[@"beacons"]; - if (beaconsNumber != nil && [beaconsNumber isKindOfClass:[NSNumber class]]) { - beacons = [beaconsNumber boolValue]; - } + double interval = [argsDict[@"interval"] doubleValue]; - double interval = 1; - NSNumber *intervalNumber = argsDict[@"interval"]; - if (intervalNumber != nil && [intervalNumber isKindOfClass:[NSNumber class]]) { - interval = [intervalNumber doubleValue]; - } + [Radar startTrackingVerifiedWithInterval:interval beacons:beacons]; + result(nil); +} - [Radar startTrackingVerified:token interval:interval beacons:beacons]; +- (void)stopTrackingVerified:(FlutterMethodCall *)call withResult:(FlutterResult)result { + [Radar stopTrackingVerified]; result(nil); } @@ -424,19 +449,25 @@ - (void)getTrackingOptions:(FlutterMethodCall *)call withResult:(FlutterResult)r - (void)mockTracking:(FlutterMethodCall *)call withResult:(FlutterResult)result { NSDictionary *argsDict = call.arguments; - NSDictionary *originDict = argsDict[@"origin"]; + NSDictionary *originDict = [self getDictionaryValueForKey:argsDict key:@"origin"]; + NSDictionary *destinationDict = [self getDictionaryValueForKey:argsDict key:@"destination"]; + if (!originDict || !destinationDict) { + result(nil); + return; + } NSNumber *originLatitudeNumber = originDict[@"latitude"]; NSNumber *originLongitudeNumber = originDict[@"longitude"]; double originLatitude = [originLatitudeNumber doubleValue]; double originLongitude = [originLongitudeNumber doubleValue]; CLLocation *origin = [[CLLocation alloc] initWithCoordinate:CLLocationCoordinate2DMake(originLatitude, originLongitude) altitude:-1 horizontalAccuracy:5 verticalAccuracy:-1 timestamp:[NSDate date]]; - NSDictionary *destinationDict = argsDict[@"destination"]; + NSNumber *destinationLatitudeNumber = destinationDict[@"latitude"]; NSNumber *destinationLongitudeNumber = destinationDict[@"longitude"]; double destinationLatitude = [destinationLatitudeNumber doubleValue]; double destinationLongitude = [destinationLongitudeNumber doubleValue]; CLLocation *destination = [[CLLocation alloc] initWithCoordinate:CLLocationCoordinate2DMake(destinationLatitude, destinationLongitude) altitude:-1 horizontalAccuracy:5 verticalAccuracy:-1 timestamp:[NSDate date]]; - NSString *modeStr = argsDict[@"mode"]; + + NSString *modeStr = [self getStringValueForKey:argsDict key:@"mode"]; RadarRouteMode mode = RadarRouteModeCar; if ([modeStr isEqualToString:@"FOOT"] || [modeStr isEqualToString:@"foot"]) { mode = RadarRouteModeFoot; @@ -445,20 +476,8 @@ - (void)mockTracking:(FlutterMethodCall *)call withResult:(FlutterResult)result } else if ([modeStr isEqualToString:@"CAR"] || [modeStr isEqualToString:@"car"]) { mode = RadarRouteModeCar; } - NSNumber *stepsNumber = argsDict[@"steps"]; - int steps; - if (stepsNumber != nil && [stepsNumber isKindOfClass:[NSNumber class]]) { - steps = [stepsNumber intValue]; - } else { - steps = 10; - } - NSNumber *intervalNumber = argsDict[@"interval"]; - int interval; - if (intervalNumber != nil && [intervalNumber isKindOfClass:[NSNumber class]]) { - interval = [intervalNumber intValue]; - } else { - interval = 1; - } + int steps = [argsDict[@"steps"] intValue]; + int interval = [argsDict[@"interval"] intValue]; [Radar mockTrackingWithOrigin:origin destination:destination mode:mode steps:steps interval:interval completionHandler:nil]; } @@ -478,9 +497,9 @@ - (void)startTrip:(FlutterMethodCall *)call withResult:(FlutterResult)result { } }; NSDictionary *argsDict = call.arguments; - NSDictionary *tripOptionsDict = argsDict[@"tripOptions"]; + NSDictionary *tripOptionsDict = [self getDictionaryValueForKey:argsDict key:@"tripOptions"]; RadarTripOptions *tripOptions = [RadarTripOptions tripOptionsFromDictionary:tripOptionsDict]; - NSDictionary *trackingOptionsDict = argsDict[@"trackingOptions"]; + NSDictionary *trackingOptionsDict = [self getDictionaryValueForKey:argsDict key:@"trackingOptions"]; RadarTrackingOptions *trackingOptions; if (trackingOptionsDict) { trackingOptions = [RadarTrackingOptions trackingOptionsFromDictionary:trackingOptionsDict]; @@ -504,9 +523,9 @@ - (void)updateTrip:(FlutterMethodCall *)call withResult:(FlutterResult)result { } }; NSDictionary *argsDict = call.arguments; - NSDictionary *tripOptionsDict = argsDict[@"tripOptions"]; + NSDictionary *tripOptionsDict = [self getDictionaryValueForKey:argsDict key:@"tripOptions"]; RadarTripOptions *tripOptions = [RadarTripOptions tripOptionsFromDictionary:tripOptionsDict]; - NSString* statusStr = argsDict[@"status"]; + NSString* statusStr = [self getStringValueForKey:argsDict key:@"status"]; RadarTripStatus status = RadarTripStatusUnknown; statusStr = [statusStr lowercaseString]; if ([statusStr isEqualToString:@"started"]) { @@ -567,6 +586,21 @@ - (void)cancelTrip:(FlutterMethodCall *)call withResult:(FlutterResult)result { [Radar cancelTripWithCompletionHandler:completionHandler]; } +- (void) acceptEvent:(FlutterMethodCall *)call withResult:(FlutterResult)result { + NSDictionary *argsDict = call.arguments; + NSString *eventId = [self getStringValueForKey:argsDict key:@"eventId"]; + NSString *verifiedPlaceId = [self getStringValueForKey:argsDict key:@"verifiedPlaceId"]; + [Radar acceptEventId:eventId verifiedPlaceId:verifiedPlaceId]; + result(nil); +} + +- (void) rejectEvent:(FlutterMethodCall *)call withResult:(FlutterResult)result { + NSDictionary *argsDict = call.arguments; + NSString *eventId = [self getStringValueForKey:argsDict key:@"eventId"]; + [Radar rejectEventId:eventId]; + result(nil); +} + - (void)getContext:(FlutterMethodCall *)call withResult:(FlutterResult)result { RadarContextCompletionHandler completionHandler = ^(RadarStatus status, CLLocation * _Nullable location, RadarContext * _Nullable context) { NSMutableDictionary *dict = [NSMutableDictionary new]; @@ -582,7 +616,7 @@ - (void)getContext:(FlutterMethodCall *)call withResult:(FlutterResult)result { NSDictionary *argsDict = call.arguments; - NSDictionary *locationDict = argsDict[@"location"]; + NSDictionary *locationDict = [self getDictionaryValueForKey:argsDict key:@"location"]; if (locationDict) { NSNumber *latitudeNumber = locationDict[@"latitude"]; NSNumber *longitudeNumber = locationDict[@"longitude"]; @@ -615,7 +649,7 @@ - (void)searchGeofences:(FlutterMethodCall *)call withResult:(FlutterResult)resu NSDictionary *argsDict = call.arguments; CLLocation *near; - NSDictionary *nearDict = argsDict[@"near"]; + NSDictionary *nearDict = [self getDictionaryValueForKey:argsDict key:@"near"]; if (nearDict) { NSNumber *latitudeNumber = nearDict[@"latitude"]; NSNumber *longitudeNumber = nearDict[@"longitude"]; @@ -623,27 +657,20 @@ - (void)searchGeofences:(FlutterMethodCall *)call withResult:(FlutterResult)resu double longitude = [longitudeNumber doubleValue]; near = [[CLLocation alloc] initWithCoordinate:CLLocationCoordinate2DMake(latitude, longitude) altitude:-1 horizontalAccuracy:5 verticalAccuracy:-1 timestamp:[NSDate date]]; } - NSNumber *radiusNumber = argsDict[@"radius"]; - int radius; - if (radiusNumber != nil && [radiusNumber isKindOfClass:[NSNumber class]]) { - radius = [radiusNumber intValue]; - } else { - radius = 1000; - } - NSArray *tags = argsDict[@"tags"]; - NSDictionary *metadata = argsDict[@"metadata"]; - NSNumber *limitNumber = argsDict[@"limit"]; - int limit; - if (limitNumber != nil && [limitNumber isKindOfClass:[NSNumber class]]) { - limit = [limitNumber intValue]; - } else { - limit = 10; - } + int radius = [self getIntegerValueForKey:argsDict key:@"radius" defaultValue:1000]; + + NSArray *tags = [self getArrayValueForKey:argsDict key:@"tags"]; + + NSDictionary *metadata = [self getDictionaryValueForKey:argsDict key:@"metadata"]; + + int limit = [self getIntegerValueForKey:argsDict key:@"limit" defaultValue:10]; + + BOOL includeGeometry = [self getBoolValueForKey:argsDict key:@"includeGeometry" defaultValue:NO]; if (near != nil) { - [Radar searchGeofencesNear:near radius:radius tags:tags metadata:metadata limit:limit completionHandler:completionHandler]; + [Radar searchGeofencesNear:near radius:radius tags:tags metadata:metadata limit:limit includeGeometry:includeGeometry completionHandler:completionHandler]; } else { - [Radar searchGeofencesWithRadius:radius tags:tags metadata:metadata limit:limit completionHandler:completionHandler]; + [Radar searchGeofences:completionHandler]; } } @@ -665,7 +692,7 @@ - (void)searchPlaces:(FlutterMethodCall *)call withResult:(FlutterResult)result NSDictionary *argsDict = call.arguments; CLLocation *near; - NSDictionary *nearDict = argsDict[@"near"]; + NSDictionary *nearDict = [self getDictionaryValueForKey:argsDict key:@"near"]; if (nearDict) { NSNumber *latitudeNumber = nearDict[@"latitude"]; NSNumber *longitudeNumber = nearDict[@"longitude"]; @@ -673,25 +700,16 @@ - (void)searchPlaces:(FlutterMethodCall *)call withResult:(FlutterResult)result double longitude = [longitudeNumber doubleValue]; near = [[CLLocation alloc] initWithCoordinate:CLLocationCoordinate2DMake(latitude, longitude) altitude:-1 horizontalAccuracy:5 verticalAccuracy:-1 timestamp:[NSDate date]]; } - NSNumber *radiusNumber = argsDict[@"radius"]; - int radius; - if (radiusNumber != nil && [radiusNumber isKindOfClass:[NSNumber class]]) { - radius = [radiusNumber intValue]; - } else { - radius = 1000; - } - NSArray *chains = argsDict[@"chains"]; - NSDictionary *chainMetadata = [argsDict[@"chainMetadata"] isKindOfClass:[NSNull class]] ? nil : argsDict[@"chainMetadata"]; - NSArray *categories = [argsDict[@"categories"] isKindOfClass:[NSNull class]] ? nil : argsDict[@"categories"]; - NSArray *groups = [argsDict[@"groups"] isKindOfClass:[NSNull class]] ? nil : argsDict[@"groups"]; - NSNumber *limitNumber = argsDict[@"limit"]; - int limit; - if (limitNumber != nil && [limitNumber isKindOfClass:[NSNumber class]]) { - limit = [limitNumber intValue]; - } else { - limit = 10; - } + + int radius = [self getIntegerValueForKey:argsDict key:@"radius" defaultValue:1000]; + NSArray *chains = [self getArrayValueForKey:argsDict key:@"chains"]; + NSDictionary *chainMetadata = [self getDictionaryValueForKey:argsDict key:@"chainMetadata"]; + NSArray *categories = [self getArrayValueForKey:argsDict key:@"categories"]; + NSArray *groups = [self getArrayValueForKey:argsDict key:@"groups"]; + + int limit = [self getIntegerValueForKey:argsDict key:@"limit" defaultValue:10]; + if (near != nil) { [Radar searchPlacesNear:near radius:radius chains:chains chainMetadata:chainMetadata categories:categories groups:groups limit:limit completionHandler:completionHandler]; } else { @@ -702,9 +720,9 @@ - (void)searchPlaces:(FlutterMethodCall *)call withResult:(FlutterResult)result - (void)autocomplete:(FlutterMethodCall *)call withResult:(FlutterResult)result { NSDictionary *argsDict = call.arguments; - NSString *query = argsDict[@"query"]; + NSString *query = [self getStringValueForKey:argsDict key:@"query"]; CLLocation *near; - NSDictionary *nearDict = argsDict[@"near"]; + NSDictionary *nearDict = [self getDictionaryValueForKey:argsDict key:@"near"]; if (nearDict) { NSNumber *latitudeNumber = nearDict[@"latitude"]; NSNumber *longitudeNumber = nearDict[@"longitude"]; @@ -712,15 +730,11 @@ - (void)autocomplete:(FlutterMethodCall *)call withResult:(FlutterResult)result double longitude = [longitudeNumber doubleValue]; near = [[CLLocation alloc] initWithCoordinate:CLLocationCoordinate2DMake(latitude, longitude) altitude:-1 horizontalAccuracy:5 verticalAccuracy:-1 timestamp:[NSDate date]]; } - NSNumber *limitNumber = argsDict[@"limit"]; - int limit; - if (limitNumber != nil && [limitNumber isKindOfClass:[NSNumber class]]) { - limit = [limitNumber intValue]; - } else { - limit = 10; - } - NSArray *layers = [argsDict[@"layers"] isKindOfClass:[NSNull class]] ? nil : argsDict[@"layers"]; - NSString *country = [argsDict[@"country"] isKindOfClass:[NSNull class]] ? nil : argsDict[@"country"]; + + int limit = [self getIntegerValueForKey:argsDict key:@"limit" defaultValue:10]; + + NSArray *layers = [self getArrayValueForKey:argsDict key:@"layers"]; + NSString *country = [self getStringValueForKey:argsDict key:@"country"]; RadarGeocodeCompletionHandler completionHandler = ^(RadarStatus status, NSArray * _Nullable addresses) { NSMutableDictionary *dict = [NSMutableDictionary new]; @@ -731,20 +745,14 @@ - (void)autocomplete:(FlutterMethodCall *)call withResult:(FlutterResult)result result(dict); }; - - NSNumber *mailableNumber = argsDict[@"mailable"]; - if (mailableNumber != nil && [mailableNumber isKindOfClass:[NSNumber class]]) { - BOOL mailable = [mailableNumber boolValue]; - [Radar autocompleteQuery:query near:near layers:layers limit:limit country:country mailable:mailable completionHandler:completionHandler]; - } else { - [Radar autocompleteQuery:query near:near layers:layers limit:limit country:country completionHandler:completionHandler]; - } + BOOL mailable = [self getBoolValueForKey:argsDict key:@"mailable" defaultValue:NO]; + [Radar autocompleteQuery:query near:near layers:layers limit:limit country:country mailable:mailable completionHandler:completionHandler]; } - (void)geocode:(FlutterMethodCall *)call withResult:(FlutterResult)result { NSDictionary *argsDict = call.arguments; - NSString *query = argsDict[@"query"]; + NSString *query = [self getStringValueForKey:argsDict key:@"query"]; [Radar geocodeAddress:query completionHandler:^(RadarStatus status, NSArray * _Nullable addresses) { NSMutableDictionary *dict = [NSMutableDictionary new]; [dict setObject:[Radar stringForStatus:status] forKey:@"status"]; @@ -765,19 +773,22 @@ - (void)reverseGeocode:(FlutterMethodCall *)call withResult:(FlutterResult)resul result(dict); }; - NSDictionary *argsDict = call.arguments; + NSDictionary *argsDict = call.arguments; - NSDictionary *locationDict = argsDict[@"location"]; - if (locationDict) { + NSArray *layers = [self getArrayValueForKey:argsDict key:@"layers"]; + + NSDictionary *locationDict = [self getDictionaryValueForKey:argsDict key:@"location"]; + + if (locationDict) { NSNumber *latitudeNumber = locationDict[@"latitude"]; NSNumber *longitudeNumber = locationDict[@"longitude"]; double latitude = [latitudeNumber doubleValue]; double longitude = [longitudeNumber doubleValue]; CLLocation *location = [[CLLocation alloc] initWithCoordinate:CLLocationCoordinate2DMake(latitude, longitude) altitude:-1 horizontalAccuracy:5 verticalAccuracy:-1 timestamp:[NSDate date]]; - [Radar reverseGeocodeLocation:location completionHandler:completionHandler]; + [Radar reverseGeocodeLocation:location layers:layers completionHandler:completionHandler]; } else { - [Radar reverseGeocodeWithCompletionHandler:completionHandler]; + [Radar reverseGeocodeWithLayers:layers completionHandler:completionHandler]; } } @@ -806,7 +817,7 @@ - (void)getDistance:(FlutterMethodCall *)call withResult:(FlutterResult)result { NSDictionary *argsDict = call.arguments; CLLocation *origin; - NSDictionary *originDict = argsDict[@"origin"]; + NSDictionary *originDict = [self getDictionaryValueForKey:argsDict key:@"origin"]; if (originDict) { NSNumber *originLatitudeNumber = originDict[@"latitude"]; NSNumber *originLongitudeNumber = originDict[@"longitude"]; @@ -814,13 +825,14 @@ - (void)getDistance:(FlutterMethodCall *)call withResult:(FlutterResult)result { double originLongitude = [originLongitudeNumber doubleValue]; origin = [[CLLocation alloc] initWithCoordinate:CLLocationCoordinate2DMake(originLatitude, originLongitude) altitude:-1 horizontalAccuracy:5 verticalAccuracy:-1 timestamp:[NSDate date]]; } - NSDictionary *destinationDict = argsDict[@"destination"]; + NSDictionary *destinationDict = [self getDictionaryValueForKey:argsDict key:@"destination"]; NSNumber *destinationLatitudeNumber = destinationDict[@"latitude"]; NSNumber *destinationLongitudeNumber = destinationDict[@"longitude"]; double destinationLatitude = [destinationLatitudeNumber doubleValue]; double destinationLongitude = [destinationLongitudeNumber doubleValue]; CLLocation *destination = [[CLLocation alloc] initWithCoordinate:CLLocationCoordinate2DMake(destinationLatitude, destinationLongitude) altitude:-1 horizontalAccuracy:5 verticalAccuracy:-1 timestamp:[NSDate date]]; - NSArray *modesArr = argsDict[@"modes"]; + + NSArray *modesArr = [self getArrayValueForKey:argsDict key:@"modes"]; RadarRouteMode modes = 0; if (modesArr != nil) { if ([modesArr containsObject:@"FOOT"] || [modesArr containsObject:@"foot"]) { @@ -835,7 +847,8 @@ - (void)getDistance:(FlutterMethodCall *)call withResult:(FlutterResult)result { } else { modes = RadarRouteModeCar; } - NSString *unitsStr = argsDict[@"units"]; + + NSString *unitsStr = [self getStringValueForKey:argsDict key:@"units"]; RadarRouteUnits units; if (unitsStr != nil && [unitsStr isKindOfClass:[NSString class]]) { units = [unitsStr isEqualToString:@"METRIC"] || [unitsStr isEqualToString:@"metric"] ? RadarRouteUnitsMetric : RadarRouteUnitsImperial; @@ -864,8 +877,8 @@ - (void)logConversion:(FlutterMethodCall *)call withResult:(FlutterResult)result NSDictionary *argsDict = call.arguments; - NSDictionary *metadata = argsDict[@"metadata"]; - NSString *name = argsDict[@"name"]; + NSDictionary *metadata = [self getDictionaryValueForKey:argsDict key:@"metadata"]; + NSString *name = [self getStringValueForKey:argsDict key:@"name"]; NSNumber *revenueNumber = argsDict[@"revenue"]; if (revenueNumber != nil && [revenueNumber isKindOfClass:[NSNumber class]]) { [Radar logConversionWithName:name revenue:revenueNumber metadata:metadata completionHandler:completionHandler]; @@ -892,7 +905,7 @@ - (void)logResigningActive:(FlutterResult)result { - (void)getMatrix:(FlutterMethodCall *)call withResult:(FlutterResult)result { NSDictionary *argsDict = call.arguments; - NSArray *originsArr = argsDict[@"origins"]; + NSArray *originsArr = [self getArrayValueForKey:argsDict key:@"origins"]; NSMutableArray *origins = [NSMutableArray new]; for (NSDictionary *originDict in originsArr) { NSNumber *latitudeNumber = originDict[@"latitude"]; @@ -904,7 +917,7 @@ - (void)getMatrix:(FlutterMethodCall *)call withResult:(FlutterResult)result { CLLocation *origin = [[CLLocation alloc] initWithCoordinate:CLLocationCoordinate2DMake(latitude, longitude) altitude:-1 horizontalAccuracy:accuracy verticalAccuracy:-1 timestamp:[NSDate date]]; [origins addObject:origin]; } - NSArray *destinationsArr = argsDict[@"destinations"]; + NSArray *destinationsArr = [self getArrayValueForKey:argsDict key:@"destinations"]; NSMutableArray *destinations = [NSMutableArray new]; for (NSDictionary *destinationDict in destinationsArr) { NSNumber *latitudeNumber = destinationDict[@"latitude"]; @@ -916,7 +929,7 @@ - (void)getMatrix:(FlutterMethodCall *)call withResult:(FlutterResult)result { CLLocation *destination = [[CLLocation alloc] initWithCoordinate:CLLocationCoordinate2DMake(latitude, longitude) altitude:-1 horizontalAccuracy:accuracy verticalAccuracy:-1 timestamp:[NSDate date]]; [destinations addObject:destination]; } - NSString *modeStr = argsDict[@"mode"]; + NSString *modeStr = [self getStringValueForKey:argsDict key:@"mode"]; RadarRouteMode mode = RadarRouteModeCar; if ([modeStr isEqualToString:@"FOOT"] || [modeStr isEqualToString:@"foot"]) { mode = RadarRouteModeFoot; @@ -929,7 +942,7 @@ - (void)getMatrix:(FlutterMethodCall *)call withResult:(FlutterResult)result { } else if ([modeStr isEqualToString:@"MOTORBIKE"] || [modeStr isEqualToString:@"motorbike"]) { mode = RadarRouteModeMotorbike; } - NSString *unitsStr = argsDict[@"units"]; + NSString *unitsStr = [self getStringValueForKey:argsDict key:@"units"]; RadarRouteUnits units; if (unitsStr != nil && [unitsStr isKindOfClass:[NSString class]]) { units = [unitsStr isEqualToString:@"METRIC"] || [unitsStr isEqualToString:@"metric"] ? RadarRouteUnitsMetric : RadarRouteUnitsImperial; @@ -950,25 +963,13 @@ - (void)getMatrix:(FlutterMethodCall *)call withResult:(FlutterResult)result { - (void)trackVerified:(FlutterMethodCall *)call withResult:(FlutterResult)result { NSDictionary *argsDict = call.arguments; - BOOL beacons = NO; - NSNumber *beaconsNumber = argsDict[@"beacons"]; - if (beaconsNumber != nil && [beaconsNumber isKindOfClass:[NSNumber class]]) { - beacons = [beaconsNumber boolValue]; - } + BOOL beacons = [self getBoolValueForKey:argsDict key:@"beacons" defaultValue:NO]; - RadarTrackCompletionHandler completionHandler = ^(RadarStatus status, CLLocation *location, NSArray *events, RadarUser *user) { + RadarTrackVerifiedCompletionHandler completionHandler = ^(RadarStatus status, RadarVerifiedLocationToken* token) { if (status == RadarStatusSuccess) { NSMutableDictionary *dict = [NSMutableDictionary new]; [dict setObject:[Radar stringForStatus:status] forKey:@"status"]; - if (location) { - [dict setObject:[Radar dictionaryForLocation:location] forKey:@"location"]; - } - if (events) { - [dict setObject:[RadarEvent arrayForEvents:events] forKey:@"events"]; - } - if (user) { - [dict setObject:[user dictionaryValue] forKey:@"user"]; - } + [dict setObject:[token dictionaryValue] forKey:@"token"]; result(dict); } }; @@ -976,27 +977,6 @@ - (void)trackVerified:(FlutterMethodCall *)call withResult:(FlutterResult)result [Radar trackVerifiedWithBeacons:beacons completionHandler:completionHandler]; } -- (void)trackVerifiedToken:(FlutterMethodCall *)call withResult:(FlutterResult)result { - NSDictionary *argsDict = call.arguments; - - BOOL beacons = NO; - NSNumber *beaconsNumber = argsDict[@"beacons"]; - if (beaconsNumber != nil && [beaconsNumber isKindOfClass:[NSNumber class]]) { - beacons = [beaconsNumber boolValue]; - } - - RadarTrackTokenCompletionHandler completionHandler = ^(RadarStatus status, NSString* token) { - if (status == RadarStatusSuccess) { - NSMutableDictionary *dict = [NSMutableDictionary new]; - [dict setObject:[Radar stringForStatus:status] forKey:@"status"]; - [dict setObject:token forKey:@"token"]; - result(dict); - } - }; - - [Radar trackVerifiedTokenWithBeacons:beacons completionHandler:completionHandler]; -} - - (void)validateAddress:(FlutterMethodCall *)call withResult:(FlutterResult)result { RadarValidateAddressCompletionHandler completionHandler = ^(RadarStatus status, RadarAddress * _Nullable address, RadarAddressVerificationStatus verificationStatus) { NSMutableDictionary *dict = [NSMutableDictionary new]; @@ -1010,116 +990,57 @@ - (void)validateAddress:(FlutterMethodCall *)call withResult:(FlutterResult)resu NSDictionary *argsDict = call.arguments; - NSDictionary *addressDict = argsDict[@"address"]; + NSDictionary *addressDict = [self getDictionaryValueForKey:argsDict key:@"address"]; RadarAddress *address = [RadarAddress addressFromObject:addressDict]; [Radar validateAddress:address completionHandler:completionHandler]; } --(void)attachListeners:(FlutterMethodCall *)call withResult:(FlutterResult)result { - NSNumber* callbackDispatcherHandle = call.arguments[@"callbackDispatcherHandle"]; - - // Retrieve the callback information - FlutterCallbackInformation *callbackInfo = [FlutterCallbackCache lookupCallbackInformation:[callbackDispatcherHandle longValue]]; - - // Create the background Flutter engine - FlutterEngine *sBackgroundFlutterEngine; - sBackgroundFlutterEngine = [[FlutterEngine alloc] init]; - self.sBackgroundFlutterEngine = sBackgroundFlutterEngine; - - FlutterMethodChannel *backgroundChannel = [FlutterMethodChannel methodChannelWithName:@"flutter_radar_background" binaryMessenger:[sBackgroundFlutterEngine binaryMessenger]]; - self.backgroundChannel = backgroundChannel; - - [self.sBackgroundFlutterEngine runWithEntrypoint:callbackInfo.callbackName libraryURI: callbackInfo.callbackLibraryPath] ; - result(nil); -} - --(void)detachListeners:(FlutterMethodCall *)call withResult:(FlutterResult)result { - self.backgroundChannel = nil; - result(nil); -} - --(void)on:(FlutterMethodCall *)call withResult:(FlutterResult)result { - NSDictionary *argsDict = call.arguments; - NSString* listener = argsDict[@"listener"]; - NSNumber *callbackHandleNumber = argsDict[@"callbackHandle"]; - long callbackHandle = [callbackHandleNumber longValue]; - NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; - [userDefaults setObject:callbackHandleNumber forKey:listener]; - result(nil); -} - --(void)off:(FlutterMethodCall *)call withResult:(FlutterResult)result { - NSDictionary *argsDict = call.arguments; - NSString* listener = argsDict[@"listener"]; - NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; - [userDefaults setObject:nil forKey:listener]; - result(nil); -} - - (void)didReceiveEvents:(NSArray *)events user:(RadarUser *)user { NSDictionary *dict = @{@"events": [RadarEvent arrayForEvents:events], @"user": user ? [user dictionaryValue] : @""}; - NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; - NSInteger callbackHandle = [userDefaults integerForKey:@"events"]; - if (callbackHandle == 0) { - return; + NSArray* args = @[@0, dict]; + if (self.channel != nil) { + [self.channel invokeMethod:@"events" arguments:args]; } - NSArray* args = @[[NSNumber numberWithInteger:callbackHandle], dict]; - [self.backgroundChannel invokeMethod:@"" arguments:args]; } - (void)didUpdateLocation:(CLLocation *)location user:(RadarUser *)user { NSDictionary *dict = @{@"location": [Radar dictionaryForLocation:location], @"user": [user dictionaryValue]}; - NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; - NSInteger callbackHandle = [userDefaults integerForKey:@"location"]; - if (callbackHandle == 0) { - return; + NSArray* args = @[@0, dict]; + if (self.channel != nil) { + [self.channel invokeMethod:@"location" arguments:args]; } - NSArray* args = @[[NSNumber numberWithInteger:callbackHandle], dict]; - [self.backgroundChannel invokeMethod:@"" arguments:args]; } - (void)didUpdateClientLocation:(CLLocation *)location stopped:(BOOL)stopped source:(RadarLocationSource)source { NSDictionary *dict = @{@"location": [Radar dictionaryForLocation:location], @"stopped": @(stopped), @"source": [Radar stringForLocationSource:source]}; - NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; - NSInteger callbackHandle = [userDefaults integerForKey:@"clientLocation"]; - if (callbackHandle == 0) { - return; + NSArray* args = @[@0, dict]; + if (self.channel != nil) { + [self.channel invokeMethod:@"clientLocation" arguments:args]; } - NSArray* args = @[[NSNumber numberWithInteger:callbackHandle], dict]; - [self.backgroundChannel invokeMethod:@"" arguments:args]; } - (void)didFailWithStatus:(RadarStatus)status { NSDictionary *dict = @{@"status": [Radar stringForStatus:status]}; - NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; - NSInteger callbackHandle = [userDefaults integerForKey:@"error"]; - if (callbackHandle == 0) { - return; + NSArray* args = @[@0, dict]; + if (self.channel != nil) { + [self.channel invokeMethod:@"error" arguments:args]; } - NSArray* args = @[[NSNumber numberWithInteger:callbackHandle], dict]; - [self.backgroundChannel invokeMethod:@"" arguments:args]; } - (void)didLogMessage:(NSString *)message { NSDictionary *dict = @{@"message": message}; - NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; - NSNumber* callbackHandle = [userDefaults objectForKey:@"log"]; - if (callbackHandle == 0) { - return; + NSArray* args = @[@0, dict]; + if (self.channel != nil) { + [self.channel invokeMethod:@"log" arguments:args]; } - NSArray* args = @[callbackHandle, dict]; - [self.backgroundChannel invokeMethod:@"" arguments:args]; } - (void)didUpdateToken:(NSString *)token { NSDictionary *dict = @{@"token": token}; - NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; - NSNumber* callbackHandle = [userDefaults objectForKey:@"token"]; - if (callbackHandle == 0) { - return; + NSArray* args = @[@0, dict]; + if (self.channel != nil) { + [self.channel invokeMethod:@"token" arguments:args]; } - NSArray* args = @[callbackHandle, dict]; - [self.backgroundChannel invokeMethod:@"" arguments:args]; } @end diff --git a/ios/flutter_radar.podspec b/ios/flutter_radar.podspec index 63f63da..e60e593 100644 --- a/ios/flutter_radar.podspec +++ b/ios/flutter_radar.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'flutter_radar' - s.version = '3.9.1' + s.version = '3.10.0-beta.3' s.summary = 'Flutter package for Radar, the leading geofencing and location tracking platform' s.description = 'Flutter package for Radar, the leading geofencing and location tracking platform' s.homepage = 'http://example.com' @@ -10,7 +10,7 @@ Pod::Spec.new do |s| s.source_files = 'Classes/**/*' s.public_header_files = 'Classes/**/*.h' s.dependency 'Flutter' - s.dependency 'RadarSDK', '3.9.14' + s.dependency 'RadarSDK', '3.16.1-beta.1' s.platform = :ios, '10.0' s.static_framework = true diff --git a/lib/flutter_radar.dart b/lib/flutter_radar.dart index c344a86..2aa0fd4 100644 --- a/lib/flutter_radar.dart +++ b/lib/flutter_radar.dart @@ -20,39 +20,66 @@ void callbackDispatcher() { }); } +typedef LocationCallback = void Function(Map locationEvent); +typedef ClientLocationCallback = void Function( + Map locationEvent, +); +typedef ErrorCallback = void Function(Map errorEvent); +typedef LogCallback = void Function(Map logEvent); +typedef EventsCallback = void Function(Map eventsEvent); +typedef TokenCallback = void Function(Map tokenEvent); + class Radar { static const MethodChannel _channel = const MethodChannel('flutter_radar'); - static Future initialize(String publishableKey) async { + static LocationCallback? foregroundLocationCallback; + static ClientLocationCallback? foregroundClientLocationCallback; + static ErrorCallback? foregroundErrorCallback; + static LogCallback? foregroundLogCallback; + static EventsCallback? foregroundEventsCallback; + static TokenCallback? foregroundTokenCallback; + + static Future initialize( + {required String publishableKey, bool fraud = false}) async { + try { await _channel.invokeMethod('initialize', { 'publishableKey': publishableKey, + 'fraud': fraud, }); + _channel.setMethodCallHandler(_handleMethodCall); } on PlatformException catch (e) { print(e); } } - static attachListeners() async { - try { - await _channel.invokeMethod('attachListeners', { - 'callbackDispatcherHandle': - PluginUtilities.getCallbackHandle(callbackDispatcher)?.toRawHandle() - }); - } on PlatformException catch (e) { - print(e); - } - } - - static Future detachListeners() async { - try { - await _channel.invokeMethod('detachListeners'); - } on PlatformException catch (e) { - print(e); - } - } - - static Future setLogLevel(String logLevel) async { + static Future _handleMethodCall(MethodCall call) async { + final args = call.arguments; + switch (call.method) { + case 'location': + foregroundLocationCallback?.call(args[1] as Map); + break; + case 'clientLocation': + foregroundClientLocationCallback?.call( + args[1] as Map, + ); + break; + case 'error': + foregroundErrorCallback?.call(args[1] as Map); + break; + case 'log': + foregroundLogCallback?.call(args[1] as Map); + break; + case 'events': + foregroundEventsCallback?.call(args[1] as Map); + break; + case 'token': + foregroundTokenCallback?.call(args[1] as Map); + break; + } + } + + static Future setLogLevel({required String logLevel}) async { try { await _channel.invokeMethod('setLogLevel', {'logLevel': logLevel}); } on PlatformException catch (e) { @@ -64,7 +91,7 @@ class Radar { return await _channel.invokeMethod('getPermissionsStatus'); } - static Future requestPermissions(bool background) async { + static Future requestPermissions({required bool background}) async { try { return await _channel .invokeMethod('requestPermissions', {'background': background}); @@ -73,7 +100,7 @@ class Radar { } } - static Future setUserId(String userId) async { + static Future setUserId({required String userId}) async { try { await _channel.invokeMethod('setUserId', {'userId': userId}); } on PlatformException catch (e) { @@ -85,7 +112,7 @@ class Radar { return await _channel.invokeMethod('getUserId'); } - static Future setDescription(String description) async { + static Future setDescription({required String description}) async { try { await _channel .invokeMethod('setDescription', {'description': description}); @@ -98,7 +125,7 @@ class Radar { return await _channel.invokeMethod('getDescription'); } - static Future setMetadata(Map metadata) async { + static Future setMetadata({required Map metadata}) async { try { await _channel.invokeMethod('setMetadata', metadata); } on PlatformException catch (e) { @@ -110,7 +137,7 @@ class Radar { return await _channel.invokeMethod('getMetadata'); } - static Future setAnonymousTrackingEnabled(bool enabled) async { + static Future setAnonymousTrackingEnabled({required bool enabled}) async { try { await _channel .invokeMethod('setAnonymousTrackingEnabled', {'enabled': enabled}); @@ -119,7 +146,7 @@ class Radar { } } - static Future getLocation([String? accuracy]) async { + static Future getLocation({String? accuracy}) async { try { return await _channel.invokeMethod('getLocation', {'accuracy': accuracy}); } on PlatformException catch (e) { @@ -129,6 +156,7 @@ class Radar { } static Future trackOnce( + // maybe type it more strongly in the future? {Map? location, String? desiredAccuracy, bool? beacons}) async { @@ -144,7 +172,7 @@ class Radar { } } - static Future startTracking(String preset) async { + static Future startTracking({required String preset}) async { try { await _channel.invokeMethod('startTracking', { 'preset': preset, @@ -154,7 +182,8 @@ class Radar { } } - static Future startTrackingCustom(Map options) async { + static Future startTrackingCustom( + {required Map options}) async { try { await _channel.invokeMethod('startTrackingCustom', options); } on PlatformException catch (e) { @@ -163,10 +192,10 @@ class Radar { } static Future startTrackingVerified( - {bool? token, int? interval, bool? beacons}) async { + {required int interval, required bool beacons}) async { try { - await _channel.invokeMethod('startTrackingVerified', - {'token': token, 'interval': interval, 'beacons': beacons}); + await _channel.invokeMethod( + 'startTrackingVerified', {'interval': interval, 'beacons': beacons}); } on PlatformException catch (e) { print(e); } @@ -180,6 +209,14 @@ class Radar { } } + static Future stopTrackingVerified() async { + try { + await _channel.invokeMethod('stopTrackingVerified'); + } on PlatformException catch (e) { + print(e); + } + } + static Future isTracking() async { return await _channel.invokeMethod('isTracking'); } @@ -194,11 +231,11 @@ class Radar { } static Future mockTracking( - {Map? origin, - Map? destination, - String? mode, - int? steps, - int? interval}) async { + {required Map origin, + required Map destination, + required String mode, + required int steps, + required int interval}) async { try { return await _channel.invokeMethod('mockTracking', { 'origin': origin, @@ -214,7 +251,7 @@ class Radar { } static Future startTrip( - {Map? tripOptions, + {required Map tripOptions, Map? trackingOptions}) async { try { return await _channel.invokeMethod('startTrip', @@ -226,7 +263,7 @@ class Radar { } static Future updateTrip( - {required Map options, required String status}) async { + {required String status, required Map options}) async { try { return await _channel.invokeMethod( 'updateTrip', {'tripOptions': options, 'status': status}); @@ -258,7 +295,26 @@ class Radar { } } - static Future getContext(Map location) async { + static Future acceptEvent( + {required String eventId, String? VerifiedPlaceId}) async { + try { + _channel.invokeMethod('acceptEvent', + {'eventId': eventId, 'VerifiedPlaceId': VerifiedPlaceId}); + } on PlatformException catch (e) { + print(e); + } + } + + static Future rejectEvent({required String eventId}) async { + try { + _channel.invokeMethod('rejectEvent', {'eventId': eventId}); + } on PlatformException catch (e) { + print(e); + } + } + + static Future getContext( + {required Map location}) async { try { return await _channel.invokeMethod('getContext', {'location': location}); } on PlatformException catch (e) { @@ -267,19 +323,22 @@ class Radar { } } + // you have to pass in all or none of the parameters static Future searchGeofences( {Map? near, int? radius, List? tags, Map? metadata, - int? limit}) async { + int? limit, + bool? includeGeometry}) async { try { return await _channel.invokeMethod('searchGeofences', { 'near': near, 'radius': radius, 'limit': limit, 'tags': tags, - 'metadata': metadata + 'metadata': metadata, + 'includeGeometry': includeGeometry }); } on PlatformException catch (e) { print(e); @@ -288,9 +347,9 @@ class Radar { } static Future searchPlaces( - {Map? near, - int? radius, - int? limit, + {required int radius, + required limit, + Map? near, List? chains, Map? chainMetadata, List? categories, @@ -312,9 +371,9 @@ class Radar { } static Future autocomplete( - {String? query, + {required String query, + required int limit, Map? near, - int? limit, String? country, List? layers, bool? mailable}) async { @@ -333,10 +392,11 @@ class Radar { } } - static Future geocode(String query) async { + static Future geocode( + {required String query, List? layers, List? countries}) async { try { - final Map? geocodeResult = - await _channel.invokeMethod('forwardGeocode', {'query': query}); + final Map? geocodeResult = await _channel.invokeMethod('forwardGeocode', + {'query': query, 'layers': layers, 'countries': countries}); return geocodeResult; } on PlatformException catch (e) { print(e); @@ -344,10 +404,11 @@ class Radar { } } - static Future reverseGeocode(Map location) async { + static Future reverseGeocode( + {Map? location, List? layers}) async { try { - return await _channel - .invokeMethod('reverseGeocode', {'location': location}); + return await _channel.invokeMethod( + 'reverseGeocode', {'location': location, 'layers': layers}); } on PlatformException catch (e) { print(e); return {'error': e.code}; @@ -364,10 +425,10 @@ class Radar { } static Future getDistance( - {Map? origin, - Map? destination, - List? modes, - String? units}) async { + {required Map destination, + required List modes, + required String units, + Map? origin}) async { try { return await _channel.invokeMethod('getDistance', { 'origin': origin, @@ -384,7 +445,7 @@ class Radar { static Future logConversion( {required String name, double? revenue, - required Map metadata}) async { + Map? metadata}) async { try { return await _channel.invokeMethod('logConversion', {'name': name, 'revenue': revenue, 'metadata': metadata}); @@ -421,7 +482,7 @@ class Radar { // Android only static Future setNotificationOptions( - Map notificationOptions) async { + {required Map notificationOptions}) async { try { await _channel.invokeMethod( 'setNotificationOptions', notificationOptions); @@ -431,10 +492,7 @@ class Radar { } static Future getMatrix( - {required List origins, - required List destinations, - required String mode, - required String units}) async { + { required List origins, required List destinations,required String mode, required String units}) async { try { return await _channel.invokeMethod('getMatrix', { 'origins': origins, @@ -448,8 +506,9 @@ class Radar { } } + //Android only static Future setForegroundServiceOptions( - Map foregroundServiceOptions) async { + {required Map foregroundServiceOptions}) async { try { await _channel.invokeMethod( 'setForegroundServiceOptions', foregroundServiceOptions); @@ -460,17 +519,17 @@ class Radar { static Future trackVerified({bool? beacons}) async { try { - return await _channel.invokeMethod('trackVerified', {'beacons': beacons}); + return await _channel.invokeMethod( + 'trackVerified', {'beacons': beacons != null ? beacons : false}); } on PlatformException catch (e) { print(e); return {'error': e.code}; } } - static Future trackVerifiedToken({bool? beacons}) async { + static Future getVerifiedLocationToken() async { try { - return await _channel - .invokeMethod('trackVerifiedToken', {'beacons': beacons}); + return await _channel.invokeMethod('getVerifiedLocationToken'); } on PlatformException catch (e) { print(e); return {'error': e.code}; @@ -481,7 +540,7 @@ class Radar { return await _channel.invokeMethod('isUsingRemoteTrackingOptions'); } - static Future validateAddress(Map address) async { + static Future validateAddress({required Map address}) async { try { return await _channel .invokeMethod('validateAddress', {'address': address}); @@ -491,166 +550,116 @@ class Radar { } } - static onLocation(Function(Map res) callback) async { - try { - final CallbackHandle handle = - PluginUtilities.getCallbackHandle(callback)!; - await _channel.invokeMethod('on', - {'listener': 'location', 'callbackHandle': handle.toRawHandle()}); - } on PlatformException catch (e) { - print(e); + static onLocation(LocationCallback callback) { + if (foregroundLocationCallback != null) { + throw RadarExistingCallbackException(); } + foregroundLocationCallback = callback; } - static offLocation() async { - try { - await _channel.invokeMethod('off', {'listener': 'location'}); - } on PlatformException catch (e) { - print(e); - } + static offLocation() { + foregroundLocationCallback = null; } - static onClientLocation(Function(Map res) callback) async { - try { - final CallbackHandle handle = - PluginUtilities.getCallbackHandle(callback)!; - await _channel.invokeMethod('on', { - 'listener': 'clientLocation', - 'callbackHandle': handle.toRawHandle() - }); - } on PlatformException catch (e) { - print(e); + static void onClientLocation(ClientLocationCallback callback) { + if (foregroundClientLocationCallback != null) { + throw RadarExistingCallbackException(); } + foregroundClientLocationCallback = callback; } - static offClientLocation() async { - try { - await _channel.invokeMethod('off', {'listener': 'clientLocation'}); - } on PlatformException catch (e) { - print(e); - } + static offClientLocation() { + foregroundClientLocationCallback = null; } - static onError(Function(Map res) callback) async { - try { - final CallbackHandle handle = - PluginUtilities.getCallbackHandle(callback)!; - await _channel.invokeMethod( - 'on', {'listener': 'error', 'callbackHandle': handle.toRawHandle()}); - } on PlatformException catch (e) { - print(e); + static onError(ErrorCallback callback) { + if (foregroundErrorCallback != null) { + throw RadarExistingCallbackException(); } + foregroundErrorCallback = callback; } - static offError() async { - try { - await _channel.invokeMethod('off', {'listener': 'error'}); - } on PlatformException catch (e) { - print(e); - } + static offError() { + foregroundErrorCallback = null; } - static onLog(Function(Map res) callback) async { - try { - final CallbackHandle handle = - PluginUtilities.getCallbackHandle(callback)!; - await _channel.invokeMethod( - 'on', {'listener': 'log', 'callbackHandle': handle.toRawHandle()}); - } on PlatformException catch (e) { - print(e); + static onLog(LogCallback callback) { + if (foregroundLogCallback != null) { + throw RadarExistingCallbackException(); } + foregroundLogCallback = callback; } - static offLog() async { - try { - await _channel.invokeMethod('off', {'listener': 'log'}); - } on PlatformException catch (e) { - print(e); - } + static offLog() { + foregroundLogCallback = null; } - - static onEvents(Function(Map res) callback) async { - try { - final CallbackHandle handle = - PluginUtilities.getCallbackHandle(callback)!; - await _channel.invokeMethod( - 'on', {'listener': 'events', 'callbackHandle': handle.toRawHandle()}); - } on PlatformException catch (e) { - print(e); + + static onEvents(EventsCallback callback) { + if (foregroundEventsCallback != null) { + throw RadarExistingCallbackException(); } + foregroundEventsCallback = callback; } - static offEvents() async { - try { - await _channel.invokeMethod('off', {'listener': 'events'}); - } on PlatformException catch (e) { - print(e); - } + static offEvents() { + foregroundEventsCallback = null; } - static onToken(Function(Map res) callback) async { - try { - final CallbackHandle handle = - PluginUtilities.getCallbackHandle(callback)!; - await _channel.invokeMethod( - 'on', {'listener': 'token', 'callbackHandle': handle.toRawHandle()}); - } on PlatformException catch (e) { - print(e); + static onToken(TokenCallback callback) { + if (foregroundTokenCallback != null) { + throw RadarExistingCallbackException(); } + foregroundTokenCallback = callback; } - static offToken() async { - try { - await _channel.invokeMethod('off', {'listener': 'token'}); - } on PlatformException catch (e) { - print(e); - } + static offToken() { + foregroundTokenCallback = null; } static Map presetContinuousIOS = { - "desiredStoppedUpdateInterval": 30, - "desiredMovingUpdateInterval": 30, - "desiredSyncInterval": 20, - "desiredAccuracy":'high', - "stopDuration": 140, - "stopDistance": 70, - "replay": 'none', - "useStoppedGeofence": false, - "showBlueBar": true, - "startTrackingAfter": null, - "stopTrackingAfter": null, - "stoppedGeofenceRadius": 0, - "useMovingGeofence": false, - "movingGeofenceRadius": 0, - "syncGeofences": true, - "useVisits": false, - "useSignificantLocationChanges": false, - "beacons": false, - "sync": 'all', -}; - - static Map presetContinuousAndroid = { - "desiredStoppedUpdateInterval": 30, - "fastestStoppedUpdateInterval": 30, - "desiredMovingUpdateInterval": 30, - "fastestMovingUpdateInterval": 30, - "desiredSyncInterval": 20, - "desiredAccuracy": 'high', - "stopDuration": 140, - "stopDistance": 70, - "replay": 'none', - "sync": 'all', - "useStoppedGeofence": false, - "stoppedGeofenceRadius": 0, - "useMovingGeofence": false, - "movingGeofenceRadius": 0, - "syncGeofences": true, - "syncGeofencesLimit": 0, - "foregroundServiceEnabled": true, - "beacons": false, - "startTrackingAfter": null, - "stopTrackingAfter": null, -}; + "desiredStoppedUpdateInterval": 30, + "desiredMovingUpdateInterval": 30, + "desiredSyncInterval": 20, + "desiredAccuracy": 'high', + "stopDuration": 140, + "stopDistance": 70, + "replay": 'none', + "useStoppedGeofence": false, + "showBlueBar": true, + "startTrackingAfter": null, + "stopTrackingAfter": null, + "stoppedGeofenceRadius": 0, + "useMovingGeofence": false, + "movingGeofenceRadius": 0, + "syncGeofences": true, + "useVisits": false, + "useSignificantLocationChanges": false, + "beacons": false, + "sync": 'all', + }; + + static Map presetContinuousAndroid = { + "desiredStoppedUpdateInterval": 30, + "fastestStoppedUpdateInterval": 30, + "desiredMovingUpdateInterval": 30, + "fastestMovingUpdateInterval": 30, + "desiredSyncInterval": 20, + "desiredAccuracy": 'high', + "stopDuration": 140, + "stopDistance": 70, + "replay": 'none', + "sync": 'all', + "useStoppedGeofence": false, + "stoppedGeofenceRadius": 0, + "useMovingGeofence": false, + "movingGeofenceRadius": 0, + "syncGeofences": true, + "syncGeofencesLimit": 0, + "foregroundServiceEnabled": true, + "beacons": false, + "startTrackingAfter": null, + "stopTrackingAfter": null, + }; static Map presetResponsiveIOS = { "desiredStoppedUpdateInterval": 0, @@ -698,54 +707,61 @@ class Radar { }; static Map presetEfficientIOS = { - "desiredStoppedUpdateInterval": 0, - "desiredMovingUpdateInterval": 0, - "desiredSyncInterval": 0, - "desiredAccuracy": "medium", - "stopDuration": 0, - "stopDistance": 0, - "replay": 'stops', - "useStoppedGeofence": false, - "showBlueBar": false, - "startTrackingAfter": null, - "stopTrackingAfter": null, - "stoppedGeofenceRadius": 0, - "useMovingGeofence": false, - "movingGeofenceRadius": 0, - "syncGeofences": true, - "useVisits": true, - "useSignificantLocationChanges": false, - "beacons": false, - "sync": 'all', -}; - - static Map presetEfficientAndroid ={ - "desiredStoppedUpdateInterval": 3600, - "fastestStoppedUpdateInterval": 1200, - "desiredMovingUpdateInterval": 1200, - "fastestMovingUpdateInterval": 360, - "desiredSyncInterval": 140, - "desiredAccuracy": 'medium', - "stopDuration": 140, - "stopDistance": 70, - "replay": 'stops', - "sync": 'all', - "useStoppedGeofence": false, - "stoppedGeofenceRadius": 0, - "useMovingGeofence": false, - "movingGeofenceRadius": 0, - "syncGeofences": true, - "syncGeofencesLimit": 10, - "foregroundServiceEnabled": false, - "beacons": false, - "startTrackingAfter": null, - "stopTrackingAfter": null, -}; + "desiredStoppedUpdateInterval": 0, + "desiredMovingUpdateInterval": 0, + "desiredSyncInterval": 0, + "desiredAccuracy": "medium", + "stopDuration": 0, + "stopDistance": 0, + "replay": 'stops', + "useStoppedGeofence": false, + "showBlueBar": false, + "startTrackingAfter": null, + "stopTrackingAfter": null, + "stoppedGeofenceRadius": 0, + "useMovingGeofence": false, + "movingGeofenceRadius": 0, + "syncGeofences": true, + "useVisits": true, + "useSignificantLocationChanges": false, + "beacons": false, + "sync": 'all', + }; + + static Map presetEfficientAndroid = { + "desiredStoppedUpdateInterval": 3600, + "fastestStoppedUpdateInterval": 1200, + "desiredMovingUpdateInterval": 1200, + "fastestMovingUpdateInterval": 360, + "desiredSyncInterval": 140, + "desiredAccuracy": 'medium', + "stopDuration": 140, + "stopDistance": 70, + "replay": 'stops', + "sync": 'all', + "useStoppedGeofence": false, + "stoppedGeofenceRadius": 0, + "useMovingGeofence": false, + "movingGeofenceRadius": 0, + "syncGeofences": true, + "syncGeofencesLimit": 10, + "foregroundServiceEnabled": false, + "beacons": false, + "startTrackingAfter": null, + "stopTrackingAfter": null, + }; static Map presetResponsive = Platform.isIOS ? presetResponsiveIOS : presetResponsiveAndroid; static Map presetContinuous = Platform.isIOS ? presetContinuousIOS : presetContinuousAndroid; - static Map presetEfficient= + static Map presetEfficient = Platform.isIOS ? presetEfficientIOS : presetEfficientAndroid; } + +class RadarExistingCallbackException implements Exception { + @override + String toString() { + return 'Existing callback already exists for this event. Please call the corresponding `off` method first.'; + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 482f01e..5268b74 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,10 +1,10 @@ name: flutter_radar description: Flutter package for Radar, the leading geofencing and location tracking platform -version: 3.9.1 +version: 3.10.0-beta.3 homepage: https://github.com/radarlabs/flutter-radar environment: - sdk: '>=2.12.0 <3.0.0' + sdk: '>=2.12.0 <4.0.0' flutter: ">=1.20.0" dependencies: