Client registration failed - android

I have developped an ibm mobile first application with adapter authorization and challenged handler.I have added an android environment and want to test it against production server, so I deployed the apk on my dev tablet.
I've seen that when trying to invoke a remote adapater worklight tries to get ClientInstanceId by executing a cordova method "WLAuthorizationManagerPlugingetClientInstanceIdHeader". This request results always in a timeout and I can see in console one new entru: "Uncaught (in promise) adapter-communication-error". The method exits with "WL.Logger.debug('Client registration failed with error: ' + JSON.stringify(error));"
Edited: Login flow:
Login implementation:
import {UserModel} from 'app-user';
import {UserService} from 'app-user-service';
import {AppSettingsService} from 'app-settings';
import {AppMasterDataService} from "../master-data/app-master-data-service";
import jsSha from 'js-sha';
import {UserRepository} from "user-repository";
import {NetworkInformation} from ../../infrastructure/phonegap/plugins/network-information';
export class LoggedInUser{
public static inject = [UserService, AppSettingsService, AppMasterDataService, UserRepository];
public info: UserModel;
public isLoggedIn: boolean;
private singleStepAuthRealmChallengeHandler: any;
private _getUserInfoPromise: Promise<UserModel>;
private _listeners: Array<(success: boolean, error: string) => void> = [];
private lastCredentials: any;
constructor(private _userService: UserService, private _settingsService: AppSettingsService, private _masterDataService: AppMasterDataService, private _userRepo: UserRepository){
if(typeof WL != "undefined"){
this.singleStepAuthRealmChallengeHandler = WL.Client.createChallengeHandler('GicarAuthRealm');
this.singleStepAuthRealmChallengeHandler.isCustomResponse = this.isCustomResponse.bind(this);
this.singleStepAuthRealmChallengeHandler.handleChallenge = this.handleChallenge.bind(this);
}
}
public async initializeUserInfo(): Promise<void>{
return this.executeLogOut(null, null);
}
public addLoginEventListener(callback: (success: boolean, error: string) => void){
if(!this._listeners.some(x => x === callback)){
this._listeners.push(callback);
}
}
public removeLoginEventListener(callback: (success: boolean, error: string) => void){
let index = this._listeners.indexOf(callback);
if(index >= 0){
this._listeners.splice(index, 1);
}
}
private raiseLoginEvent(success: boolean, error?: string){
for (var listener of this._listeners){
try {
listener(success, error);
}catch (e){
this.removeLoginEventListener(listener);
}
}
}
public prepareLogin(){
if(NetworkInformation.connected())
this._getUserInfoPromise = this._userService.getUserInfo();
}
public async executeLogIn(userName: string, password: string){//: Promise<boolean>{
await this.executeLogOut(userName, password);
if(this.singleStepAuthRealmChallengeHandler){
if(NetworkInformation.connected()){
var userNameSha = new jsSha("SHA-512", "TEXT");
userNameSha.update(userName);
var userNameHash = userNameSha.getHash("B64");
var passwordSha = new jsSha("SHA-512", "TEXT");
passwordSha.update(password);
var passwordHash = passwordSha.getHash("B64");
this.lastCredentials = {
userName: userNameHash,
password: passwordHash
};
var invocationData = {
adapter : "GicarAuthAdapter",
procedure : "submitAuthentication",
parameters : [ userName, window.btoa(userName + ':' + password) ]
};
this.singleStepAuthRealmChallengeHandler.submitAdapterAuthentication(invocationData);
}else {
this.doDisconnectedLogin(userName, password);
}
}
else{
this._userService.logIn(userName, password)
.then(info =>{
this.info = info;
this.isLoggedIn = typeof info !== 'undefined' && info != null;
this.raiseLoginEvent(this.isLoggedIn);
}).catch(e =>{
this.isLoggedIn = false;
this.info = null;
this.raiseLoginEvent(false, e.message ? e.message : e.toString())
});
}
}
private async doDisconnectedLogin(userName: string, password: string){
var userNameSha = new jsSha("SHA-512", "TEXT");
userNameSha.update(userName);
var userNameHash = userNameSha.getHash("B64");
var passwordSha = new jsSha("SHA-512", "TEXT");
passwordSha.update(password);
var passwordHash = passwordSha.getHash("B64");
var persisted = await this._userRepo.findUserByUserName(userNameHash);
let success = persisted && persisted.password == passwordHash;
this.info = persisted;
this.isLoggedIn = success;
this.raiseLoginEvent(success, success ? null : 'user-invalid-credentials');
}
public executeLogOut(userName: string, password: string): Promise<void>{
this.lastCredentials = null;
if(NetworkInformation.connected()){
return this._userService.logOut(this.info).then(() =>{
this.isLoggedIn = false;
this.info = null;
});
}
else
return Promise.resolve();
}
private isCustomResponse(response: any): boolean{
if (!response || !response.responseJSON || response.responseText === null) {
return false;
}
if (typeof(response.responseJSON.authRequired) !== 'undefined'){
return true;
} else {
return false;
}
}
private async handleChallenge(response: JQueryXHR){
var authRequired = response.responseJSON.authRequired;
if(authRequired == true){
this.info == null;
this.raiseLoginEvent(false, response.responseJSON.errorMessage);
}else {
try {
if(this.info == null){
this.singleStepAuthRealmChallengeHandler.submitSuccess();
this.info = await this._getUserInfoPromise;
await this._masterDataService.initializeMasterData(false);
if(this.lastCredentials){
await this._userRepo.saveUser({
entityId: this.lastCredentials.userName,
firstName: this.info.firstName,
lastName: this.info.lastName,
fullName: this.info.fullName,
email: this.info.email,
nif: this.info.nif,
address: this.info.address,
userName: this.lastCredentials.userName,
password: this.lastCredentials.password
});
}
this.isLoggedIn = true;
this.raiseLoginEvent(true);
}
}catch (error){
this.raiseLoginEvent(false, error.message ? error.message : error.toString());
}
}
}
}

I think I found the issue.
In order to support several environment, including desktopbrowser's one, I'm calling MFP adapter using the "old" method:`
WL.Client.invokeProcedure({
adapter: "UserServiceAdapter",
procedure: 'getUserInfo'
parameters: [],
compressResponse: false
},{
timeout:30000,
onSuccess: handleSuccess,
onFailure: handleFailure
});
If I replace above code by:
var resourceRequest = new WLResourceRequest("/adapters/UserServiceAdapter/getUserInfo", WLResourceRequest.GET, 30000);
resourceRequest.send().then(
handleSuccess,
handleFailure
);
It's working fine on Android.
It seems I have to check the environment in order to decide the adapter invocation method

Related

App uses to much memory as time increases

My app takes too much memory; 1GB and increases by time. If my app stays open for two days it crashes. Two possible causes:
utils-decorators used to cache data from an API:
import { memoizeAsync, Cache, memoize } from 'utils-decorators';
#memoizeAsync({
expirationTimeMs: 1000 * 60 * 60,
cache: serviceTempData.HttpClientCache
})
async getHtml(url: string, isImage?: boolean): Promise<HTMLElement>{
....
}
The custom cache :
export default class CustomCache implements Cache<any> {
private loadedFiles = new Map<string, any>();
private maxItems: number;
private clearSize: number;
constructor(maxItems?: number, clearSize?: number) {
this.maxItems = maxItems ?? 1000;
this.clearSize = clearSize ?? 500;
}
keys(){
var result = [] as string[];
for(var x of this.loadedFiles.keys())
result.push(x);
return result;
}
clearAll() {
this.loadedFiles.clear();
}
validate() {
var counter = this.clearSize;
if (this.loadedFiles.size > this.maxItems)
for (var key of this.loadedFiles.keys()) {
counter--;
this.loadedFiles.delete(key);
if (counter <= 0)
break;
}
}
set = (key: string, parameter: any) => {
this.validate();
this.loadedFiles.set(key, parameter);
}
get = (key: string) => {
return this.loadedFiles.get(key);
}
delete = (key: string) => {
if (this.loadedFiles.has(key))
this.loadedFiles.delete(key)
}
has = (key: string) => {
return this.loadedFiles.has(key)
}
}
Using expo.sqlight. I build and ORM expo-sqlite-wrapper around expo-sqlight.
I also have a background service running:
while (BackgroundService.isRunning()) {
const dData = [...downloads.filter(x => serviceOperations.DownloadTasks[x.novel] === undefined)]
if (dData.length > 0) {
await dData.asyncForeach(async x => {
console.log("Downloading" + x.novel);
serviceOperations.DownloadTasks[x.novel] = x;
var parser = BackGroundOperator.includedParser.find(f => x.parserName == f.name);
if (parser) {
var novel = await parser.getNovel(x.novel)
parser.downloadNovel(novel, () => {
if (BackGroundOperator.onDownloadStart && BackGroundOperator.onDownloadStart[x.novel] != undefined) {
BackGroundOperator.onDownloadStart[x.novel]();
delete BackGroundOperator.onDownloadStart[x.novel];
}
});
}
});
}
if (!workingOnMessages)
validateMessages();
if (!BackGroundOperator.serviceData && data) {
console.log("Playing")
BackGroundOperator.serviceData = data;
AudioService.task(BackGroundOperator.includedParser);
} else if (!data)
BackGroundOperator.serviceData = undefined;
if (!isWorking)
checkRemovableFiles();
if (!workingOnSessionProgress)
validateSession();
if (__DEV__ && pinger % 100 === 0) {
console.log("Service is still alive")
pinger = 0;
}
await HttpClient.wait(4000);
if (__DEV__)
pinger++
}

How to keep the user logged in even after closing the app in ionic/angular project?

I am new to angular/ionic and I am assigned with a project where the user supposed to be logged in even after he close the application unless logging out. can anyone suggest me how to modify the following code?
login.page.ts
import { AuthenticationService } from '../../services/authentication/authentication.service';
import {
ToastController,
AlertController,
NavController,
ModalController,
Platform,
} from '#ionic/angular';
import { FormBuilder, Validators, FormGroup } from '#angular/forms';
import { ApiService } from '../../services/api/api.service';
import { Router } from '#angular/router';
import { crm, environment } from '../../../environments/environment';
import { DataService } from '../../services/data/data.service';
import { ToastService } from '../../services/toast/toast.service';
import { AlertService } from '../../services/alert/alert.service';
import { ForgotPasswordModalPage } from '../forgot-password-modal/forgot-password-modal.page';
import { Device } from '#ionic-native/device/ngx';
import { FcmService } from '../../services/fcm/fcm.service';
import { SplashScreen } from '#ionic-native/splash-screen/ngx';
import { LoadingService } from 'src/app/services/loading/loading.service';
import { ServerService } from 'src/app/services/server/server.service';
import * as moment from 'moment';
import { AppComponent } from '../../app.component';
#Component({
selector: 'app-login',
templateUrl: './login.page.html',
styleUrls: ['./login.page.scss'],
})
export class LoginPage implements OnInit {
loginForm: FormGroup;
development: boolean;
counts: number = 0;
platformName: string;
settings: any;
constructor(
private authService: AuthenticationService,
public formBuilder: FormBuilder,
private api: ApiService,
private router: Router,
private alert: AlertService,
private dataService: DataService,
private toast: ToastService,
private navCtrl: NavController,
private modalCtrl: ModalController,
private device: Device,
private fcmService: FcmService,
private splashScreen: SplashScreen,
private loadingService: LoadingService,
private server: ServerService,
private alertCtrl: AlertController,
private platform: Platform,
private app: AppComponent,
) {
this.initForm();
}
ngOnInit(): void {
this.setupServerUrl();
}
async setSettings() {
console.log('settings called in appcomp');
// check if in storage get it from storage
this.dataService.getStorageData('settings').then((data) => {
if (data != null) {
this.settings = JSON.parse(data);
console.log('seetings from storage:', this.settings);
// this.dataService.setData('settings', this.settings)
} else {
// not found in storage get from api
this.getSettingsApi();
}
});
}
async getSettingsApi() {
// this.loadingService.loading();
let mainLogos = document.getElementsByClassName('logo');
for (let i = 0; i < mainLogos.length; i++) {
mainLogos[i].setAttribute('src', 'assets/img/spinner.gif');
}
await this.api.get(crm.SETTINGS).subscribe((res) => {
console.log('the api is ', this.api.url);
// Note the api I supposed to get
console.log('setting from appcomp api: ', res);
if (res['code'] === '000') {
this.settings = res;
// this.dataService.setData('settings', this.settings)
console.log('settings from appcomp done');
this.dataService.setStorageData('settings', res);
for (let i = 0; i < mainLogos.length; i++) {
mainLogos[i].setAttribute('src', this.settings.image_id.src);
}
// this.loadingService.dismissLoading();
}
});
}
// async setSettings() {
// console.log('settings from login')
// await this.dataService.getStorageData('settings').then( data => {
// console.log('seetings from storage: ', data)
// if (data != null) {
// this.settings = JSON.parse(data);
// this.dataService.setData('settings', this.settings)
// }else { // not found in storage get from api
// this.api.get(crm.SETTINGS).subscribe(res => {
// if (res['code'] === '000') {
//
// this.settings = res
// this.dataService.setData('settings', this.settings)
// this.dataService.setStorageData('settings', res);
// // this.settingsService.data = this.settings
//
// // toolbar logo
// // let mainLogos = document.getElementsByClassName('logo')
// // for (let i = 0; i < mainLogos.length; i++) {
// // mainLogos[i].setAttribute('src', this.settings.image_id.src)
// // }
// }
// })
// }
// })
// }
// Note : server set up and function coming from server.service
setupServerUrl() {
this.dataService.getStorageData('url').then((res) => {
if (res) {
this.server.url = JSON.parse(res);
console.log('server', res);
console.log('server result123: ', this.server.url);
console.log('login result123: ', this.server.login_url);
this.server.login_url = JSON.parse(res);
console.log('login', res);
// console.log('have result serve url:', this.server.url);
// console.log('have result login url:', this.server.login_url);
this.getApiDomain('https://oasis.api.app360.my/');
} else {
console.log('empty result url:', this.server.url);
this.getApiDomain('oasis.member.app360.my');
}
});
}
ionViewDidEnter() {
if (this.server.login_url === this.server.login_dev) {
this.development = true;
}
if (this.server.login_url === this.server.login_prod) {
this.development = false;
}
// this.setup()
// this.development = true;
// break;
// case this.server.prod:
// this.server.url = this.server.prod // added by me
// this.development = false;
// break;
// }
// })
}
initForm() {
this.loginForm = this.formBuilder.group({
email: [
'',
Validators.compose([
Validators.pattern('.+#.+\\..+'),
Validators.required,
]),
],
password: ['', Validators.required],
});
}
async getApiDomain(urlDomain: String) {
console.log('beforeeee', this.server.url);
await this.api
.getBeforeLogin(crm.API_DOMAIN, '', '?url=' + urlDomain)
.subscribe((res) => {
if (res['code'] === '000') {
// console.log('resulttt',res['domain'])
this.server.url = 'https://' + res['domain'] + '/';
this.server.prod = 'https://' + res['domain'] + '/';
this.server.secret = res['api_key'];
// this.server.url = "http://oasis.api.app360.my/"
console.log('afterrrr', this.server.url);
// console.log('afterrrr', this.server.secret);
this.getSettingsApi();
this.setHome();
this.checkToken();
}
});
}
// resolveSettings() {
// console.log('settings from login')
// this.api.get(crm.SETTINGS).subscribe(res => {
// if (res['code'] === '000') {
//
// this.settings = res
// this.dataService.setData('settings', this.settings)
// // this.settingsService.data = this.settings
//
// // toolbar logo
// let mainLogos = document.getElementsByClassName('logo')
// for (let i = 0; i < mainLogos.length; i++) {
// mainLogos[i].setAttribute('src', this.settings.image_id.src)
// }
//
//
// }
// })
// }
setup() {
console.log('testttt', this.settings);
// set toolbar color
let toolbars = document.getElementsByTagName('ion-toolbar');
for (let i = 0; i < toolbars.length; i++) {
toolbars[i].setAttribute(
'style',
`--background: ${this.settings.colours.colour_menu_background}`,
);
}
// toolbar logo
let mainLogos = document.getElementsByClassName('logo');
for (let i = 0; i < mainLogos.length; i++) {
mainLogos[i].setAttribute('src', this.settings.image_id.src);
console.log('wahaha', this.settings.image_id.src);
}
let button = document.getElementsByClassName('login-btn')[0];
button.setAttribute(
'style',
`--background: ${this.settings.colours.colour_button1};
--color: ${this.settings.colours.colour_menu_font}`,
);
console.log('endend');
}
async login(form) {
await this.loadingService.loading();
form.platform = this.device.platform;
form.device_type = this.device.model;
form.platform_token = this.device.uuid;
form.push_token = this.fcmService.pushToken;
console.log('form', form);
await this.api.post(crm.LOGIN, form).subscribe((res) => {
this.loadingService.dismissLoading();
console.log('login', res);
if (res.code === '000') {
console.log('code', res.code);
this.toast.showToast('Login Successful');
//proceed with auth
this.doAuth(res);
} else {
// let message = res.status+':'+res.statusText+'<br/>'+res.error.code+':'+res.error.message
this.alert.showAlert({
header: 'Error: ' + res.error.code,
message: res.error.message,
});
console.log('error', res);
}
});
}
async forgotPassword() {
console.log('do forgot password');
let modal = await this.modalCtrl.create({
component: ForgotPasswordModalPage,
cssClass: 'forgot-password',
});
return await modal.present();
}
doAuth(data) {
console.log('from do auth: ', data);
this.authService.login(data).then((res) => {
if (res) {
this.navCtrl.navigateRoot('/tabs/tabs/home');
console.log('doauth', data);
}
});
}
counter() {
this.counts++;
console.log(this.counts);
if (this.counts >= 8) this.presentPrompt(); //TODO: change to 8
}
async presentPrompt() {
this.counts = 0;
const alert = await this.alertCtrl.create({
header: ' ',
inputs: [
{
name: 'passcode',
placeholder: 'Passcode',
type: 'password',
},
],
buttons: [
{
text: 'Cancel',
role: 'cancel',
handler: (data) => {
console.log('Cancel clicked');
},
},
{
text: 'Ok',
handler: (data) => {
this.api
.getBeforeLogin(crm.SWITCH, null, `?passcode=${data.passcode}`)
.subscribe((res) => {
if (res['code'] == '000') {
this.changeServer();
console.log('Switched');
this.toast.showToast('Switched');
// this.loadingService.dismissLoading();
} else {
this.alert.showAlert({
header: 'Error: ' + res['code'],
message: res['error'],
});
console.log('error', res);
}
});
},
},
],
cssClass: 'alertCustomCss',
backdropDismiss: false,
});
await alert.present();
}
changeServer() {
this.server.switchURL();
switch (this.server.login_url) {
case this.server.login_prod:
this.development = false;
// this.api.url = this.server.prod;
this.server.login_url = this.server.login_prod;
console.log('api url', this.server.login_url);
break;
case this.server.login_dev:
this.development = true;
this.server.login_url = this.server.login_dev;
console.log('api url', this.server.login_url);
break;
}
this.checkDownload();
// Note :
this.getApiDomain('https://oasis.api.app360.my/');
// this.getApiDomain('com.apppay.cohibacustomer');
}
async checkDownload() {
await this.dataService.getStorageData('stats_for_dev').then((res) => {
if (!res) {
let params = {};
if (this.platform.is('android')) {
this.platformName = 'android';
} else if (this.platform.is('ios')) {
this.platformName = 'ios';
} else {
this.platformName = 'web';
}
params['refno'] = moment().format('YYYYMMDDHHmm');
params['data'] = [
{
action_cd: 'install',
user_id: null,
item_id: this.platformName[0], // a for android, i for ios
cnt: 1,
created_ts: moment().format('YYYY-M-D'),
},
];
} else {
console.log('have stats', JSON.parse(res));
}
});
}
async setHome() {
await this.api.get(crm.HOME).subscribe((res) => {
console.log('home>>>>>>>>>>>>>>>>>>>>>>>>> ', res);
this.dataService.setStorageData('home', res);
this.dataService.setData('home', res);
return res;
});
}
async checkToken() {
await this.dataService.getStorageData('member').then((res) => {
if (res != null) {
let token = res ? JSON.parse(res) : null;
token = token['secret'] ? token['secret'] : null;
if (token) {
this.authService.authenticationState.next(true);
if (this.server.url != this.server.check_url) {
this.navCtrl.navigateRoot('/tabs/tabs/home');
}
} else {
this.authService.authenticationState.next(false);
this.navCtrl.navigateRoot('');
}
}
});
}
}
authentication.service.ts
import { Platform, NavController } from "#ionic/angular";
import { Injectable } from "#angular/core";
import { Storage } from "#ionic/storage";
import { BehaviorSubject } from "rxjs";
import { DataService } from "../data/data.service";
import { ObservablesService } from "../observable/observables.service";
import { SplashScreen } from "#ionic-native/splash-screen/ngx";
import { Badge } from "#ionic-native/badge/ngx";
import { ServerService } from "../server/server.service";
const TOKEN_KEY = "auth-token";
export interface OcOAuth {
success: number;
error: any;
data: {
access_token: string;
expire_in: number;
token_type: string;
};
}
#Injectable({
providedIn: "root",
})
export class AuthenticationService {
authenticationState = new BehaviorSubject(false);
constructor(
private storage: Storage,
private plt: Platform,
private dataService: DataService,
private observable: ObservablesService,
private splashScreen: SplashScreen,
private navCtrl: NavController,
private badge: Badge,
private server: ServerService
) {
this.plt.ready().then(() => {
this.checkToken();
});
this.observable.unread().subscribe((res) => {
this.badge.set(res);
console.log("observed unread", res);
});
}
async checkToken() {
await this.storage.get("member").then((res) => {
if (res != null) {
let token = res ? JSON.parse(res) : null;
token = token["secret"] ? token["secret"] : null;
if (token) {
this.authenticationState.next(true);
if (this.server.url != this.server.check_url) {
this.navCtrl.navigateRoot("/tabs/tabs/home");
}
// console.log('server url: ', this.server.url);
//
} else {
this.authenticationState.next(false);
this.navCtrl.navigateRoot("");
}
}
});
}
login(data) {
return this.storage.set(TOKEN_KEY, "Bearer 1234").then(() => {
console.log("auth login", TOKEN_KEY);
this.dataService.setStorageData("member", data);
this.dataService.setData("member", data);
// this.dataService.setStorageData('profile', data.user)
this.observable.user.next(data.user);
this.authenticationState.next(true);
return true;
});
}
logout() {
return this.storage.remove("member").then(() => {
this.badge.clear();
this.authenticationState.next(false);
});
}
isAuthenticated() {
return this.authenticationState.value;
}
}
Firstly your code is so long that can not help with that but i can explain what u must do the concept is when you logged in successfully u must get a token and store that.
After at app openning you must check that stored token. If that token still available u can navigate to main screen. Else u must navigate to ur login page.
login() {
const attempt = login(username,pw)
if(attempt.status === 200) {
//if username and pw is correct web service must be return token
this.storage.set("token", attempt.token)
navigate("where u want")
} else {
//Error when username or pw wrong.
}
If u using ionic u must check ur token in app.component.ts
const token = await this.storage.get("token")
const checkTokenIsAvailable = await checkToken(token)
if(checkTokenIsAvailable) {
navigate("where u want")
//Token is still available
} else {
navigate("login screen")
}
That's all.
In your app.component.ts after platform is ready, add
if(this.authenticationService.isAuthenticated())
{
//Navigate to Home Page
}
else{
//Navigate to Login Page
}
so I was able to solve the issue with the subscribe() method. Inside platfrom.ready I called this
this.authService.authenticationState.subscribe((state) => {
if (state) {
this.navCtrl.navigateRoot("/tabs/tabs/home");
} else {
this.navCtrl.navigateRoot("");
}
});

ArgumentError (Invalid argument(s): Invalid internet address newsapi.org)

i have got runtime error "invalid internet address" but the api works fine .
Exception has occurred.
HttpException (HttpException: , uri = https://newsapi.org/v2/top-headlines?country=us&category=business&apiKey=d2c9e9553c4647f3add970ed74a812ee)
class News {
List<ArticleModel> news = [];
Future<void> getNews() async {
String url;
url = "https://newsapi.org/v2/top-headlines?country=us&category=business&apiKey=d2c9e9553c4647f3add970ed74a812ee";
var response = await http.get(Uri.parse(url));
var jsonData = jsonDecode(response.body);
if (jsonData['status'] == "ok") {
jsonData["articles"].forEach((element) {
if (element['urlToImage'] != null && element['description'] != null) {
ArticleModel articleModel = ArticleModel(
title: element['title'],
author: element['author'],
description: element['description'],
urlToImage: element['urlToImage'],
// publshedAt: DateTime.parse(element['publishedAt']),
content: element["content"],
url: element["url"],
);
news.add(articleModel);
}
});
}
}
}
The code worked for me after this change:
Future<void> getNews() async {
var url = Uri.parse('https://newsapi.org/v2/top-headlines?country=eg&apiKey=api');
var response = await http.get(url);

Retrofit Unexpected end of stream Connection

I'm currently trying to connect my android application to a local ASP.NET backend.
While doing so, I keep getting the error
Retrofit Unexpected end of stream Connection
I really have no clue where I'm wrong. I looked at other solutions, but none of those seem to help me.
I've read something about the content length being the issue. In my Startup.cs's configure method, I've noticed the following piece of code.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, DataInitializer dataInitializer)
{
app.Use(async (ctx, next) =>
{
await next();
if (ctx.Response.StatusCode == 204)
{
ctx.Response.ContentLength = 0;
}
});
However I have no idea if this is the cause of my issue.
Below I've added the rest of the code which might be part of the problem.
Startup.cs of .Net
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
//AddScopeds for each repository//
//...//
services.AddCors(o => o.AddPolicy("AllowAllOrigins", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();
}));
services.AddIdentity<IdentityUser, IdentityRole>(cfg => cfg.User.RequireUniqueEmail = true).AddEntityFrameworkStores<ApplicationDbContext>();
services.AddOpenApiDocument(
c =>
{
c.DocumentName = "apidocs";
c.Title = "Test API";
c.Version = "v1";
c.Description = "The Test API documentation description.";
c.DocumentProcessors.Add(new SecurityDefinitionAppender("JWT Token", new SwaggerSecurityScheme
{
Type = SwaggerSecuritySchemeType.ApiKey,
Name = "Authorization",
In = SwaggerSecurityApiKeyLocation.Header,
Description = "Copy 'Bearer' + valid JWT token into field"
}));
c.OperationProcessors.Add(new OperationSecurityScopeProcessor("JWT Token"));
}
);
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme =
JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x =>
{
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(Configuration["Tokens:Key"])),
ValidateIssuer = false,
ValidateAudience = false,
RequireExpirationTime = true //Ensure token hasn't expired
};
});
services.Configure<IdentityOptions>(options =>
{
// Password settings.
options.Password.RequireDigit = true;
options.Password.RequireLowercase = true;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
options.Password.RequiredLength = 8;
options.Password.RequiredUniqueChars = 1;
// Lockout settings.
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
options.Lockout.MaxFailedAccessAttempts = 5;
options.Lockout.AllowedForNewUsers = true;
// User settings.
options.User.AllowedUserNameCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._#+";
options.User.RequireUniqueEmail = true;
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, KlimaatMobielDataInitializer dataInitializer)
{
app.Use(async (ctx, next) =>
{
await next();
if (ctx.Response.StatusCode == 204)
{
ctx.Response.ContentLength = 0;
}
});
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseCors("AllowAllOrigins"); //
app.UseStaticFiles();
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", #"Resources")),
RequestPath = new PathString("/Resources")
});
app.UseHttpsRedirection();
app.UseMvc();
app.UseSwaggerUi3();
app.UseSwagger();
app.UseAuthentication();
}
}
Retrofit interface
private const val BASE_URL = "http://10.0.2.2:5001/api/"
private val retrofit = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(CoroutineCallAdapterFactory())
.baseUrl(BASE_URL)
.build()
interface TestApiService {
#GET("material")
fun getMaterials():
Call<List<Material>>
}
object TestApi {
val retrofitService: KlimaatApiService by lazy {
retrofit.create(KlimaatApiService::class.java)
}
}
Using the interface
public fun getMaterialen() {
Timber.plant(Timber.DebugTree())
KlimaatApi.retrofitService.getMaterialen().enqueue(object : Callback<List<Material>> {
override fun onFailure(call: Call<List<Material>>, t: Throwable) {
_response.value = "Failure: " + t.message
Timber.e(t.message)
}
override fun onResponse(
call: Call<List<Material>>,
response: Response<List<Material>>
) {
if(!response.isSuccessful){
Timber.e("Code: ${response.code()}")
}
var materials = response.body()
for(mat in materials!!){
Timber.e(mat.name)
}
}
})
}

Unable to retrieve access token for Moodle on Android phone

I have created an authentication service based on Jason Watmore's example, and it works fine in the Ripple emulator for Android, logs in, saves the token to jStorage, and uses it to access other web services.
It was also working in the actual Android phone till yesterday.
I have tested to see if jStorage is working in my Android phone (it is), and I have tried removing all the app's data using the Settings.
Any idea why the Android phone is not fetching the token from the Moodle server (but the emulator is fetching it)?
Here's my service:
myApp.factory('AuthenticationService',
['$http', '$cookies', '$rootScope', '$timeout', '$log',
function ($http, $cookies, $rootScope, $timeout, $log) {
var service = {};
service.Login = function (username, password, callback) {
//$log.info('Login function called');
if ((username.length && password.length) && (username !== '' && password != '')) {
var loginUrl = 'https://my.moodle.url/local/token.php';
// use $.param jQuery function to serialize data from JSON
var data = $.param({
username: username,
password: password,
service: 'brookesid_ws'
});
//$log.info(data);
var config = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8;'
}
}
$http.post(loginUrl, data, config)
.success(function (data, status, headers, config) {
$log.info(data);
myToken = data.token;
dataString = JSON.stringify(data);
if (dataString.indexOf('error') > 0) {
$rootScope.className = 'error';
$rootScope.PostDataResponse = 'Invalid user credentials, please try again';
$rootScope.isAuthenticated = false;
$rootScope.dataLoading = false;
}
else {
$.jStorage.set('session', myToken, { TTL: 28800000 });
//$cookies.put('session', myToken);
}
$rootScope.isAuthenticated = true;
// $log.info('isAuthenticated = true');
callback(dataString);
})
.error(function (data, status, header, config) {
$rootScope.isAuthenticated = false;
$rootScope.ResponseDetails = "data: " + data +
"<br />status: " + status +
"<br />headers: " + header +
"<br />config: " + config;
responsedata = JSON.stringify(data);
callback(responsedata);
$log.info('error: '+responsedata);
});
} else {
$rootScope.className = 'error';
$rootScope.isAuthenticated = false;
$rootScope.PostDataResponse = 'Please enter a username and password';
}
};
service.SetCredentials = function (sessionToken) {
var JSONObject = JSON.parse(sessionToken);
var key = 'token';
myToken = JSONObject[key];
$log.info('session Token: ' + sessionToken);
$log.info('myToken: ' + myToken);
$rootScope.globals = {
currentUser: {
token: myToken
}
};
$http.defaults.headers.common['Authorization'] = 'Basic ' + sessionToken; // jshint ignore:line
//retrieve last login date and then update it
$rootScope.lastLogin = $.jStorage.get('lastLogin', '');
var today = new Date();
epochToday = Math.round(today.getTime() / 1000);
$.jStorage.set('lastLogin', epochToday, { TTL: 28800000 });
//$log.info('Rootscope Last Login: '+$rootScope.lastLogin);
$.jStorage.set('globals', $rootScope.globals, { TTL: 28800000 });
$.jStorage.set('session', myToken, { TTL: 28800000 });
$.jStorage.set('loginStatus', 'logged in', { TTL: 28800000 });
$log.info('Token (jStorage) ' + $.jStorage.get('session', ''));
//$log.info('Last login (jStorage) ' + $.jStorage.get('lastLogin', ''));
//$log.info('Login status (jStorage) ' + $.jStorage.get('loginStatus', ''));
};
service.ClearCredentials = function () {
$rootScope.globals = {};
//$cookies.remove('globals');
//$cookies.remove('session');
$.jStorage.deleteKey('globals');
$.jStorage.deleteKey('session');
$http.defaults.headers.common.Authorization = 'Basic ';
};
return service;
}])
Here is my login Controller:
.controller('loginCtrl',
['$scope', '$rootScope', '$location', 'AuthenticationService', '$routeParams', '$http',
function ($scope, $rootScope, $location, AuthenticationService, $routeParams, $http) {
$scope.login = function () {
$scope.dataLoading = true;
AuthenticationService.Login($scope.username, $scope.password, function (response) {
responsedata = JSON.stringify(response);
/* error handling*/
if (responsedata.indexOf('error') > 0 || responsedata.indexOf('invalid') > 0) {
$scope.error = response.message;
$rootScope.className = 'error';
$rootScope.dataLoading = false;
} else {
AuthenticationService.SetCredentials(response);
console.log('response: '+response);
$location.path('/home');
};
});
};
$scope.logout = function () {
$rootScope.dataLoading = false;
$rootScope.hideMe = true;
$rootScope.PostDataResponse = '';
$rootScope.ResponseDetails = '';
//alert('logging out');
AuthenticationService.ClearCredentials();
};
$scope.showMenuPanel = function () {
$scope.hideMenuPanel = false;
};
$scope.doHideMenuPanel = function () {
$scope.hideMenuPanel = true;
$rootScope.PostDataResponse = '';
};
}])
It was actually the Cordova app's URL whitelisting settings that were causing the problem.

Categories

Resources