简体   繁体   English

如何在本机后台服务中使用(角度)HTTP客户端-NativeScript

[英]How to use (angular) HTTP Client in native background service - NativeScript

How can i use an angular http client in my background service (android). 如何在后台服务(android)中使用有角度的http客户端。

My app needs to send the data from the background service to my server. 我的应用程序需要将数据从后台服务发送到我的服务器。

Im using NativeScript / Angular. 我正在使用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). (1)。 Using Injector to inject my service 使用Injector注入我的服务

         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) 发行(1)

System.err: TypeError: Cannot read property 'post' of undefined

(2). (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) 发行(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 我需要使用AsyncTask只是不确定如何

Please look at this link How do I fix android.os.NetworkOnMainThreadException? 请查看此链接如何修复android.os.NetworkOnMainThreadException?

Add the following to your native code like you mention in option 2. And it should work 像在选项2中提到的那样,将以下内容添加到您的本机代码中。

let policy = new 
android.os.StrictMode.ThreadPolicy.Buiilder().permitAll().build();
andriod.os.StrictMode.setThreadPolicy(policy);

You can try using ReflectiveInjector , but remember to use NativeScriptHttpClientModule. 您可以尝试使用ReflectiveInjector ,但请记住使用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 . 我最终使用的是非角度的Http模块 It's a bit hacky to not use services, but it works. 不使用服务有点麻烦,但是可以。

Edit (June/2019) 编辑(2019年6月)

In the example below I was using BrowserXhr from the deprecated @angular/http package. 在下面的示例中,我使用了不推荐使用的@angular/http包中的BrowserXhr I've updated to use the private angular API instead. 我已更新为使用私有的angular API。 The example has been updated. 该示例已更新。

Edit (April/2019) 编辑(2019年4月)

So I ended up actually needing this and managed to inject the HttpClient in a non-angular application. 因此,我最终实际上需要这个,并设法将HttpClient注入非角度应用程序中。 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. 此实现缺少HttpClientXsrfModule ,因此,如果要使用它,则必须自己添加它。 That said, it seems XHR cookies are not currently supported: https://github.com/NativeScript/NativeScript/issues/2424 也就是说,似乎当前不支持XHR cookie: 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: 您可以将以下内容添加到数组的顶部(在Injector.create[ ):

{ provide: MyService, useClass: MyService, deps: [HttpClient] } (remeber that deps must be in the order required by your constructor!) { provide: MyService, useClass: MyService, deps: [HttpClient] } (请记住,deps必须按照构造函数要求的顺序!)

and then, you get your service by calling const myService = httpClientInjector.get(MyService); 然后,通过调用const myService = httpClientInjector.get(MyService);获得服务const myService = httpClientInjector.get(MyService);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM