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++
}
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("");
}
});
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)
}
}
})
}
webview video event "onShowCustomView" is firing on fullscreen but when I go back to small screen no listner works.
also when I put in on in fullscreen. both functions
onShowCustomView and onHideCustomView works togeather . whe i try to come back to small screen . nither of function is called .
function onWebViewLoaded1(webargs, url) {
var page = webargs.object.page;
var webview = webargs.object;
var customViewContainer = view.getViewById(webview, 'singleimgpopup');
var viewr = view;
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var MyWebChromeClient = /** #class */ (function (_super) {
__extends(MyWebChromeClient, _super);
function MyWebChromeClient() {
var _this = _super.call(this) || this;
return global.__native(_this);
}
MyWebChromeClient.prototype.onStop = function(){
console.log("this");
}
MyWebChromeClient.prototype.onShowCustomView = function (view, callback) {
// Store the view and its callback for later (to kill it properly)
if(this.mCustomView != null){
callback.onCustomViewHidden(); return
}
this.mCustomView = view;
// webview.setVisibility(View.GONE);
this.mCustomViewCallback = callback;
console.log('fullscreen');
};
MyWebChromeClient.prototype.onHideCustomView = function () {
console.log("this2");
_super.prototype.onHideCustomView.call(this);
_super.prototype.mCustomView = null;
};
return MyWebChromeClient;
}(android.webkit.WebChromeClient));
webview.android.getSettings().setJavaScriptEnabled(true);
webview.android.getSettings().setAppCacheEnabled(true);
webview.android.getSettings().setBuiltInZoomControls(true);
webview.android.getSettings().setSaveFormData(true);
let myWebChromeClient = new MyWebChromeClient();
webview.android.setWebChromeClient(myWebChromeClient);
// console.log("1=====================url",url);
// webview.android.loadUrl(url);
}
the above works but i can console.log("put fullscreen").
But
I am not able to catch instance/event/listner on "EXIT FULLSCREEN" when i click on icon given below.How can i know if some person has clicked on icon given below.
This is the code for nativescript-videoplayer fullscreen button you need to update code in videoplayer.android.js for more you can ask me in detail.
var viewx = android.view.View;
const view_n = require("tns-core-modules/ui/core/view");
var isFullScreen="";
var fullscreenx = android.widget.MediaController.extend({
init:function(context){
;
},
setAnchorView:function(view) {
this.super.setAnchorView(view);
//image button for full screen to be added to media controller
var fullScreen = new android.widget.ImageButton(this.super.getContext());
var params = new FrameLayout.LayoutParams(80,80);
params.gravity = Gravity.RIGHT;
// params.layout_width = 'wrap_content';
// params.layout_height = 'match_parent'; MATCH_PARENT
//fullScreen.style="background-color:#000000; background-image: url('~/images/info.png'); background-repeat:no-repeat;background-size: 40 40;background-position:center center;";
params.rightMargin = 80;
var x = this.super.getContext().getResources().getIdentifier("minimizescreen", "drawable",
this.super.getContext().getPackageName() );
var y = this.super.getContext().getResources().getIdentifier("fullscreen", "drawable",
this.super.getContext().getPackageName() );
// fullScreen.setBackgroundResource("#drawable/icon");
this.addView(fullScreen, params);
//fullscreen indicator from intent
// isFullScreen = view.getContext().getIntent().
// getStringExtra("fullScreenInd");
if(isFullScreen=="y"){
fullScreen.setImageResource(x);
//fullScreen.setBackgroundResource(R.drawable.buttonOff);
//fullScreen.setImageResource(this.getContext().getResources().getDrawable(android.support.customtabs.R.drawable.icon));
// console.log('android.R.drawable.ic_fullscreen_exit=============',android.support.customtabs.R.drawable(), android.support.customtabs.R.drawable.abc_ic_star_black_16dp());
}else{
fullScreen.setImageResource(y);
//fullScreen.setBackgroundResource(R.drawable.buttonOn);
//fullScreen.setImageResource(this.getContext().getResources().getDrawable(android.support.customtabs.R.drawable.icon));
// console.log('android.R.drawable.ic_fullscreen=============',android.support.customtabs.R.drawable, android.support.customtabs.R.drawable.abc_popup_background_mtrl_mult());
}
var completionListener = new android.view.View.OnClickListener({
onClick: function(v) {
if(isFullScreen=="y"){
isFullScreen ="";
var nativeVideoPlayer12 = frame.topmost().getViewById("nativeVideoPlayer12");
var currenttime12 = nativeVideoPlayer12.getCurrentTime();
const navEntryWithContext = {
moduleName: "home/videosingle",
context: {
url: url,
currenttime:currenttime12,
data:breadcrumvar[breadcrumvar.length-1]
}
};
frame.topmost().navigate(navEntryWithContext);
console.log('Video small screen');
}else{
isFullScreen ="y";
console.log('Video fullscreen');
var nativeVideoPlayer = frame.topmost().getViewById("nativeVideoPlayer");
console.log(nativeVideoPlayer.getCurrentTime() ,nativeVideoPlayer.src);
var url = nativeVideoPlayer.src;
var currenttime = nativeVideoPlayer.getCurrentTime();
const navEntryWithContext = {
moduleName: "home/v",
context: {
url: url,
currenttime:currenttime,
data:frame.topmost().navigationContext
}
};
frame.topmost().navigate(navEntryWithContext);
}
}
});
fullScreen.setOnClickListener(completionListener);
}
});
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