Just wanted to share what I discovered today with my testing. You will need to create a new APNs cert if you haven't done that lately and are using cert based push notifications. They have updated the text to read:
Apple Push Notification service SSL (Sandbox & Production)
Establish connectivity between your notification server, the Apple Push Notification service sandbox, and production environments to deliver remote notifications to your app. When utilizing HTTP/2, the same certificate can be used to deliver app notifications, update ClockKit complication data, and alert background VoIP apps of incoming activity. A separate certificate is required for each app you distribute.
After I updated my cert, I was able to get the incoming push notification to properly deliver to:
func incomingPushResult(channelManager: PTChannelManager, channelUUID: UUID, pushPayload: [String : Any]) -> PTPushResult
I was using a simple script that calls curl like this:
curl -v \
-d '{"activeSpeaker":"Bart"}' \
-H "apns-push-type: pushtotalk" \
-H "apns-topic: <insert your bundle id here>.voip-ptt" \
-H "apns-priority: 10" \
-H "apns-expiration: 0" \
--http2 \
--cert key.pem \
https://api.sandbox.push.apple.com/3/device/8f12332d93d45d39d407368175e07b76d2494d0d67439289b3a50c7bd6f8f206
Also, I noticed that PTChannelTransmitRequestSource is always of type .unknown when the system UI is used to transmit.
I would love to have some sample code too. I'm still working on hooking up the portions of my app that would record/playback the audio.
Post
Replies
Boosts
Views
Activity
Is there some documentation on the errors for Live Activities? I've tried to create a sample app using the documentation article listed above. I get an error when I try to start a Live Activity. I'm not sure what it means, since I can't find any documentation on the errors.
Error requesting pizza delivery Live Activity The operation couldn’t be completed. (com.apple.ActivityKit.ActivityInput error 1.)
I'm sure you have already found a solution, but I wanted to add a solution for anybody else looking at this question. You will need to covert the file to a wav file and then play it. There are some libraries out there to make this a bit easier. Check out https://github.com/arkasas/OggDecoder. It supports Swift Package Manager.
import OggDecoder
let decoder = OGGDecoder()
let oggFile = oggFileURL()
decoder.decode(oggFile) { (savedWavUrl: URL?) in
// Do whatever you want with URL
// If convert was fail, returned url is nil
}
Thank you for the quick response! This information really helps a lot. Could you provide more information about option "a" that you described above?
The linked documentation states, "If your app doesn’t map these button events to transmission actions...". Does this mean that my application needs to enable this functionality using setAccessoryButtonEventsEnabled and then map the button presses? If so, is this mapping process documented?
Should this button mapping work when my application is not in the foreground and the user is joined to the PTT channel ID that is specified when my app calls setAccessoryButtonEventsEnabled?
Which buttons in the standard media profile map to the various actions within the PTT UI? For example, does the play/pause button map to start/stop recording?
Thank you for your link to the video that shows the use of activityFamilies. My goal is to show a more compact layout for the Live Activity on Apple Watch and show the normal layout on iPhone.
My issue was that I had declared the @Environment line in the wrong place. In the WWDC session, the View is created in the Dynamic Island configuration and the @Environment is configured in that new view. This allows the activityFamily to be correctly set to small for Apple Watch. In my sample code above it was only set once when the activity is created on the iPhone.
struct DeliveryActivityContent: View {
@Environment(\.activityFamily) var activityFamily
var context: ActivityViewContext<DeliveryActivityAttributes>
var body: some View {
switch activityFamily {
case .small:
DeliverySmallContent(context: context)
case .medium:
DeliveryMediumContent(context: context)
@unknown default:
DeliveryMediumContent(context: context)
}
}
}