Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Push notifications #27

Merged
merged 16 commits into from
May 5, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import org.xmtp.android.library.XMTPException
import org.xmtp.android.library.messages.InvitationV1ContextBuilder
import org.xmtp.android.library.messages.PrivateKeyBuilder
import org.xmtp.android.library.messages.Signature
import org.xmtp.android.library.push.XMTPPush
import org.xmtp.proto.message.contents.SignatureOuterClass
import java.util.Date
import java.util.UUID
Expand Down Expand Up @@ -84,6 +85,7 @@ class XMTPModule : Module() {
)

private var client: Client? = null
private var xmtpPush: XMTPPush? = null
private var signer: ReactNativeSigner? = null
private val conversations: MutableMap<String, Conversation> = mutableMapOf()
private val subscriptions: MutableMap<String, Job> = mutableMapOf()
Expand Down Expand Up @@ -190,6 +192,18 @@ class XMTPModule : Module() {
AsyncFunction("unsubscribeFromMessages") { topic: String, conversationID: String? ->
unsubscribeFromMessages(topic = topic, conversationId = conversationID)
}

Function("registerPushToken") { pushServer: String, token: String ->
xmtpPush = XMTPPush(appContext.reactContext!!, pushServer)
xmtpPush?.register(token)
}

Function("subscribePushTopics") { topics: List<String> ->
if (xmtpPush == null) {
throw XMTPException("Push server not registered")
}
xmtpPush?.subscribe(topics)
}
}

//
Expand Down
2 changes: 2 additions & 0 deletions example/android/app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
apply plugin: "com.android.application"
apply plugin: "com.facebook.react"
apply plugin: 'com.google.gms.google-services'

import com.android.build.OutputFile

Expand Down Expand Up @@ -192,6 +193,7 @@ android {
dependencies {
// The version of react-native is set by the React Native Gradle Plugin
implementation("com.facebook.react:react-android")
implementation platform('com.google.firebase:firebase-bom:31.5.0')

def isGifEnabled = (findProperty('expo.gif.enabled') ?: "") == "true";
def isWebpEnabled = (findProperty('expo.webp.enabled') ?: "") == "true";
Expand Down
131 changes: 98 additions & 33 deletions example/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,34 +1,99 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="expo.modules.xmtpreactnativesdk.example">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<queries>
<intent>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="https"/>
</intent>
</queries>
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme" android:usesCleartextTraffic="true">
<meta-data android:name="expo.modules.updates.ENABLED" android:value="true"/>
<meta-data android:name="expo.modules.updates.EXPO_SDK_VERSION" android:value="48.0.0"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATE_URL" android:value="https://exp.host/@anonymous/xmtp-react-native-sdk-example"/>
<activity android:name=".MainActivity" android:label="@string/app_name" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.App.SplashScreen" android:exported="true" android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="expo.modules.xmtpreactnativesdk.example"/>
</intent-filter>
</activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" android:exported="false"/>
</application>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="expo.modules.xmtpreactnativesdk.example">

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<permission
android:name="${applicationId}.permission.C2D_MESSAGE"
android:protectionLevel="signature" />

<uses-permission android:name="${applicationId}.permission.C2D_MESSAGE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" />
</intent>
</queries>
<application
android:name=".MainApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true">
<meta-data
android:name="expo.modules.updates.ENABLED"
android:value="true" />
<meta-data
android:name="expo.modules.updates.EXPO_SDK_VERSION"
android:value="48.0.0" />
<meta-data
android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH"
android:value="ALWAYS" />
<meta-data
android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS"
android:value="0" />
<meta-data
android:name="expo.modules.updates.EXPO_UPDATE_URL"
android:value="https://exp.host/@anonymous/xmtp-react-native-sdk-example" />

<activity
android:name=".MainActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
android:exported="true"
android:label="@string/app_name"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:theme="@style/Theme.App.SplashScreen"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data android:scheme="expo.modules.xmtpreactnativesdk.example" />
</intent-filter>
</activity>
<activity
android:name="com.facebook.react.devsupport.DevSettingsActivity"
android:exported="false" />

<meta-data
android:name="com.dieam.reactnativepushnotification.notification_channel_name"
android:value="YOUR NOTIFICATION CHANNEL NAME" />
<meta-data
android:name="com.dieam.reactnativepushnotification.notification_channel_description"
android:value="YOUR NOTIFICATION CHANNEL DESCRIPTION" />
<meta-data
android:name="com.dieam.reactnativepushnotification.notification_color"
android:resource="@android:color/white" />
<receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationPublisher" />
<receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationBootEventReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service
android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
</application>
</manifest>
1 change: 1 addition & 0 deletions example/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ buildscript {
dependencies {
classpath('com.android.tools.build:gradle:7.4.1')
classpath('com.facebook.react:react-native-gradle-plugin')
classpath 'com.google.gms:google-services:4.3.15'
}
}

Expand Down

This file was deleted.

23 changes: 23 additions & 0 deletions example/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@
"react-native-crypto": "^2.2.0",
"react-native-get-random-values": "^1.8.0",
"react-native-mmkv": "^2.8.0",
"react-native-push-notification": "^8.1.1",
"react-native-randombytes": "^3.6.1",
"react-native-svg": "^13.9.0",
"react-native-safe-area-context": "4.5.0",
"react-native-screens": "~3.20.0",
"react-native-safe-area-context": "4.5.0"
"react-native-svg": "^13.9.0"
},
"devDependencies": {
"@babel/core": "^7.20.0",
Expand Down
2 changes: 1 addition & 1 deletion example/src/AuthView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ function AuthView({
}, [signer]);

const generateWallet = async () => {
const client = await XMTP.Client.createRandom("dev");
const client = await XMTP.Client.createRandom("production");
setClient(client);
};

Expand Down
5 changes: 4 additions & 1 deletion example/src/ConversationListView.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { NativeStackScreenProps } from "@react-navigation/native-stack";
import React, { useEffect, useState } from "react";
import { Text, ScrollView, RefreshControl } from "react-native";
import { Conversation } from "xmtp-react-native-sdk";
import { Conversation, XMTPPush } from "xmtp-react-native-sdk";

import HomeHeaderView from "./HomeHeaderView";
import { RootStackParamList } from "./HomeView";
import PushController from "./PushController";

type Props = NativeStackScreenProps<RootStackParamList, "Conversation List">;

Expand All @@ -18,6 +19,7 @@ export default function ConversationListView({

async function refreshConversations() {
const conversations = await client.conversations.list();
XMTPPush.subscribe(conversations.map((c) => c.topic));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It only subscribes once you refresh the list view. Not super great at react couldn't figure out how to get it to subscribe on streaming conversations but this is a minor detail and we can improve it later.

setConversations(conversations);
}

Expand Down Expand Up @@ -73,6 +75,7 @@ export default function ConversationListView({
{conversations.length === 0 && (
<Text style={{ padding: 12 }}>No conversations yet.</Text>
)}
<PushController />
</ScrollView>
);
}
36 changes: 36 additions & 0 deletions example/src/PushController.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Component } from "react";
import { PushNotificationIOS } from "react-native/Libraries/PushNotificationIOS/PushNotificationIOS";
import PushNotification from "react-native-push-notification";
import { XMTPPush } from "xmtp-react-native-sdk";

export default class PushController extends Component {
componentDidMount() {
PushNotification.configure({
// (optional) Called when Token is generated (iOS and Android)
onRegister(token: any) {
console.log("TOKEN:", token);
XMTPPush.register("10.0.2.2:8080", token);
},
// (required) Called when a remote or local notification is opened or received
onNotification(notification: { finish: (arg0: any) => void; }) {
console.log("NOTIFICATION:", notification);
// process the notification here
// required on iOS only
notification.finish(PushNotificationIOS.FetchResult.NoData);
},
// Android only
senderID: "609788839593",
nplasterer marked this conversation as resolved.
Show resolved Hide resolved
// iOS only
permissions: {
alert: true,
badge: true,
sound: true,
},
popInitialNotification: true,
requestPermissions: true,
});
}
render() {
return null;
}
}
Loading