How to debug iOS 14 widget in Xcode 12? - ios

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.

Related

Xcode iOS 14 WidgetKit not always attached to debugger

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 {}
}
}

Will Firebase Analytics work from the simulator in Xcode?

In an IOS app I have
and I ensured the plist "defeat" entry is not there, and then I have analytics events like
Analytics.logEvent("touchedButton", parameters: nil)
In fact, if I run the app just in the Xcode simulator .. are these events reported to Firebase Analytics and show up?
Or perhaps if you build to an iPhone?
Or does it only work if it's an actual build which has gone through TestFlight?
Surprisingly I couldn't find this info anywhere.
Is it precisely here that such custom events will show:
Yes, both simulator or device will work.
If you haven't already read, read their getting started tutorials, it covers most of it https://firebase.google.com/docs/analytics/ios/start
A couple of points
Make sure when you configure your Firestore settings , you enable analytics
AnalyticsConfiguration.shared().setAnalyticsCollectionEnabled(true)
I do all of this initial settings in AppDelegate
something like
//init Firebase
FirebaseConfiguration.shared.setLoggerLevel(.min)
FirebaseApp.configure()
Fabric.with([Crashlytics.self])
let _ = FirebaseConfig.sharedInstance // This is a custom singelton class where I enable the analytics
In Scheme settings for your target you need to add -FIRAnalyticsDebugEnabled
As you can see I have also a disable option there, sometimes analytics goes crazy and spams the console , so I'd like to disable it with . -FIRDebugDisabled
Analytics clusters your events unless you specify it is a custom event.
For example I use following to tag the viewcontroller names
func logEvent(eventTitle:String , eventContent:String)
{
Analytics.logEvent(AnalyticsEventSelectContent, parameters: [
AnalyticsParameterItemID: "AppName-\(eventTitle)" as NSObject,
AnalyticsParameterItemName: eventTitle as NSObject,
AnalyticsParameterContentType: eventContent as NSObject
])
}
But int the firestore these are clustered under select_content section because I used AnalyticsEventSelectContent key when creating the log.
Under main events screen , select_content my view controlers logged with above function
4.There is a specific DebugView in the FirestoreConsole that works with a device, it updates every 60 seconds as long as settings for -FIRAnalyticsDebugEnabled is true in the scheme.
There is a significant delay in the Event Section of Firestore console, I don't know why this happens, but sometimes there is a delay up to 15 - 30 mins. Havent researched that issue yet, it really doesnt bother me.
Just follow https://firebase.google.com/docs/analytics/ios/start
To enable Analytics Debug mode on your development device, specify the following command line argument in Xcode :
-FIRDebugEnabled
It works perfectly for Simulator and device.
Note: For react-native debugging, launch app from xcode with the selected scheme and not with 'yarn ios', then it works perfectly for Simulator also

iOS 10: How to debug a Today Widget - "Unable to load" message

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.

iOS 10 doesn't print NSLogs

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.

PhoneGap + Sencha2 screen blank

I've started a project in PhoneGap which will utilise Sencha Touch 2.
I tried to change the app name from 'app', since I've heard that conflicts with PhoneGap on Android devices. I altered app.js to main.js and that worked, but then I tried changing the Ext.application.name. All I got was a white screen after the loading splash, even with the old name Sencha. Debug console shows nothing at all happening, and the document <body> was empty. This happens with both sencha-touch-all.js and sencha-touch-all-debug.js. Test device is an iPad 1G running iOS 4.3.5.
Aside: To debug this issue, I set up weinre on my Mac and added the appropriate <script> tag to index.html. After making that change, though, the app didn't even launch. It hung on the PhoneGap splash png and I got this message from gdb-remote:
error: failed to launch '<app URI>' -- failed to send the qLaunchSuccess packet
The only reference to that message besides its definition in gdb-remote source that I can find is here, and it's unrelated. I managed to get the issue to go away by restarting the iPad and removing build intermediates.
SOLVED: The issue here was a missing value in the Ext.application definition (key with no associated value), so the whole app definition probably tanked as a result of that. Hence blank screen.

Resources