Launch mail app with react-native [Android] - android

Is there a way to launch mail app using Linking on Android.
The point is the scheme (Deep link) mesage: is working only on iOS.
Here is a little example which work on iOS but not on Android:
Linking.canOpenURL('message:0').then(supported => {
if (!supported) {
console.log('Can\'t handle url');
} else {
return Linking.openURL('message:0');
}
});
Many posts official/non official talks about an activity Intent or about the scheme mailto: but I don't want to write an email. I would like to open the mail app than the user could check the email I sent him.
By the way, I'm using react-native.

I resolved this problem with a Native Module in RN
Firstly the cross platform code in JS to open the mailbox:
openMailApp() {
if (Platform.OS === 'android') {
NativeModules.UIMailLauncher.launchMailApp(); // UIMailLauncher is the
return;
}
Linking.openURL('message:0'); // iOS
return;
}
Linking is a cross platform provided by React-Native. Anyway, the URL message:0 did not work on Android.
The only solution that I found is to create an intern wrapper in my app and to create a ReactMethod in Java.
#ReactMethod
public void launchMailApp() {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_APP_EMAIL);
getCurrentActivity().startActivity(intent);
}
If you already developed native code using React-Native framework, this is a basic ReactMethod where
private static final String REACT_MODULE = "UIMailLauncher";
#Override
public String getName() {
return REACT_MODULE;
}

https://github.com/verypossible/react-native-mail-launcher
This native-module will open the mail app
import * as React from "react";
import { View, Button } from "react-native";
import launchMailApp from "react-native-mail-launcher";
export default class Example extends React.Component {
render() {
return (
<View>
<Button onPress={launchMailApp}>Go to mail client</Button>
</View>
);
}
}

Try a "mailto" intent but with Intent.ACTION_VIEW instead of send:
http://www.gaanza.com/blog/email-client-intent-android/comment-page-1/

To fire intents you can use the Linking.openURL API:
import { Linking } from 'react-native'
Linking.openURL("mailto:?to=blah#hotmail.com");
This works because from the docs:
any URL that can be opened with {#code Intent.ACTION_VIEW}.

Related

Enable Ignore Battery Optimization for Ionic app

I want to Ignore Battery Optimization in our Ionic App, I have read about https://developer.android.com/reference/android/Manifest.permission#REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
For this I have added cordova-plugin-power-optimization Plugin that will add <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/> in AndroidManifest.xml,
Now I want to send Intent https://developer.android.com/reference/android/provider/Settings#ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS for the user to go to settings screen where he can exclude battery optimization,
I am not sure how to achieve this with Ionic WebIntent plugin, which we generally use to send/receive Intents
So far I am trying this code but not sure how to set Options and startActivity
Can anyone help please, I am using Ionic 4 with Cordova 7.1.4
this.androidPermissions.checkPermission(this.androidPermissions.PERMISSION.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
.then((result) => {
alert('Has permission?'+result.hasPermission)
this.androidPermissions.requestPermission(this.androidPermissions.PERMISSION.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
.then((data)=>{
alert('request permission then' + data.hasPermission);
//what should go here in options and startActivity
const openOptions = {
action: this.webIntent.ACTION_VIEW,
url: packageFileUrl,
type: 'application/vnd.android.package-archive'
};
this.webIntent.startActivity(openOptions).then((data1)=>{alert('data:'+data1)});
})
.catch((data)=>{
alert('request permission catch'+data.hasPermission)
})
},
);```
I am able to send Intent through WebIntent, Its just I need to use Constant value
"android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" in Action part of Intent Options, This constant values are mentioned on
https://developer.android.com/reference/android/provider/Settings#ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
Also for url, I have used getPackageName() method of AppVersion Plugin and pass this in url section of Intent Options,Here appName contains package Name and getPackageName() method is called from constructor.
Also Type is not needed here.
private async IntentIgnoreBatteryOptimization(resolve, reject) {
const openOptions = {
action:'android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS',
url: 'package:'+this.appName
};
try{
resolve(await this.webIntent.startActivity(openOptions));
}
catch(err){
reject('Permission denied'+err);
}
}
async getPackageName(){
if (this.device.isVirtual !== null) {
await this.appVersion.getPackageName().then((result)=>{
this.appName = result;
})
}
}
I think we can achieve this scenario by using the ionic Cordova native settings, in which you can pass battery_optimization and the native device will lead you to the battery optimization area.

include line only if platform is Android

One problem that I have is that when I navigate to a page containing a form on android the keyboard pops up automatically. I found a solution for it but it only works on Android:
import { View } from "tns-core-modules/ui/core/view";
export class AutoFocusView extends View {
createNativeView() {
if (typeof android !== "undefined") {
const linearLayout = new android.widget.LinearLayout(this._context);
linearLayout.setFocusableInTouchMode(true);
linearLayout.setFocusable(true);
return linearLayout;
}
return super.createNativeView();
}
onLoaded() {
super.onLoaded();
this.requestFocus();
}
requestFocus() {
const nativeViewProtected = this.nativeViewProtected;
nativeViewProtected.requestFocus();
}
}
I use this component. but it only works on android so I need to comment it from my code everytime I want to build for IOS. I was wondering if there was an easier way.
You could do like this:
import {isAndroid, isIOS} from '#nativescript/core';
then in your computed:
isandroid() {
return isAndroid;
}
then use this flag in any method you need:
if(isAndroid) {
this.requestFocus();
}
You also can use this isAndroid flag in your template if need be with v-if.
Just call requestFocus() only if platform is Android.
onLoaded() {
super.onLoaded();
if (typeof android !== "undefined") {
this.requestFocus();
}
}
You may also write it as a plugin within project, separate code for iOS and Android in platform specific file.

How do I open a React Native Android deeplink when the app is open in the background?

I'd like to open a React Native Android deeplink when the app is open in the background. Here's how I handle other similar cases:
iOS App is open in the background:
Linking.addEventListener('url', this.handleOpenURL);
iOS app is closed in the background
Linking.getInitialURL().then(url => this.handleOpenURL({ url }));
Android app is open in the background:
? - What's the best way to handle this case?
Android app is closed in the background:
Linking.getInitialURL().then(url => this.handleOpenURL({ url }));
The react native Linking does not seem to work with android running in the background. You can solve this by using native android code. In the main activity override the method like this:
#Override
public void onNewIntent(Intent intent) {
if(intent.getData() != null) {
Uri deepLinkURL = intent.getData();
DeepLink deepLink = new DeepLink(deepLinkURL.toString());
}
}
What you need to do then is integrate this java code with the react native javascript. This can be done with react native - native modules. There is some documentation on it on the website. To make it a more effective solution you can use something like http://square.github.io/otto/ to create an event bus that listens on that deeplink object. Then the deeplink event will fire effectively once a event has occured. I hope this helps man :)
Add this to MainActivity.java
#Override
public void onNewIntent(Intent intent) {
if(intent.getData() != null) {
Uri deepLinkURL = intent.getData();
ReactContext reactContext = getReactNativeHost().getReactInstanceManager().getCurrentReactContext();
sendEvent(reactContext,"deepLinking", deepLinkURL.toString());
}
}
private void sendEvent(ReactContext reactContext,
String eventName,
String str) {
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(eventName, str);
}
then add this to react
componentDidMount() {
this.subscription = DeviceEventEmitter.addListener('deepLinking', function(e: Event) {
// handle event
});
}
componentWillUnmount() {
// When you want to stop listening to new events, simply call .remove() on the subscription
this.subscription.remove();
}

Meteor.call doesn’t work on android App

I created a simple app using Meteor 1.3, which has only one method. It works like that: When a button is clicked, the method is invoked - it calculates a specific value and returns the result.
The app works perfectly on the localhost server, but when I launch it on my device with "meteor run android-device", it cannot access the method (simply opens the app, but nothing happens when I press a button.
Do you know how I could resolve this?
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
import { ReactiveDict } from 'meteor/reactive-dict';
import './main.html';
Template.check.onCreated(function checkOnCreated() {
this.state = new ReactiveDict();
});
Template.check.events({
'click .checkit'(event, instance) {
Meteor.call('code.check', function(error, result){
if(error){
console.log('Error from the client side!');
} else {
instance.state.set('fett', result.titles[0]);
}
});
},
});
Template.check.helpers({
fett() {
const instance = Template.instance();
if (instance.state.get('fett')) {
return instance.state.get('fett');
} else {
return 'Value still not known...'
}
},
});
Ensure your smartphone's WiFi is turned on and it connected to the same WiFi network as you computer where meteor app is running. Then everything should work fine.
Also, I recommend to use chrome://inspect feature (more info here) in order to debug your app on Android. Then, you will be able quickly investigate any problems with mobile app.

How to pause YouTube video on InAppBrowser when my Cordova app goes to background?

I am developing an Android app using Cordova and Ionic framework. I am playing a YouTube video with InAppBrowser using the code below:
window.open('https://www.youtube.com/embed/rAiw2SXPS-4', '_self');
But when I press the home button on the device while playing the video, the video is not paused. Due to this issue, my app is rejected after submitting to Google Play with the reason below:
Your submission has been rejected for enabling background playing of YouTube videos in violation of the YouTube API Terms of Service. If this submission was an update to an existing app, the version published prior to this update is still available in Google Play. Please modify your app and resubmit. Additional details have been sent to your account owner's email address.
I searched for a solution but have no luck. Can anybody help?
I was also struggling to find complete solution to pause(not stop) ongoing video(s) when device locks, but with no success. Eventually I found solution myself by combining several parts together.
Here is the directive that accomplishes YouTube player pause on device lock:
import { Directive, ElementRef, OnInit } from '#angular/core'
import { Platform } from 'ionic-angular'
import * as _ from 'lodash-es'
/* tslint:disable */
(function (apiInit) {
let _registerYouTubeAPIIfNotAlready = function () {
if (!window[ 'onYouTubeIframeAPIReady' ]) {
window[ 'onYouTubeIframeAPIReady' ] = function () {
apiInit.youTubeApiRegistered = true
if ((typeof apiInit.callback !== "undefined") && _.isFunction(apiInit.callback)) {
apiInit.callback()
}
}
} else {
console.error("trying to register YouTube API when it's already registered")
}
}
apiInit.setupYouTubeApiOrDefault = function (callback) {
if ((typeof callback === "undefined") || !_.isFunction(callback)) {
_registerYouTubeAPIIfNotAlready()
return
}
if(apiInit.youTubeApiRegistered){
callback()
return;
}
apiInit.callback = callback
_registerYouTubeAPIIfNotAlready()
}
}(window[ 'youTubeApiInit' ] = window[ 'youTubeApiInit' ] || {}))
#Directive({
selector: "[preventYoutubePlayOnBackground]",
})
export class PreventYouTubePlayOnBackgroundDirective implements OnInit {
public static youTubeIframeAPI = 'https://www.youtube.com/iframe_api'
public static injectYouTubeIframeApi(): void {
let youTubeCheckQuery = "script[src*='" + PreventYouTubePlayOnBackgroundDirective.youTubeIframeAPI + "']"
if (!document.querySelector(youTubeCheckQuery)) {
// from YouTube API documentation
let tag = document.createElement('script')
tag.src = PreventYouTubePlayOnBackgroundDirective.youTubeIframeAPI
let firstScriptTag = document.getElementsByTagName('script')[ 0 ]
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag)
}
}
public iframeId: string
private youTubeIframeElm: any
constructor(
public elm: ElementRef,
private platform: Platform,) {
this.youTubeIframeElm = elm.nativeElement
this.iframeId = this.youTubeIframeElm.getAttribute('id')
}
ngOnInit(): void {
this.platform.ready().then(() => {
PreventYouTubePlayOnBackgroundDirective.injectYouTubeIframeApi()
window[ 'youTubeApiInit' ].setupYouTubeApiOrDefault(() => {
this.setYouTubeApi()
this.platform.pause.subscribe(() => {
let player = new window[ 'YT' ].Player(this.iframeId) // TODO: add youtube API node module
player.a.contentWindow.postMessage('{"event":"command","func":"' + 'pauseVideo' + '","args":""}', '*')
})
})
})
}
private setYouTubeApi(): void {
let url = new URL(this.youTubeIframeElm.src)
if (!url.searchParams.get("enablejsapi")) { // enabling youTube js api to be able to create player
let prefix = (this.youTubeIframeElm.src.indexOf("?") === -1) ? "?" : "&"
this.youTubeIframeElm.src += prefix + "enablejsapi=true"
}
}
}
HTML for embedded YouTube player will be:
<iframe id="onboarding-video"
width="400"
height="300"
[src]="videoUrl"
frameborder="0"
allowfullscreen
preventYoutubePlayOnBackground
iframe-id="onboarding-video">
</iframe>
Note: above code is for ionic 2+, however for ionic 1 you can use:
(function() {
// same kind of logic here as written in above constructor body
$ionicPlatform.on('pause', function(event) {
// pausing player here
});
}())
Also you will need to create Angular 1 style directive instead of TypeScript one written above.
With $ionicPlatform you can use "on" method:
$ionicPlatform.on('pause', function(event) {
// pause video here
});
It is based on Cordova pause event:
document.addEventListener("pause", onPause, false);
function onPause() {
// Handle the pause event
}
See ionic documentation here and cordova documentation here.
You need to set shouldPauseOnSuspend=yes within the options when calling the open method for the inappbrowser. See the documentation here: https://github.com/apache/cordova-plugin-inappbrowser.
Something like this will work:
window.open('http://google.com','_blank', 'shouldPauseOnSuspend=yes');

Categories

Resources