Struggling to get a return from makeWebRequest() via Background


I'm attempting to make a makeWebRequest() from the background (of a DataField) but get absolutely no response (no error response) , not even a call to the designated 'callBackMethod'. I am able to use other methods in the communications class. For example, I'm able to use 'openWebPage()' no problem. I was curious if anyone has run into this problem or had any insight of changes that might occur when running things like this from the background.

Thanks

Here is the code:

using Toybox.Background;
using Toybox.Communications as Com;

function onReceive(responseCode, data) {

    if (responseCode == 200) {
         System.println("Request Successful | Data -> " + data);
    } else {
        System.println(responseCode);
    }
}

function makeRequest() {
    var url = "">www.mocky.io/.../5185415ba171ea3a00704eed";

    var options = {
        :method => Comm.HTTP_REQUEST_METHOD_GET,
        :responseType => Comm.HTTP_RESPONSE_CONTENT_TYPE_JSON
    };
        Comm.makeWebRequest(url, {}, options, method(:onReceive));
}

  • If this is in the sim, check out "View HTTP Traffic" under "File" in the sim.

  • Sample code seems to work in the simulator.

    using Toybox.Application;
    using Toybox.Background;
    using Toybox.Communications;
    using Toybox.System;
    using Toybox.WatchUi;
    
    (:background)
    class MyServiceDelegate extends System.ServiceDelegate {
    
    	function initialize() {
    		System.println("ServiceDelegate.initialize");
    		ServiceDelegate.initialize();
    	}
    	
    	function onTemporalEvent() {
    		System.println("ServiceDelegate.onTemporalEvent");
    		self.makeWebRequest();
    	}
    
        function makeWebRequest() {
            System.println("ServiceDelegate.makeWebRequest");
            
            var params = {
            };
            
            var options = {
                :method => Communications.HTTP_REQUEST_METHOD_GET,
                :headers => {
                	"Content-Type" => Communications.REQUEST_CONTENT_TYPE_JSON
                },
                :responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_JSON
            };
            
            Communications.makeWebRequest("https://www.mocky.io/v2/5185415ba171ea3a00704eed", params, options, self.method(:onWebResponse));
        }
        
        function onWebResponse(responseCode, data) {
        	System.println("ServiceDelegate.onWebResponse");
    	    if (responseCode == 200) { 
    	         System.println("Request Successful | Data -> " + data); 
    	    } else { 
    	        System.println(responseCode);
    	    }
    
        	Background.exit({});
        }	
    }
    
    class MyDataField extends WatchUi.SimpleDataField {
    
    	hidden var mEventTime;
    
    	function initialize() {
    		SimpleDataField.initialize();
    	}
    	
    	function compute(info) {
    		var timeNow = Time.now();
    		if (mEventTime == null) {
    			mEventTime = timeNow.add(new Time.Duration(300));
    		}
    		
    		return mEventTime.subtract(timeNow);
    	}
    }
    
    (:background) 
    class MyApp extends Application.AppBase {
    
        function initialize() {
        	System.println("App.initialize");
            AppBase.initialize();
        }
    
        function onStart(state) {
        	System.println("App.onStart");
        	AppBase.onStart(state);
        }
    
        function onStop(state) {
        	System.println("App.onStop");
        	AppBase.onStop(state);
        }
        
        function onAppInstall() {
        	System.println("App.onAppInstall");
        	AppBase.onAppInstall();
        }
        
        function onAppUpdate() {
        	System.println("App.onAppUpdate");
        	AppBase.onAppUpdate();
        }
        
        function getServiceDelegate() {
        	System.println("App.getServiceDelegate");
        	return [ new MyServiceDelegate() ];
        }
    
        function getInitialView() {
        	System.println("App.getInitialView");
        	
        	// 5 minutes from now
        	var eventTime = Time.now().add(new Time.Duration(300);
        	
        	Background.registerForTemporalEvent(eventTime);
    
            return [ new MyDataField() ];
        }
    }
    

  • This displays in the console immediately.

    Background: App.initialize
    Background: App.onStart
    Background: App.getServiceDelegate
    Background: ServiceDelegate.initialize
    Background: App.onAppUpdate
    Background: App.onStop
    App.initialize
    App.onStart
    App.getInitialView
    

    I press CTRL+A to terminate the app and leave the simulated device running, and I see this added to the console log:

    App.onStop
    

    I wait 5 minutes, and I see this appear:

    Background: App.initialize
    Background: App.onStart
    Background: App.getServiceDelegate
    Background: ServiceDelegate.initialize
    Background: ServiceDelegate.onTemporalEvent
    Background: ServiceDelegate.makeWebRequest
    Background: ServiceDelegate.onWebResponse
    Background: Request Successful | Data -> {hello=>world}
    Background: App.onStop

    I did notice an issue when creating this sample app. If you don't return an array from getServiceDelegate, the background process will start the app but it will stop immediately after returning to the system. There will be no error, it just stops silently.

  • hey  and guys please help me with this:
    how could i register some bg stuff ASAP, and after 1st run register again at every 5 minutes. how can i reach that? if i register a duration it will launch 1st time only after that; if i register a moment, it will only run once.

  • See https://forums.garmin.com/developer/connect-iq/f/discussion/5287/very-simple-sample-of-a-watch-face-with-a-background-process 

    and https://developer.garmin.com/connect-iq/connect-iq-faq/how-do-i-create-a-connect-iq-background-service/#howdoicreateaconnectiqbackgroundservice

    A background service will run at most ever 5 minutes, and if you exit an app and start it again, it will only run 5 minutes after it last ran.  To have something run right away, you're app needs to delete the temporal event when the main app exits, but even then, it will only run at startup if it last ran 5 or more minutes before.

  • thx mate! i did stumbled upon example link before, but i already had my bg task version running and ended up ignoring.
    now im gonna study both example and 2nd link to see what i missed.
    about your explanation, i feel like i could be clearer:

    -this page Toybox.Background (garmin.com) says in watches and widgets 5m restriction is reset upon app startup if you use a Time.Moment upon registering temporal event. but i am simulating a forerunner 245 music and the restriction is kept even so.

    -suposing 4 mins passed after last call when i just run app, how could i register temporal events in a way that it run 1 min after now (4+1 = 5 then ok) and then it keep running every 5 min. i know the basic would be to flag 1st run and register it with a Time.Moment = lastrun+5min, and then register again with a 5 min Time.Duration, but i am having trouble on where to place register calls, probably coz i am not very cozy at bg'ing ecosystem yet.

    any comments on these subject will be welcome.

  • Understand that if you require the main app to run to set the next temporal event, there are times that a temporal event won't run.  For example, if you are running a CIQ device app, no temporal events run during that time, and also there is the max of 30 seconds that a temporal event can run at one time.

  • With my background services, here's something else I do.  In the callback for the makeWebRequest, if the status is 200, I return the data (a dictionary), but if it's anything else, I return the status.

    Then in onBackground data, I use 

    if(data instanceof Number)

    to see if there was an error, and if so, display/handle it in the main app.  So if the background sees -104 in the callback for the makeWebRequest, the main app sees that -104 and can display a message like "No Phone"

  • thanks for all advices and examples i got all ideas running. but now i realized i will only need to make ONE web request per day and so i'm wondering if i call the web request once after day shifted without all the bg stuff would be safe and with no drawbacks. what you guys say about that?