We created an app for iphone which includes a Watch app. The app works well during debugging, and also in TestFlight the Watch app installs nicely and does what it is supposed to do. However, when we make the app available through the Apple Business Manager (the app is for internal use by a company) the Iphone app downloads without problems, but the app for the Apple Watch does not work.
When I go to the Watch app on my Iphone (where you can manage the apps on your Watch and so on) my app is listed, but when I press install I see a loader for a few seconds, then it stops but nothing else happens.
So the code seems to be good, but after I download the app with a code through the Business Manager, then I cannot install the Watch version of the app.
WatchKit
RSS for tagBuild apps that leverage watchOS features like background tasks, extended runtime sessions, and access to the Digital Crown using WatchKit.
Posts under WatchKit tag
132 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
I'm trying to start and stop recording when my app is in background periodically. I implemented it using Timer and DispatchQueue. However whenever I am trying to initiate the recording I get this error. This issue does not exist in foreground.
Here is the current state of my app and configuration.
I have added "Background Modes" capability in the Signing & Capability and I also checked Audio and Self Care. Here is my Info.plist:
<plist version="1.0">
<dict>
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
</array>
<key>WKBackgroundModes</key>
<array>
<string>self-care</string>
</array>
</dict>
</plist>
I also used the AVAudioSession with .record category and activated it. Here is the code snippet:
func startPeriodicMonitoring() {
let session = AVAudioSession.sharedInstance()
do {
try session.setCategory(AVAudioSession.Category.record, mode: .default, options: [.mixWithOthers])
try session.setActive(true, options: [])
print("Session Activated")
print(session)
// Start recording.
measurementTimer = Timer.scheduledTimer(withTimeInterval: measurementInterval, repeats: true) { _ in
self.startMonitoring()
DispatchQueue.main.asyncAfter(deadline: .now() + self.recordingDuration) {
self.stopMonitoring()
}
}
measurementTimer?.fire() // Start immediately
} catch let error {
print("Unable to set up the audio session: \(error.localizedDescription)")
}
}
Any thoughts on this? I have tried most of the ways but the issue is still there.
Long story short, I had my App and Watch app already uploaded to the app store. However, I needed to add a WatchConnectivity to have App to Watch communication.
At the beginning My app bundle id was: com.x My watch bundle id was: com.x.watchkitapp
However, while developing Watch Connectivity, I noticed that my Apps are not connected unless I changed it to com.x.watchkitapp -> com.x.watch
However after changing it I cannot submit my bundle anymore.
I'm getting Asset validation failed error
Invalid Bundle Identifier. Attempting to change bundle identifier from com.x.watchkitapp to com.x.watch is disallowed for bundle x.app/Watch/WatchX Watch App.app. (ID: 75a4621a-7e28-411d-a2a7-84674e460656)
Any ideas how this could be solved?
Hello,
The Apple Watch's connectivity to Xcode has always been finicky. Sometimes it would start doing "transport errors" and you'd have to repair the watch/phone to xcode to resolve it. Now after the 10.4 upgrade, it seems that there are cases where the watch doesn't even show in the device list. Here's what I've observed:
The watch will connect the first time you launch xcode(after 10.4 install or a new restore).
If you unpair the watch, it will never show in the device list again. This is despite any remediation efforts, such as unpairing the phone from xcode, restarting the watch/phone, and clearing trusted devices.
Erasing the watch and restoring it will allow it to connect again to xcode, but only if you never unpair it. If you unpair the watch, it will repeat the behavior of not showing in the device list again.
So, the only solution is to erase/restore the watch to get it to show in the device list on xcode. Every single time.
Again, this is new behavior for Watch OS 10.4
As TN3135 clearly explains the limitations apple puts on the low level networking, it doesn’t really give a reason. Presumably the power consumption problem. But as the battery technology continues evolving, it could be exciting that apple might loose the restrictions someday. The watch itself is powerful enough to do a lot of sophisticated works, sure it works best with companion apps on iPhone, but even as a standalone device, we can still provide many advanced user experience with low level networking supports.
wish apple guys can read it and give a consideration.
I am running two different background modes(not at the same time), 1 with a workout and 1 with a location. I noticed that the app logo appears above the watch face for both background modes but does not show up consistently. I wonder what the significance of the logo showing up above watch face is? Additionally why does it show up sometimes but not others?
Thanks
On android there is a way for my app to know when the device has been restarted or powered up after a restart or powering off. I wonder if there is a way to listen for the restart/power up even on the iphone and the Apple Watch?
Hi,
I would like to stream live audio (hls) from watch itself, our app can start stream on paired device, but when phone is not near by i want to start streaming on watchos (just like spotify or Apple music app) I watched the 2019 wwdc video about streaming and also looked to the documentation
Documentation : https://developer.apple.com/documentation/watchkit/storyboard_support/playing_background_audio
I can present the route controller to select output, but for example after selecting Air Podcas, stream did not start..
Here is the code: (I have enabled background mode audio)
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, policy: .longFormAudio, options: [])
}
catch {
print("no audiosession!")
}
AVAudioSession.sharedInstance().activate(options: []) { success, error in
dump(success)
dump(error)
DispatchQueue.main.async {
if let streamURL = moduleItem.media?[0] as? String {
dump(streamURL)
let asset = AVURLAsset(url: URL(string: streamURL)!, options: nil)
let item = AVPlayerItem(asset: asset)
let player = AVQueuePlayer(playerItem: item)
player.play()
}
}
}
I'm working on an app that has the following structure:
MyApp
MyWidgetExtension
MyWatchKitApp
-- MyWatchKitAppExtension
---- MyWatchKitAppWidgetExtension
Both MyWidgetExtension and MyWatchKitAppWidgetExtension were developed using a shared MyWidgetBundle defined as follows:
@main
struct MyWidgetBundle : WidgetBundle
However, I'm running into an issue when attempting to run this on devices with iOS 14. I get an error stating "App extensions must define either NSExtensionMainStoryboard or NSExtensionPrincipalClass keys in the NSExtension dictionary in their Info.plist."
Interestingly, if I remove MyWatchKitAppWidgetExtension, the app installs just fine. But, if I add NSExtensionPrincipalClass or NSExtensionMainStoryboard, when I try to distribute the app to TestFlight, I receive an error stating "Unexpected key NSExtensionPrincipalClass found in extension Info.plist".
I'm at a loss as to how to resolve this issue. Does anyone have any suggestions or insights?
I noticied that my workout session is sometimes being killed by apple when the app is in the background and it seems that the func workoutSession(_ workoutSession: HKWorkoutSession, didChangeTo toState: HKWorkoutSessionState, from fromState: HKWorkoutSessionState, date: Date) {
is only being called when the app comes back into the foreground.
I wonder if there is a way for us to get notified when the workout is about to die or has already been killed.
Thanks
Hello Apple Developer Forum,
I'm reaching out because I've encountered an issue with my app's implementation involving the ScrollView and the digitalCrown, and I'm hoping to find some guidance or assistance from the community.
Currently, I'm developing an app where users can navigate through dates using the digitalCrown to change the "$scrollAmount", which then dynamically updates the ScrollView with events corresponding to that date. However, I've run into a problem where the ScrollView is being inadvertently scrolled by the digitalCrown every time it's initiated.
Ideally, I would like to disable the digitalCrown's interaction with the ScrollView altogether, so that the ScrollView is only scrolled using touch inputs and not by the digitalCrown. I've tried several approaches to achieve this, but haven't had much success so far.
Could anyone please provide some guidance or suggestions on how I can effectively disable the digitalCrown's interaction with the ScrollView while still allowing touch-based scrolling?
Any help or insights into this matter would be greatly appreciated. Thank you very much in advance for your time and assistance.
Best regards,
Example code:
var body: some View {
NavigationView {
VStack {
HStack{
Text("\(formattedDate(for: scrollAmount, format: lineOne))")
.onTapGesture {
scrollAmount = 0.0
}
}
ScrollView{
ForEach(viewModel.events, id: \.event) { viewModelItem in
let event = viewModelItem.event
VStack {
HStack {
Text(event.title)
}
}
}
}
.scrollDisabled(true)
}
}
.focusable(isFocused)
.digitalCrownRotation(
detent: $scrollAmount,
from: -365.0,
through: 365.0,
by: 1.0,
sensitivity: .low,
isContinuous: false,
isHapticFeedbackEnabled: true)
.onChange(of: scrollAmount) {
let roundedValue = round(scrollAmount)
scrollAmount = roundedValue
viewModel.fetchEvents(for: scrollAmount)
}
}
}
如何自定义开发表盘模版,不是表盘组件,比如设置背景图片,调整各个表盘组件的位置
手表系统: 10.2
表现:从手机Watch App上看,表盘组件部分都显示关闭;从手表上看,表盘组件不展示
I did a timer that fires every thousandth of a second and it stops after a certain period of time unless I restart the watch and this doesn't happen in the watch simulator so something is wrong with the real watch while the simulator doesn't show this phenomenon. There is definitely a lower software stack bug or the processor cannot handle the load while the Ultra and Ultra 2 have no problems AFAIK.
Hi,
I'm triggering a notification from the audio interruption handler (but also have a debug button set to trigger it manually) and it frequently does not show up. I don't think I have ever seen it show up when the watch face is off.
I have created a singleton class to trigger this notification as follows. Note that I use a UUID in the identifier because an old thread here suggests this is necessary, but it makes no difference as far as I can tell.
Any ideas? I'd like this notification to be reliable. I'm also surprised that with trigger set to nil, it does not trigger instantaneously.
Any help would be much appreciated!
Thanks,
-- B.
import Foundation
import UserNotifications
class NotificationSender: NSObject, UNUserNotificationCenterDelegate {
static let shared = NotificationSender()
override init() {
super.init()
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.sound, .badge]) { granted, error in
if granted {
print("Notification permission granted")
} else {
print("Notification permission denied")
}
}
center.delegate = self
// Define the action to open the app
let openAction = UNNotificationAction(identifier: "openAction", title: "Open App", options: [.foreground])
// Add the action to the notification content
let category = UNNotificationCategory(identifier: "resumeAudioCategory", actions: [openAction], intentIdentifiers: [], options: [])
center.setNotificationCategories([category])
}
func sendNotification() {
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = "Recording Interrupted"
content.body = "You will need to restart it manually."
content.categoryIdentifier = "resumeAudioCategory"
// Create the notification request
//let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
let request = UNNotificationRequest(identifier: "ResumeAudioNotification-\(UUID().uuidString)", content: content, trigger: nil)
center.add(request) { error in
if let error = error {
print("Error adding notification request: \(error)")
}
}
}
// Handle notification when the app is in the foreground
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
// Display the notification while the app is in the foreground
completionHandler([.sound, .badge, .banner, .list])
}
// Handle notification response
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
// Handle the user's response to the notification
// For example, navigate to a specific screen in your app
completionHandler()
}
}
I am developing an AppleWatch applet. There is no IOS side, only the Apple Watch side. I want to evoke SIRI on the Apple Watch, then say "Open my software" or a specific sentence, and then my software will be automatically opened.
I am a watchOS 10.0 device, try to open the developer mode, according to the official website to enter the Settings > Privacy > Developer Mode. But I don't see the developer mode option, how do I turn on the developer mode for watchOS 10.0 device?
TLDR; Can I have a widget without a Timeline?
My previous watch app had a complication. Simply so it can be added to the watch face for a quick launch of the app. However now seeing that method is deprecated in favour of widgets. Can I add a widget without the need for all the Timeline as all I want is a button on the watch face to launch into my app. No data is updated over time so no need for all the extra timeline code.
Good morning,
I come to you for a question:
When I install my application on my iPhone for the first time, and I install the watch application from the native "Watch" application, the Watch Connectivity function does not work, I have to do the installation from Xcode to the watch for this function to work.
Is this normal? if yes, the problem will not arise during a publication?
I have the same problem when using watch and iPhone simulators, WatchConnectivity does not work.
I am this error code in Xcode:
-[WCSession handleIncomingUserInfoWithPairingID:]_block_invoke delegate (null) does not implement session:didReceiveUserInfo:, discarding incoming content
Here is the code for the iPhone and the watch:
In my iPhone app:
import WatchConnectivity
let userDefaultsDataVenantWatch = UserDefaults.standard
class PhoneDataModel : NSObject, WCSessionDelegate, ObservableObject {
static let shared = PhoneDataModel()
let session = WCSession.default
@Published var TableauSynchroIphoneVersWatch : [String:String] = ["0":"0"]
@Published var dataWatchVersIphone: [String:String] = ["":""]
override init() {
super.init()
if WCSession.isSupported() {
session.delegate = self
session.activate()
} else {
print("ERROR: Watch session not supported")
}
}
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
if let error = error {
print("session activation failed with error: \(error.localizedDescription)")
return
}
}
func sessionDidBecomeInactive(_ session: WCSession) {
session.activate()
}
func sessionDidDeactivate(_ session: WCSession) {
session.activate()
}
func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any]) {
guard let newCount = userInfo["TableauSynchroIphoneWatch"] as? [String:String] else {
print("ERROR: unknown data received from Watch TableauSynchroIphoneWatch")
return
}
DispatchQueue.main.async {
print(newCount)
}
}
}
In my Watch app:
import WatchConnectivity
let userDefaultsDataVenantIphone = UserDefaults.standard
var TableauVenantIphone:[String:String] = ["":""]
class WatchDataModel : NSObject, WCSessionDelegate, ObservableObject {
static let shared = WatchDataModel()
let session = WCSession.default
@Published var TableauSynchroIphoneWatch : [String:String] = ["0":"0"]
override init() {
super.init()
if WCSession.isSupported() {
session.delegate = self
session.activate()
} else {
print("ERROR: Watch session not supported")
}
}
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
if let error = error {
print("session activation failed with error: \(error.localizedDescription)")
return
}
}
func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any]) {
guard let newCount = userInfo["TableauSynchroIphoneVersWatch"] as? [String:String] else {
print("ERROR: unknown data received from Watch TableauSynchroIphoneWatch")
return
}
DispatchQueue.main.async {
print(newCount)
}
}
}
Thank for your answers !
AFAIK, background execution with Background Tasks framework is all budgeted. E.g., if we try to use it too much, the system would simply stop letting us do it, at least for some time.
Is it the same when we do sendMessage from Watch app to iOS app? Is there a chance we may overuse it so that system stops waking up the iOS app? Or I can rely and use sendMessage as often and heavy as I need?