Ionic IOS & Firebase (White Screen of Death) - ios

I've hit a very difficult bug so if you're up for a challenge, read on. :)
Steps to recreate what I'm seeing:
Deploy my app to a device. (this bug never happens on emulate, serve, or Xcode)
Leave the app running in the background for an undetermined amount of time (usually a day or so).
Sometimes when opening the app again you'll get a white screen of death.
I have a feeling that something is happening to the firebase connection and when the app opens it can't resolve $requireAuth() in the route.
Any help would be appreciated. Is there anyway issues like that can get logged somewhere?
Here is part of my route file:
$urlRouterProvider.otherwise(function ($injector) {
var $state = $injector.get("$state");
$state.go("app.dashboard");
});
$stateProvider.state('app', {
url: '/app',
abstract: true,
templateUrl: 'skinsaver/app/app.html',
controller: 'AppController as app',
resolve: {
"userAuth": ["AppAuth", resolveUser]
},
});
$stateProvider.state('app.dashboard', {
url: '/dashboard',
templateUrl: 'skinsaver/app/dashboard/dashboard.html',
controller: 'DashboardController as dashboard',
});
function resolveUser(AppAuth){
return AppAuth.firebaseAuth.$requireAuth();
};
//watch for route errors to redirect to login
$rootScope.$on('$stateChangeError', function(event, toState, toParams, fromState, fromParams, error) {
if(error === 'AUTH_REQUIRED'){
event.preventDefault();
AppAuth.returnToState = toState;
$state.go("public.login");
}
});

Related

How can I make React Native in Android aware of a click event in a tooltip in a Highcharts chart?

I have a React Native application built with Expo. On How can I add links in a Highcharts tooltip that will open on mobile's browser? I was able to pass a URL to Highcharts so that when a tooltip is clicked, that URL is opened:
return(
<View style={styles.container}>
<ChartView
onMessage={m => this.onMessage(m)}
config={config}
/>
</View>
This triggers this method to open the URL:
onMessage = (m) => {
let data = JSON.parse(m.nativeEvent.data);
Linking.openURL(data.url)
};
And the URL gets populated through a global variable window.myURL and sending the message with postMessage():
render() {
let Highcharts = "Highcharts";
let config ={
...
plotOptions: {
series: {
stickyTracking: false,
point: {
events: {
click: function(e) {
window.postMessage(JSON.stringify({'url': window.myUrl}));
}
}
}
},
},
tooltip: {
useHTML: true,
formatter: function () {
window.myUrl = extras.url;
return `<div class="text">some text</div>`;
}
};
This works well on iOS (both physical and emulator), but does not on Android (neither physical nor emulator).
I have gone through different Github issues such as onMessage not called in native code even though sent from webview( android) and react native html postMessage can not reach to WebView and they tend to suggest using some timeout on window.postMessage(). However, I see that even this does not work:
plotOptions: {
series: {
point: {
events: {
click: function(e) {
setTimeout(function() {
console.log('bla');
window.postMessage(JSON.stringify({'url': window.myUrl}));
}, 200);
}
}
}
},
},
Since even console.log() does not work, it looks to me as if the click event is not being caught by Android.
How can I make Android aware of this event so that I can go through the message and then open the URL?
The "click" event is fine. Problem is that, RN core's <WebView> implementation for Android is flawed at polyfilling window.postMessage(). This issue has been well discussed in this github issue.
So it seems the nature of problem, is RN has to polyfill the native window.postMessage for some reason, but the override didn't take place timely, causing window.postMessage calls still made to the native one.
One solution (for Android) proposed in that github issue, is simply stop using the native window.postMessage, and directly use the internal interface, which is the actual polyfill function.
// in place of `window.postMessage(data)`, use:
window.__REACT_WEB_VIEW_BRIDGE.postMessage(String(data))
One heads-up though, this API is not public and might be subject to change in future.

How to toggle devtools in an Electron app while focused on devtools?

I want to make my Electron app toggle developer tools in response to F12.
In the renderer page, I added:
const currentWebContents = require("electron").remote.getCurrentWebContents();
window.addEventListener("keydown", (e: KeyboardEvent) => {
if (e.keyCode === 123) { // F12
currentWebContents.toggleDevTools();
}
});
This works when I'm focused on the main page. However, immediately after the dev tools opens up, focus goes to the dev tools, so F12 is no longer detected.
I tried fixing this by adding a listener to the devtools webcontents right after calling toggleDevTools() like so:
if (currentWebContents.devToolsWebContents) {
currentWebContents.devToolsWebContents.on("before-input-event", (event: Electron.Event, input: Electron.Input) => {
if (input.type === "keyDown" && input.key === "F12") {
currentWebContents.toggleDevTools();
}
});
}
However, currentWebContents.devToolsWebContents is null right after opening it. My first question is how to ensure that it isn't null - is there a way to wait until it's fully opened?
I worked around this by putting the if (currentWebContents.devToolsWebContents) code into a setTimeout(..., 1000);
However, upon doing that, my before-input-event handler does not get triggered when pressing keys while focused on the devtools.
Does anybody know why that is?
There is no easy way to do this.
As per this issue, you can't detect input from devtools.
An Electron developer posted a comment here:
I think this is because the toggleDevTools menu role doesn't properly check for the 'parent' window of a devtools window. it would probably be possible to have the toggleDevTools menu role check to see if the currently focused window is a devtools window, and if so, call toggleDevTools on the webcontents for which the devtools is opened, instead of on the devtools window itself.
In any case, this requires Electron development to solve.
Update: Someone here suggested this workaround - I haven't tried it myself:
mainWindow.webContents.on("before-input-event", (e, input) => {
if (input.type === "keyDown" && input.key === "F12") {
mainWindow.webContents.toggleDevTools();
mainWindow.webContents.on('devtools-opened', () => {
// Can't use mainWindow.webContents.devToolsWebContents.on("before-input-event") - it just doesn't intercept any events.
mainWindow.webContents.devToolsWebContents.executeJavaScript(`
new Promise((resolve)=> {
addEventListener("keydown", (event) => {
if (event.key === "F12") {
resolve();
}
}, { once: true });
})
`)
.then(() => {
mainWindow.webContents.toggleDevTools();
});
});
}
});

Permission denied - geolocation in React Native

I've been playing around with React Native, getting custom locations to work and setting the "NSLocationWhenInUseUsageDescription" key. The error, when running on the ios simulator, is this:
{
"code": 2,
"message": "Unable to retrieve location.",
"PERMISSION_DENIED": 1,
"POSITION_UNAVAILABLE": 2,
"TIMEOUT": 3
}
This is what I have, pretty much straight from the Geolocation example page https://facebook.github.io/react-native/docs/geolocation.html
/* eslint no-console: 0 */
'use strict';
var React = require('react');
var ReactNative = require('react-native');
var {
StyleSheet,
Text,
View,
} = ReactNative;
export default class GeolocationExample extends React.Component {
state = {
initialPosition: 'unknown'
};
componentDidMount() {
navigator.geolocation.getCurrentPosition(
(position) => {
var initialPosition = JSON.stringify(position);
this.setState({initialPosition});
},
(error) => alert(JSON.stringify(error)),
{enableHighAccuracy: true, timeout: 20000, maximumAge: 1000}
);
}
render() {
return (
<View>
<Text>
<Text style={styles.title}>Initial position: </Text>
{this.state.initialPosition}
</Text>
</View>
);
}
}
var styles = StyleSheet.create({
title: {
fontWeight: '500',
},
});
Any help would be appreciated!
You need to set the location in the Simulator. There is an option for that in simulator menus as described in this question: Set the location in iPhone Simulator
In Simulator navigator, Choose Debug, at bottom choose Location, next choose Apple, then CMD+R to reload and it worked.
As Santosh suggested, you need to set the location in the iOS Simulator: Debug > Location.
Keep in my mind that from time to time, you will get the "PERMISSION_DENIED " error even tho you set the location in the simulator. If this is happening, you need to select a different predefined location and then the error goes away.
Adding an update to Santosh's answer, please note that in my current version of simulator (11.4) the option to set location is found in:
Features -> Location
(Posting this as a new answer since I am not allowed to comment yet).
I was testing on a real device and it was giving the same error.
I just restarted my device and it started working. Anyone who is still facing the issue can give it a try.
So, for those who are still looking for the answer in Physical device
if you're using
import Geolocation from '#react-native-community/geolocation';
then
Geolocation.getCurrentPosition(
info => {console.log(info)},error=>{console.log(error)}});
if you don't handle the error it will throw error or make your app crash.
Now it's iOS Simulator: Features > Location.

iOS: Can't start cordova inAppBrowser -> "Warning: Attempt to present <inAppBrowser> on <MainViewController> while a presentation is in progress"

I really need some help, because I'm very new to iOS and Phonegap developing and all topics on my Xcode-warning I could find were about Objective-C.
As my app is mainly written with Cordova (Phonegap) these solutions aren't really helpful.
So, what is there to tell:
I have a simple start screen, where you can start a barcode-scanner. The result (which in the end is always an url) should be displayed in the inAppBrowser of cordova.
If I call the window.open() with "_self" it works, but then it is very difficult to get back to the startscreen, as far as I found out.
So I wanted to call the url with the inAppBrowser so there is a "Done" button, but Xcode screams:
"Warning: Attempt to present <CDVInAppBrowserViewController:
0x1ed97060> on <MainViewController: 0x1ed64730> while a presentation
is in progress!"
Here the JavaScript code where I'm calling the window.open() function...
app.initialize();
function demoScan() {
try {
var scanned = scan();
} catch (e) {
alert('scan failed');
}
}
function scan() {
var scanner = window.cordova.require("cordova/plugin/BarcodeScanner");
scanner.scan( function (result) {
var ref = window.open(encodeURI(result.text),'_blank','location=yes');
},
function (error) {
("Scanning failed: " + error);
});
}
In the end, I only need a (simple) solution, to get back to the start page "index.html" when I'm on the Webpage the Barcode scanner is calling. If it is through the inAppBrowser or with a self-coded "back" button in the WebView, I really don't care.
Thanks in advance! :)
Okay, I found the answer. You have to set a timeout before calling the inAppBrowser:
setTimeout( function() {
var ref = window.open(encodeURI(result.text),'_blank','location=no');
}, 500);
Apparently iOS needs some time to end whatever it was doing, before it can start the inAppBrowser.
In Android it works without the timeout.

Phonegap: BarcodeScanner & Childbrowser plugins

I'm facing a problem using this 2 PhoneGap plugins: "BarcodeScanner" & "ChildBrowser" (inside an iOS app, with XCode 4 & PhoneGap 2.0).
I've a button "Scan" on my app UI. When the user clic on this button, the barcode scanner is launched.
So, in the Success function of the barcode scanner callback, I need to open the recovered URL from the scan in a new Childbrowser window (inner the app).
But the new Childbrowser window is never been opened, while the console displays "Opening Url : http://fr.wikipedia.org/" (for example).
Here is my JS part of code:
$("#btnStartScan").click(function() {
var scanBarcode = window.plugins.barcodeScanner.scan(
function(result) {
if (!result.cancelled){
openUrl(result.text);
}
},
function(error) {
navigator.notification.alert("scanning failed: " + error);
});
});
function openUrl(url)
{
try {
var root = this;
var cb = window.plugins.childBrowser;
if(cb != null) {
cb.showWebPage(url);
}
else{
alert("childbrowser is null");
}
}
catch (err) {
alert(err);
}
}
And all works fine if I call my openURL() function inside a Confirm alert callback for example, like this:
if (!result.cancelled){
navigator.notification.confirm("Confirm?",
function (b) {
if (b === 1) {
openUrl(result.text);
}
},
'Test',
'Yes, No');
}
But I need to launch the ChildBrowser window directly after a scan, without any confirm alert etc.
Does anybody know how to solve this please?
I also have this same problem.
Solve it by set timeout.
var scanBarcode = window.plugins.barcodeScanner.scan(
function(result) {
if (!result.cancelled){
setTimeout(function(){ openUrl(result.text); },500);
}
},
function(error) {
navigator.notification.alert("scanning failed: " + error);
});
I'm running into the exact same problem.
My application also has another mechanism to show a webpage besides the barcode reader and when I do that action I can see that the barcode-related page HAD loaded, but it never was shown.
In ChildBrowserViewController.m, I'm looking at the last line of loadURL() which is webView.hidden = NO; and I'm thinking that the child browser is set visible after we barcode but something about the barcode reader window caused the child browser to get set to the wrong z-order, but I'm not familiar enough with the sdk to know how to test that or try to bring it to the front.
Hope this helps target a potential area.

Resources