Post

Replies

Boosts

Views

Activity

No mic capture on iOS 18.5
Hello! We stumbled upon a problem with our karaoke app where user on iPhone 16e/iOS 18.5 has problem with mic capture, other users cannot hear him. The mic capture is working fine on 17.5, 16.8. Maybe there is something else we need when configuring AVAudioSession for iOS 18.5? Currently it's set up like this: override func viewDidLoad() { super.viewDidLoad() UIApplication.shared.isIdleTimerDisabled = true mRoomId = appDelegate.getRoomId() let audioSession = AVAudioSession.sharedInstance() try! audioSession.setCategory(.playAndRecord, mode: .voiceChat, options: [.defaultToSpeaker]) try! audioSession.setPreferredSampleRate(48000) try! audioSession.setActive(true, options: []) }
1
0
249
Nov ’25
I can't verify App Store Notification
I'm setting up App Store Notifications for my app. Having trouble verifying even the TEST notification, through. I'm generating JWT-token and sending it via Postman. I get a successful notification UUID as a response. But my Node.JS endpoint says it can't verify it. Here's the endpoint: const fs = require('fs'); const path = require('path'); const { SignedDataVerifier, Environment } = require('@apple/app-store-server-library'); module.exports = function (sqlexec) { function loadRootCAs() { // const gPath = path.resolve(__dirname, "AppleIncRootCertificate.cer"); const g3Path = path.resolve(__dirname, "AppleRootCA-G3.cer"); // const g2Path = path.resolve(__dirname, "AppleRootCA-G2.cer"); const loadedCerts = []; try { // loadedCerts.push(fs.readFileSync(gPath)); loadedCerts.push(fs.readFileSync(g3Path)); // loadedCerts.push(fs.readFileSync(g2Path)); if (loadedCerts.length === 0) { throw new Error("No Apple Root CA certificates were loaded."); } console.log("[APPLE NOTIFICATIONS2] Apple Root CA certificates loaded successfully."); return loadedCerts; } catch (error) { console.error("❌ CRITICAL: Error loading Apple Root CA certificate(s):", error.message); console.error("Ensure 'AppleRootCA-G3.cer' (and others if specified) are present at the expected path and readable."); throw new Error("Failed to load essential Apple Root CA certificates. Notification processing will fail."); } } const appleRootCAs = loadRootCAs(); const enableOnlineChecks = true; const environment = Environment.SANDBOX; const bundleId = "SomeBundleID"; const appAppleId = undefined; // Set if you're in PRODUCTION const verifier = new SignedDataVerifier( appleRootCAs, enableOnlineChecks, environment, bundleId, appAppleId ); router.post('/notifications_refund', async function (req, res) { const signedPayload = req.body.signedPayload; try { const notificationVerificationResult = await verifier.verifyAndDecodeNotification(signedPayload); if (!notificationVerificationResult.isValid) { console.error(`[APPLE NOTIFICATIONS2] Failed to verify notification. Status: ${notificationVerificationResult.verificationStatus}, Error: ${notificationVerificationResult.errorMessage || 'N/A'}`); return res.status(400).json({ status: "error", message: "Invalid notification signature or payload." }); } const decodedNotification = notificationVerificationResult.payload; const notificationType = decodedNotification.notificationType; const subtype = decodedNotification.subtype; if (notificationType === 'TEST') { console.log(`[APPLE NOTIFICATIONS2] Received TEST notification. Subtype: ${subtype}`); // The TEST notification's data.signedTransactionInfo is a JWS representing a sample transaction. } else if (notificationType === 'REFUND') { console.log(`[APPLE NOTIFICATIONS2] Received REFUND notification. Subtype: ${subtype}`); } else { console.log(`[APPLE NOTIFICATIONS2] Received notificationType: ${notificationType}, Subtype: ${subtype}. Skipping non-refund/test type for this endpoint.`); return res.status(200).json({ status: "success", message: "Notification received, but not a type processed by this refund endpoint." }); } // Ensure data and signedTransactionInfo exist if (!decodedNotification.data || !decodedNotification.data.signedTransactionInfo) { console.error("[APPLE NOTIFICATIONS2] Notification payload is missing data or signedTransactionInfo."); return res.status(400).json({ status: "error", message: "Notification missing transaction info." }); } const transactionInfoJWS = decodedNotification.data.signedTransactionInfo; const transactionVerificationResult = await verifier.verifyAndDecodeTransaction(transactionInfoJWS); if (!transactionVerificationResult.isValid) { console.error(`[APPLE NOTIFICATIONS2] Failed to verify signedTransactionInfo. Status: ${transactionVerificationResult.verificationStatus}, Error: ${transactionVerificationResult.errorMessage || 'N/A'}`); return res.status(400).json({ status: "error", message: "Invalid signedTransactionInfo in notification." }); } const verifiedTransactionPayload = transactionVerificationResult.payload; const transactionId = verifiedTransactionPayload.originalTransactionId || verifiedTransactionPayload.transactionId; console.log(`[APPLE NOTIFICATIONS2] Successfully decoded Transaction ID: ${transactionId} for notification type ${notificationType}`); // This is where my refund logic starts in case the notif is refund, but fow now I'm just trying to verify a TEST notif return res.status(200).json({ status: "success", message: "Refund (or TEST) notification processed successfully and validated." }); } catch (error) { console.error("[APPLE NOTIFICATIONS2] Critical error processing notification:", error); // Check if the error is from the verifier or elsewhere if (error.name === 'SignedDataVerificationError') { // Example, check actual error type from library return res.status(400).json({status: "error", message: `Notification verification failed: ${error.message}`}); } return res.status(500).json({ status: "error", message: "Failed to process notification due to an internal server error." }); } }); return router; }; I tried different root certs, only G3 works, other two give errors. Also tried adding G3 intermediate (WWDRCAG3), but it doesn't seem to help. What am I doing wrong?
0
0
54
May ’25