Given the following JSON payload: {"foo": 42}
If makeWebRequest fetches that payload from outside a Media.SyncDelegate context, 42 is parsed as Lang.Number. However, if the makeWebRequest fetch is made within a Media.SyncDelegate context, it will be parsed as a Lang.Float.
This only occurs in CIQ 4.1.5. Previous versions don't exhibit this behavior.
LOGGING OUTPUT
- CIQ 4.1.5
Making request outside of SyncDelegate
responseCode=200 data={foo=>42}
[OK] saw a number
Making request inside of SyncDelegate.onStartSync()
responseCode=200 data={foo=>42.000000}
[FAIL] saw a float
Making request outside of SyncDelegate
responseCode=200 data={foo=>42}
[OK] saw a number
- CIQ 4.1.4
Making request outside of SyncDelegate
responseCode=200 data={foo=>42}
[OK] saw a number
Making request inside of SyncDelegate.onStartSync()
responseCode=200 data={foo=>42}
[OK] saw a number
- CIQ 4.1.3
Making request outside of SyncDelegate
responseCode=200 data={foo=>42}
[OK] saw a number
Making request inside of SyncDelegate.onStartSync()
responseCode=200 data={foo=>42}
[OK] saw a number
Example Code
// App.mc import Toybox.Application; import Toybox.Communications; import Toybox.Lang; import Toybox.Media; import Toybox.System; import Toybox.WatchUi; class FloatJSONBugApp extends Application.AudioContentProviderApp { var inFlight = false; function initialize() { AudioContentProviderApp.initialize(); } // onStart() is called on application start up function onStart(state as Dictionary?) as Void { } function makeRequest(msg) { if (self.inFlight) { return; } System.println(msg); self.inFlight = true; var url = "https://garmin-check-tls.s3.amazonaws.com/floatbug.json"; var parameters = {}; var options = {}; var responseCallback = self.method(:onResponse); Communications.makeWebRequest(url, parameters, options, responseCallback); } function onResponse(responseCode, data) { self.inFlight = false; var msg = "responseCode=" + responseCode + " data=" + data; System.println(msg); if (responseCode != 200) { return; } switch (data["foo"]) { case instanceof Lang.Float: System.println("[FAIL] saw a float"); break; case instanceof Lang.Number: System.println("[OK] saw a number"); break; default: System.println("[FAIL] saw other"); break; } } // onStop() is called when your application is exiting function onStop(state as Dictionary?) as Void { } // Get a Media.ContentDelegate for use by the system to get and iterate through media on the device function getContentDelegate(arg as PersistableType) as ContentDelegate? { return new FloatJSONBugContentDelegate(); } // Get a delegate that communicates sync status to the system for syncing media content to the device function getSyncDelegate() as SyncDelegate? { return new FloatJSONBugSyncDelegate(); } // Get the initial view for configuring playback function getPlaybackConfigurationView() as Array<Views or InputDelegates>? { self.makeRequest("Making request outside of SyncDelegate"); return [ new FloatJSONBugConfigurePlaybackView(), new FloatJSONBugConfigurePlaybackDelegate() ] as Array<Views or InputDelegates>; } // Get the initial view for configuring sync function getSyncConfigurationView() as Array<Views or InputDelegates>? { return [ new FloatJSONBugConfigureSyncView(), new FloatJSONBugConfigureSyncDelegate() ] as Array<Views or InputDelegates>; } } function getApp() as FloatJSONBugApp { return Application.getApp() as FloatJSONBugApp; } // SyncDelegate.mc import Toybox.Application; import Toybox.Communications; import Toybox.Lang; import Toybox.Media; import Toybox.System; class FloatJSONBugSyncDelegate extends Media.SyncDelegate { function initialize() { SyncDelegate.initialize(); } // Called when the system starts a sync of the app. // The app should begin to download songs chosen in the configure // sync view . function onStartSync() as Void { var app = Application.getApp(); app.makeRequest("Making request inside of SyncDelegate.onStartSync()"); Media.notifySyncComplete(null); } // Called by the system to determine if the app needs to be synced. function isSyncNeeded() as Boolean { return true; } // Called when the user chooses to cancel an active sync. function onStopSync() as Void { Communications.cancelAllRequests(); Media.notifySyncComplete(null); } }