2

I'm working on an ionic-angular app and post request is working fine when tested on browser using ionic serve but when excecuted on anroid device or emulator, the request doesn't work.

The backend is a rest api using slim php and xampp on windows server

The response for the request in android device is:

{"headers":{"normalizedNames":{},"lazyUpdate":null,"headers":{}},"status":0,"statusText":"Unknown Error","url":"http://<>/ws_login.php/login","ok":false,"name":"HttpErrorResponse","message":"Http failure response for http://<>/ws_login.php/login: 0 Unknown Error","error":{"isTrusted":true}}

My login code looks like:

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { HttpClientModule, HttpClient, HttpHeaders } from '@angular/common/http';
import { AuthConstants } from '../config/auth-constants';
import { ToastService } from './../services/toast.service';
import { LoadingService } from './../services/loading.service';
import { StorageService } from './../services/storage.service';
import { environment } from '../../environments/environment';

@Component({
    selector: 'app-login',
    templateUrl: './login.page.html',
    styleUrls: ['./login.page.scss'],
})
export class LoginPage implements OnInit {
    data = {
        user : '',
        pass : ''
    }

    constructor(
        public http: HttpClient, 
        private router: Router, 
        private toastService: ToastService,
        private loadingService: LoadingService,
        private storageService: StorageService
    ) { }

    ngOnInit() {
        this.storageService.get(AuthConstants.AUTH).then(
            data => data?this.router.navigate(["home"]):null
        )
    }

    login() {
        var headers = new HttpHeaders();
        headers.append("Accept", 'application/json');
        headers.append('Content-Type', 'application/json' );
        const requestOptions = { headers: headers };

        if(this.data.user == "" || this.data.pass == "")
            return this.toastService.presentToast("Debe completar ambos campos", "danger");

        this.loadingService.showLoading("Iniciando sesión");
        console.log(environment.apiUrl+'ws_login.php/login');
        this.http.post(environment.apiUrl+'ws_login.php/login', this.data, requestOptions).subscribe(
            resp => {
                this.loadingService.hideLoading();
                if(resp){
                    if(resp['error'] == 1)
                        this.toastService.presentToast(resp['mensaje'], "danger");
                    else{
                        this.storageService.store(AuthConstants.AUTH, 1);
                        this.toastService.presentToast("Sesión iniciada con éxito", "success");
                        this.router.navigate(["home"]);
                    }
                }
                else
                    this.toastService.presentToast("Error de red", "danger");
            }, 
            error => {
                this.data.user = JSON.stringify(error);
                this.loadingService.hideLoading();
                this.toastService.presentToast("Error de red", "danger");
            }
        );/*
        console.log(AuthConstants.AUTH);
        AuthConstants.AUTH = {id: 1};*/
        //this.router.navigate(["home"]);
    }
}

I also test the api using a rest app on device and the same url answers without problem.

I added android:usesCleartextTraffic="true" to androd manifest and was not the solution.

Here mi ionic info

Ionic:

   Ionic CLI                     : 6.3.0 (C:\Users\Manu\AppData\Roaming\npm\node_modules\@ionic\cli)
   Ionic Framework               : @ionic/angular 5.0.7
   @angular-devkit/build-angular : 0.803.26
   @angular-devkit/schematics    : 8.3.26
   @angular/cli                  : 8.3.26
   @ionic/angular-toolkit        : 2.2.0

Capacitor:

   Capacitor CLI   : 2.0.0
   @capacitor/core : 2.0.0

Utility:

   cordova-res : 0.11.0
   native-run  : 0.3.0

System:

   NodeJS : v12.16.1 (C:\Program Files\nodejs\node.exe)
   npm    : 6.13.4
   OS     : Windows 10

Thanks!

Manolo
  • 125
  • 2
  • 10

4 Answers4

1

Since the error says that you are posting to http://<>/ws_login.php/login, I guess that there is a mistake in your environment variable apiUrl, when you deploy to mobile. If you serve the app on your developer machine, it will take the environment.ts to get the variables. Maybe you build the app for your phone in production and thus don't get the right environment variables (since Ionic then uses environment.prod.ts?

Eweren
  • 277
  • 1
  • 12
  • The url is fine, I used console log and toasts to check it, I thougth the enviromets could be the problem so I set the same apiUrl for both to avoid this problem – Manolo Apr 17 '20 at 20:46
  • Maybe. Relating to https://stackoverflow.com/questions/41968860/istrustedtrue-exception-in-core-umd-js, the core of this issue could be cors. – Eweren Apr 18 '20 at 03:11
0

Apparently angular httpClient has some issues when executed on native devices and emulators, my solution was migrating the request to ionic native http.

Thanks for the help!

Manolo
  • 125
  • 2
  • 10
0

you can try ionic advance HTTP with mobile device https://ionicframework.com/docs/native/http, but it does not work with web browsers it only works in the mobile device. so you can try solution as check the platform and return HTTP service object as per users platform. example: if user platform==web then return Angular HttpClient else if user platform==Android/Ios then return Advnace Http object.

or you can use this code directly which has a wrapper around HTTP service,

import { Injectable } from '@angular/core';
import { Platform } from '@ionic/angular';
import { HttpClient } from '@angular/common/http';
import { HTTP } from '@ionic-native/http/ngx';
import { from, observable, Observable, of } from 'rxjs';
import { environment } from './../../environments/environment';
import { map, catchError } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})

export class HttpService {

  constructor(private platform: Platform, private httpclient: HttpClient, private http: HTTP) {
  }

  HttpRequest(method: 'POST'|'GET', url: string, requestBody: any): any
  {

    url = environment.serverBaseUrl + url;

    const headers = {};

    if (this.platform.is('ios') || this.platform.is('android') || this.platform.is('mobile'))
    {
    if (method === 'POST')
    {
      console.log('Advance_HTTP_POST');
      return from(this.http.post(url, requestBody, headers)).pipe(map((data: any) => JSON.parse(data?.data)));
    } else if (method === 'GET')
    {
      console.log('Advance_HTTP_GET');
      return from(this.http.get(url, {}, headers)).pipe(map((data: any) => JSON.parse(data?.data)));
    }
  } else {
    if (method === 'POST')
    {
      console.log('HTTPClient_HTTP_POST');
      return this.httpclient.post(url, requestBody, {headers});
    } else if (method === 'GET')
    {
      console.log('HTTPClient_HTTP_GET');
      return this.httpclient.get(url, {headers});
    }
    }
  }
}
0

I was facing the same issue. In my case, I was doing a PROD build and the environment.prod.ts file didn't have the hosted API links.

I followed the below steps and my issue was resolved:

  1. Update the environment.prod.ts file links to your hosted api.

    enter image description here

  2. Build your SPA to the www (any folder configured in your app) folder with the required configuration.

  3. Add platform if it is the first instance - npx cap add android

  4. Copy resources to the platform code - npx cap copy

  5. Update the android app if any plugin is added - npx cap update

  6. Open android app - npx cap open android

  7. Check the app in the emulator and test API response.

BINGO! Hope this helps someone in need.

Prasad Kaiche
  • 591
  • 3
  • 10