I am getting the following error while trying to implement the Nativescript tutorial code found here
"originalStack": "Error: java.net.ConnectException: Connection refused\n
at ZoneAwareError (file:///data/data/org.nativescript.NotecardRestaurants/
files/app/tns_modules/nativescript-angular/zone-js/dist/zone-nativescript.js:993:33)\n...
Here is the source for app.module
import { NgModule, NO_ERRORS_SCHEMA } from "#angular/core";
import { NativeScriptModule } from "nativescript-angular/nativescript.module";
import { AppRoutingModule } from "./app.routing";
import { AppComponent } from "./app.component";
import { NativeScriptFormsModule } from "nativescript-angular/forms";
import { NativeScriptHttpModule } from "nativescript-angular/http";
import { UserService } from './shared/user/user.service';
import { LoginComponent } from "./login/login.component";
#NgModule({
bootstrap: [
AppComponent
],
imports: [
NativeScriptModule,
AppRoutingModule,
NativeScriptFormsModule,
NativeScriptHttpModule,
],
declarations: [
AppComponent,
LoginComponent
],
providers: [
UserService
],
schemas: [
NO_ERRORS_SCHEMA
]
})
export class AppModule { }
Here is the source for user.service that is causing the issue
import { Injectable } from "#angular/core";
import { Http, Headers, Response } from "#angular/http";
import { Observable } from "rxjs/Rx";
import "rxjs/add/operator/do";
import "rxjs/add/operator/map";
import { User } from "./user";
import { Config } from "../config";
#Injectable()
export class UserService {
constructor(private http: Http) {}
register(user: User) {
let headers = new Headers();
headers.append("Content-Type", "application/json");
return this.http.post(
Config.apiUrl + "/user/register",
JSON.stringify({
name: user.name,
email: user.email,
password: user.password
}),
{ headers: headers }
)
.map(response => response.json().token)
.catch(this.handleErrors);
}
login(user: User) {
let headers = new Headers();
headers.append("Content-Type", "application/json");
return this.http.post(
Config.apiUrl + "user/login",
JSON.stringify({
email: user.email,
password: user.password
}),
{ headers: headers }
)
.map(response => response.json().token)
.catch(this.handleErrors);
}
handleErrors(error: Response) {
console.dir(error.json());
return Observable.throw(error);
}
}
I have independently verified the integrity of the api I am using. The routes given do work. I am running the nativescript project using
tns run android --emulator
if you are running your application on IOS simulator or Android emulator, which is basically virtual machine and if you are referring 'localhost' or '127.0.0.1' these are IP of virtual machine not your development machine. you can solve your problem by providing IP of your development machine or in android you can use 10.0.2.2 IP for your development machine. sample of your api url is
https://10.0.2.2:5001/api/news/getnews
Related
I've been trying to set up this Ionic CLI proxy server following this guide, but it's from 2015 and I have no idea how to implement it in Angular 10.
So when I run my app with a command:
ionic capacitor run android --project=myApp -c=production
I have this error in Android Studio:
E/Capacitor/Console: File: http://localhost/login - Line 0 - Msg: Access to XMLHttpRequest at 'https://remoteServer.com/api/v1/oauth/v2/token' from origin 'http://localhost' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' head
This is my capacitor.config.json file:
{
"appId": "io.ionic.starter",
"appName": "myApp",
"bundledWebRuntime": false,
"npmClient": "npm",
"webDir": "www",
"plugins": {
"SplashScreen": {
"launchShowDuration": 0
}
},
"cordova": {},
"linuxAndroidStudioPath": "/opt/android-studio/bin/studio.sh"
}
And this is my ionic.config.json file:
{
"name": "myApp",
"integrations": {
"capacitor": {}
},
"type": "angular",
"proxies": [
{
"path": "/api",
"proxyUrl": "https://remoteServer.com/api"
}
]
}
ionic info
Ionic:
Ionic CLI : 6.10.1 (/home/user/.nvm/versions/node/v12.18.3/lib/node_modules/#ionic/cli)
Ionic Framework : #ionic/angular 5.3.1
#angular-devkit/build-angular : 0.1000.5
#angular-devkit/schematics : 10.0.5
#angular/cli : 10.0.5
#ionic/angular-toolkit : 2.3.3
Capacitor:
Capacitor CLI : 2.4.0
#capacitor/core : 2.4.0
Utility:
cordova-res : not installed
native-run : not installed
System:
NodeJS : v12.18.3 (/home/user/.nvm/versions/node/v12.18.3/bin/node)
npm : 6.14.6
OS : Linux 5.4
Any ideas how to resolve this? I've been searching for ages...
edit:
So I followed Angular's instructions on how to make an interceptor and this article that explains how to implement both HttpClient and Ionic's native HTTP, but I run into new issues.
Using the code from article, TS is complaining about this line:
headers: nativeHttpResponse.headers
(property) headers?: HttpHeaders
Type '{ [key: string]: string; }' is missing the following properties from type 'HttpHeaders': headers, normalizedNames, lazyInit, lazyUpdate, and 12 more.ts(2740)
http.d.ts(3406, 9): The expected type comes from property 'headers' which is declared here on type '{ body?: any; headers?: HttpHeaders; status?: number; statusText?: string; url?: string; }'
Here's the whole native-http.interceptor.ts:
import { Injectable } from "#angular/core";
import {
HttpInterceptor,
HttpRequest,
HttpHandler,
HttpEvent,
HttpResponse,
} from "#angular/common/http";
import { Observable, from } from "rxjs";
import { Platform } from "#ionic/angular";
import { HTTP } from "#ionic-native/http/ngx";
type HttpMethod =
| "get"
| "post"
| "put"
| "patch"
| "head"
| "delete"
| "upload"
| "download";
#Injectable()
export class NativeHttpInterceptor implements HttpInterceptor {
constructor(private nativeHttp: HTTP, private platform: Platform) {}
public intercept(
request: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
if (!this.platform.is("cordova")) {
return next.handle(request);
}
return from(this.handleNativeRequest(request));
}
private async handleNativeRequest(
request: HttpRequest<any>
): Promise<HttpResponse<any>> {
const headerKeys = request.headers.keys();
const headers = {};
headerKeys.forEach((key) => {
headers[key] = request.headers.get(key);
});
try {
await this.platform.ready();
const method = <HttpMethod>request.method.toLowerCase();
// console.log(‘— Request url’);
// console.log(request.url)
// console.log(‘— Request body’);
// console.log(request.body);
const nativeHttpResponse = await this.nativeHttp.sendRequest(
request.url,
{
method: method,
data: request.body,
headers: headers,
serializer: "json",
}
);
let body;
try {
body = JSON.parse(nativeHttpResponse.data);
} catch (error) {
body = { response: nativeHttpResponse.data };
}
const response = new HttpResponse({
body: body,
status: nativeHttpResponse.status,
headers: nativeHttpResponse.headers, <--------
url: nativeHttpResponse.url,
});
// console.log(‘— Response success’)
// console.log(response);
return Promise.resolve(response);
} catch (error) {
if (!error.status) {
return Promise.reject(error);
}
const response = new HttpResponse({
body: JSON.parse(error.error),
status: error.status,
headers: error.headers,
url: error.url,
});
return Promise.reject(response);
}
}
}
Here's how my app.module.ts looks like:
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { RouterModule } from '#angular/router';
import { FormsModule, ReactiveFormsModule } from '#angular/forms';
import { BrowserAnimationsModule } from '#angular/platform-browser/animations';
import { IonicModule } from '#ionic/angular';
import { HTTP } from '#ionic-native/http/ngx';
import { CoreModule } from './core/core.module';
import { SharedModule } from './shared/shared.module';
import { AppComponent } from './app.component';
import { PageNotFoundComponent } from './shared/page-not-found/page-not-found.component';
import { appRoutes } from './app.routes';
#NgModule({
imports: [
BrowserModule,
BrowserAnimationsModule,
FormsModule,
ReactiveFormsModule,
SharedModule,
CoreModule,
RouterModule.forRoot(
appRoutes
),
IonicModule.forRoot()
],
providers: [HTTP],
declarations: [
AppComponent,
PageNotFoundComponent
],
bootstrap: [AppComponent]
})
export class AppModule { }
Andd here is how my core.module.ts (where I want to use interceptor) looks like:
import { NgModule } from "#angular/core";
import { CommonModule } from "#angular/common";
import { HTTP_INTERCEPTORS, HttpClientModule } from "#angular/common/http";
import { NativeHttpInterceptor } from "./service/native-http.interceptor";
import { AuthService } from "./service/auth.service";
import { ApiService } from "./service/api.service";
import { AuthGuardService } from "./service/auth-guard.service";
import { AuthInterceptor } from "./service/auth-interceptor";
import { WindowRef } from "./service/window-ref-service";
#NgModule({
imports: [CommonModule, HttpClientModule],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: NativeHttpInterceptor,
multi: true,
},
AuthService,
ApiService,
AuthGuardService,
WindowRef,
{
provide: HTTP_INTERCEPTORS,
useClass: AuthInterceptor,
multi: true,
},
],
})
export class CoreModule {}
The proxy configs will only work for the ionic serve or the livereload of the native builds.
If you can't change any option in the BE, then the easiest way is to use a native plugin for the HTTP requests cordova-plugin-advanced-http which will send the requests without the origin header (As it is not sent from the browser).
You can use the Ionic Native wrapper for this from here.
Initial Situation:
I need to implement a Google login with Ionic which works on a web platform as well as on an android device.
Therefore I use:
Ionic 5.2.2
Capacitor 1.1.1
Capacitor OAuth 2 client plugin 1.0.0
With that setup I achieved already:
Web-Login workes perfectly
Problem:
Login in from an Android device doesn't work
I followed the steps in the readme from https://github.com/moberwasserlechner/capacitor-oauth2/blob/master/README.md
I registered the plugin OAuth2Client in my app.component.ts
I implemented a method googleLogin() where I call Plugins.OAuth2Client.authenticate() with OAuth2AuthenticateOptions
app.component.ts
import { Component, OnInit } from '#angular/core';
import { registerWebPlugin } from "#capacitor/core";
import { OAuth2Client } from '#byteowls/capacitor-oauth2';
#Component({
selector: 'app-root',
templateUrl: 'app.component.html'
})
export class AppComponent implements OnInit {
constructor() {}
ngOnInit() {
console.log("Register custom capacitor plugins");
registerWebPlugin(OAuth2Client);
}
}
home.page.ts
import { Component } from '#angular/core';
import { Plugins } from '#capacitor/core';
#Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
constructor() { }
async googleLogin() {
try {
const resourceUrlResponse = await Plugins.OAuth2Client.authenticate({
appId: "XXX.apps.googleusercontent.com",
authorizationBaseUrl: "https://accounts.google.com/o/oauth2/auth",
accessTokenEndpoint: "https://www.googleapis.com/oauth2/v4/token",
scope: "email profile",
resourceUrl: "https://www.googleapis.com/userinfo/v2/me",
web: {
redirectUrl: "http://localhost:8100",
windowOptions: "height=600,left=0,top=0"
},
android: {
appId: "XXX.apps.googleusercontent.com",
responseType: "code",
customScheme: "com.xxx.playground.googleLogin07"
}
})
}
catch (err) {
console.error(err);
}
}
}
On an device this code results in an error-message from Google:
enter image description here
This is plausible. It seems to be that the method Plugins.OAuth2Client.authenticate() tries to do a web-based login where an android login is needed. Am I right?
If I make a call without the "web"-parameter like this...
const resourceUrlResponse = await Plugins.OAuth2Client.authenticate({
appId: "XXX.apps.googleusercontent.com",
authorizationBaseUrl: "https://accounts.google.com/o/oauth2/auth",
accessTokenEndpoint: "https://www.googleapis.com/oauth2/v4/token",
scope: "email profile",
resourceUrl: "https://www.googleapis.com/userinfo/v2/me",
android: {
appId: "XXX.apps.googleusercontent.com", //--> I tried both, android- and web-client key from the google clout platform console.
responseType: "code",
customScheme: "com.xxx.playground.googleLogin07"
}
})
...the method Plugins.OAuth2Client.authenticate() returns a blank error object --> {}
What am I doing wrong?
My ionic 4 project works great on chrome, devapp and even after compiling to apk.
But once I add firebase config it fails to load using both devapp or even after compiling to apk.
here is how I add firebase:
first of all, I install it using npm install #angular/fire firebase --save
My environments.ts it looks like:
export const environment = {
production: false,
firebase: {
apiKey: 'xxxxxxxxxxxxxxx',
authDomain: 'xxxxxxxxxxxx.firebaseapp.com',
databaseURL: 'https://xxxxxxxxxxxxxx.firebaseio.com',
projectId: 'xxxxxxxxxxxxxxx',
storageBucket: 'xxxxxxxxxxxxxx.appspot.com',
messagingSenderId: 'xxxxxxxxxxxxxxx'
}
};
then I add these lines with trailing <<<< to my app.module.ts :
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { RouteReuseStrategy } from '#angular/router';
import { IonicModule, IonicRouteStrategy } from '#ionic/angular';
import { SplashScreen } from '#ionic-native/splash-screen/ngx';
import { StatusBar } from '#ionic-native/status-bar/ngx';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import { environment } from '../environments/environment'; <<<<
import { AngularFireModule } from '#angular/fire'; <<<<<
import { AngularFirestoreModule } from '#angular/fire/firestore'; <<<<
#NgModule({
declarations: [AppComponent],
entryComponents: [],
imports: [
BrowserModule,
IonicModule.forRoot(),
AppRoutingModule,
AngularFireModule.initializeApp(environment.firebase), <<<<
AngularFirestoreModule <<<<
],
providers: [
StatusBar,
SplashScreen,
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
],
bootstrap: [AppComponent]
})
export class AppModule {}
once I finish this, the app is no longer working on mobile ( white death screen)
And that is what I get when I use the chrome remote dev. tools:
Uncaught TypeError: Failed to construct 'HTMLElement': Please use the 'new' operator, this DOM object constructor cannot be called as a function.
Good afternoon guys, I'm using ng2-translate to do the translation of the app and run perfectly with the command: tns run ios | Android
But I'm having an error while running with webpack with the following parameters: tns run ios --bundle --env.uglify --env.aot
Error:
CONSOLE LOG file:///app/vendor.js:1:1200993:
CONSOLE ERROR file:///app/vendor.js:1:28276: ERROR TypeError: this.http.get(this.prefix+"/"+e+this.suffix).map is not a function. (In 'this.http.get(this.prefix+"/"+e+this.suffix).map(function(e){return e.json()})', 'this.http.get(this.prefix+"/"+e+this.suffix).map' is undefined)
CONSOLE ERROR file:///app/vendor.js:1:1125775: bootstrap: ERROR BOOTSTRAPPING ANGULAR
CONSOLE ERROR file:///app/vendor.js:1:1125775: bootstrap: this.http.get(this.prefix+"/"+e+this.suffix).map is not a function. (In 'this.http.get(this.prefix+"/"+e+this.suffix).map(function(e){return e.json()})', 'this.http.get(this.prefix+"/"+e+this.suffix).map' is undefined)
getTranslation#file:///app/vendor.js:1:886381
getTranslation#file:///app/vendor.js:1:887491
retrieveTranslations#file:///app/vendor.js:1:887380
setDefaultLang#file:///app/vendor.js:1:886824
n#file:///app/bundle.js:1:88782
ka#file:///app/vendor.js:1:110925
Repository to test: https://github.com/gustavost26/teste-ng2-translate
Good that you provided a example project, I was able to quickly review it and looks like you are using latest version of Angular and rxjs but your translate module is completely outdated.
Replace it with the refactored latest version of same package
npm install --save #ngx-translate/core #ngx-translate/http-loader
Updated app.module.ts
import { NgModule, NO_ERRORS_SCHEMA } from "#angular/core";
import { NativeScriptModule } from "nativescript-angular/nativescript.module";
import { NativeScriptFormsModule } from 'nativescript-angular/forms';
import { NativeScriptHttpClientModule } from 'nativescript-angular/http-client';
import { AppRoutingModule } from "./app.routing";
import { AppComponent } from "./app.component";
import { TranslateModule, TranslateLoader } from "#ngx-translate/core";
import { TranslateHttpLoader } from "#ngx-translate/http-loader";
import { ItemService } from "./pages/item/item.service";
import { ItemsComponent } from "./pages/item/items.component";
import { ItemDetailComponent } from "./pages/item/item-detail.component";
import { HttpClient } from "#angular/common/http";
export function HttpLoaderFactory(httpClient: HttpClient) {
return new TranslateHttpLoader(httpClient, '/assets/i18n/', '.json');
}
#NgModule({
bootstrap: [
AppComponent
],
imports: [
NativeScriptModule,
AppRoutingModule,
NativeScriptFormsModule,
NativeScriptHttpClientModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient]
}
})
],
declarations: [
AppComponent,
ItemsComponent,
ItemDetailComponent
],
providers: [
ItemService
],
schemas: [
NO_ERRORS_SCHEMA
]
})
/*
Pass your application module to the bootstrapModule function located in main.ts to start your app
*/
export class AppModule { }
Updated app.component.ts
import { Component } from "#angular/core";
import { TranslateService } from '#ngx-translate/core';
import * as Platform from "platform";
#Component({
selector: "ns-app",
moduleId: module.id,
templateUrl: "./app.component.html",
})
export class AppComponent {
constructor(private translate: TranslateService) {
this.translate.setDefaultLang('en'); //chage pt
//this.translate.use(Platform.device.language.split('-')[0]);
}
}
While running the app on device it does not get the api url
it does not fetch the url
I have used following coding
{
"v2": true,
"typescript": true,
"proxies": [
{
"path": "/api",
"proxyUrl": 'api url here'
}
]
}
Please give any suggustions
The proxy service is meant for testing in the browser to avoid the No 'Access-Control-Allow-Origin' header is present on the requested resource error when using an external API. But this is not a problem on devices and therefor there is no need for this proxy service. So, on devices use direct calls to your API url in stead of calls to http://localhost:8100.
If you want to test on both a device and browser, just check if Cordova is available (and so you're on a device) and then define which URL to use. Something like this:
import {Injectable} from '#angular/core';
import {Headers, Http} from '#angular/http';
import {Platform} from 'ionic-angular';
import 'rxjs/add/operator/toPromise';
import ...
#Injectable()
export class AccessService {
private headers = new Headers({'Content-Type': 'application/json'});
private apiUrl = '/v1/';
constructor(private http: Http,
public platform: Platform) {
if (this.platform.is('cordova')) { // <<< is Cordova available?
this.apiUrl = 'https://api.instagram.com/v1/';
}
}
login(username: string, password: string): Promise<string> {
let postParams = {
username: username,
password: password
};
return this.http
.post(this.apiUrl + 'login', postParams, this.headers)
.toPromise()
.then(response => response.json().devicetoken as string)
.catch(this.handleError);
}
}
...
}