Unhandled Promise Rejection when using local notifications in emulator

I’m trying to get basic local notifications to work in a bare-minimum app. It works just fine in the expo client, but when I try to run it in a Galaxy Nexus API 28 emulator in Android Studio with yarn react-native run-android I get this exception when pressing the “Press to Send Notification” button:

 LOG  Running "main" with {"rootTag":1}
 WARN  Possible Unhandled Promise Rejection (id: 0):
TypeError: null is not an object (evaluating '_ExponentNotifications.default.presentLocalNotification')
presentLocalNotificationAsync$@http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:109860:79
tryCatch@http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:26262:23
invoke@http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:26438:32
tryCatch@http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:26262:23
invoke@http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:26338:30
http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:26348:21
tryCallOne@http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:27618:16
http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:27719:27
_callTimer@http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:31173:17
_callImmediatesPass@http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:31209:19
callImmediates@http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:31428:33
callImmediates@[native code]
__callImmediates@http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:3238:35
http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:3015:34
__guard@http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:3221:15
flushedQueue@http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:3014:21
flushedQueue@[native code]
invokeCallbackAndReturnFlushedQueue@[native code]

This is my App.js

import React from 'react';
import { Text, View, Button, Vibration, Platform } from 'react-native';
import { Notifications } from 'expo';

export default class AppContainer extends React.Component {

  componentDidMount() {
    Notifications.createChannelAndroidAsync(
      "test1", {name: "test1 name", priority: "max"},
    );
  }

  sendPushNotification() {
    const notification = {
      title: "My title NEW",
      body: "My body",
      android: {
        channelId: "test1",
      },
    };
    Notifications.presentLocalNotificationAsync(notification);
  }

  render() {
    return (
      <View
        style={{
          flex: 1,
          alignItems: 'center',
          justifyContent: 'space-around',
        }}>
        <Button title={'Press to Send Notification'} onPress={() => this.sendPushNotification()} />
      </View>
    );
  }
}

This is my package.json

{
  "main": "index.js",
  "scripts": {
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "web": "expo start --web",
    "start": "react-native start",
    "test": "jest"
  },
  "dependencies": {
    "expo": "~37.0.3",
    "expo-notifications": "^0.1.2",
    "expo-updates": "~0.1.0",
    "react": "~16.9.0",
    "react-dom": "~16.9.0",
    "react-native": "~0.61.5",
    "react-native-gesture-handler": "~1.6.0",
    "react-native-reanimated": "~1.7.0",
    "react-native-screens": "~2.2.0",
    "react-native-unimodules": "~0.9.0",
    "react-native-web": "~0.11.7"
  },
  "devDependencies": {
    "@babel/core": "~7.9.0",
    "babel-jest": "~25.2.6",
    "jest": "~25.2.6",
    "react-test-renderer": "~16.9.0"
  },
  "jest": {
    "preset": "react-native"
  },
  "private": true
}

+1 Having the same issue

I think I figured out what’s going on. It looks like there are actually TWO expo notifications APIs, one for the managed workflow and the other for the bare workflow. The documentation doesn’t make this clear as far as I can tell. The code I have above uses the managed workflow API, so it works in the expo client but not in the android emulator. I switched to the other API (which is described on the expo-notifications github page), and now it works in the android emulator but not in the expo client. I’m just going to not use the expo client anymore since I want to use native code anyway.

any tips on how we can make it more clear? in installation we say this:

Installation

This API is pre-installed in managed apps. See the expo-notifications README for information on how to integrate notifications into bare React Native apps.

we could call this out more prominently maybe?

Yeah, I think it would be helpful to explain that the two APIs literally require different code to work. From that sentence I thought that only the installation is different. Apparently integration != installation, but that’s how I read it. (Also, that sentence is in a section titled Installation, another reason I think I read it that way) It’s also confusing that both APIs have the same name and are imported in the same way, and the API calls are similar.

In my case I’m doing a bare app, so I read that sentence, then I went and followed the installation instructions in the README, then I went back to the documentation page, followed the instructions, and was very puzzled when it didn’t work.

I’m surprised I was even able to use the managed workflow notifications API at all in the expo client, since I started with a bare app. When did the API get installed if it’s only pre-installed in managed apps? Why is an API that doesn’t work in bare apps pre-installed into them?

Ideally there would be a whole other section of the documentation explaining how to use the other expo-notifications API, the one that works in the device emulator, but for now I’d just add to that page. Something like NOTE: The code below will not work in.a bare app! Look at the expo-notifications README to learn what code to use for the other API.

Yep, same happened to me. I just got used to above sentences in other modules, where there are just some additional steps to do in a bare workflow. Specifically calling out, that this module does not work in the bare workflow would help!