Show AdMob Rewarded Ad multiple times in React Native - android

I have created a Button to display a rewarded Ad whenever it gets clicked.
There are two issues now:
1. It takes too much time to load the Ad (I can click the button once or twice before anything happens).
2. I want to reload the Ad right after it closes. It works but the App needs to restart.
AdMobRewardedComponent.js
async componentDidMount() {
await setTestDeviceIDAsync("EMULATOR");
AdMobRewarded.setAdUnitID("ca-app-pub-3940256099942544/5224354917");
AdMobRewarded.addEventListener("rewardedVideoDidLoad", () => {
console.log("VideoLoaded")
});
AdMobRewarded.addEventListener("rewardedVideoDidFailToLoad", () =>
console.log("FailedToLoad")
);
AdMobRewarded.addEventListener("rewardedVideoDidOpen", () =>
console.log("Opened")
);
AdMobRewarded.addEventListener("rewardedVideoDidClose", () => {
loadAd(request.build());
console.log("Closed")
});
AdMobRewarded.addEventListener("rewardedVideoWillLeaveApplication", () =>
console.log("LeaveApp")
);
AdMobRewarded.addEventListener("rewardedVideoDidStart", () =>
console.log("Started")
);
AdMobRewarded.addEventListener("rewardedVideoDidRewardUser", () =>
console.log("Rewarded"),
);
await AdMobRewarded.requestAdAsync();
}
componentWillUnmount() {
AdMobRewarded.removeAllListeners();
}
_handlePress = async () => {
await AdMobRewarded.showAdAsync();
};
render() {
const { loadedAd } = this.state;
return (
<TouchableButton onPress={this._handlePress} title="Coins erhalten!" image="adButton" status="active" style={styles.adButton}/>
);
}
};
Is there a way to request a new Ad without restarting the whole App?
Thanks for every answer!

In order to prevent the problem which the button can be pressed several times you can use debounce functionality:
React Native: Using lodash debounce
Or, you can manage your open ads at your store, so you can make sure that you don't open an ad twice and you can open a new ad once the previous ad had been closed, for instance:
const { isInterstitialAdOpen, } = useSelector(state => state.home);
if ((!__DEV__ && !isInterstitialAdOpen)) {
dispatch(openInterstitialAd());
AdMobInterstitial.setAdUnitID(AdMobController.getGeneralInterstitialId());
AdMobInterstitial.setTestDevices([AdMobInterstitial.simulatorId]);
AdMobInterstitial.addEventListener('adClosed', () => dispatch(closeInterstitialAd()));
AdMobInterstitial.requestAd().then(() => AdMobInterstitial.showAd()).catch((error) => {
});
}

Related

Create a custom notification with Actions Buttons

import BackgroundService from 'react-native-background-actions';
const sleep = (time) => new Promise((resolve) => setTimeout(() => resolve(), time));
// You can do anything in your task such as network requests, timers and so on,
// as long as it doesn't touch UI. Once your task completes (i.e. the promise is resolved),
// React Native will go into "paused" mode (unless there are other tasks running,
// or there is a foreground app).
const veryIntensiveTask = async (taskDataArguments) => {
// Example of an infinite loop task
const { delay } = taskDataArguments;
await new Promise( async (resolve) => {
for (let i = 0; BackgroundService.isRunning(); i++) {
console.log(i);
await sleep(delay);
}
});
};
const options = {
taskName: 'Example',
taskTitle: 'ExampleTask title',
taskDesc: 'ExampleTask description',
taskIcon: {
name: 'ic_launcher',
type: 'mipmap',
},
color: '#ff00ff',
linkingURI: 'yourSchemeHere://chat/jane', // See Deep Linking for more info
parameters: {
delay: 1000,
},
};
await BackgroundService.start(veryIntensiveTask, options);
await BackgroundService.updateNotification({taskDesc: 'New ExampleTask description'}); // Only Android, iOS will ignore this call
// iOS will also run everything here in the background until .stop() is called
await BackgroundService.stop();
I am using react-native-background-actions. I need 2 buttons in this. But I don’t have any good experience with native code in react native so let me know how can I add custom buttons In it and changes buttons according condition. How can I make changes in the native android for notification buttons.

When React native RNIap.purchaseErrorListener is called?

I have integrated react-native-iap for in app purchase.
Android Payment flow works properly(payment success, payment failed and user cancel payment).
But facing issue when purchase card is shown and I click outside the card, card is dismissed but not getting event inside RNIap.purchaseErrorListener .
Hence my state variable did not updated.
here is sample:
Listener code :
useEffect(() => {
initPurchase()
purchaseErrorSubscription = RNIap.purchaseErrorListener(
(error) => {
console.log('purchaseErrorListener INAPP>>>>', error);
if(error.code == "E_USER_CANCELLED") {
//for cancelled or refund sku
setSelectedPackage(null)
RNToasty.Show({
title: error.message,
});
} else if(error.code == "E_ITEM_UNAVAILABLE") {
//item not found
setSelectedPackage(null)
} else {
setSelectedPackage(null)
}
},
);
}, [])
Listener not called when I perform above action.
Can anyone help me to get this event?
Thanks in advance!!
you need to put this in a function, and in useEffect call this function
const checkCurrentPurchaseError = async () => {
purchaseErrorListener(async currentPurchaseError => {
if (currentPurchaseError) {
Here is your code...
}
});
};
useEffect(() => {
checkCurrentPurchaseError(currentPurchaseError);
}, []);

How to mock PermissionAndroid from react native

I'm building an android app using React-native and using PermissionsAndroid from react-native to get user permission.
import {PermissionsAndroid} from 'react-native'
Now i'm writing unit test and i need to verify the component behaviour based on the Permission.
hence i need to mock PermissionsAndroid.
Is there a way to do this?
jest.mock('react-native//Libraries/PermissionsAndroid/PermissionsAndroid', () => {
const PermissionsAndroid = jest.requireActual(
'react-native//Libraries/PermissionsAndroid/PermissionsAndroid',
);
console.log(PermissionsAndroid);
return {
...PermissionsAndroid,
check: jest.fn(() => new Promise(resolve => resolve(true))),
request: jest.fn(() => new Promise(resolve => resolve(true))),
};
});
This worked for me in 2022
jest.mock('react-
native//Libraries/PermissionsAndroid/PermissionsAndroid', () => {
return {
...jest.requireActual('react- native//Libraries/PermissionsAndroid/PermissionsAndroid'),
request: jest.fn(() => new Promise(resolve => resolve('granted')))
}
})
Because it is async you have to later on await it e.g. with react testing library const element = await findByText(...)
Simply mocking
jest.doMock('react-native', () => ({ PermissionsAndroid: {... did not work for me. Here is how I got it to work specifically mocking requestMultiple and check.
let fineLocationPermissionResult: String = PermissionsAndroid.RESULTS.GRANTED;
let courseLocationPermissionResult: String = PermissionsAndroid.RESULTS.GRANTED;
let fineLocationPermissionGranted = true;
let coarseLocationPermissionGranted = true;
const permissionsAndroidModule = jest.requireActual('react-native/Libraries/PermissionsAndroid/PermissionsAndroid.js');
jest.doMock('react-native/Libraries/PermissionsAndroid/PermissionsAndroid', () => ({
...permissionsAndroidModule,
requestMultiple: () => {
return {
[PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION]: fineLocationPermissionResult,
[PermissionsAndroid.PERMISSIONS.ACCESS_COARSE_LOCATION]: courseLocationPermissionResult,
};
},
check: () => {
return fineLocationPermissionGranted && coarseLocationPermissionGranted;
},
}));
I've included some of the variables I used in my tests to manipulate the results of the mock but essentially you need to mock the entire module path ('react-native/Libraries/PermissionsAndroid/PermissionsAndroid') and then include the rest of the module that you are not mocking via jest.requireActual.
Solution below:
jest.mock(
'react-native//Libraries/PermissionsAndroid/PermissionsAndroid',
() => ({
PermissionsAndroid: {
request: () => {
true;
},
check: () => {
true;
},
},
})
);
You can mock this from react-native directly, just like:
jest.doMock('react-native', () => ({
PermissionsAndroid: {
request: (permission: string) => {
//whatever you want
},
},
}))
Notice that you might see some issues with the components you are using for that unit test, i.e. it might show an error if you are using <View> from React Native and not mocking it. Given that case, you have to import <View> and then include it in your mock.
import { View } from 'react-native'
...
jest.doMock('react-native', () => ({
View,
PermissionsAndroid: {
request: (permission: string) => {
//whatever you want
},
},
}))

How to Play Multiple Audio's in React Native?

I want to play multiple audio files in my React Native application. Currently, it is one audio at a time and i also want single audio to be played at a time. What I want is if one audio is playing and suddenly the user tapped on the second audio button the first one will get paused and second should play. And when the user tapped the first again the paused audio will start again from where it is paused. Similar to whatsapp Audio Messages.
I am using react-native-audio-recorder-player for recording and playing audio in my application.
check app design
My FlatList Item Design:
{ { this.toggleMediaPlayer(item.audiourl, index) } }}>
<TouchableOpacity
style={styles.viewBarWrapper}
onPress={this.onStatusPress}
>
<View style={styles.viewBar}>
<View style={styles.viewBarPlay} />
</View>
</TouchableOpacity>
<Text style={styles.txtCounter}>
{/* {this.state.playTime} / {this.state.duration} */}
</Text>
</View>
MediaPlayer Function:
`toggleMediaPlayer(mediaPath, index) {
if (this.state.mediaFlag[index] == false) {
this.onStartPlay(mediaPath, index)
this.state.mediaFlag[index] = true;
var cloneObj = Object.assign({}, this.state.mediaFlag);
this.setState({ mediaFlag: cloneObj });
console.log(this.state.mediaFlag)
}
else {
this.onPausePlay(mediaPath)
this.state.mediaFlag[index] = false;
var cloneObj = Object.assign({}, this.state.mediaFlag);
this.setState({ mediaFlag: cloneObj });
console.log(this.state.mediaFlag)
}
}
`
REST CODE
audioRecorderPlayer = new AudioRecorderPlayer();
async onStartPlay(path, index) {
console.log('onStartPlay');
this.audioRecorderPlayer.stopPlayer();
const msg = await this.audioRecorderPlayer.startPlayer(path);
console.log(msg);
this.audioRecorderPlayer.addPlayBackListener(async (e) => {
if (e.current_position === e.duration) {
console.log('finished');
// await this.setState({ mediaFlag: !this.state.mediaFlag });
this.state.mediaFlag[index] = false;
var cloneObj = Object.assign({}, this.state.mediaFlag);
this.setState({ mediaFlag: cloneObj });
console.log(this.state.mediaFlag)
this.audioRecorderPlayer.stopPlayer();
this.audioRecorderPlayer.removePlayBackListener();
}
else {
this.setState({
currentPositionSec: e.current_position,
currentDurationSec: e.duration,
playTime: this.audioRecorderPlayer.mmssss(Math.floor(e.current_position)),
duration: this.audioRecorderPlayer.mmssss(Math.floor(e.duration)),
})
}
return;
});
};
onPausePlay = async () => {
await this.audioRecorderPlayer.pausePlayer();
};
async onStopPlay(index) {
console.log('onStopPlay');
this.audioRecorderPlayer.stopPlayer();
this.audioRecorderPlayer.removePlayBackListener();
};
As of v2.4.3, it is not a feature of react-native-audio-recorder-player (see https://github.com/dooboolab/react-native-audio-recorder-player/issues/130)
But i had to do it myself so here's how i managed to do it:
The main point is to have a parent component of all players (or a store - like redux or react context) which knows the state of the players (is a player reading its sound? which one?)
Then, when a player plays a sound, it calls the parent component and the parent component will stop any other player currently reading - it has to be done in a certain order to avoid odd behaviour
Here's my code simplified:
const ParentComponent = () => {
const [playerRecording, setPlayerRecording] = useState(false); // Which recording is currently playing?
const onPlay = async (onStartPlay, playerId) => {
// No player are reading or it is the same player
if (!playerRecording || playerRecording === playerId)
return onStartPlay();
// Another player is reading - stop it before starting the new one
audioRecorderPlayer.removePlayBackListener();
await audioRecorderPlayer.resumePlayer();
await audioRecorderPlayer.stopPlayer();
// Start the new player
onStartPlay();
};
}
const PlayerComponent = ({onPlay, setPlayerRecording, playerId}) => {
const onStartPlay = async () => {
setPlayerRecording(playerId);
audioRecorderPlayer.startPlayer(path);
...
}
return (
<PlayButton onPress={() => onPlay(onStartPlay, playerId)} />
)
}

React-Native - Facing issues while navigating to another screen after fetch api cal

This is a CRNA app with expo.
On button click in the First screen, I need to first make a fetch API call, capture the response and navigate to the Second screen passing the API response.
The issue I am facing is while I am invoking the fetchData method on button click of 'Create', it successfully navigates to the SecondScreen in the callback function of then(responseJson) but I noticed that even after displaying the SecondScreen, the screen keeps on refreshing automatically and I checked in the logs and saw this log sequence after successful navigation to SecondScreen:
In Second Screen -> Log from Second Screen
response -> Log from First Screen
responseData: .. -> Log from First Screen
Navigate to the Second screen -> Log from First Screen
inside fetchData -> Log from First Screen
response -> Log from First Screen
responseData: .. -> Log from First Screen
In Second Screen -> Log from Second Screen
and this goes into a loop.
First Screen code:
class FirstScreen extends Component {
constructor(props){
super(props);
this.state = {
isSubCreated: false,
isItemSelected : '',
subdata: {}
};
}
fetchData(){
console.log("inside fetchData");
fetch('http://hostname:port/',{
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
.then((response) => {console.log('response'); return response.json();})
.then((responseJson) => {console.log('responseData: '+responseJson); this.setState({isSubCreated : true, subdata : responseJson}); this.props.navigation.navigate('SecondScreen', {subdata : responseJson});})
.catch((err) => {console.log(err)}).done();
}
render() {
const subdata = this.state.subdata;
const { params } = this.props.navigation.state.params;
if (this.state.isSubCreated) {
console.log("Navigate to Second screen");
}
return (
<Container style={styles.container}>
<View>
<TouchableHighlight onPress={this.fetchData()}>
<Text>Create</Text>
</TouchableHighlight>
</View>
</Container>
)
}
}
Second Screen code:
class SecondScreen extends Component {
constructor(props){
super(props);
this.state = {
subdata: {}
};
}
render() {
const subdata = this.state.subdata;
const { params } = this.props.navigation.state.params;
console.log("In Second screen");
return (
<Container style={styles.container}>
<Content padder style={{ padding: 20 }}>
<View>
<Text>{this.props.navigation.state.params.subdata.data}</Text>
<View>
</Content
</Container>
)
}
}
Please help me understand why is it coming back to fetch API call of FirstScreen even after successfully navigating to SecondScreen?
Version:
react-native#0.50.4
Device: Android
Have you considered moving fetchData function to the Second screen and putting inside componentDidMount lifecycle method?

Categories

Resources