background app in iOS that detects incoming phone calls - iphone

I need to write a background application in iOS which listens to incoming phone calls on the iPhone.
Is it possible? Can anyone suggest some good pointers ?
Thankyou

This would be very much against Apple's privacy policy and there's no chance an app like this would be approved.
There are call recording apps that sneak around this restriction, though, but they use third party services and no actual built-in iPhone API's.

You can do it in applicationWillEnterForeground using CTCallCenter's CTCallState properties. Don't forget to import the CoreTelephony framework. Here's an example:
#import <CoreTelephony/CTCall.h>
#import <CoreTelephony/CTCallCenter.h>
#import <CoreTelephony/CTCarrier.h>
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
- (void)applicationWillEnterForeground:(UIApplication *)application
{
[callCenter setCallEventHandler:^(CTCall *call) {
if ([[call callState] isEqual:CTCallStateIncoming] || [[call callState] isEqual:CTCallStateDialing]) {
if ([viewController isPlaying])
{
NSLog(#"Call was started.");
}
} else if ([[call callState] isEqual:CTCallStateDisconnected]) {
if (callWasStarted)
{
NSLog(#"Call was ended.");
}
}
}];
}

Related

How can I get CTCallCenter Events in an iPhone Enterprise app in the background

I am looking for a way to get CTCallCenter Events on an enterprise app while it is in the background. I came across the suggested solution by OhadM on this post: How to get a call event using CTCallCenter:setCallEventHandler: that occurred while the app was suspended?, but I can't get it to work with the app in the background.
I created a new single view app, added a callCenter property on the appDelegate and set the callEventHandler as shown in the post and listed below. I also added the Voice over IP and Background fetch Background Modes Capabilities as described.
Is there any other settings or code not mentioned in the solution that may help? I am using iOS 9.3.1 and Xcode 7.3.1.
[self.callCenter setCallEventHandler:^(CTCall *call)
{
NSLog(#"Event handler called");
if ([call.callState isEqualToString: CTCallStateConnected])
{
NSLog(#"Connected");
}
else if ([call.callState isEqualToString: CTCallStateDialing])
{
NSLog(#"Dialing");
}
else if ([call.callState isEqualToString: CTCallStateDisconnected])
{
NSLog(#"Disconnected");
} else if ([call.callState isEqualToString: CTCallStateIncoming])
{
NSLog(#"Incomming");
}
}];

link to a book in iBook store from an iphone app

After looking around I could not get a straight answer to the following case: can I link to a book in the iBook store from my iphone app without integrating the in-app purchases API?
As far as I know, iBooks does charge you for placing the book, so my logic says that it should be possible since otherwise you would be charged twice.
Many thanks.
If your app is targeting iOS 6.0 you can use the new SKStoreProductViewController to allow users to purchase iTunes, App Store, and iBooks content directly from your app without having to leave it.
Here is how to present it from a UIViewController. You must add the StoreKit.framework to your application.
ViewController.h
#import <StoreKit/StoreKit.h>
#interface UIViewController : UIViewController <SKStoreProductViewControllerDelegate>
#end
ViewController.m
-(void)showProductPageForProductID:(NSInteger)productID {
SKStoreProductViewController *sv = [[SKStoreProductViewController alloc] init];
sv.delegate = self;
NSDictionary *product = #{ SKStoreProductParameterITunesItemIdentifier: #(productID)};
[sv loadProductWithParameters:product completionBlock:^(BOOL result, NSError *error) {
if(result)
[self presentModalViewController:sv animated:YES];
else {
//product not found, handle appropriately
}
}];
}
-(void)productViewControllerDidFinish:(SKStoreProductViewController *)viewController {
[viewController dismissModalViewControllerAnimated:YES];
}
If your targeting devices below iOS 6.0 you can just use this:
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"http://itunes.apple.com/us/book/the-casual-vacancy/id518781282?mt=11"]];
Just replace that URL string with your link, and it will leave your app and enter the iBooks app displaying that product.
If you want to target both iOS 6.0 and lower, you can just check if they have the new SKStoreProductViewController by using the following conditional
if([SKStoreProductViewController class]) {
//show the SKStoreProductViewController
}
else {
//use UIApplication's openURL:
}
In order to get the Apple product ID for a product, you can just check the URL to the product for example:
http://itunes.apple.com/us/book/the-casual-vacancy/id518781282?mt=11
The product ID is 518781282. It comes after the id portion in the URL. Don't include the ? or anything after it.

How to add an icon into iphone/ipod status bar?

Does Apple not allow developers to add an icon into a status bar?
I followed code from a book. The code is simple:
#interface UIApplication (extended)
- (void) addStatusBarImageNamed:(NSString *)aName;
- (void) removeStatusBarImageNamed:(NSString *)aName;
#end
- (void)performAction{
if (xxx) {
[[UIApplication sharedApplication]addStatusBarImageNamed:#"Default_EN.png"];
}
else {
[[UIApplication sharedApplication]addStatusBarImageNamed:#"Default_EC.png"];
}
}
But it gives the following feedback :
-addStatusBarImageNamed: is deprecated. Doing nothing.
What can I do?
To my best knowledge, this isn't permitted within the SDK, but there could be the possibilities that they could have some private API to do so but so far they haven't exposed those, I think you are'nt able to add icon in status bar. If someone know please correct me .
In Classes/YourViewController.m, the addStatusBarImageNamed:removeOnExit: method needs to be overwritten with this.
- (void) addStatusBarImageNamed:(NSString*)image removeOnExit: (BOOL) remove {
if(_statusbarimage!=nil && _responds) {
if ([[[NSUserDefaults standardUserDefaults] objectForKey:#"statusBarEnabled"] integerValue] == 1)
[self removeStatusBarImageNamed:_statusbarimage];
statusbarimage=image;
}
if (_responds) {
if ([[[NSUserDefaults standardUserDefaults] objectForKey:#"statusBarEnabled"] integerValue] == 1)
[super addStatusBarImageNamed:image removeOnExit: remove];
}
}
See if it works fine.

applicationWillEnterForeground never called

Hey there, I'm trying Multitasking in the Simulator (I only have a 2nd gen iPod and an iPad) and I'm still having some problems. My testing methods look like this:
- (void)applicationDidBecomeActive:(UIApplication *)application {
NSLog(#"Entering %s",__FUNCTION__);
if (enteredFromBackground) {
NSLog(#"Entering from Background");
enteredFromBackground = NO;
}
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
NSLog(#"Entering %s",__FUNCTION__);
enteredFromBackground = YES;
}
Unforntunately, I'm not seeing the NSLog from applicationWillEnterForeground, that's why I added the line to show me something in applicationDidBecomeActive.
All I get is the
2010-11-20 15:58:12.796 iBeat[45997:207] Entering -[AppDelegate_Shared applicationDidEnterBackground:]
2010-11-20 15:58:18.160 iBeat[45997:207] Entering -[AppDelegate_Shared applicationDidBecomeActive:]
After having this problem in iOS 13, I found out that I was waiting for applicationWillEnterForeground(_ application: UIApplication) to be called instead of sceneWillEnterForeground(_ scene: UIScene).
For more information, read this answer:
enter link description here
Finally I found my problem!
Since I have a universal Application, I have an Appdelegate_Shared, an Appdelegate_iPhone, and an Appdelegate_iPad.
I had an empty implementation of "applicationWillEnterForeground" in the two subclasses but didn't call super!
And then I wondered why the method in Appdelegate_Shared never got called o.O

How can my iPhone Objective-C code get notified of Javascript errors in a UIWebView?

I need to have my iPhone Objective-C code catch Javascript errors in a UIWebView. That includes uncaught exceptions, syntax errors when loading files, undefined variable references, etc.
This is for a development environment, so it doesn't need to be SDK-kosher. In fact, it only really needs to work on the simulator.
I've already found used some of the hidden WebKit tricks to e.g. expose Obj-C objects to JS and to intercept alert popups, but this one is still eluding me.
[NOTE: after posting this I did find one way using a debugging delegate. Is there a way with lower overhead, using the error console / web inspector?]
I have now found one way using the script debugger hooks in WebView (note, NOT UIWebView). I first had to subclass UIWebView and add a method like this:
- (void)webView:(id)webView windowScriptObjectAvailable:(id)newWindowScriptObject {
// save these goodies
windowScriptObject = newWindowScriptObject;
privateWebView = webView;
if (scriptDebuggingEnabled) {
[webView setScriptDebugDelegate:[[YourScriptDebugDelegate alloc] init]];
}
}
Next you should create a YourScriptDebugDelegate class that contains methods like these:
// in YourScriptDebugDelegate
- (void)webView:(WebView *)webView didParseSource:(NSString *)source
baseLineNumber:(unsigned)lineNumber
fromURL:(NSURL *)url
sourceId:(int)sid
forWebFrame:(WebFrame *)webFrame
{
NSLog(#"NSDD: called didParseSource: sid=%d, url=%#", sid, url);
}
// some source failed to parse
- (void)webView:(WebView *)webView failedToParseSource:(NSString *)source
baseLineNumber:(unsigned)lineNumber
fromURL:(NSURL *)url
withError:(NSError *)error
forWebFrame:(WebFrame *)webFrame
{
NSLog(#"NSDD: called failedToParseSource: url=%# line=%d error=%#\nsource=%#", url, lineNumber, error, source);
}
- (void)webView:(WebView *)webView exceptionWasRaised:(WebScriptCallFrame *)frame
sourceId:(int)sid
line:(int)lineno
forWebFrame:(WebFrame *)webFrame
{
NSLog(#"NSDD: exception: sid=%d line=%d function=%#, caller=%#, exception=%#",
sid, lineno, [frame functionName], [frame caller], [frame exception]);
}
There is probably a large runtime impact for this, as the debug delegate can also supply methods to be called for entering and exiting a stack frame, and for executing each line of code.
See http://www.koders.com/noncode/fid7DE7ECEB052C3531743728D41A233A951C79E0AE.aspx for the Objective-C++ definition of WebScriptDebugDelegate.
Those other methods:
// just entered a stack frame (i.e. called a function, or started global scope)
- (void)webView:(WebView *)webView didEnterCallFrame:(WebScriptCallFrame *)frame
sourceId:(int)sid
line:(int)lineno
forWebFrame:(WebFrame *)webFrame;
// about to execute some code
- (void)webView:(WebView *)webView willExecuteStatement:(WebScriptCallFrame *)frame
sourceId:(int)sid
line:(int)lineno
forWebFrame:(WebFrame *)webFrame;
// about to leave a stack frame (i.e. return from a function)
- (void)webView:(WebView *)webView willLeaveCallFrame:(WebScriptCallFrame *)frame
sourceId:(int)sid
line:(int)lineno
forWebFrame:(WebFrame *)webFrame;
Note that this is all hidden away in a private framework, so don't try to put this in code you submit to the App Store, and be prepared for some hackery to get it to work.
I created a nice little drop-in category that you can add to your project...
It is based on Robert Sanders solution. Kudos.
You can dowload it here:
UIWebView+Debug
This should make it a lot easier to debug you UIWebView :)
I used the great solution proposed from Robert Sanders: How can my iPhone Objective-C code get notified of Javascript errors in a UIWebView?
That hook for webkit works fine also on iPhone. Instead of standard UIWebView I allocated derived MyUIWebView. I needed also to define hidden classes inside MyWebScriptObjectDelegate.h:
#class WebView;
#class WebFrame;
#class WebScriptCallFrame;
Within the ios sdk 4.1 the function:
- (void)webView:(id)webView windowScriptObjectAvailable:(id)newWindowScriptObject
is deprecated and instead of it I used the function:
- (void)webView:(id)sender didClearWindowObject:(id)windowObject forFrame:(WebFrame*)frame
Also, I get some annoying warnings like "NSObject may not respond -windowScriptObject" because the class interface is hidden. I ignore them and it works nice.
One way that works during development if you have Safari v 6+ (I'm uncertain what iOS version you need) is to use the Safari development tools and hook into the UIWebView through it.
In Safari: Enable the Develop Menu (Preferences > Advanced > Show Develop menu in menu bar)
Plug your phone into the computer via the cable.
List item
Load up the app (either through xcode or just launch it) and go to the screen you want to debug.
Back in Safari, open the Develop menu, look for the name of your device in that menu (mine is called iPhone 5), should be right under User Agent.
Select it and you should see a drop down of the web views currently visible in your app.
If you have more than one webview on the screen you can try to tell them apart by rolling over the name of the app in the develop menu. The corresponding UIWebView will turn blue.
Select the name of the app, the develop window opens and you can inspect the console. You can even issue JS commands through it.
Straight Forward Way: Put this code on top of your controller/view that is using the UIWebView
#ifdef DEBUG
#interface DebugWebDelegate : NSObject
#end
#implementation DebugWebDelegate
#class WebView;
#class WebScriptCallFrame;
#class WebFrame;
- (void)webView:(WebView *)webView exceptionWasRaised:(WebScriptCallFrame *)frame
sourceId:(int)sid
line:(int)lineno
forWebFrame:(WebFrame *)webFrame
{
NSLog(#"NSDD: exception: sid=%d line=%d function=%#, caller=%#, exception=%#",
sid, lineno, [frame functionName], [frame caller], [frame exception]);
}
#end
#interface DebugWebView : UIWebView
id windowScriptObject;
id privateWebView;
#end
#implementation DebugWebView
- (void)webView:(id)sender didClearWindowObject:(id)windowObject forFrame:(WebFrame*)frame
{
[sender setScriptDebugDelegate:[[DebugWebDelegate alloc] init]];
}
#end
#endif
And then instantiate it like this:
#ifdef DEBUG
myWebview = [[DebugWebView alloc] initWithFrame:frame];
#else
myWebview = [[UIWebView alloc] initWithFrame:frame];
#endif
Using #ifdef DEBUG ensures that it doesn't go in the release build, but I would also recommend commenting it out when you're not using it since it has a performance impact. Credit goes to Robert Sanders and Prcela for the original code
Also if using ARC you may need to add "-fno-objc-arc" to prevent some build errors.
I have created an SDK kosher error reporter that includes:
The error message
The name of the file the error happens in
The line number the error happens on
The JavaScript callstack including parameters passed
It is part of the QuickConnectiPhone framework available from the sourceForge project
There is even an example application that shows how to send an error message to the Xcode terminal.
All you need to do is to surround your JavaScript code, including function definitions, etc. with try catch. It should look like this.
try{
//put your code here
}
catch(err){
logError(err);
}
It doesn't work really well with compilation errors but works with all others. Even anonymous functions.
The development blog is here
is here and includes links to the wiki, sourceForge, the google group, and twitter. Maybe this would help you out.
I have done this in firmware 1.x but not 2.x.
Here is the code I used in 1.x, it should at least help you on your way.
// Dismiss Javascript alerts and telephone confirms
/*- (void)alertSheet:(UIAlertSheet*)sheet buttonClicked:(int)button
{
if (button == 1)
{
[sheet setContext: nil];
}
[sheet dismiss];
}*/
// Javascript errors and logs
- (void) webView: (WebView*)webView addMessageToConsole: (NSDictionary*)dictionary
{
NSLog(#"Javascript log: %#", dictionary);
}
// Javascript alerts
- (void) webView: (WebView*)webView runJavaScriptAlertPanelWithMessage: (NSString*) message initiatedByFrame: (WebFrame*) frame
{
NSLog(#"Javascript Alert: %#", message);
UIAlertSheet *alertSheet = [[UIAlertSheet alloc] init];
[alertSheet setTitle: #"Javascript Alert"];
[alertSheet addButtonWithTitle: #"OK"];
[alertSheet setBodyText:message];
[alertSheet setDelegate: self];
[alertSheet setContext: self];
[alertSheet popupAlertAnimated:YES];
}
See exception handling in iOS7:
http://www.bignerdranch.com/blog/javascriptcore-example/
[context setExceptionHandler:^(JSContext *context, JSValue *value) {
NSLog(#"%#", value);
}];
First setup WebViewJavascriptBridge ,
then override console.error function.
In javascript
window.originConsoleError = console.error;
console.error = (msg) => {
window.originConsoleError(msg);
bridge.callHandler("sendConsoleLogToNative", {
action:action,
message:message
}, null)
};
In Objective-C
[self.bridge registerHandler:#"sendConsoleLogToNative" handler:^(id data, WVJBResponseCallback responseCallback) {
NSString *action = data[#"action"];
NSString *msg = data[#"message"];
if (isStringValid(action)){
if ([#"console.error" isEqualToString:action]){
NSLog(#"JS error :%#",msg);
}
}
}];
A simpler solution for some cases might be to just add Firebug Lite to the Web page.