Skip to content

Commit

Permalink
Feature: Add Wake Lock Permission with replace configuration in Andro…
Browse files Browse the repository at this point in the history
…idManifest.xml (#6)

* feat: Add WAKE_LOCK permission to AndroidManifest

* feat: Add with-enabled-flag and with-permissions plugins

* feat: upgrade example expo to 51 and adding fcm

* feat: Update README with instructions for running example app

* chore: Bump version to 0.1.5 in package.json
  • Loading branch information
puguhsudarma authored May 22, 2024
1 parent 01e5a08 commit b1248ed
Show file tree
Hide file tree
Showing 18 changed files with 1,315 additions and 1,119 deletions.
25 changes: 18 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,27 @@ If you want to enable it only for staging, not the production build (obviously),
```js
plugins: [
[
'expo-chucker',
"expo-chucker",
{
enabled: process.env.APP_ENV === 'staging' // Only enable Chucker on staging environment
}
]
]
enabled: process.env.APP_ENV === "staging", // Only enable Chucker on staging environment
},
],
];
```

Don't forget to prebuild your app each time you made changes to the config.

# Contributing
### Example App

1. Clone this repo
2. Run `yarn install` to install the dependencies
3. Run `yarn build` to build the expo plugin
4. Goto `example` directory
5. Run `yarn install` to install the dependencies for the example app
6. You need to have firebase project and get the `google-services.json` and `GoogleService-Info.plist` and put it in the `example/` directory. This is required for testing the push notification feature crashed by chucker library (see [here](https://github.com/ChuckerTeam/chucker/issues/1077))
7. Run `yarn prebuild` to prebuild the app
8. Run `yarn android` to run the app on android device or emulator

### Contributing

Contributions are very welcome! Please refer to guidelines described in the [contributing guide](https://github.com/expo/expo#contributing).
Contributions are very welcome!.
2 changes: 2 additions & 0 deletions example/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,5 @@ yarn-error.*

ios/
android/
google-services.json
GoogleService-Info.plist
46 changes: 0 additions & 46 deletions example/App.tsx

This file was deleted.

34 changes: 33 additions & 1 deletion example/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,49 @@ export default (): ExpoConfig => {
ios: {
supportsTablet: true,
bundleIdentifier: "com.chucker.example",
googleServicesFile: "./GoogleService-Info.plist",
privacyManifests: {
NSPrivacyAccessedAPITypes: [
{
NSPrivacyAccessedAPIType:
"NSPrivacyAccessedAPICategoryUserDefaults",
NSPrivacyAccessedAPITypeReasons: ["CA92.1"],
},
],
},
},
android: {
adaptiveIcon: {
foregroundImage: "./assets/adaptive-icon.png",
backgroundColor: "#ffffff",
},
package: "com.chucker.example",
googleServicesFile: "./google-services.json",
},
web: {
favicon: "./assets/favicon.png",
},
plugins: [["../app.plugin.js", { enabled: true }]],
plugins: [
"@react-native-firebase/app",
[
"expo-build-properties",
{
android: {
extraMavenRepos: [
"../../node_modules/@notifee/react-native/android/libs",
],
},
ios: {
useFrameworks: "static",
},
},
],
[
"../app.plugin.js",
{
enabled: true,
},
],
],
};
};
5 changes: 5 additions & 0 deletions example/firebase.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"react-native": {
"messaging_android_notification_channel_id": "high-priority"
}
}
4 changes: 4 additions & 0 deletions example/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { registerRootComponent } from "expo";
import App from "./src";

registerRootComponent(App);
19 changes: 12 additions & 7 deletions example/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "expo-chucker-example",
"version": "1.0.0",
"main": "node_modules/expo/AppEntry.js",
"main": "./index.js",
"scripts": {
"prebuild": "expo prebuild",
"start": "expo start",
Expand All @@ -10,15 +10,20 @@
"web": "expo start --web"
},
"dependencies": {
"expo": "^50.0.7",
"expo-splash-screen": "~0.26.4",
"expo-status-bar": "~1.11.1",
"@notifee/react-native": "^7.8.2",
"@react-native-firebase/app": "^20.0.0",
"@react-native-firebase/messaging": "^20.0.0",
"expo": "^51.0.0",
"expo-build-properties": "~0.12.1",
"expo-splash-screen": "~0.27.4",
"expo-status-bar": "~1.12.1",
"expo-system-ui": "~3.0.4",
"react": "18.2.0",
"react-native": "0.73.4"
"react-native": "0.74.1"
},
"devDependencies": {
"@babel/core": "^7.20.0",
"@types/react": "~18.2.45",
"@babel/core": "^7.24.0",
"@types/react": "~18.2.79",
"babel-plugin-module-resolver": "^5.0.0",
"typescript": "^5.1.3"
},
Expand Down
21 changes: 21 additions & 0 deletions example/src/hooks/use-device-token.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import messaging from "@react-native-firebase/messaging";
import { useEffect, useState } from "react";

export const useDeviceToken = (enabled: boolean = true) => {
const [deviceToken, setDeviceToken] = useState<string>();

useEffect(() => {
messaging()
.registerDeviceForRemoteMessages()
.then(async () => {
const token = await messaging().getToken();

if (token) {
console.log("Device token:", token);
setDeviceToken(token);
}
});
}, [enabled]);

return deviceToken;
};
33 changes: 33 additions & 0 deletions example/src/hooks/use-github-user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { useEffect, useState } from "react";

export interface User {
id: number;
login: string;
avatar_url: string;
url: string;
}

export const getGithubUsers = async (): Promise<User[]> => {
try {
const response = await fetch("https://api.github.com/users");
const users = await response.json();
return users as User[];
} catch (e) {
console.error(e);
return [];
}
};

export const useGithubUsers = (enabled: boolean = true) => {
const [users, setUsers] = useState<User[]>([]);

useEffect(() => {
if (!enabled) {
return;
}

getGithubUsers().then((users) => setUsers(users));
}, [enabled]);

return users;
};
28 changes: 28 additions & 0 deletions example/src/hooks/use-notification-permission.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import notifee, { AuthorizationStatus } from "@notifee/react-native";
import messaging from "@react-native-firebase/messaging";
import { useEffect, useState } from "react";

export function useNotificationPermission() {
const [enabled, setEnabled] = useState(false);

useEffect(() => {
Promise.all([
messaging().requestPermission(),
notifee.requestPermission(),
]).then(([authStatus, notifStatus]) => {
const enabled =
authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
authStatus === messaging.AuthorizationStatus.PROVISIONAL;

const localNotificationGranted =
notifStatus.authorizationStatus === AuthorizationStatus.AUTHORIZED;

console.log("Authorization status:", authStatus);
console.log("Local notification status:", notifStatus);

setEnabled(enabled && localNotificationGranted);
});
}, []);

return enabled;
}
47 changes: 47 additions & 0 deletions example/src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { FlatList, SafeAreaView, StyleSheet, Text } from "react-native";
import { useDeviceToken } from "./hooks/use-device-token";
import { useGithubUsers } from "./hooks/use-github-user";
import { useNotificationPermission } from "./hooks/use-notification-permission";
import "./utils/set-background-notification-handler";

export default function App() {
const isPermissionGranted = useNotificationPermission();
const deviceToken = useDeviceToken(isPermissionGranted);
const users = useGithubUsers(isPermissionGranted);

return (
<SafeAreaView style={styles.container}>
<Text style={styles.text} selectable>
{isPermissionGranted
? "Notification permission granted"
: "No notification permission"}
</Text>

<Text style={styles.text} selectable>
{deviceToken ? `Device token: ${deviceToken}` : "No device token"}
</Text>

<FlatList
data={users}
renderItem={({ item }) => (
<Text selectable style={[styles.text, { marginBottom: 8 }]}>
{item.login}
</Text>
)}
/>
</SafeAreaView>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
},
text: {
marginBottom: 16,
marginHorizontal: 16,
fontSize: 14,
textAlign: "left",
},
});
21 changes: 21 additions & 0 deletions example/src/utils/create-local-notification.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import notifee from "@notifee/react-native";

export async function createLocalNotification(title: string, body: string) {
// Request permissions (required for iOS)
await notifee.requestPermission();

// Create a channel (required for Android)
const channelId = await notifee.createChannel({
id: "high-priority",
name: "High Priority Notifications",
});

// Display a notification
await notifee.displayNotification({
title,
body,
android: {
channelId,
},
});
}
11 changes: 11 additions & 0 deletions example/src/utils/set-background-notification-handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import messaging from "@react-native-firebase/messaging";
import { createLocalNotification } from "./create-local-notification";

messaging().setBackgroundMessageHandler(async (remoteMessage) => {
console.log("Message handled in the background!", remoteMessage);

await createLocalNotification(
remoteMessage.notification?.title ?? "No title",
remoteMessage.notification?.body ?? "No body"
);
});
Loading

0 comments on commit b1248ed

Please sign in to comment.