I'm developing WidgetKit extension on iOS 14,
however, the extension doesn't always connect to Xcode debugger after build and run, causing I can't see logs, as this image shows: (But sometimes it'll automatically attach, I don't know why)
If the extension is attached to debugger, it should look like this, and print logs:
Manually attach process to debugger doesn't works, it should be attached at first launch to see logs.
Does anyone know how to properly debug iOS 14 widget?
Xcode 14.1 known issue:
Xcode 14.1 release notes seems to mention a known issue
After Running a widget extension, users will need to manually start the debugging session with Debug -> Attach to Process. (99285608)
Approach (works on simulator and device)
Run app target and widget target at the same time
Attach debugger to your widget
Steps
Select app scheme and run on iOS device (don't stop)
Select widget scheme and run on iOS (don't stop)
So both the targets are running at the same time
Select widget scheme then Debug > Attach to Process > Select your widget target name
On device / simulator add widget
In case above doesn't work:
Delete app from device
Restart device
Quit Xcode
Clear DerivedData folder
Open Xcode
Try original steps
Note:
You need to attach the debugger every time you run (Xcode forgets debugger added for the previous run)
Now your breakpoints should work as expected and you can debug
Log messages
Use Logger to log messages, open the console (Mac app) and view the log messages there. That way you can debug even when you are not running the app / widget
https://developer.apple.com/documentation/os/logger
https://developer.apple.com/wwdc20/10168
Try plugging in your physical device and running it on that instead of a simulator. That fixed the logging issue for me.
To debug, or see print info: (This works for me)
On the top left of Xcode->
Click project name, you can see a list, select widget name, run it
Click widget name, you can see a list, select project name, run it
Xcode: Version 12.3, iPad: iPadOS 14.3
You can log your useful information in local file, just like this:
public func XXLogToFile(_ text: String) {
if let documentsDirectory = FileManager().containerURL(forSecurityApplicationGroupIdentifier: "group.xxx") {
let logFileUrl = documentsDirectory.appendingPathComponent("log.txt")
do {
var logContent = try String(contentsOf: logFileUrl, encoding: .utf8)
logContent = (logContent.count > 0 ? "\(logContent)\n\(text)" : text)
try logContent.write(to: logFileUrl, atomically: false, encoding: .utf8)
}
catch {}
}
}
Related
I am working on an iOS 14 widget which I would like to my existing iOS 11+ app. The whole process is quite cumbersome because it happens quite often that something does not work as expected.
For example the widget shows unexpected data, or is not rendered as expected (e.g. as described here). I assume that something wents wrong when the system requests the widget and its content from my app extension. However I cannot figure out what this might be.
Is there any way to actually debug the widget extension? Seeing when the code is executed and how it works?
I have already tried to hook up the debugger to the widget extension (using the Debug/Attach to process menu in Xcode). While the process is listed there, the debugger shows no log output nor stops on breakpoints.
Using the system console to show the logs of the iOS simulator devices does not work as well. It does not matter if print(...) or NSLog(...) is used. No output reaches the console.
On the top left of Xcode->
Click project name, you can see a list, select widget name, run it
Click widget name, you can see a list, select project name, run it
Xcode: Version 12.3, iPad: iPadOS 14.3
This works for me.
Since I found no other way to debug the widget extension I wrote a logging method which adds the log output to a a file a the apps group folder:
static func logToFile(_ text: String) {
if let documentsDirectory = FileManager().containerURL(forSecurityApplicationGroupIdentifier: "my.app.group.key") {
let logFileUrl = documentsDirectory.appendingPathComponent("log.txt")
do {
var logContent = try String(contentsOf: logFileUrl, encoding: .utf8)
logContent = (logContent.count > 0 ? "\(text)\n\(logContent)" : text)
try logContent.write(to: logFileUrl, atomically: false, encoding: .utf8)
}
catch {}
}
}
Not the best solution but the only one I found so far.
Select your widget target at the top left corner of Xcode, build and run the app,
then the widget process will be able to debug and show logs.
(This example project is downloaded provided by Apple: https://developer.apple.com/documentation/widgetkit/building_widgets_using_widgetkit_and_swiftui)
Seems Xcode bug here.
Quick fix works for me is open log console manually by cmd + shift + y.
And also add breakpoints.
And then run widget to see logs.
I've run into this issue as well. Logs were not showing (or only showing sometimes) when I run my widget extension in Xcode.
After hours of debugging, the thing that fixed it for me was plugging in my actual device (iPhone 12 Pro Max) and running the widget on that physical device instead of the simulator.
Try disabling bitcode in your extensions, I've had a hard time getting logs until I do it.
I usually do debugging with support of print() method at which shows on Xcode logs as long as it is not terminated. However I have some conditions that I need to test in didFinishLaunchingWithOptions method of AppDelegate when the app's been terminated and then reopened. By "reopened" I mean by clicking on the app on simulator/iphone instead of running it from Xcode again. Sadly after termination print logs do not show. Any other way I could do it? Thanks!
Click on the options near the Appname on the upper-left corner of Xcode.
Click on Edit Scheme -> Check the Wait for executable to launch option and run as you usually do. Happy Coding :) .
Check "Wait for executable to launch" as #vishnu_146 mentioned.
CMD + R to run the app (first launch)
Double press Home and kill the app
CMD + R to run the app again (I tested that run without build will fresh launch the app).
App open with previous status. Can hit break points, but could not print logs. Reason: NSLog not working when "wait for executable to be launched" is set
In Swift 4.2,
var paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let documentsDirectory = paths[0]
let fileName = "\(Date()).log"
let logFilePath = (documentsDirectory as NSString).appendingPathComponent(fileName)
freopen(logFilePath.cString(using: String.Encoding.ascii)!, "a+", stderr)
Just add this block of code in application:didFinishLaunchingWithOptions method in the app delegate file and it will create a log file in app document directory on iPhone which logs all console log events. You need to import this file from iTunes to see all console events.
Note: In the .plist file make sure that Application supports iTunes file sharing exists and is set to YES so that you can access through iTunes.
To get Logfiles: Launch iTunes, after your device has connected
select Apps - select your App - in Augmentnt Document you will get your
file. You can then save it to your disk
You can try printing logs through "NSLog". On Xcode, go to "Devices and Simulators" and select your device. All the NSLogs will be visible there at the bottom.
It seems to me that whenever a Today Widget crashes for any reason it displays the "Unable to load" message (as on the attached screen).
When this happens nothing kicks off in the debugger, nothing appears on the Console. It seems to me like searching for a needle in the haystack. Is it possibl to debug the "Unable to load" message in Xcode in any way?
Xcode version: 8.2
iOS Simulator: 10.2
You can debug you Today Extension by doing the following:
With the application running in your device/simulator, open the widget. Then, when you have your widget open, go to Xcode->Debug->Attach to Process and you should find your widget name.
Note this will only work if you have your widget opened. You can set breakpoints and debug step by step to find out why the "Unable to Load" message appears.
You can simply select the widget's target in XCode and just run the project, and debug it as usual, with breakpoints, etc.
There is a catch: if the widget is already showing "Unable to load", then it means it crashed, and the debugging won't work.
What I found to be consistently working in restarting the widget is changing the device's language.
So, go to Settings -> General -> Change language
Then run your widget's target from XCode on that phone. Wait until the widgets page shows up and scroll down until your widget appears on the screen (that is when the widget gets loaded).
Even if it crashes now, you will see the crash in XCode.
Nothing prints from NSLog on Xcode 8.0 beta (8S128d). printf is unchanged
Here's my code:
NSLog(#"hello from NSLog");
printf("hello from printf");
Here's the output on iOS 9 Simulator:
2016-06-17 09:49:10.887 calmapp-dev[28517:567025] hello from NSLog
hello from printf
Here's the output on iOS 10 Simulator:
hello from printf
It could be that you added the property "OS_ACTIVITY_MODE": "disable" in the Scheme environment variables (to hide OS output from the simulator) and forgot about it, and now are running on a real device.
In Xcode 8:
Product -> Scheme -> Edit Scheme -> Run -> Arguments -> Environment Variables
Only add OS_ACTIVITY_MODE and check it(Don't add a value)
Summary:
This is a bug of Xcode 8 + iOS10, we can solve it in this way:
When using the simulator, add the Name "OS_ACTIVITY_MODE" and the Value "disable" and check it.
When on a real device, only add "OS_ACTIVITY_MODE" and check it(Don't add the Value).
You will see the NSLog in the Xcode8 Console.
If you check the Xcode 8 beta release notes, you'll find that it says:
When debugging an app running on Simulator, logs may not be visible in the console.
Workaround: Use command + / in Simulator.app to open the system log in the Console app to view NSLogs. (26457535)
the NSlog or print actually is executed but is hidden among lots of other console debug outputs to solve this issue
Open Xcode8:
Product -> Scheme -> Edit Scheme -> Run -> Arguments -> Environment Variables
add "OS_ACTIVITY_MODE" and set the Value to "disable" and check it.
click close
xcode9
add "OS_ACTIVITY_MODE" and set the Value to "default" and check it.
Also, make sure the Console is actually visible in Xcode (i.e., make sure the right-hand side icon is highlighted in blue, as per the image below). After I upgraded Xcode, it hide the Console and showed me just the Variables view. This made it look like NSLog() was not working properly, whereas it was indeed working correct, I just couldn't see the output.
I can't see NSLog output in real iOS 10 device neither. If you're using real devices, you can open Devices window from Xcode (Shift + Command + 2) and see device logs there, but it's hard to look at your app's logs because the console shows logs from system and all apps.
(I'm using Xcode 7, so it's may not Xcode's problem but iOS 10 problem)
For anyone who comes upon this in the future. The reason NSLog doesn't print to syslog in iOS 10 and iOS 11 is due to Apple changing to Unified Logging.
You can see the WWDC talk about it here: https://developer.apple.com/videos/play/wwdc2016/721/
Documentation here: https://developer.apple.com/documentation/os/logging
From 10 on you should be using os_log instead of NSLog.
How to find the logs on disk: https://www.blackbagtech.com/blog/2017/09/22/accessing-unified-logs-image/
To summarize, the logs are located in /var/db/diagnostics which can be found for a VM at /Users/USERNAME/Library/Developer/CoreSimulator/Devices/SIMULATOR-GUID/data/var/db/
Copy all items inside diagnostics and uuidtext into a single folder (don't include the folders diagnostics or uuidtext just what is inside).
Rename that folder foldername.xarchive.
Open it in Console.app or use the OSX util log: log show <path to archive> --info --predicate <options>
Hmmm... it seems like the property "OS_ACTIVITY_MODE": "disable" PREVENTS NSlog from showing up in the Xcode 9 log.
Unchecking this value in my scheme restored my logs.
I'm using Xcode 8,so I also encountered the same problem . And I solved this problem by adding value = disable on the simulator, but on a real machine I don't add value.
NSLog messages no longer displayed when I upgraded to Xcode 9.1 + iOS 11.1. Initially the accepted answer gave me a way to work around this using the Console app and enabling the Simulator (see Lucas' answer).
In the Console app under Action I tried selecting Include Debug Messages and deselecting Include Info Messages (so the Console isn't swamped with system messages). NSLog messages appeared in the Console window in Xcode but not in the Console app.
I realised there had to be a more direct way to disable or enable (i.e. default) NSLogs thanks to Coeur's comment in response to this answer. In my opinion it is the best answer because setting OS_ACTIVITY_MODE to disable or default will make more sense for beginners.
I'm developing iOS apps with Xcode. So when I build through Xcode I get device logs shown in the console output. But when I disconnect the iPhone from USB, or detach the process, then plug in the phone again and try to attach the process (my app is running on the phone still), the console doesn't output anything anymore.
If I go to Window -> Devices and my iPhone it doesn't show any output in that console either. The console app doesn't show any output either. I've tried to kill Xcode, clean the project, but to no success.
Anyone know how to show output logs from the built app after the iPhone have been detached?
I solved the log output mystery. Since we're using Cocoa Lumberjack it "devoured" the normal NSLog output, I added another log output by writing this row:
DEBUG_LOGS([DDLog addLogger:[DDASLLogger sharedInstance] withLevel:DDLogLevelDebug]);
Where DDASLLogger is the apple console.