Как реализовать фоновые звуковые уведомления для Android в React Native с помощью Expo?Android

Форум для тех, кто программирует под Android
Ответить Пред. темаСлед. тема
Anonymous
 Как реализовать фоновые звуковые уведомления для Android в React Native с помощью Expo?

Сообщение Anonymous »

Я создаю приложение React Native с использованием Expo, которое включает в себя функции уведомлений о времени молитвы со звуком азана (призыва к молитве). Приложение предназначено для работы как на iOS, так и на Android, но я хочу реализовать фоновое поведение, специфичное для Android, не затрагивая существующий код iOS.
Текущая настройка:
iOS:
Уведомления и воспроизведение звука работают должным образом.
Конфигурация звука использует Audio.setAudioModeAsync с InterruptionModeIOS.Android:
Мне нужно использовать expo-background-fetch и expo-task-manager, чтобы запускать воспроизведение Адхана и уведомления в фоновом и заблокированном состоянии. Он работает на IOS, но не на Android.
При воспроизведении звука используются локально сохраненные файлы .wav.
Проблема: >
При попытке добавить логику, специфичную для Android (например, expo-background-fetch), я хочу, чтобы существующая функциональность iOS осталась нетронутой. Однако я обеспокоен тем, что мои изменения могут случайно нарушить или изменить код iOS.
Вот соответствующая часть моего текущего кода для фоновой выборки Android:
if (Platform.OS === 'android') {
TaskManager.defineTask(BACKGROUND_FETCH_TASK, async () => {
const now = new Date();
const storedPrayerTimes = await AsyncStorage.getItem(`prayerTimes[${formatPrayerDateString(now)}]`);
if (storedPrayerTimes) {
const prayerTimes = JSON.parse(storedPrayerTimes);
const currentPrayer = Object.values(prayerTimes).find(prayer =>
Math.abs(prayer.timestamp - now.getTime()) < 60000
);

if (currentPrayer) {
const adhanFilename = 'Mishari.wav'; // Placeholder for the actual file
await playLocalSound(adhanFilename);

await Notifications.scheduleNotificationAsync({
content: {
title: `It's time for ${currentPrayer.name}`,
body: `The time is ${currentPrayer.time}`,
},
trigger: null,
});
}
}
return BackgroundFetch.BackgroundFetchResult.NewData;
});

async function registerBackgroundFetch() {
try {
await BackgroundFetch.registerTaskAsync(BACKGROUND_FETCH_TASK, {
minimumInterval: 60 * 15,
stopOnTerminate: false,
startOnBoot: true,
});
console.log('Background fetch task registered');
} catch (err) {
console.error('Background fetch failed to register:', err);
}
}
}

Ключевые вопросы:
Есть ли лучший способ структурировать мой код, чтобы четко разделить логику, специфичную для платформы?
Можете ли вы проверить код, чтобы найти решение для фонового воспроизведения Android и воспроизведения звука в заблокированном состоянии?
Будем очень признательны за любые советы и рекомендации!
вот полный код:
import * as Notifications from 'expo-notifications';
import { Audio, InterruptionModeIOS, InterruptionModeAndroid } from 'expo-av';
import * as TaskManager from 'expo-task-manager';
import * as BackgroundFetch from 'expo-background-fetch';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { DuaData, fetchDuasByCategory } from './FirebaseService';
import { router } from 'expo-router';
import { Platform } from 'react-native';

const BACKGROUND_FETCH_TASK = 'background-fetch-task';

let sound: Audio.Sound | null = null;
let notificationListener: Notifications.Subscription | null = null;

// Create a mapping of sound names to their require statements
const SOUND_MAP: Record = {
'Madinah.wav': require('../../assets/sounds/Madinah.wav'),
'Makkah.wav': require('../../assets/sounds/Makkah.wav'),
'Mishari.wav': require('../../assets/sounds/Mishari.wav'),
'isti11.mp3': require('../../assets/sounds/isti11.mp3'),

// Add other sound files as needed
};

async function playLocalSound(filename: string) {
console.log(`Playing sound: ${filename}`);
try {
if (sound) {
await sound.unloadAsync();
}

// Get the sound from our mapping
const soundSource = SOUND_MAP[filename];
if (!soundSource) {
throw new Error(`Sound file ${filename} not found in SOUND_MAP`);
}

const { sound: newSound } = await Audio.Sound.createAsync(
soundSource,
{ shouldPlay: true }
);
sound = newSound;

// Wait for the sound to finish playing
await new Promise((resolve, reject) => {
sound?.setOnPlaybackStatusUpdate((status) => {
if (status.isLoaded && status.didJustFinish) {
resolve(null);
}
});
});
} catch (error) {
console.error('Error playing sound:', error);
}
}

const formatPrayerDateString = (date: Date): string => {
const day = String(date.getDate()).padStart(2, '0');
const month = String(date.getMonth() + 1).padStart(2, '0');
const year = date.getFullYear();
return `${day}-${month}-${year}`;
};

TaskManager.defineTask(BACKGROUND_FETCH_TASK, async () => {
const now = new Date();
const key = formatPrayerDateString(now);
const storedPrayerTimes = await AsyncStorage.getItem(`prayerTimes[${key}]`);
if (storedPrayerTimes) {
const prayerTimes: TimingData = JSON.parse(storedPrayerTimes);
const currentPrayer = Object.values(prayerTimes).find(prayer =>
Math.abs(prayer.timestamp - now.getTime()) < 60000 // Within 1 minute
);

if (currentPrayer) {
const notificationStatus = await AsyncStorage.getItem('notificationStatus');
const parsedNotificationStatus = notificationStatus ? JSON.parse(notificationStatus) : {};
const adhanPath = parsedNotificationStatus[currentPrayer.name]?.adhan || 'https://download.quranplayermp3.com/sal ... ishari.wav';
const adhanFilename = adhanPath.split('/').pop() || "Mishari.wav";
await playLocalSound(adhanFilename);
// Trigger a local notification
await Notifications.scheduleNotificationAsync({
content: {
title: `It's time for ${currentPrayer.name}`,
body: `The time is ${currentPrayer.time}`,
},
trigger: null,
});
}
}
return BackgroundFetch.BackgroundFetchResult.NewData;
});

async function registerBackgroundFetch() {
try {
await BackgroundFetch.registerTaskAsync(BACKGROUND_FETCH_TASK, {
minimumInterval: 60 * 15, // 15 minutes
stopOnTerminate: false,
startOnBoot: true,
});
console.log('Background fetch task registered');
} catch (err) {
console.error('Background fetch failed to register:', err);
}
}

function scheduleNotifications(prayerTimes: TimingData, city: string, notificationStatus: Record) {
Object.entries(prayerTimes).forEach(([key, prayer]) => {
const prayerNotificationStatus = notificationStatus[prayer.name].status;
if (prayerNotificationStatus === "unactive") return;

const now = new Date();
const timeDiffInSeconds = Math.floor((prayer.timestamp - now.getTime()) / 1000);

if (timeDiffInSeconds

Подробнее здесь: https://stackoverflow.com/questions/793 ... ative-with
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Android»