Testing CoreLocation on iPhone Simulator - ios

UPDATE: As of iOS 5 and Xcode 4.1 is is now possible to test location in the simulator and even define routes. See http://developer.apple.com for more details.
Legacy Question
Is there anyway to test CoreLocation on the iPhone Simulator?
All I require is to be able to set the location myself and have CoreLocation return it.

Here is my simple hack that forces the CLLocationMager to return
the geocoords of Powell's Tech Bookstore only on the simulator:
#ifdef TARGET_IPHONE_SIMULATOR
#interface CLLocationManager (Simulator)
#end
#implementation CLLocationManager (Simulator)
-(void)startUpdatingLocation {
CLLocation *powellsTech = [[[CLLocation alloc] initWithLatitude:45.523450 longitude:-122.678897] autorelease];
[self.delegate locationManager:self
didUpdateToLocation:powellsTech
fromLocation:powellsTech];
}
#end
#endif // TARGET_IPHONE_SIMULATOR

Thanks for the great feedback, it has prompted me to find a robust solution.
All the code can be found here:
http://code.google.com/p/dlocation/
It is very messy but as I use it it will be become much better.
The solution was to subclass CLLocationManager and define a new delegate #protocol, called DLocationManagerDelegate.
It is designed to be a simple drop-in replacement for CLLocationManagerDelegate that compiles down to a very thin layer when deployed on an actual device.
When running on the device it will return data as normal using CoreLocation, but in the simulator it will read latitude and longitude from a text file (defined in the DLocationManager.h file).
I hope this helps, the implementation is on the simple side and you have to startUpdatingLocation and stopUpdatingLocation to update the display.
Comments and feedback will be gratefully received.

Use a filtering function to swap in a test instance when running on the simulator. Wherever you previously received the location (delegate call, etc), pass it through this:
+ (CLLocation *) wakkawakka: (CLLocation*) loc {
#ifdef TARGET_IPHONE_SIMULATOR
/* replace with a test instance */
return [[CLLocation alloc] initWithLatitude:10.0 longitude:20.0];
#else
return loc;
#endif
}
Memory management issues aside...

I think there's another (better IMHO) approach here than subclassing CLLocationManager like in
http://code.google.com/p/dlocation/
In ObjectiveC it seems to be possible to replace an existing method from a class without overriding it. This is often called "method swizzling" : you define your own category for an existing class an implement an existing method in it.
From the client perspective, everything is transparent : he has the feeling he's dealing with the real CLLocationManager but actually, you "took the control from it". So that he doesn't need to deal with any special subclass or any special delegate protocol : he keeps on using the same class / protocol as the one from CoreLocation.
Here's an example to took the control over the delegate a client would inject :
#implementation CLLocationManager (simulator)
-(void) setDelegate:(id)delegate {
//your own implementation of the setDelegate...
}
-(id)delegate {
//your own implementation of the delegate....
}
-(void)startUpdatingLocation {
}
-(void)stopUpdatingLocation {
}
//....
//same for the rest of any method available in the standard CLLocationManager
#end
Then in this implementation, you're free to deal with a pre defined set of coordinates (coming from a file of whatever) that will be "pushed" to the delegate using the standard CLLocationManagerDelegate protocol.

Trigger the Core Location callbacks from a test class, if you need to set a location other than the one the simulator gives you.

the locationManager:didUpdateToLocation and locationManager:didFailedWithError overloaded callbacks are never called in the iphone simulator, that's kinda strange, all i get is 0.0000 for lat., and 0.0000 for lon. as the position. In the situation you develop something, that's kinda hard to implement all the possible situations that can occur during the location handling, using only simulator environment.

If you're interested in updating the blue userLocation dot in a MKMapView with the simulated location updates, check out my FTLocationSimulator at http://github.com/futuretap/FTLocationSimulator
It reads a KML file generated by Google Earth to provide continuous location updates.

Testing CoreLocation on iPhone Simulator
1) To test the location in simulator,best way is to use GPX files,just go to Files -> New -> Resource -> GPX File.
2) After Adding the GPX file update the location coordinates as desired.
3) once the GPX file is added to the project,Select the Scheme -> Edit Scheme -> Run -> Allow Location Simulation.tick the location simulation and select the name of the GPX file you just created.
this way simulator will always pick your desired coordinates,that we have added in our GPX File.

Related

Mute Voice Directions in Here Maps iOS SDK

I want to toggle the voice directions in my iOS app between on and off. The HERE maps instructions (https://developer.here.com/mobile-sdks/documentation/ios-hybrid-plus/topics_api_nlp_hybrid_plus/protocolnmaaudiomanagerdelegate-p.html) are still all in objective-C. It is quite clear in that language how to do this, but I am looking for the Swift 3 equivalent. That manual says:
#optional (BOOL) audioManager:( NMAAudioManager *) audioManager shouldPlayOutput:( NMAAudioOutput *) output
Called when the audio manager has output to play.
If the delegate returns YES, or the delegate does not implement this
method, the output is played immediately. If the delegate returns NO,
the delegate takes over responsiblity for handling the output.
I am guessing something similar to this, but I can't get it right:
func audioManagerShouldPlayOutput(_ audioManager: NMAAudioManager!, shouldPlayOutput:false) {
}
This is the signature created using the XCode "Generated Interface" assistant editor, hopefully it is helpful! Looks like you are off just a little bit.
optional public func audioManager(_ audioManager: NMAAudioManager!, shouldPlay output: NMAAudioOutput!) -> Bool

Possible to bring the app from background to foreground?

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?
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.
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!
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.
}
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
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()
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)
ยดยดยด

How to intercept adding calls to call history in iOS?

I'm developing a tweak for jailbroken iPhones. I'm trying to intercept the process of a call being added to the call history. With a little bit search I found CTCallHistoryStoreAddCall function in CoreTelephony framework found here. When I try to use it I get an error:
Undefined symbols for architecture armv7: "_CTCallHistoryStoreAddCall"
I linked the CoreTelephony framework and the way I used it in my code was:
typedef struct __CTCall * CTCallRef;
extern "C" void CTCallHistoryStoreAddCall(CTCallRef call);
I guess that means this function does not exist anymore or if it does I'm not using it in the correct way.
How can I find the right function that is responsible for adding an incoming phone call to the call history?
Thanks in advanced.
I'm using iOSOpenDev on Xcode 5.
There is no such function. At least in iOS7.
I've posted solution for iOS7 here Hide a phone call completely in iOS (jailbreak device)
Here is the code:
//Private API from CoreTelephony.framework
void CTCallDeleteFromCallHistory(CTCallRef call);
%hook PHRecentCall
-(id)initWithCTCall:(CTCallRef)call
{
if (IsCallShouldBeDeleted(call) == YES)
{
//Delete call from call history
CTCallDeleteFromCallHistory(call);
//Update MobilePhone app UI
id PHRecentsViewController = [[[[[UIApplication sharedApplication] delegate] rootViewController] tabBarViewController] recentsViewController];
if ([PHRecentsViewController isViewLoaded])
{
[PHRecentsViewController resetCachedIndexes];
[PHRecentsViewController _reloadTableViewAndNavigationBar];
}
//Try uncommenting this, may be it will work. Should make the code faster.
//return nil;
}
return %orig;
}
%end
Tweak hooks class inside MobilePhone app so bundle filter is com.apple.mobilephone.
IsCallShouldBeDeleted is pseudo function that determines whether a call should be deleted. You can remove it or implement your own. It's there just to make the code more clear.
On iOS6 class names are different but code is exactly the same - Apple just renamed the classes. I use that solution since iOS4. Also on iOS4 it requires a bit more code as there was no CTCallDeleteFromCallHistory function.
You are encountering this error because the CoreTelephony framework is not being linked to your program. To fix this, add the following to your makefile:
PROJECT_NAME_PRIVATE_FRAMEWORKS = CoreTelephony
Note that you have to replace PROJECT_NAME with your own project's name.

What is initWithCoder actually doing when used in conjunction with a core location manager object?

Ok so I'd like to full understand what is going on in this piece of code with initWithCoder.
Here's what I think is going on after reading through several suggested docs and reading chapters from a book on delegation, core location, designated initializers over and over again.
Initialize my viewcontroler with a pointer to an NSCoder object.
If that works then create an instance of a location manager object
Make the delegate my viewcontroller.
Set location accuracy to best.
Tell the location manager to start updating.
Log the info "stored in the delegate" to console. The lat and long are stored in a pointer to an NSArray object that is passed in as an argument to locationManager:DidUpdateLocations:
method.
If location was not found also log this status in console.
.h interface file:
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#interface WhereamiViewController : UIViewController
{
CLLocationManager *locationManager;
}
#end
.m implementation file:
#import "WhereamiViewController.h"
#interface WhereamiViewController ()
#end
#implementation WhereamiViewController
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self){
//create location manager object
locationManager = [[CLLocationManager alloc] init];
//there will be a warning from this line of code
[locationManager setDelegate:self];
//and we want it to be as accurate as possible
//regardless of how much time/power it takes
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
//tell our manager to start looking for its location immediately
[locationManager startUpdatingLocation];
}
return self;
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations
{
NSLog(#"%#", locations);
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error
{
NSLog(#"Could not find location: %#", error);
}
#end
Some further questions:
1) Is the setDelegate part of the code important because that is where the the "startUpdatingLocation method will store it's data?
2) Is the data stored archived? I asked because the fact that the delegate I set has the initializer initWithCoder. Which from what I've read is an unarchiver of archived data. So maybe the info from locationManager is archived and needs to be un-archived if that makes sense.
I get this warning on XCode. Am I doing something wrong?
Am I still suppose to set delegates this way or is there a new way of doing so? in another post I remember seeing an answer with something like <UIViewControllerDelegate> and was told to put this in my interface file.
I realise that most of this post may not make sense and I may be totally wrong but I learn most from my failures and maybe others will in future if they choose to learn to develop for ios.
Thanks for your time.
Regards
Overall, yes.
1) Yes, it's important. It tells the location manager who wants to know about location updates. startUpdatingLocation isn't storing data in the delegate. startUpdatingLocation triggers the location system to start up and find out where you are. The delegate gets told about the location and can do what it wants with it.
2) initWithCoder recreates the WhereamiViewController from an archive. That archive is most likely an XIB or storyboard. It has nothing to do with the location manager or delegate relationship.
As #ArkadiuszHolko says, you should be specifying <CLLocationManagerDelegate>. The purpose of this is to tell the compiler that you promise to implement the required methods of the protocol, so it can check that you do an raise an issue otherwise.
1) Is the setDelegate part of the code important because that is where
the the "startUpdatingLocation method will store it's data?
Yes, you won't be able to receive the data from CLLocationManager as it won't know on which object to call locationManager:didUpdateLocations:, locationManager:didFailWithError: and other methods you haven't implemented yet. You should get accustomed with the delegate pattern in Objective-C.
2) Is the data stored archived? I asked because the fact that the
delegate I set has the initializer initWithCoder. Which from what I've
read is an unarchiver of archived data. So maybe the info from
locationManager is archived and needs to be un-archived if that makes
sense.
The data won't be archived, because you don't store it anywhere. CLLocationManager also doesn't store the data anywhere.
I get this warning on XCode. Am I doing something wrong?
You're missing the declaration that your view controller conforms to CLLocationManagerDelegate protocol. You can fix it by replacing:
#interface WhereamiViewController ()
with:
#interface WhereamiViewController () <CLLocationManagerDelegate>
You should read about working with protocols in Objective-C.

EXC_BAD_ACCESS using ARC only during testing

I have an issue where I'm getting bad access exceptions but only when running a testing build (calling the same methods in a debug build doesn't cause the problem to come up). The project has ARC enabled and I'm running this on the iPad 5.1 simulator using Xcode 4.3:
Here's where the problem crops up:
- (void)testChangeFoodNotification {
Player* p = [[Player alloc] init];
[p addObserver:self forKeyPath:#"food" options:0 context:0]; // <-EXC_BAD_ACCESS (code=2)
p.food += 1;
STAssertTrue(_wasNotifiedOfFoodChange, nil);
}
At the point when the addObserver: method is called it doesn't seem like any of the objects involved should have been released so what could be causing the exception?
EDIT:
Apologies if it wasn't clear but the code above is being executed as part of a test case (using the standard Xcode OCUnit). Also in case it clarifies anything here's the relevant code from the player class (there's other ivars and methods but they don't have any connection to the property or methods being tested):
// Public interface
#interface Player : NSObject
#property (nonatomic, assign) NSInteger food;
#end
// Private interface
#interface Player() {
NSInteger _food;
}
#end
#implementation Player
#synthesize food = _food;
#pragma mark - Getters/Setters
- (void)setFood:(NSInteger)food {
[self willChangeValueForKey:#"food"];
_food = food;
[self didChangeValueForKey:#"food"];
}
If your class is indeed key-value compliant, ensure that the implementation for the class exhibiting the issue is not included in your test product. This means that the Target Membership panel of the Identity inspector for your .m file should only have your app checked (not YourAppTests).
I experienced the same issue in Xcode 4.3.1 when an implementation was included in both products and I registered observers in both production and test code. The following logs tipped me off:
Class YourClass is implemented in both /Users/yourUser/Library/Application Support/iPhone Simulator/5.1/Applications//YourApp.app/YourApp and /Users/yourUser/Library/Developer/Xcode/DerivedData/YourApp-/Build/Products/Debug-iphonesimulator/YourAppTests.octest/YourAppTests. One of the two will be used. Which one is undefined.
As per the Key-Value Observing Programming Guide, is your Player key-value-compliant? You want to make sure you are Ensuring KVC Compliance. I also assume that you have also implemented your observeValueForKeyPath:ofObject:change:context:? If you think you've done all of this and it's still not working, then perhaps you can share your code.
Also, minor thing, but I assume this is a code snippet to highlight the issue. I only mention it because ARC is going to be releasing your p object at the end of your testChangeFoodNotification and I would have thought that you'd want to remove your observer first.

Resources