I've created an app that uses a set of embed videos of YouTube.
Since this is made for kids, my app after 6 years got removed because I did not implement parental gateway when kids might accidentally click on the YouTube logo - it will load the YouTube app and continue there.
i'm trying to understand how, in general, I can grab such event, that is fired when something ( click ) wants to open another app ( not just youtube ) - and then activate my page that I've created as a parental gateway - and if the answer is correct - then I continue.
EDIT: Was able to do so far:
I found event that might help suspendEvent
I'm able to catch it and forward to my page
[stuck] unable to catch the event the loads the native app
DOES NOT WORK: Things that doesn't work so far:
(1) suspendEvent, the event is fired when the native app loads - but cannot prevent/disable/control the native app lunch for a "parental gate" in the middle ( youtube app still loaded and in the background - parental gate page is switched )
import { on as applicationOn } from "tns-core-modules/application";
...
applicationOn(suspendEvent, this.activateParentalGateway, this);
(2) WebViewExt
it has an event called WebViewExt.shouldOverrideUrlLoadingEvent, but I'm unable to load the YouTube plugin inside it
<WebViewExt debugMode="true" (loaded)="onWebViewLoaded($event)">
<YoutubePlayer id="player" [src]="settings.player.src"></YoutubePlayer>
</WebViewExt>
webview.on(WebViewExt.shouldOverrideUrlLoadingEvent, (args1: ShouldOverrideUrlLoadEventData) => {
console.log("shouldOverrideUrlLoadingEvent firing for url : ", args1.url);
utils.openUrl(args1.url);
});
is there a native replacement for shouldOverrideUrlLoadingEvent ?
I want to share my solution for now, I've seen tons of posts related to parental gate which non were answered.
Not sure if Google Play will accept it, but was able to set a parental gate in my app, please share your answers as well if you find something better !
So I'm using this pkg: https://github.com/Notalib/nativescript-webview-ext, which is a webview component (browser) and my code looks like this
player.component.html
<GridLayout class="page page-content" xmlns="http://schemas.nativescript.org/tns.xsd" xmlns:nota="#nota/nativescript-webview-ext">
... other html code ...
<nota:WebViewExt (loaded)="onWebViewLoaded($event)"
src='https://www.youtube.com/embed/{{ src }}'
width="100%" height="100%">
</nota:WebViewExt>
</GridLayout>
player.component.ts
import { Component, OnInit, NgZone } from "#angular/core";
import { RouterExtensions } from "nativescript-angular/router";
import { WebView } from "tns-core-modules/ui/web-view";
import { WebViewExt, ShouldOverrideUrlLoadEventData } from "#nota/nativescript-webview-ext";
/*
Events
*/
onWebViewLoaded(args) {
let webview: WebView = args.object;
// This code will grab any click that try to load/switch to an external app/url
webview.on(WebViewExt.shouldOverrideUrlLoadingEvent, (_args: ShouldOverrideUrlLoadEventData) => {
// Disable the event
_args.cancel = true;
// Switch to parental gateway
this.activateParentalGateway(_args.url);
});
}
activateParentalGateway(blocked_url) {
if (typeof(blocked_url) !== "string") {
return false;
}
// run inside the ngZone to connect the event back to the
// component state ( otherwise there's no "this" variable )
this.zone.run(() => {
this.routerExtensions.navigate(['parental_gateway', blocked_url], {
transition: {
name: "fade"
}
});
});
}
parental_gateway.component.html
This is where we ask some "grownup" question ... for now just made two buttons for testing correct / wrong answers.
<GridLayout columns="*" rows="*">
<StackLayout row="0" width="100%" orientation="horizontal">
<Label text="Answer this question please" width="20%" height="50"></Label>
<Button text="Correct" (tap)="answeredCorrect($event)"></Button>
<Button text="Failed" (tap)="answeredWrong($event)"></Button>
</StackLayout>
</GridLayout>
parental_gateway.component.ts
import { RouterExtensions } from "nativescript-angular/router";
import { openUrl } from "tns-core-modules/utils/utils";
answeredCorrect() {
console.log("Answer was correct");
// openUrl will actually open the YouTube video
// in a native app ( basically continue the event )
openUrl(this.blocked_url);
// In the background we want to go back from the
// parental gate page that we've been in
// and switch to the video where we first clicked it.
this.routerExtensions.backToPreviousPage();
}
answeredWrong() {
console.log("Wrong answer go back");
// Just go back to our page where we've clicked the link
this.routerExtensions.backToPreviousPage();
}
Hope this helps others, if so, please vote up.
Related
I have a NativeScript 6.8 JavaScript app that uses WebView to display an html string composed within the app that references local image files. The Google Play Store is forcing me to support API 30, and when I do, the WebView fails with
net::ERR_ACCESS_DENIED(-1)
I found this post that suggests I modify some of the Android WebView's access settings, such that my code now looks like this
AndroidManifest.xml:
<application
...
android:usesCleartextTraffic="true">
xml:
<GridLayout>
<WebView id="annbyday" loadFinished="onLoadFinished" src="{{ htmlsrcForDay }}" />
</GridLayout>
js:
exports.onLoadFinished = function (args) {
if (args.object.android) {
if (!args.error) {
let webView = args.object.android;
webView.getSettings().setAllowFileAccess(true);
webView.getSettings().setAllowContentAccess(true);
console.log("announce-page.onLoadFinished: settings set");
} else {
console.warn("announce-page.onLoadFinished: " + args.error);
}
}
}
When I run this, I get these messages in the console:
JS: announce-page.onLoadFinished: settings set
JS: announce-page.onLoadFinished: net::ERR_ACCESS_DENIED(-1)
JS: announce-page.onLoadFinished: net::ERR_ACCESS_DENIED(-1)
JS: announce-page.onLoadFinished: settings set
On first navigation to the page the android error screens displayed. But, if I re-navigate to the page I get just the "settings set" messages and the html displays correctly.
It's as if the settings work, but they're not being set soon enough. Moving the code to the LoadStarted event has no effect.
I feel like I'm close; I welcome any help.
I moved the code to the page's loaded event handler, and now everything works as expected, and I don't use the WebView's loadStarted or LoadFinished events at all. The final code is,
exports.onLoaded = function (args) {
const page = args.object;
const webView = page.getViewById("<WebView id>");
if (webView.android) {
let setter = webView.android.getSettings();
setter.setAllowFileAccess(true);
setter.setAllowContentAccess(true);
}
Android devices has back button on menu toolbar. I want to disable the possibility when i login to my app and click on that back button to route on login page.
I want if user click on back button after login then i close the app.
Here is my initial code for routing below.
if (token) {
this.router.navigate(['/main-tabs/tabs/dashboard'])
} else {
this.router.navigate(['/login']).then();
}
I've tried many other answers but none of them really works for me. But this one works :
To disallow the login from going 'back' to the authenticated page after logged out, just do something like this in your app-routing.module.ts :
{
path: 'home',
loadChildren: './home/home.module#HomePageModule',
canActivate: [LoggedAuthGuard]
}
The same for the opposite (to prevent going back into login page with back button) :
{
path: 'login',
loadChildren: './login/login.module#LoginPageModule',
canActivate: [NotLoggedAuthGuard]
}
And both LoggedAuthGuard and NotLoggedAuthGuard must implement CanActivate. Sample code as below (with Promise, but it also works with boolean return) :
import { Injectable } from '#angular/core';
import {CanActivate} from "#angular/router";
import {Storage} from "#ionic/storage";
#Injectable({
providedIn: 'root'
})
export class LoggedAuthGuard implements CanActivate {
constructor(protected storage: Storage) { }
async canActivate() {
return (await !!this.storage.get('access_token'));
}
}
For the NotLoggedAuthGuard you just returns the opposite of LoggedAuthGuard.
async canActivate() {
return (await !this.storage.get('access_token'));
}
Hope this helps.
This answer provides a solution for removing the login page from the browser's history by replacing it with a page, that the user was navigated to after successful login. It might be a good and quick solution to:
I want to disable the possibility when i login to my app and click on
that back button to route on login page.
What I understood from your question is after user login, You don't want to navigate to login page if back button is clicked. If I understood your question correctly you can try below solution.
one approach is changing root page
this.navCtrl.setRoot(HomePage);
or
You can achieve this by removing page from stack after successful transition. Place below code inside Login success method
let currentIndex = this.navCtrl.getActive().index;
this.navCtrl.push(DestinationPage).then(() => {
this.navCtrl.remove(currentIndex);
});
Hope this helps you.
I think you can do like that :
this.platform.backButton.subscribe((()=>{
if(this.router.url == <insertpathhome>)
{
this.platform.exitApp();
}
else{
//go back
}
});
I saw the solution in many different sources for this, including Stack Overflow. This is working for me partially: I can't swipe to the left or right to switch the pages. That's fine ! But if the user click a button , keep the button pressed and swipe, this will cause pagination. (I just testing using Android)
The solution according with many sources is that one:
<ion-slides [options]="{onlyExternal: false}">
</ion-slides>
Let me illustrate this with screenshots...
If I swipe here, nothing will happen
Now, if I hold and swipe the red button, this will cause pagination.
The way i do this is:
On my .ts file of the page i have a slide i do this
import { Component, ViewChild } from '#angular/core';
import { Slides } from 'ionic-angular';
#Component({
selector: 'page',
templateUrl: 'page.html'
})
export class Page{
#ViewChild(Slides) slides: Slides;
contructor() {
this.slides.lockSwipes(true);
}
nextSlide(){
this.slides.lockSwipes(false);
this.slides.slideNext();
this.slides.lockSwipes(true);
}
}
And in your HTML you call the function on a button
<button ion-button block (tap)="nextSlide()">NEXT</button>
So when the page is beeing constructed i lock the swipe, and when someone click next/back i unlock the swipe, go to next slide and lock it back.
Hope it helps
Since externalOnly isn't working in Ionic 4 anymore, i looked into the Swiper API documentation and saw that it changed to allowTouchMove now.
So: <ion-slides [options]="{allowTouchMove:false}"
Another way to achieve it is adding the swiper-no-swiping class:
Example:
<ion-slides #slides class="swiper-no-swiping">
...
</ion-slides>
you should use the function ionViewDidLoad() because when you put the "this.slides.lockSwipes(true);" in the constructor, the page havent load yet, try to do this.
ionViewDidLoad(){
this.slides.lockSwipes(true);
}
Use the onlyExternal option. You can access it by ViewChild.
#ViewChild('slider') slider: Slides;
ionViewDidLoad() {
this.slider.onlyExternal = true;
this.slider.paginationClickable = false;
}
nextSlide() {
this.slider.slideNext();
}
<ion-slides pager #slider>
...
</ion-slides>
You can call nextSlide() e.g. by button within slide.
Update: paginationClickable does not work. :/
Currently this is the best solution to really control the behavior.
ionViewDidLoad() {
this.slider.lockSwipes(true);
}
nextSlide() {
this.slider.lockSwipes(false);
this.slider.slideNext();
this.slider.lockSwipes(true);
}
I would like to disable or override the Android Back button while I am navigating pages on the InAppBrowser. Can I add an event listener that can handle that?
EDIT:
Looking at the answer by #T_D below the solutions provided are the closest I could get to. It does not seem to be possible to override the button in InAppBrowser as all the PhoneGap tweaks stop working while navigating pages on this plugin. I was not able to find any other solution rather than modifying the API library. If there are any PhoneGap guys here and know something more, I 'll be glad to get some comment. Thanks.
The closest I got:
var ref = window.open('http://apache.org', '_blank', 'location=yes');
ref.addEventListener("backbutton", function () { })
According to the documentation the behaviour of the hardware back button can be configured now for the InAppBrowser:
hardwareback: set to yes to use the hardware back button to navigate backwards through the InAppBrowser's history. If there is no previous page, the InAppBrowser will close. The default value is yes, so you must set it to no if you want the back button to simply close the InAppBrowser.
Thanks to Kris Erickson.
So just update your InAppBrowser plugin if the backward navigation is the desired behaviour.
For more details see: https://github.com/apache/cordova-plugin-inappbrowser/pull/86
You can do it quite easily now (as of InAppBrowser version 0.3.3), but you will have to edit the Java files. Go to src/com/org/apache/corodova/inappbrowser directory and edit the InAppBrowserDialog.java:
Change
public void onBackPressed () {
if (this.inAppBrowser == null) {
this.dismiss();
} else {
// better to go through the in inAppBrowser
// because it does a clean up
this.inAppBrowser.closeDialog();
}
}
to
public void onBackPressed () {
if (this.inAppBrowser == null) {
this.dismiss();
} else {
if (this.inAppBrowser.canGoBack()) {
this.inAppBrowser.goBack();
} else {
this.inAppBrowser.closeDialog();
}
}
}
Then go to InAppBrowser and find the goBack function, change:
/**
* Checks to see if it is possible to go back one page in history, then does so.
*/
private void goBack() {
if (this.inAppWebView.canGoBack()) {
this.inAppWebView.goBack();
}
}
to
/**
* Checks to see if it is possible to go back one page in history, then does so.
*/
public void goBack() {
if (this.inAppWebView.canGoBack()) {
this.inAppWebView.goBack();
}
}
public boolean canGoBack() {
return this.inAppWebView.canGoBack();
}
And now the hardware back button will go back until there are no more backs to do. I really think this should be the default behavior in android since the Done button already closes the InAppBrowser window.
This worked for me in PhoneGap 2.7, help came from here, How do I disable Android Back button on one page and change to exit button on every other page
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
document.addEventListener("backbutton", function (e) {
e.preventDefault();
}, false );
}
I was having this same issue and finally got it to work, I'll post the answer here in case it helps someone.
This is the code I use:
window.new_window = window.open(url, '_blank', 'location=no');
window.new_window.addEventListener("exit", function () {
window.new_window.close();
});
So the key basically is to attach the exit event, which gets called when the back button of the device is tapped.
BTW, I used cordova.js, and build my apps locally using the Cordova CLI, I don't know if that makes any difference, I mention it just in case.
EDIT NOTE: As far as I know, it's not possible to override the back-button for the InAppBrowser in PhoneGap. But I did my best searching for possible solutions...
There's an eventListener to override back-button in PhoneGap -doesn't work for InAppBrowser-
function onDeviceReady(){
document.addEventListener("backbutton", onBackKeyDown, false);
}
Alternative eventListener to override back-button -the OP said this didn't work either-
var ref = window.open('http://www.stackoverflow.com', '_blank', 'location=yes');
ref.addEventListener("backbutton", function () {
//logic here
})
Overriding the Back-button in an Activity -this is plain java, obviously didn't work in PhoneGap-
#Override
public void onBackPressed()
{
//logic here
}
Conclusion:
Above solutions didn't work, following links (this answer, this one and a third one) didn't help either. So it's highly possible that overriding the back-button for the InAppBrowser in PhoneGap is not possible. If someone does come up with a solution or if things changed for a new PhoneGap version feel free to let us know...
EDIT:
Installing this plugin may take you to closest solution:
cordova plugin add org.apache.cordova.inappbrowse
What this plugin will do, in WP8, it will overlay back/forward/close button on InAppBrowser whenever you open any link/page in it.
See this image:
Use jQuery mobile:
$(document).on('backbutton',
function(e){
e.preventDefault();
// YOUR CODE GOES HERE
});
Running Cordova 5.1.1 and when i load pages in the inappbroswer i like having the back button work until the inappbrowser exits back to my index.html page because it's blank and just sits there. So i used the following code to fix this. It exits the app when it exits the inappbrowser.
window.open = cordova.InAppBrowser.open;
var ref = window.open(url, '_blank', 'location=no');
ref.addEventListener('exit', function () {
navigator.app.exitApp();
});
As far as I know it's not possible to override or detect the back button from inAppBrowser. When you press the back button, inAppBrowser will hide and return control to the Phonegap page. You can catch this with the focus event on the window, (using jQuery) like
var browser = window.open('http://example.com', '_blank', 'location=no');
$(window).on('focus', function() {
browser.show();
});
to reopen the browser. You could then use browser.executeScript() to signal the webapp loaded in the browser, if you like.
Inspired by this forum post.
I know this question has an answer already but I post my answer for those who any of these answers didn't work for them(such as myself):
so I have a multi page app for android and IOS and I am using cordova 5.x and I added the code below in every page except the page I needed InAppBrowser:
delete window.open;
and then for the rest of the pages I used:
document.addEventListener("backbutton", onBackKeyDown, false);
function onBackKeyDown(event) {
// your code for handling back button comes here
}
for handling back button
note that: delete window.open; base on the documentation
manually restore the default behaviour of 'window.open'
after that InAppBrowser plugin worked great and I handled back button in all pages correctly.
one last thing don't forget to add:<script type="text/javascript" charset="utf-8" src="cordova.js"></script> in pages you need to have InAppBrowser.
hope this help.
I'm creating a mobile site where I have a video I'd like to play when someone clicks on a link:
<div id="player"></div>
<?php echo $result_videos[$i]["camera_name"]; ?>
<script type="text/javascript">
function DoNav(theUrl)
{
// only add the player if it doesn't yet exist
if($('#myfileplayer').length == 0) {
var mydiv = $("#player");
var myvideo = $("<video id='myfileplayer' src='"+ theUrl + "' width='320' height='240' controls></video>");
mydiv.append(myvideo);
} else {
$('#myfileplayer').attr("src",theUrl);
}
}
</script>
With the iPhone, this works great, I click on video and it goes full screen. Android works as well but it requires you to click the video to play then click on the full screen. Is it possible to get to the full screen like iPhone just when you hit play?
This should work, with plain Javascript:
var myVideo = document.getElementById('myVideoTag');
myVideo.play();
if (typeof(myVideo.webkitEnterFullscreen) != "undefined") {
// This is for Android Stock.
myVideo.webkitEnterFullscreen();
} else if (typeof(myVideo.webkitRequestFullscreen) != "undefined") {
// This is for Chrome.
myVideo.webkitRequestFullscreen();
} else if (typeof(myVideo.mozRequestFullScreen) != "undefined") {
myVideo.mozRequestFullScreen();
}
You have to trigger play() before the fullscreen instruction, otherwise in Android Browser it will just go fullscreen but it will not start playing.
Tested with the latest version of Android Browser, Chrome, Safari.
I've given up on this. My conclusion is that the html5 video tag on Android devices blows chunks. It works in some devices but not on others. And there is no common criteria like 3.x or 4.x, it just seems to be random. I hope this gets better sometime soon especially since flash support is not longer existent.
Oddly sticking with a simple href seems to be the most consistent. You lose some controls but way better than the video tag...at least so far.
Have you checked out mediaelement.js?
Try something along the lines of:
document.getElementById('myfileplayer').addEventListener('play', function (e) { this.mozRequestFullScreen ? this.mozRequestFullScreen() : this.webkitRequestFullScreen ? this.webkitRequestFullScreen() : null; }, false);
Either that or maybe something along the lines of:
document.getElementById('myfileplayer').addEventListener('play', function (e) { this.webkitEnterFullscreen(); }, false);
webkitEnterFullscreen is the fullscreen method of a VIDEO element that is currently working on iOS. I'm not sure about support on Android devices.
mozRequestFullScreen and webkitRequestFullScreen are implementations of Mozilla and Google's FullScreen API which is used to activate full screen mode on practically any DOM element.
Hopefully that gives you at least a starting point to work from...
Most vendors require user interaction to go full screen, which is why natalee's answer doesn't work. For Andriod, you can call webkitEnterFullScreen() inside your anchor's click handler since it's a valid user interaction:
myvideo[0].webkitEnterFullScreen();
myvideo[0].play();
or
$('#myfileplayer')[0].webkitEnterFullScreen();
$('#myfileplayer')[0].play();
Note how I'm stripping jQuery's wrapper with [0]. It doesn't work otherwise.