Check whether Running the app or Testing UI - ios

I need a set of code to run only when testing the app(UITesting) not when running the app. I have been trying to find whether running the app or it's a UITesting?.
This is new on xcode 8 and above.
Can some help me with this please.

Now we can simply check this with one line of code for "UITesting".
[[[NSProcessInfo processInfo] arguments]
containsObject:#"-ui_testing"]
-ui_testing would appear only when testing the app.

Related

EarlGrey launches APP with black screen

After successfully adding EarlGrey to existing project (using CocoaPods) project is successfully built (both "for running" and "for testing"). The problem is that if I run the app from XCode it runs as expected. If I run it as a test only splash screen appears and then whole screen turns black. Have anyone encountered such issue? What might be a problem here?
There is somewhat similar question Black screen with EarlGrey but author did not share his solution.
Additional info:
XCode 8
CocoaPods 1.2.1
EarlGrey 1.9.3
I followed #khandpur advice and tried debugging my app first. So I found out, that in main.m file we're checking if current run is a test run, by
BOOL areWeRunningTests = NSClassFromString(#"XCTestCase") != nil;
Based on that we are running app differently.
To everyone in similar situation: I've added a check
BOOL areWeRunningUITests = NSClassFromString(#"EarlGreyImpl") != nil;
and if that's true app is starting normally.
Final comments - you have to know your app a little to be able to use EarlGrey easily... :)

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.

Xamarin.UITests - testing on real device - iOS - app permissions popups issue

I've iOS app that needs some privileges (GPS, Push notifications).
When app starts for a first time iOS asks user if they're ok with granting those permissions to application.
I've written some UITests and want to automate running them on locally connected iPhone.
The problem is that I cannot override permissions questions and my tests fails.
I found out that application deployed by IDE (Xamarin Studio) will ask for permissions, but application deployed via UITests will not.
So I tried with .AppBundle(path_to_app) but it says this is only valid for deploying to Simulator.
SetUp : System.Exception : This app bundle is not valid for running on
a simulator. To fix this issue please ensure that your target device
is a simulator. DTPlatformName is 'iphoneos', not 'iphonesimulator' in
the apps Info.plist.
Like it's trying to deploy iPhone app to Simulator. But Target in Xamarin Studio is set to real device.
I tried to add .DeviceIdentifier. When Used with .InstalledApp it was starting up (still asking for permissions).
But when I used DeviceIdentifier and AppBundle there was the same error as above.
My tests works fine on Test Cloud. They work fine on Simulator.
They work fine when I deploy to device manually, start app and approve permissions then run UI tests.
What I cannot achieve is to make UITests override permissions questions on real device.
Anyone made this work?
Last thing is that I found is in documentation for AppBundle method
"Will force a run on simulator"
https://developer.xamarin.com/api/member/Xamarin.UITest.Configuration.iOSAppConfigurator.AppBundle/p/System.String/
So I may be doomed with the task but maybe someone knows a workaround?
You can dismiss system dialogs with UITest by using InvokeUIA. The test below works by tapping the "OK" button of an iOS system alert:
[Test]
public void AppLaunches ()
{
app.Screenshot ("First screen.");
app.InvokeUia ("uia.query('[:view {:marked \"OK\"}]')");
app.InvokeUia ("uia.tapMark(\"OK\")");
}
A working sample app & UITest is also here:
https://github.com/King-of-Spades/InvokeUia-for-System-Dialogs
Warning about system dialogs in Test Cloud
The reason that you don't see this issue in Test Cloud is because Test Cloud automatically dismisses the system alerts; so usually you don't have to worry about it. However, if your alert launches too soon; so that it appears before the automation has fully started your app, then it will be unable to detect & dismiss the alert and cause your test to fail.
So you want to make sure that when running your app in Test Cloud that the request for permissions are delayed, or you can even deactivate them if they aren't explicitly needed for a particular test. More information is available in this Calabash guide: https://github.com/calabash/calabash-ios/wiki/Managing-Privacy-Alerts%3A--Location-Services%2C-APNS%2C-Contacts
(Even though it's Calabash, you can use the same strategy in UITest; albeit with a C# syntax.)
Update for Xcode 8 / iOS 10
Xcode 8 / iOS 10 removed UIAutomation, so the InvokeUIA workaround will only continue to be possible if you're using Xcode 7 and iOS 7-9. References:
UITest: https://developer.xamarin.com/guides/testcloud/UITest/xcode7/
Calabash: https://developer.xamarin.com/guides/testcloud/calabash/xcode7/#Automation_API
For real devices you dont need any of those.
{
app = ConfigureApp
.iOSAppBundle
.StartApp();
}
this piece of code is good enough, if you are connecting real device to the system, then select that before running.
We use this to execute the UI tests on iPhones:
ConfigureApp.iOS.InstalledApp("com.appcenter.UITestDemo").StartApp();
InstalledApp requires you to build an IPA using the Debug
configuration & a valid provisioning profile, and preinstalling it on
the target device.
https://github.com/microsoft/appcenter-Xamarin.UITest-Demo/blob/main/UITestDemo.UITest/AppInitializer.cs
To confirm system dialogs we use this:
private Query ConfirmLocalNetworkPermissionDialogButton
=> AppInitializer.Platform == Platform.iOS
? new Query(x => x.ClassFull("_UIAlertControllerActionView").Marked("OK"))
: x => x.Class("AppCompatButton").Marked("button1");

Cycript script to run app in background

I have a cycript backboardd script that works great on iOS 7 for modifying an app to continue running in the background.
app = [BKProcess processForPid:$PID];
alive = [[BKProcessAssertion alloc] initWithReason:7 identifier:"AppKeepAlive"];
[alive setFlags:0xF];
[sc addAssertion:alive];
This is all that's needed. However on iOS 8 this does't work as BKProcess is now BKSProcess and BKProcessAssertion is now BKSProcessAssertion and they have different methods.
There doesn't seem to be a way to attach the assertion to the app like on iOS 7.
Can some please help me get this working under iOS 8.
There is, however when I used this I simply used the initializer with the required PID.
- (id)initWithPID:flags:reason:name:withHandler:
Check out the BKSProcessAssertion header for reference.
If you want to see an implementation for reference, check out MessageBox (now deprecated, but for reference):

Xcode+watchkit simulation: does not support a debuggable architecture:

I am trying to run in Xcode both the main App (which is active in background) and the WatchkitApp (which sends requests to main App through the watchkit extension). Everything works fine in standalone, but no way to make it work simultaneously.
My main concern is to understand this message when trying to attach a process: what does this mean ?
Xcode couldn't attach to "myApp"
"myApp" does not support a debuggable architecture
Thank you.
Edit:
I just read that main app in ObjectiveC and watch app in swift is a problem: https://mkswap.net/m/blog/How+to+debug+an+iOS+app+while+the+WatchKit+app+is+currently+running+in+the+simulator
It happened to me when an extension process was hanging around refusing to terminate. Find and kill it in the Activity Monitor.
Actually, I had that same error message, and I fixed it by resolving a bug that crashed my phone app on launch.
I didn't think to run just the phone in debug so I got confused too.
I'm running ObjC on the phone and Swift on the Watch App.

Resources