Skip to content

Instantly share code, notes, and snippets.

@VeraZab
Last active February 26, 2023 23:26
Show Gist options
  • Star 32 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
  • Save VeraZab/c3f13d51588bcfdf6799da65decf26fa to your computer and use it in GitHub Desktop.
Save VeraZab/c3f13d51588bcfdf6799da65decf26fa to your computer and use it in GitHub Desktop.
Simple local notification with Expo
import React, {Component} from 'react';
import {TextInput, View, Keyboard} from 'react-native';
import {Constants, Notifications, Permissions} from 'expo';
export default class Timer extends Component {
onSubmit(e) {
Keyboard.dismiss();
const localNotification = {
title: 'done',
body: 'done!'
};
const schedulingOptions = {
time: (new Date()).getTime() + Number(e.nativeEvent.text)
}
// Notifications show only when app is not active.
// (ie. another app being used or device's screen is locked)
Notifications.scheduleLocalNotificationAsync(
localNotification, schedulingOptions
);
}
handleNotification() {
console.warn('ok! got your notif');
}
async componentDidMount() {
// We need to ask for Notification permissions for ios devices
let result = await Permissions.askAsync(Permissions.NOTIFICATIONS);
if (Constants.isDevice && result.status === 'granted') {
console.log('Notification permissions granted.')
}
// If we want to do something with the notification when the app
// is active, we need to listen to notification events and
// handle them in a callback
Notifications.addListener(this.handleNotification);
}
render() {
return (
<View style={{flex: 1, flexDirection: 'row', justifyContent: 'center'}}>
<TextInput
onSubmitEditing={this.onSubmit}
placeholder={'time in ms'}
/>
</View>
);
}
};
@khasky
Copy link

khasky commented Jun 23, 2019

Thanks for an example 👍

@yastrebovb
Copy link

Great example

@Edweis
Copy link

Edweis commented Dec 22, 2019

Here is the same with hooks and latest expo :

import React, { useEffect } from 'react';
import { Input } from 'react-native-elements';

import { Keyboard } from 'react-native';
import { Notifications } from 'expo';
import * as Permissions from 'expo-permissions';
import Constants from 'expo-constants';

const localNotification = { title: 'done', body: 'done!' };

const onSubmit = text => {
  Keyboard.dismiss();
  const schedulingOptions = {
    time: new Date().getTime() + Number(text),
  };
  // Notifications show only when app is not active.
  // (ie. another app being used or device's screen is locked)
  Notifications.scheduleLocalNotificationAsync(
    localNotification,
    schedulingOptions,
  );
};
const handleNotification = () => {
  console.warn('ok! got your notif');
};

const askNotification = async () => {
  // We need to ask for Notification permissions for ios devices
  const { status } = await Permissions.askAsync(Permissions.NOTIFICATIONS);
  if (Constants.isDevice && status === 'granted')
    console.log('Notification permissions granted.');
};

const TimerNotification = () => {
  useEffect(() => {
    askNotification();
    // If we want to do something with the notification when the app
    // is active, we need to listen to notification events and
    // handle them in a callback
    const listener = Notifications.addListener(handleNotification);
    return () => listener.remove();
  }, []);

  return <Input onChangeText={onSubmit} label="time in ms" />;
};

export default TimerNotification;

@abhilash-ss
Copy link

Thanks
It is very helpful

@blydewright
Copy link

Thanks for the example. Is Android local notification persistence still an issue? (being cleared on device restart).

@lucj
Copy link

lucj commented May 7, 2020

@Edweis any chance you have the same kind of example (hooks based approach) with Expo remote notifications ? :)

@peterkortvel
Copy link

Thank you!

@vital-tech-results
Copy link

Here is the same with hooks and latest expo :

import React, { useEffect } from 'react';
import { Input } from 'react-native-elements';

import { Keyboard } from 'react-native';
import { Notifications } from 'expo';
import * as Permissions from 'expo-permissions';
import Constants from 'expo-constants';

const localNotification = { title: 'done', body: 'done!' };

const onSubmit = text => {
  Keyboard.dismiss();
  const schedulingOptions = {
    time: new Date().getTime() + Number(text),
  };
  // Notifications show only when app is not active.
  // (ie. another app being used or device's screen is locked)
  Notifications.scheduleLocalNotificationAsync(
    localNotification,
    schedulingOptions,
  );
};
const handleNotification = () => {
  console.warn('ok! got your notif');
};

const askNotification = async () => {
  // We need to ask for Notification permissions for ios devices
  const { status } = await Permissions.askAsync(Permissions.NOTIFICATIONS);
  if (Constants.isDevice && status === 'granted')
    console.log('Notification permissions granted.');
};

const TimerNotification = () => {
  useEffect(() => {
    askNotification();
    // If we want to do something with the notification when the app
    // is active, we need to listen to notification events and
    // handle them in a callback
    const listener = Notifications.addListener(handleNotification);
    return () => listener.remove();
  }, []);

  return <Input onChangeText={onSubmit} label="time in ms" />;
};

export default TimerNotification;

this is really awesome! Is there a way to set this notification to occur based on date from a JSON file? Something like if(date == month){Notifications.scheduleLocalNotificationAsync( localNotification, schedulingOptions, )}

I am stuck on getting the localNotification object to accept a dynamic variable from the result of mapping over a JSON file.

@ronaldaraujo
Copy link

Hello.

How do I get the notification id? Following the example of the official Expo page, I was unable to understand exactly how to obtain this value.

This is the excerpt from my code that creates the notification.

let id = Notifications.scheduleLocalNotificationAsync(
    notification,
    options
);

The id variable holds a promise and the example says that I can get the value within _55. Is that correct? In my scenario, this value always comes to zero.

Promise {
 "_40": 0,
 "_55": null,
 "_65": 0,
 "_72": null,
}

Does anyone have any ideas?

Thank you!

This is the example I am following. See line 42.

@tomathosauce
Copy link

tomathosauce commented Mar 29, 2021

I just did a version of the example by Edweis with the new Expo Notifications API (from SDK40 I think), as well as some minor changes.

import React, { useEffect, useState } from 'react';
import { Keyboard, TextInput, View, Button } from 'react-native';
import Constants from 'expo-constants';
import * as Permissions from 'expo-permissions';
import * as Notifications from 'expo-notifications';

const onSubmit = (seconds) => {
  Keyboard.dismiss();
  const schedulingOptions = {
    content: {
      title: 'This is a notification',
      body: 'This is the body',
      sound: true,
      priority: Notifications.AndroidNotificationPriority.HIGH,
      color: "blue"
    },
    trigger: {
      seconds: seconds,
    },
  };
  // Notifications show only when app is not active.
  // (ie. another app being used or device's screen is locked)
  Notifications.scheduleNotificationAsync(
    schedulingOptions,
  );
};
const handleNotification = () => {
  console.warn('ok! got your notif');
};

const askNotification = async () => {
  // We need to ask for Notification permissions for ios devices
  const { status } = await Permissions.askAsync(Permissions.NOTIFICATIONS);
  if (Constants.isDevice && status === 'granted')
    console.log('Notification permissions granted.');
};

const TimerNotification = () => {
  const [text, onChangeText] = useState("");

  useEffect(() => {
    askNotification();
    // If we want to do something with the notification when the app
    // is active, we need to listen to notification events and
    // handle them in a callback
    const listener = Notifications.addNotificationReceivedListener(handleNotification);
    return () => listener.remove();
  }, []);

  return (<View>
    <TextInput
        onChangeText={onChangeText}
        value={text}
        placeholder="Seconds"
        style={{fontSize: 30, borderWidth: 1, width: 300}}
        keyboardType="numeric"
    />
    <Button onPress={() => onSubmit(Number(text))} title="Schedule"/>
  </View>)
};

export default TimerNotification

@BoGnY
Copy link

BoGnY commented Apr 1, 2021

Hi, is it possible to read other application's notifications with Expo?

@vital-tech-results
Copy link

I just did a version of the example by Edweis with the new Expo Notifications API (from SDK40 I think), as well as some minor changes.

this is awesome! I'm trying to figure out how to get the trigger to work on both Android and iOS. I see you have seconds but how many seconds? I need to input a specific date here for seconds.

trigger: {
      seconds: seconds,
    },

@whiteclouds7
Copy link

whiteclouds7 commented May 18, 2021

Hi,
I'm using SKD41 and Expo is currently moving the permissions to the specific dependency packages and probably won't support the "expo-permissions" in future releases. This means that you should use the getPermissionsAsync() and requestPermissionsAsync() from the expo-notifications package.

I've included a one line change inside the askNotification function into the example provided by @tomathosauce

import React, { useEffect, useState } from 'react';
import { Keyboard, TextInput, View, Button } from 'react-native';
import Constants from 'expo-constants';
import * as Notifications from 'expo-notifications';

const onSubmit = (seconds) => {
  Keyboard.dismiss();
  const schedulingOptions = {
    content: {
      title: 'This is a notification',
      body: 'This is the body',
      sound: true,
      priority: Notifications.AndroidNotificationPriority.HIGH,
      color: "blue"
    },
    trigger: {
      seconds: seconds,
    },
  };
  // Notifications show only when app is not active.
  // (ie. another app being used or device's screen is locked)
  Notifications.scheduleNotificationAsync(
    schedulingOptions,
  );
};
const handleNotification = () => {
  console.warn('ok! got your notif');
};

const askNotification = async () => {
  // We need to ask for Notification permissions for ios devices
  const { status } = await await Notifications.requestPermissionsAsync();
  if (Constants.isDevice && status === 'granted')
    console.log('Notification permissions granted.');
};

const TimerNotification = () => {
  const [text, onChangeText] = useState("");

  useEffect(() => {
    askNotification();
    // If we want to do something with the notification when the app
    // is active, we need to listen to notification events and
    // handle them in a callback
    const listener = Notifications.addNotificationReceivedListener(handleNotification);
    return () => listener.remove();
  }, []);

  return (
  <View>
    <TextInput
        onChangeText={onChangeText}
        value={text}
        placeholder="Seconds"
        style={{fontSize: 30, borderWidth: 1, width: 300}}
        keyboardType="numeric"
    />
    <Button onPress={() => onSubmit(Number(text))} title="Schedule"/>
  </View>)
};

export default TimerNotification

I hope this helps someone out 😊

@loitd
Copy link

loitd commented Jun 19, 2021

tried both @tomathosauce and @whiteclouds7 successfully with sdk40. Thank you for an awesome gist.

@alexanderdavide
Copy link

alexanderdavide commented Dec 14, 2021

There aren't any changes in SDK version 43 compared to @whiteclouds7 proposed solution but here follows a refined example that is also working in TypeScript:

import { registerRootComponent } from 'expo';
import { PermissionStatus } from 'expo-modules-core';
import * as Notifications from 'expo-notifications';
import { Notification } from 'expo-notifications';
import React, { useEffect, useState } from 'react';
import { Button, StyleSheet, View } from 'react-native';

const App = () => {
  const [notificationPermissions, setNotificationPermissions] = useState<PermissionStatus>(
    PermissionStatus.UNDETERMINED,
  );

  const scheduleNotification = (seconds: number) => {
    const schedulingOptions = {
      content: {
        title: 'This is a notification',
        body: 'This is the body',
        sound: true,
        priority: Notifications.AndroidNotificationPriority.HIGH,
        color: 'blue',
      },
      trigger: {
        seconds: seconds,
      },
    };
    Notifications.scheduleNotificationAsync(schedulingOptions);
  };

  const handleNotification = (notification: Notification) => {
    const { title } = notification.request.content;
    console.warn(title);
  };

  const requestNotificationPermissions = async () => {
    const { status } = await Notifications.requestPermissionsAsync();
    setNotificationPermissions(status);
    return status;
  };

  useEffect(() => {
    requestNotificationPermissions();
  }, []);

  useEffect(() => {
    if (notificationPermissions !== PermissionStatus.GRANTED) return;
    const listener = Notifications.addNotificationReceivedListener(handleNotification);
    return () => listener.remove();
  }, [notificationPermissions]);

  return (
    <View style={styles.container}>
      <Button onPress={() => scheduleNotification(1)} title="Notify" />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
    paddingLeft: 10,
    paddingRight: 10,
  },
});

registerRootComponent(App);

export default App;

@KeithMarex
Copy link

KeithMarex commented Mar 28, 2022

The expo-constants isDevice recently became deprecated. Make sure to now use the Device library from Expo.

expo install expo-device

import * as Device from 'expo-device';

And replace Constants.isDevice with Device.isDevice

@jmjaimesmendoza
Copy link

Hi, i'm trying to use @whiteclouds7 example but for some reason the notifications don't show when the app is in the background on a physical device, they do work properly on Xcode iphone Simulator, any clues on why this may be?

@9Dave9
Copy link

9Dave9 commented Aug 20, 2022

I have this exact same issue, the notifications register just fine on a non APK/bundle but the moment I bundle the app.. the scheduleNotificationsAsync function just don't set the notification.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment