App.js 8.98 KB
Newer Older
renato's avatar
renato committed
1 2 3 4 5 6
/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */

Libin Lu's avatar
Libin Lu committed
7
import React, { Component } from "react";
renato's avatar
renato committed
8 9 10 11
import {
  StyleSheet,
  Text,
  TouchableOpacity,
12
  View,
Libin Lu's avatar
Libin Lu committed
13
  Clipboard,
Libin Lu's avatar
Libin Lu committed
14 15
  Platform,
  ScrollView
Libin Lu's avatar
Libin Lu committed
16
} from "react-native";
renato's avatar
renato committed
17

Libin Lu's avatar
Libin Lu committed
18
import { StackNavigator } from "react-navigation";
Libin Lu's avatar
Libin Lu committed
19

Libin Lu's avatar
Libin Lu committed
20
import FCM, { NotificationActionType } from "react-native-fcm";
Libin Lu's avatar
Libin Lu committed
21

Libin Lu's avatar
Libin Lu committed
22 23
import { registerKilledListener, registerAppListener } from "./Listeners";
import firebaseClient from "./FirebaseClient";
renato's avatar
renato committed
24

Libin Lu's avatar
Libin Lu committed
25 26
registerKilledListener();

Libin Lu's avatar
Libin Lu committed
27
class MainPage extends Component {
28 29 30 31
  constructor(props) {
    super(props);

    this.state = {
32 33
      token: "",
      tokenCopyFeedback: ""
Libin Lu's avatar
Libin Lu committed
34
    };
35 36
  }

Libin Lu's avatar
Libin Lu committed
37
  async componentDidMount() {
Libin Lu's avatar
Libin Lu committed
38
    //FCM.createNotificationChannel is mandatory for Android targeting >=8. Otherwise you won't see any notification
Libin Lu's avatar
Libin Lu committed
39 40 41 42 43 44
    FCM.createNotificationChannel({
      id: 'default',
      name: 'Default',
      description: 'used for example',
      priority: 'high'
    })
Libin Lu's avatar
Libin Lu committed
45
    registerAppListener(this.props.navigation);
Libin Lu's avatar
Libin Lu committed
46 47 48
    FCM.getInitialNotification().then(notif => {
      this.setState({
        initNotif: notif
Libin Lu's avatar
Libin Lu committed
49 50 51 52 53
      });
      if (notif && notif.targetScreen === "detail") {
        setTimeout(() => {
          this.props.navigation.navigate("Detail");
        }, 500);
Libin Lu's avatar
Libin Lu committed
54
      }
Libin Lu's avatar
Libin Lu committed
55
    });
Libin Lu's avatar
Libin Lu committed
56

Libin Lu's avatar
Libin Lu committed
57 58 59 60 61 62 63
    try {
      let result = await FCM.requestPermissions({
        badge: false,
        sound: true,
        alert: true
      });
    } catch (e) {
Libin Lu's avatar
Libin Lu committed
64 65 66 67 68
      console.error(e);
    }

    FCM.getFCMToken().then(token => {
      console.log("TOKEN (getFCMToken)", token);
Libin Lu's avatar
Libin Lu committed
69
      this.setState({ token: token || "" });
Libin Lu's avatar
Libin Lu committed
70 71
    });

Libin Lu's avatar
Libin Lu committed
72
    if (Platform.OS === "ios") {
Libin Lu's avatar
Libin Lu committed
73 74 75 76
      FCM.getAPNSToken().then(token => {
        console.log("APNS TOKEN (getFCMToken)", token);
      });
    }
Libin Lu's avatar
Libin Lu committed
77 78 79 80

    // topic example
    // FCM.subscribeToTopic('sometopic')
    // FCM.unsubscribeFromTopic('sometopic')
Libin Lu's avatar
Libin Lu committed
81 82
  }

Libin Lu's avatar
Libin Lu committed
83 84
  showLocalNotification() {
    FCM.presentLocalNotification({
Libin Lu's avatar
Libin Lu committed
85
      channel: 'default',
Libin Lu's avatar
Libin Lu committed
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
      id: new Date().valueOf().toString(), // (optional for instant notification)
      title: "Test Notification with action", // as FCM payload
      body: "Force touch to reply", // as FCM payload (required)
      sound: "bell.mp3", // "default" or filename
      priority: "high", // as FCM payload
      click_action: "com.myapp.MyCategory", // as FCM payload - this is used as category identifier on iOS.
      badge: 10, // as FCM payload IOS only, set 0 to clear badges
      number: 10, // Android only
      ticker: "My Notification Ticker", // Android only
      auto_cancel: true, // Android only (default true)
      large_icon:
        "https://image.freepik.com/free-icon/small-boy-cartoon_318-38077.jpg", // Android only
      icon: "ic_launcher", // as FCM payload, you can relace this with custom icon you put in mipmap
      big_text: "Show when notification is expanded", // Android only
      sub_text: "This is a subText", // Android only
      color: "red", // Android only
      vibrate: 300, // Android only default: 300, no vibration if you pass 0
      wake_screen: true, // Android only, wake up screen when notification arrives
      group: "group", // Android only
      picture:
        "https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png", // Android only bigPicture style
      ongoing: true, // Android only
      my_custom_data: "my_custom_field_value", // extra data you want to throw
      lights: true, // Android only, LED blinking (default false)
      show_in_foreground: true // notification when app is in foreground (local & remote)
Libin Lu's avatar
Libin Lu committed
111 112 113
    });
  }

Libin Lu's avatar
Libin Lu committed
114 115
  scheduleLocalNotification() {
    FCM.scheduleLocalNotification({
Libin Lu's avatar
Libin Lu committed
116 117
      id: "testnotif",
      fire_date: new Date().getTime() + 5000,
Libin Lu's avatar
Libin Lu committed
118
      vibrate: 500,
Libin Lu's avatar
Libin Lu committed
119 120 121
      title: "Hello",
      body: "Test Scheduled Notification",
      sub_text: "sub text",
Libin Lu's avatar
Libin Lu committed
122
      priority: "high",
Libin Lu's avatar
Libin Lu committed
123 124
      large_icon:
        "https://image.freepik.com/free-icon/small-boy-cartoon_318-38077.jpg",
Libin Lu's avatar
Libin Lu committed
125
      show_in_foreground: true,
Libin Lu's avatar
Libin Lu committed
126 127
      picture:
        "https://firebase.google.com/_static/af7ae4b3fc/images/firebase/lockup.png",
Libin Lu's avatar
Libin Lu committed
128
      wake_screen: true,
Libin Lu's avatar
Libin Lu committed
129
      extra1: { a: 1 },
Libin Lu's avatar
Libin Lu committed
130
      extra2: 1
Libin Lu's avatar
Libin Lu committed
131 132 133
    });
  }

Libin Lu's avatar
Libin Lu committed
134 135 136
  sendRemoteNotification(token) {
    let body;

Libin Lu's avatar
Libin Lu committed
137
    if (Platform.OS === "android") {
Libin Lu's avatar
Libin Lu committed
138
      body = {
Libin Lu's avatar
Libin Lu committed
139 140 141 142 143 144 145 146 147 148 149 150 151
        to: token,
        data: {
          custom_notification: {
            title: "Simple FCM Client",
            body: "Click me to go to detail",
            sound: "default",
            priority: "high",
            show_in_foreground: true,
            targetScreen: "detail"
          }
        },
        priority: 10
      };
Libin Lu's avatar
Libin Lu committed
152
    } else {
Libin Lu's avatar
Libin Lu committed
153 154 155 156 157 158
      body = {
        to: token,
        notification: {
          title: "Simple FCM Client",
          body: "Click me to go to detail",
          sound: "default"
Libin Lu's avatar
Libin Lu committed
159 160
        },
        data: {
Libin Lu's avatar
Libin Lu committed
161
          targetScreen: "detail"
Libin Lu's avatar
Libin Lu committed
162
        },
Libin Lu's avatar
Libin Lu committed
163 164 165
        priority: 10
      };
    }
Libin Lu's avatar
Libin Lu committed
166 167 168 169 170 171

    firebaseClient.send(JSON.stringify(body), "notification");
  }

  sendRemoteData(token) {
    let body = {
Libin Lu's avatar
Libin Lu committed
172 173 174 175 176 177 178 179
      to: token,
      data: {
        title: "Simple FCM Client",
        body: "This is a notification with only DATA.",
        sound: "default"
      },
      priority: "normal"
    };
Libin Lu's avatar
Libin Lu committed
180 181 182 183

    firebaseClient.send(JSON.stringify(body), "data");
  }

Libin Lu's avatar
Libin Lu committed
184 185
  showLocalNotificationWithAction() {
    FCM.presentLocalNotification({
Libin Lu's avatar
Libin Lu committed
186 187
      title: "Test Notification with action",
      body: "Force touch to reply",
Libin Lu's avatar
Libin Lu committed
188 189
      priority: "high",
      show_in_foreground: true,
Libin Lu's avatar
Libin Lu committed
190
      click_action: "com.myidentifi.fcm.text", // for ios
Libin Lu's avatar
Libin Lu committed
191 192 193 194 195 196 197 198 199 200
      android_actions: JSON.stringify([
        {
          id: "view",
          title: "view"
        },
        {
          id: "dismiss",
          title: "dismiss"
        }
      ]) // for android, take syntax similar to ios's. only buttons are supported
Libin Lu's avatar
Libin Lu committed
201
    });
Libin Lu's avatar
Libin Lu committed
202 203
  }

renato's avatar
renato committed
204
  render() {
205
    let { token, tokenCopyFeedback } = this.state;
206

renato's avatar
renato committed
207 208
    return (
      <View style={styles.container}>
Libin Lu's avatar
Libin Lu committed
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
        <ScrollView style={{ paddingHorizontal: 20 }}>
          <Text style={styles.welcome}>Welcome to Simple Fcm Client!</Text>

          <Text style={styles.feedback}>{this.state.tokenCopyFeedback}</Text>

          <Text style={styles.feedback}>
            Remote notif won't be available to iOS emulators
          </Text>

          <TouchableOpacity
            onPress={() => this.sendRemoteNotification(token)}
            style={styles.button}
          >
            <Text style={styles.buttonText}>Send Remote Notification</Text>
          </TouchableOpacity>

          <TouchableOpacity
            onPress={() => this.sendRemoteData(token)}
            style={styles.button}
          >
            <Text style={styles.buttonText}>Send Remote Data</Text>
          </TouchableOpacity>

          <TouchableOpacity
            onPress={() => this.showLocalNotification()}
            style={styles.button}
          >
            <Text style={styles.buttonText}>Show Local Notification</Text>
          </TouchableOpacity>

          <TouchableOpacity
            onPress={() => this.showLocalNotificationWithAction(token)}
            style={styles.button}
          >
            <Text style={styles.buttonText}>
              Show Local Notification with Action
            </Text>
          </TouchableOpacity>

          <TouchableOpacity
            onPress={() => this.scheduleLocalNotification()}
            style={styles.button}
          >
            <Text style={styles.buttonText}>Schedule Notification in 5s</Text>
          </TouchableOpacity>

          <Text style={styles.instructions}>Init notif:</Text>
          <Text>{JSON.stringify(this.state.initNotif)}</Text>

          <Text style={styles.instructions}>Token:</Text>
          <Text
            selectable={true}
            onPress={() => this.setClipboardContent(this.state.token)}
          >
            {this.state.token}
          </Text>
Libin Lu's avatar
Libin Lu committed
265
        </ScrollView>
renato's avatar
renato committed
266 267 268
      </View>
    );
  }
269 270 271

  setClipboardContent(text) {
    Clipboard.setString(text);
Libin Lu's avatar
Libin Lu committed
272 273 274 275
    this.setState({ tokenCopyFeedback: "Token copied to clipboard." });
    setTimeout(() => {
      this.clearTokenCopyFeedback();
    }, 2000);
276 277 278
  }

  clearTokenCopyFeedback() {
Libin Lu's avatar
Libin Lu committed
279
    this.setState({ tokenCopyFeedback: "" });
280
  }
renato's avatar
renato committed
281 282
}

Libin Lu's avatar
Libin Lu committed
283
class DetailPage extends Component {
Libin Lu's avatar
Libin Lu committed
284 285 286 287 288 289
  render() {
    return (
      <View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
        <Text>Detail page</Text>
      </View>
    );
Libin Lu's avatar
Libin Lu committed
290 291 292
  }
}

Libin Lu's avatar
Libin Lu committed
293 294 295 296 297 298 299 300
export default StackNavigator(
  {
    Main: {
      screen: MainPage
    },
    Detail: {
      screen: DetailPage
    }
Libin Lu's avatar
Libin Lu committed
301
  },
Libin Lu's avatar
Libin Lu committed
302 303
  {
    initialRouteName: "Main"
Libin Lu's avatar
Libin Lu committed
304
  }
Libin Lu's avatar
Libin Lu committed
305
);
Libin Lu's avatar
Libin Lu committed
306

renato's avatar
renato committed
307 308 309
const styles = StyleSheet.create({
  container: {
    flex: 1,
Libin Lu's avatar
Libin Lu committed
310 311 312
    justifyContent: "center",
    alignItems: "center",
    backgroundColor: "#F5FCFF"
renato's avatar
renato committed
313 314 315
  },
  welcome: {
    fontSize: 20,
Libin Lu's avatar
Libin Lu committed
316 317
    textAlign: "center",
    margin: 10
renato's avatar
renato committed
318 319
  },
  instructions: {
Libin Lu's avatar
Libin Lu committed
320 321 322
    textAlign: "center",
    color: "#333333",
    marginBottom: 2
323 324
  },
  feedback: {
Libin Lu's avatar
Libin Lu committed
325 326 327
    textAlign: "center",
    color: "#996633",
    marginBottom: 3
renato's avatar
renato committed
328 329 330 331
  },
  button: {
    backgroundColor: "teal",
    paddingHorizontal: 20,
Libin Lu's avatar
Libin Lu committed
332 333
    paddingVertical: 15,
    marginVertical: 10,
renato's avatar
renato committed
334 335 336 337 338
    borderRadius: 10
  },
  buttonText: {
    color: "white",
    backgroundColor: "transparent"
Libin Lu's avatar
Libin Lu committed
339
  }
renato's avatar
renato committed
340
});