Possible to bring the app from background to foreground?
Asked Answered
C

6

16

When running an XCT UI test it is possible to put the application under test in the background with:

XCUIDevice().pressButton(XCUIDeviceButton.Home)

It it possible in some way to bring the app back to foreground (active state) without relaunching the application?

Carola answered 9/2, 2016 at 14:53 Comment(1)
Swift 5 syntax: XCUIDevice.shared.press(XCUIDevice.Button.home)Batish
B
12

Update for Xcode 9: Starting in Xcode 9, you can now simply call activate() on any XCUIApplication.

let myApp = XCUIApplication()
myApp.activate() // bring to foreground

https://developer.apple.com/documentation/xctest/xcuiapplication/2873317-activate


Yes, it is. But, you'll need XCUIElement's private headers (which are available via header dump from Facebook here). In order to foreground the app, you need to call resolve which I believe resolves the element's query (which for applications means foregrounding the app).

For Swift, you'll have to import the XCUIElement.h into your bridging header. For Objective-C you'll just need to import XCUIElement.h.

With the app backgrounded:

Swift:

XCUIApplication().resolve()

Objective-C

[[XCUIApplication new] resolve];

If this is the only functionality you need, you could just write a quick ObjC category.

@interface XCUIElement (Tests)
- (void) resolve;
@end

If you need to launch / resolve another app. Facebook has an example of that here by going through the Springboard.

Bill answered 12/4, 2016 at 20:42 Comment(9)
I'm sure this method also works, but it's a lot of workaround for what you can simply accomplish by using XCUIApplication().launch().Formula
When I wrote this -- calling launch() killed the app and restarted it. As far as I know, you still need to call resolve() if you need to foreground the app without relaunching it.Bill
I think you're right. I was only thinking about launching the app (not without killing the app first).Formula
Is this still working for you guys? I feel @brandenbyers solution might just be better.Kisser
How do you do this part?: you'll have to import the XCUIElement.h into your bridging headerBranchia
Yes @rfodge, you'll need to import the category file into your bridging header. As of Xcode 9, this is no longer necessary, though, as there is a new public API to accomplish this task.Bill
Yeah i saw that is what is needed to do but how exactly do you do that? Sorry i am not familiar with where i even find the bridging header, or what i would need to put. If you could let me know or add to above, that would be awesome! ThamksBranchia
If you add any objective-c class file to your test target (via the File -> New File, not dragging in), Xcode will give you an option to create a bridging header automatically. Just replace the contents of the created file with the XCUIElement interface.Bill
The .activate() doesn't seem to be working in Xcode 10.2. It always fails for me.Smetana
H
5

As of Xcode 8.3 and iOS 10.3, you can accomplish this with Siri:

XCUIDevice.shared().press(XCUIDeviceButton.home)
XCUIDevice.shared().siriService.activate(voiceRecognitionText: "Open {appName}")

Include @available(iOS 10.3, *) at the top of your test suite file and you should be good to go!

Halliburton answered 27/3, 2017 at 23:11 Comment(2)
It is important to note that to get this to work on the iOS Simulator you need to enable Siri in the Settings app (off by default). I'm not sure if there is a way to turn this on via a command line argument or anything unfortunately.Litman
Good point. Siri must be enabled for this to work whether a physical device or simulator. Luckily, siri only need be enabled once on each simulated device. From my experience the setting remains between relaunches of simulator. I haven't found a way to enable siri on simulators via the command line.Halliburton
D
3

This is what I have in my XCUITest and it works like a charm (xcode 10.1 and test device is iPhone X 11.0)

func testWhatever() {

// You test steps go here until you need the background foreground to run

XCUIDevice.shared.press(XCUIDevice.Button.home) // To background the app XCUIApplication().activate() // To bring the app back

// You test continues after background foreground has been done. }

Dagall answered 22/5, 2019 at 15:8 Comment(0)
M
1

If somebody needs just move app back from background i have written (based on answer above) category that really works(great thanks to pointing to FB git)

@implementation XCUIApplication(SpringBoard)

+ (instancetype)springBoard
{
    XCUIApplication * springboard  = [[XCUIApplication alloc] performSelector:@selector(initPrivateWithPath:bundleID:)
                                                                   withObject:nil
                                                                   withObject:@"com.apple.springboard"];




    [springboard performSelector:@selector(resolve) ];
    return springboard;
}

- (void)tapApplicationWithIdentifier:(NSString *)identifier
{
    XCUIElement *appElement = [[self descendantsMatchingType:XCUIElementTypeAny]
                           elementMatchingPredicate:[NSPredicate predicateWithFormat:@"identifier = %@", identifier]
                           ];
    [appElement tap];
}
@end
Metacarpal answered 10/5, 2016 at 9:25 Comment(0)
B
0

For Swift, you need to declare the XCUIApplication private methods interface in Bridging-Header.h like this:

@interface XCUIApplication (Private)
- (id)initPrivateWithPath:(NSString *)path bundleID:(NSString *)bundleID;
- (void)resolve;
@end

Then call resolve() in your test cases to bring the app back:

XCUIApplication().resolve()
Beghard answered 27/2, 2017 at 3:20 Comment(2)
Where do you find the Brigding-Header.h file?Branchia
It's automatically created when you add an objc file to your Swift target. If you don't already have one, the easiest thing to do is to just create an empty objc file and add it to your target. Xcode will ask if you want a bridging header -- say yes. Then delete the empty objc file you created. The bridging header will remain. Otherwise you can create a header file and set its path in Project->Build Settings->Objective-C Bridging Header.Bill
H
0

Since Xcode 13 we got several errors that the app was not in foreground state after returning to the app.

applying this code to our "goToSpringboardAndBack()" works

XCUIDevice.shared.press(XCUIDevice.Button.home)
if XCUIApplication().wait(for: .runningBackground, timeout: 5.0) {
   XCUIApplication().activate()
}

_ = XCUIApplication().wait(for: .runningForeground, timeout: 5.0)
´´´
Hightension answered 11/10, 2021 at 14:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.