Reputation: 3653
How can i use an angular http client in my background service (android).
My app needs to send the data from the background service to my server.
Im using NativeScript / Angular.
My Background Service
declare var android;
if (application.android) {
(<any>android.app.Service).extend("org.tinus.Example.BackgroundService", {
onStartCommand: function (intent, flags, startId) {
this.super.onStartCommand(intent, flags, startId);
return android.app.Service.START_STICKY;
},
onCreate: function () {
let that = this;
geolocation.enableLocationRequest().then(function () {
that.id = geolocation.watchLocation(
function (loc) {
if (loc) {
// should send to server from here
}
},
function (e) {
console.log("Background watchLocation error: " + (e.message || e));
},
{
desiredAccuracy: Accuracy.high,
updateDistance: 5,
updateTime: 5000,
minimumUpdateTime: 100
});
}, function (e) {
console.log("Background enableLocationRequest error: " + (e.message || e));
});
},
onBind: function (intent) {
console.log("on Bind Services");
},
onUnbind: function (intent) {
console.log('UnBind Service');
},
onDestroy: function () {
geolocation.clearWatch(this.id);
}
});
}
Two approaches i tried.
(1). Using Injector to inject my service
const injector = Injector.create([ { provide: ExampleService, useClass: ExampleService, deps: [HttpClient] }]);
const service = injector.get(ExampleService);
console.log(service.saveDriverLocation); // This prints
service.saveDriverLocation(new GeoLocation(loc.latitude, loc.longitude, loc.horizontalAccuracy, loc.altitude), ['id']); // This complains
Issue for (1)
System.err: TypeError: Cannot read property 'post' of undefined
(2). Using Native code
let url = new java.net.URL("site/fsc");
let connection = null;
try {
connection = url.openConnection();
} catch (error) {
console.log(error);
}
connection.setRequestMethod("POST");
let out = new java.io.BufferedOutputStream(connection.getOutputStream());
let writer = new java.io.BufferedWriter(new java.io.OutputStreamWriter(out, "UTF-8"));
let data = 'mutation NewDriverLoc{saveDriverLocation(email:"' + (<SystemUser>JSON.parse(getString('User'))).email + '",appInstanceId:' + (<ApplicationInstance>JSON.parse(getString('appInstance'))).id + ',geoLocation:{latitude:' + loc.latitude + ',longitude:' + loc.longitude + ',accuracy:' + loc.horizontalAccuracy + '}){id}}';
writer.write(data);
writer.flush();
writer.close();
out.close();
connection.connect();
Issue for (2)
System.err: Caused by: android.os.NetworkOnMainThreadException
So basically the first approach is angular, issue is that im not injecting all the needed services / not sure how.
Second approach is native, and the issue is the network is on the main thread. I need to use AsyncTask just not sure how
Upvotes: 1
Views: 1427
Reputation: 341
You can try using ReflectiveInjector, but remember to use NativeScriptHttpClientModule. I haven't tried it, so I can't say it'll work.
What I ended up using was the non-angular Http module. It's a bit hacky to not use services, but it works.
In the example below I was using BrowserXhr
from the deprecated @angular/http
package. I've updated to use the private angular API instead. The example has been updated.
So I ended up actually needing this and managed to inject the HttpClient in a non-angular application. This should also work with background services and workers.
import { HttpBackend, HttpClient, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HTTP_INTERCEPTORS, XhrFactory, ɵangular_packages_common_http_http_d as BrowserXhr, ɵHttpInterceptingHandler } from "@angular/common/http";
import { Injector } from '@angular/core';
import { NSFileSystem } from "nativescript-angular/file-system/ns-file-system";
import { NsHttpBackEnd } from "nativescript-angular/http-client/ns-http-backend";
import { Observable } from 'rxjs';
export class TestInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
console.log("intercepted", req);
return next.handle(req);
}
}
const httpClientInjector = Injector.create([
{
provide: HttpClient, useClass: HttpClient, deps: [
HttpHandler
]
},
{ provide: HttpHandler, useClass: ɵHttpInterceptingHandler, deps: [HttpBackend, Injector] },
{ provide: HTTP_INTERCEPTORS, useClass: TestInterceptor, multi: true, deps: [] }, // remove or copy this line to remove/add more interceptors
{ provide: HttpBackend, useExisting: NsHttpBackEnd },
{ provide: NsHttpBackEnd, useClass: NsHttpBackEnd, deps: [XhrFactory, NSFileSystem] },
{ provide: XhrFactory, useExisting: BrowserXhr },
{ provide: BrowserXhr, useClass: BrowserXhr, deps: [] },
{ provide: NSFileSystem, useClass: NSFileSystem, deps: [] }
]);
export const httpClient = httpClientInjector.get(HttpClient);
Note that I'm also leveraging Interceptors.
This implementation is missing HttpClientXsrfModule
, so you'll have to add it yourself if you intend to use it. That said, it seems XHR cookies are not currently supported: https://github.com/NativeScript/NativeScript/issues/2424
If you want to use a service like:
export class MyService {
constructor(private http: HttpClient) { }
}
You can add to the top of the array (after Injector.create[
) the following:
{ provide: MyService, useClass: MyService, deps: [HttpClient] }
(remeber that deps must be in the order required by your constructor!)
and then, you get your service by calling const myService = httpClientInjector.get(MyService);
Upvotes: 1
Reputation: 188
Please look at this link How do I fix android.os.NetworkOnMainThreadException?
Add the following to your native code like you mention in option 2. And it should work
let policy = new
android.os.StrictMode.ThreadPolicy.Buiilder().permitAll().build();
andriod.os.StrictMode.setThreadPolicy(policy);
Upvotes: 3