[nativescript] How do I keep a native script - angular app running in the background in IOS. I have a button that opens the in-app browser and there I have a webpage that plays music, I'd like the music to carry on playing when the user leaves the application.
here is my component.ts
export class BrowseComponent implements OnInit {
openLink = async () => {
try {
const url = ''
if (await InAppBrowser.isAvailable()) {
const result = await InAppBrowser.open(url, {
// iOS Properties
dismissButtonStyle: 'done',
preferredBarTintColor: '#3e00be',
preferredControlTintColor: 'white',
readerMode: false,
animated: true,
modalPresentationStyle: 'fullScreen',
modalTransitionStyle: 'crossDissolve',
modalEnabled: true,
enableBarCollapsing: false,
// Android Properties
showTitle: true,
toolbarColor: '#3e00be',
secondaryToolbarColor: 'white',
enableUrlBarHiding: true,
enableDefaultShare: true,
forceCloseOnRedirection: false,
// Specify full animation resource identifier(package:anim/name)
// or only resource name(in case of animation bundled with app).
animations: {
startEnter: 'slide_in_right',
startExit: 'slide_out_left',
endEnter: 'slide_in_left',
endExit: 'slide_out_right'
},
headers: {
'my-custom-header': 'my custom header value'
}
})
// alert({
// title: 'Response',
// message: JSON.stringify(result),
// okButtonText: 'Ok'
// })
}
else {
MyDelegate.prototype.applicationDidEnterBackground = function (application: UIApplication) {
console.log('App is running in background');openUrl(url);
AVAudioSession.sharedInstance().setCategoryWithOptionsError(
AVAudioSessionCategoryPlayAndRecord,
AVAudioSessionCategoryOptions.DefaultToSpeaker
);
};
}
}
catch(error) {
// alert({
// title: 'Error',
// message: error.message,
// okButtonText: 'Ok'
// })
}
}
}
Related
I created an app (done for OSX) that will send a message even when the main window is hidden, currently my main.js is like this:
const { app, shell, BrowserWindow, dialog } = require('electron')
const path = require('path')
const electron = require('electron')
// Enable live reload for all the files inside your project directory
require('electron-reload')(__dirname);
let win = null
function createWindow () {
win = new BrowserWindow({
width: 420,
height: 420,
resizable: false,
fullscreenable: false,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: true
}
})
win.on('close', (event) => {
if (app.quitting) {
win = null
} else {
event.preventDefault()
win.hide()
}
})
win.loadFile('index.html')
win.webContents.on('new-window', function(e, url) {
// make sure local urls stay in electron perimeter
if('file://' === url.substr(0, 'file://'.length)) {
return;
}
// and open every other protocols on the browser
e.preventDefault();
shell.openExternal(url);
});
}
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => { win.show() })
app.on('before-quit', () => app.quitting = true)
The idea is that when the user try to close the app it will just hide it. I'll need to add something that at certain hours of the day the app will launch the main window again.
Is there a way to make the main window be reopened or to run a code in the background so at certain time of the day the window will be unhidden?
Sure....this will reopen your minimized window
if (win) {
if (win.isMinimized()) win.restore()
win.focus()
}
using
"react-navigation": "^4.0.10",
"react-navigation-stack": "^1.10.3",
import {
createStackNavigator, StackViewTransitionConfigs,
} from 'react-navigation-stack';
const HomeStackNavigator = createStackNavigator({
List:ListContainer,
Detail:DetailContainer,
Modal: {
screen: ModalContainer,
navigationOptions: {
...StackViewTransitionConfigs.ModalSlideFromBottomIOS,
},
},
}, {
mode: 'card',
headerMode: 'none',
defaultNavigationOptions: {
gestureEnabled: true,
...StackViewTransitionConfigs.SlideFromRightIOS,
},
});
All other screens open in the form of a card, and I want to open only one specific screen in modal form.
i tried
const HomeStackNavigator = createStackNavigator({
List:ListContainer,
Detail:DetailContainer,
},
}, {
mode: 'card',
headerMode: 'none',
defaultNavigationOptions: {
gestureEnabled: true,
...StackViewTransitionConfigs.SlideFromRightIOS,
},
});
const HomeStackNavigator2 = createStackNavigator({
Home:HomeStackNavigator,
Modal: {
screen: ModalContainer,
},
}, {
mode: 'modal',
headerMode: 'none',
});
The first code failed because all the arcs were opened in card format.
In the second code I tried, the screen I wanted was opened in modal form, but when I moved from modal to detail, the modal was closed.
In the first code, is it possible to open only the modal screen in modal form?
I solved it this way.
import {
createStackNavigator, StackViewTransitionConfigs, StackViewStyleInterpolator,
} from 'react-navigation-stack';
const transitionConfigs = (props) => {
const { scene } = props;
const { route } = scene;
const params = route.params || {};
const transition = params.transition || 'forHorizontal';
if (transition === 'forVertical') {
return StackViewTransitionConfigs.ModalSlideFromBottomIOS;
}
return StackViewTransitionConfigs.SlideFromRightIOS;
};
const HomeStackNavigator = createStackNavigator({
List:ListContainer,
Detail:DetailContainer,
Modal: {
screen: ModalContainer,
},
}, {
mode: 'card',
headerMode: 'none',
transitionConfig:transitionConfigs,
});
Change animation by sending trasition:'forVertical' to params when navigate.
Is it possible to detect in electron if window is already created and close before creating another one?
here is my sample code
// video window listener
ipcMain.on("load-video-window", (event, data) => {
// create the window
//window.close() if window exist;
let videoPlayer = new BrowserWindow({
show: true,
width: 840,
height: 622,
webPreferences: {
nodeIntegration: true,
plugins: true,
},
});
if (process.env.WEBPACK_DEV_SERVER_URL) {
// Load the url of the dev server if in development mode
videoPlayer.loadURL(
process.env.WEBPACK_DEV_SERVER_URL + "video_player.html"
);
if (!process.env.IS_TEST) videoPlayer.webContents.openDevTools();
} else {
videoPlayer.loadURL(`app://./video_player`);
}
videoPlayer.on("closed", () => {
videoPlayer = null;
});
// here we can send the data to the new window
videoPlayer.webContents.on("did-finish-load", () => {
videoPlayer.webContents.send("data", data);
});
});
I think this should work
let playerWindow;
ipcMain.on("load-video-window", (event, data) => {
if (playerWindow) {
playerWindow.close();
}
playerWindow = new BrowserWindow();
});
Extending #Lord Midi code, we can check to see if a window is not destroyed and is still focusable. You can do that with the following code:
let playerWindow;
const isPlayerWindowOpened = () => !playerWindow?.isDestroyed() && playerWindow?.isFocusable();
ipcMain.on("load-video-window", (event, data) => {
if (isPlayerWindowOpened()) {
playerWindow.close();
}
playerWindow = new BrowserWindow();
})
I'm developing an ionic 3 application like instagram, to let users pick photos from their phone album, while they can preview the photo on the same page.
I've tried cordova-plugin-photo-library here, but there's no limit function so I have to get all photos from user album, which could be very large volume. Users have to wait until all photos are loaded before they can click and select one picture. This is really bad user experience.
Anyone has an idea? Thanks.
you can use base64 image
# view
<img *ngFor='let image of images' [src]="DomSanitizer.bypassSecurityTrustUrl('data:image/jpeg;base64,'+image)" style="width: 100px;height:100px;" [hidden]="lastImage === null">
# choice select method
public presentActionSheet() {
let actionSheet = this.actionSheetCtrl.create({
title: 'choice select method',
buttons: [
{
text: 'gallery',
handler: () => {
this.takePicture(this.camera.PictureSourceType.SAVEDPHOTOALBUM);
}
},
{
text: 'take image',
handler: () => {
this.takePicture(this.camera.PictureSourceType.CAMERA);
}
},
{
text: 'cancel',
role: 'cancel'
}
]
});
actionSheet.present();
}
public takePicture(sourceType) {
// Create options for the Camera Dialog
var options = {
quality: 100,
sourceType: sourceType,
encodingType: this.camera.EncodingType.JPEG,
allowEdit: true,
saveToPhotoAlbum: true,
targetWidth: 600,
targetHeight: 600,
correctOrientation: true,
destinationType: this.camera.DestinationType.DATA_URL
};
// Get the data of an image
this.camera.getPicture(options).then((imagePath) => {
// Special handling for Android library
if (this.platform.is('android') && sourceType === this.camera.PictureSourceType.SAVEDPHOTOALBUM) {
this.images.push(imagePath);
} else {
this.images.push(imagePath);
}
}, (err) => {
this.presentToast('Error while selecting image.');
});
}
I'm using the plugin image-picker for nativescript and I copied the example code to see how it works and to adapt it to my code. But the code doesn't work. When I tap the button it's supposed that the screen gallery from my device should be opened, but nothing happen when I tap the button.
The code below is how I implements this.
album_list.component.ts
import { Component } from '#angular/core';
import { RouterExtensions } from 'nativescript-angular/router';
//image picker
var imagepicker = require("nativescript-imagepicker");
#Component({
selector:'album_list',
moduleId: module.id,
templateUrl: "album_list.component.html",
})
export class AlbumListComponent{
constructor(private routerExt: RouterExtensions ){}
ngOnInit() {
}
onSelectMultipleTap() {
console.log('Im in');
function selectImages() {
var context = imagepicker.create({
mode: "multiple"
});
context
.authorize()
.then(function() {
return context.present();
})
.then(function(selection) {
console.log("Selection done:");
selection.forEach(function(selected) {
console.log(" - " + selected.uri);
});
}).catch(function (e) {
console.log(e);
});
}
}
}
album_list.component.html
<StackLayout>
<Button text="Pick Multiple Images" (tap)="onSelectMultipleTap()" > </Button>
</StackLayout>
As I said, when I tap the button in the html the log from the function onSelectMultipleTap appears, but nothing else.
Thanks!!
You arent calling selectImages(), you just declare it. Replace with this:
onSelectMultipleTap() {
console.log('Im in');
function selectImages() {
var context = imagepicker.create({
mode: "multiple"
});
context
.authorize()
.then(function() {
return context.present();
})
.then(function(selection) {
console.log("Selection done:");
selection.forEach(function(selected) {
console.log(" - " + selected.uri);
});
}).catch(function (e) {
console.log(e);
});
}
selectImages()
}
I had a slightly different issue that only occurred on iOS. I'm working on an upgraded Nativescript project from 4 to 6, and yes I know NS 8 is out right now, but some of the libraries being used aren't supported on the latest NS.
My application had a modal list view that popped up to allow the user to select between camera and gallery, and once the user clicked one of the options the list modal would close. At that time the camera or gallery modal should have appeared but it didn't. What was happening was the closing of the first model was somehow blocking the second modal from opening. My fix was to add a conditional async timeout in my method before calling the context.present(). See my code below:
public takePicture() {
// const options = { width: 1280, height: 720, keepAspectRatio: false, saveToGallery: false};
const self = this;
camera.requestPermissions()
.then(async function () {
//This iOS pause is needed so the camera modal popup will not be stopped by the list option modal closing
if (isIOS) {
await new Promise(resolve => setTimeout(() => resolve(), 1000));
}
})
.then (function() {
camera.takePicture()
.then((imageAsset) => {
const imagePost = new TripMessagePostModel();
ImageSource.fromAsset(imageAsset).then((result) => {
const time = new Date();
imagePost.image = result.toBase64String("jpeg", 50);
imagePost.imageFileName = `${self.userId}-${time.getTime()}.jpeg`;
self.addPost(imagePost);
});
}).catch((err) => {
console.log("Error -> " + err.message);
});
}
)
}
public selectImage() {
const context = imagepicker.create({
mode: "single",
});
const imagePost = new TripMessagePostModel();
context
.authorize()
.then(async function() {
//This iOS pause is needed so the camera modal popup will not be stopped by the list option modal closing
if (isIOS) {
await new Promise(resolve => setTimeout(() => resolve(), 1000));
}
return context.present();
})
.then(function(selection) {
selection.forEach(async (selected) => {
ImageSource.fromAsset(selected).then((result) => {
//console.log(selected.android.toString());
const time = new Date();
imagePost.image = result.toBase64String("jpeg", 40);
imagePost.imageFileName = `${this.userId}-${time.getTime()}.jpeg`;
this.addPost(imagePost);
});
});
}).catch((e) => {
console.log(e);
});
}