Call blocking feature in iOS 10 - ios

I am trying to integrate CallDirectory Extension for blocking some incoming call. But application is not even recognising the numbers provided for blocking. Is there anyone who have succeeded in doing this ??
You can see the format that i have used..
private func addIdentificationPhoneNumbers(to context: CXCallDirectoryExtensionContext) throws {
let phoneNumbers: [CXCallDirectoryPhoneNumber] = [ 18775555555, 18885555555,+91949520]
let labels = [ "Telemarketer", "Local business","myPhone"]
for (phoneNumber, label) in zip(phoneNumbers, labels) {
context.addIdentificationEntry(withNextSequentialPhoneNumber: phoneNumber, label: label)
}
}
And , i referred this for development. http://iphoneramble.blogspot.in/2016/07/ios-10-callkit-directory-extension.html
Testing Device & iOS Version - iphone 5s ,iOS 10.1

Atlast , I have got the solution for call blocking. I haven't had a way to check if the call blocking code is working or not. Here are some of the things that i have done for making it work.
Check if your application is running in 64 bit iOS device
(iphone 5s or greater devices)
Adding the numbers in numerically ascending order
Add country code to every number
A sample code for adding mobile numbers for blocking is given below
let phoneNumber : CXCallDirectoryPhoneNumber =
CXCallDirectoryPhoneNumber("+9194******")!
context.addBlockingEntry(withNextSequentialPhoneNumber: phoneNumber)
Check your application has given permission to black calls
(setting -> phone -> call Blocking & identification -> Check your app is allowed to block calls)
You can also check the enabledStatus by putting this below code in your viewController
CXCallDirectoryManager.sharedInstance.getEnabledStatusForExtension(withIdentifier:
"bundleIdentifierOfYourExtension", completionHandler:
{(status, error) -> Void in
if let error = error {
print(error.localizedDescription)
}
})
Also , add following code to viewController
CXCallDirectoryManager.sharedInstance.reloadExtension(withIdentifier:
“bundleIdentifierOfYourExtension”, completionHandler: { (error) -> Void in
if let error = error {
print(error.localizedDescription)
}
})
You will find these url's helpful for the development.
http://iphoneramble.blogspot.in/2016/07/ios-10-callkit-directory-extension.html
https://translate.google.com/translate?hl=en&sl=zh-CN&u=http://colin1994.github.io/2016/06/17/Call-Directory-Extension-Study/&prev=search
Kindly please let me know if you have got improved methods and corrections.
Thanks and happy coding.

Good to see Apple listening to enhancement requests with CX. With iOS 13.4, Apple added the ability to open Call Blocking & Identification settings directly from the app.
func openSettings(completionHandler completion: ((Error?) -> Void)? = nil)
https://developer.apple.com/documentation/callkit/cxcalldirectorymanager/3521394-opensettings

The array of phone numbers must be a sorted list of int64's. From smallest to largest. The list will be rejected with an "entries out of order" error otherwise.

Related

Force user to update the app programmatically in iOS

In my iOS app I have enabled force app update feature. It is like this.
If there is a critical bug fix. In the server we are setting the new release version. And in splash screen I am checking the current app version and if its lower than the service version, shows a message to update the app.
I have put 2 buttons "Update now", "Update later"
I have 2 questions
If I click now. App should open my app in the appstore with the button UPDATE. Currently I use the link "http://appstore.com/mycompanynamepvtltd"
This opens list of my company apps but it has the button OPEN, not the UPDATE even there is a new update for my app. whats the url to go for update page?
If he click the button "Update Later" is it ok to close the app programmatically? Does this cause to reject my app in the appstore?
Please help me for these 2 questions
Point 2 : You should only allow force update as an option if you don't want user to update later. Closing the app programmatically is not the right option.
Point 1 : You can use a good library available for this purpose.
Usage in Swift:
Library
func applicationDidBecomeActive(application: UIApplication) {
/* Perform daily (.daily) or weekly (.weekly) checks for new version of your app.
Useful if user returns to your app from the background after extended period of time.
Place in applicationDidBecomeActive(_:)*/
Siren.shared.checkVersion(checkType: .daily)
}
Usage in Objective-C: Library
-(void)applicationDidBecomeActive:(UIApplication *)application {
// Perform daily check for new version of your app
[[Harpy sharedInstance] checkVersionDaily];
}
How it works : It used lookup api which returns app details like link including version and compares it.
For an example, look up Yelp Software application by iTunes ID by calling https://itunes.apple.com/lookup?id=284910350
For more info, please visit link
Don't close the app programmatically. Apple can reject the app. Better approach will be do not allow user to use the app. Keep the update button. Either user will go to app store or close the app by himself.
According to Apple, your app should not terminate on its own. Since the user did not hit the Home button, any return to the Home screen gives the user the impression that your app crashed. This is confusing, non-standard behavior and should be avoided.
Please check this forum:
https://forums.developer.apple.com/thread/52767.
It is happening with lot of people. In my project I redirected the user to our website page of downloading app from app store. In that way if the user is not getting update button in app store, at least the user can use the website in safari for the time being.
To specifically answer your question:
Use this URL to directly open to your app in the app store:
https://apps.apple.com/app/id########## where ########## is your app's 10 digit numeric ID. You can find that ID in App Store Connect under the App Information section. It's called "Apple ID".
I actually have terminate functionality built into my app if it becomes so out of date that it can no longer act on the data it receives from the server (my app is an information app that requires connectivity to my web service). My app has not been rejected for having this functionality after a dozen updates over a couple years, although that function has never been invoked. I will be switching to a static message instead of terminating the app, just to be safe to avoid future updates from being rejected.
I have found that the review process is at least somewhat subjective, and different reviewers may focus on different things and reject over something that has previously been overlooked many times.
func appUpdateAvailable() -> (Bool,String?) {
guard let info = Bundle.main.infoDictionary,
let identifier = info["CFBundleIdentifier"] as? String else {
return (false,nil)
}
// let storeInfoURL: String = "http://itunes.apple.com/lookupbundleId=\(identifier)&country=IN"
let storeInfoURL:String = "https://itunes.apple.com/IN/lookup?
bundleId=\(identifier)"
var upgradeAvailable = false
var versionAvailable = ""
// Get the main bundle of the app so that we can determine the app's
version number
let bundle = Bundle.main
if let infoDictionary = bundle.infoDictionary {
// The URL for this app on the iTunes store uses the Apple ID
for the This never changes, so it is a constant
let urlOnAppStore = NSURL(string: storeInfoURL)
if let dataInJSON = NSData(contentsOf: urlOnAppStore! as URL) {
// Try to deserialize the JSON that we got
if let dict: NSDictionary = try?
JSONSerialization.jsonObject(with: dataInJSON as Data, options:
JSONSerialization.ReadingOptions.allowFragments) as! [String:
AnyObject] as NSDictionary? {
if let results:NSArray = dict["results"] as? NSArray {
if let version = (results[0] as! [String:Any]).
["version"] as? String {
// Get the version number of the current version
installed on device
if let currentVersion =
infoDictionary["CFBundleShortVersionString"] as? String {
// Check if they are the same. If not, an
upgrade is available.
print("\(version)")
if version != currentVersion {
upgradeAvailable = true
versionAvailable = version
}
}
}
}
}
}
}
return (upgradeAvailable,versionAvailable)
}
func checkAppVersion(controller: UIViewController){
let appVersion = ForceUpdateAppVersion.shared.appUpdateAvailable()
if appVersion.0 {
alertController(controller: controller, title: "New Update", message: "New version \(appVersion.1 ?? "") is available")
}
}
func alertController(controller:UIViewController,title: String,message: String){
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Update", style: .default, handler: { alert in
guard let url = URL(string: "itms-apps://itunes.apple.com/app/ewap/id1536714073") else { return }
if #available(iOS 10.0, *) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
} else {
UIApplication.shared.openURL(url)
}
}))
DispatchQueue.main.async {
controller.present(alertController, animated: true)
}
}
Use appgrades.io. Keep your app focus on delivering the business value and let 3rd party solution do their tricks. With appgrades, you can, once SDK integrated, create a custom view/alert to display for your old versions users asking them to update their apps. You can customize everything in the restriction view/alert to make it appear as part of your app.

Is it okay to download data directly to watch OS from server

So I'm trying to make a watchOS app for a music streaming app, and I found an example pretty much close to what I'm going to make.
(https://github.com/belm/BaiduFM-Swift)
But It seems like the project is kinda outdated. According to the codes below, watch extension is getting required datas like sound, images via HttpRequest. From what I read, watchOS 3 supports Background Connectivity, (which enables app to transfer data more efficiently) and Apple encourages developers to process and get data from the main app.
What is right way to do it? Is there any good example to see?
// play song method in interface controller
HttpRequest.getSongLink(info.id, callback: {(link:SongLink?) -> Void in
if let songLink = link {
DataManager.shareDataManager.curSongLink = songLink
DataManager.shareDataManager.mp.stop()
var songUrl = Common.getCanPlaySongUrl(songLink.songLink)
DataManager.shareDataManager.mp.contentURL = NSURL(string: songUrl)
DataManager.shareDataManager.mp.prepareToPlay()
DataManager.shareDataManager.mp.play()
DataManager.shareDataManager.curPlayStatus = 1
Async.main{
self.songTimeLabel.setText(Common.getMinuteDisplay(songLink.time))
}
HttpRequest.getLrc(songLink.lrcLink, callback: { lrc -> Void in
if let songLrc = lrc {
DataManager.shareDataManager.curLrcInfo = Common.praseSongLrc(songLrc)
//println(songLrc)
}
})
}
})

swift nearby api doesn't find beacons

I want to use my swift ios app to scan for beacons using google nearby api (not iBeacon api)
I saw Google developer doc, and I took the git sample from the same site.
Here is my code
I have installed the app on a real ios device for the first time
but the found and lost handlers are never called.
I doubled checked the bundle id, the public ios API key (same google console project of the beacon attachment)
but it still doesn't work near a working and registered beacon.
I also have an android app which succeeds in scanning the same beacon.
What else can I check?
I'm missing the "Strategy" piece of code in my swift code.
How can I add this? Why is this missing in the github example?
GNSStrategy *beaconStrategy = [GNSStrategy
strategyWithParamsBlock:^(GNSStrategyParams *params) {
params.includeBLEBeacons = YES;
}];
GNSSubscriptionParams *beaconParams = [GNSSubscriptionParams
paramsWithMessageNamespace:#"com.mycompany.mybeaconservice"
type:#"mybeacontype"
strategy:beaconStrategy];
_beaconSubscription = [_messageManager subscriptionWithParams:beaconParams
messageFoundHandler:myMessageFoundHandler
messageLostHandler:myMessageLostHandler];
in my code:
func startScanning() {
if let messageMgr = self.messageMgr {
// Subscribe to messages from nearby devices and display them in the message view.
subscription = messageMgr.subscriptionWithMessageFoundHandler({[unowned self] (message: GNSMessage!) -> Void in
self.mainViewController.location_text.text = (String(data: message.content, encoding:NSUTF8StringEncoding))
self.mainViewController.startRefreshTimer()
},
messageLostHandler: {[unowned self](message: GNSMessage!) -> Void in
if (self.mainViewController.userState.enrollState == EnrollState.confirmPosition)
{
self.mainViewController.stopRefreshTimer()
self.mainViewController.enrollButtonManager.setSearchingForBeaconsBtn()
}
})
}
}
You'll need to add the GNSStrategy to your subscription, which lets you enable beacon scanning. Try this:
let params: GNSSubscriptionParams = GNSSubscriptionParams.init(strategy:
GNSStrategy.init(paramsBlock: { (params: GNSStrategyParams!) -> Void in
params.includeBLEBeacons = true;
}))
subscription = messageMgr.subscriptionWithParams(params,
messageFoundHandler:{[unowned self] (message: GNSMessage!) -> Void in
self.mainViewController.location_text.text = (String(data: message.content, encoding:NSUTF8StringEncoding))
self.mainViewController.startRefreshTimer()
},
messageLostHandler: {[unowned self](message: GNSMessage!) -> Void in
if (self.mainViewController.userState.enrollState == EnrollState.confirmPosition) {
self.mainViewController.stopRefreshTimer()
self.mainViewController.enrollButtonManager.setSearchingForBeaconsBtn()
}
})
Beacon scanning is off by default because iOS presents the user with the location permission dialog when beacon scanning is first turned on, and this is unacceptable for apps that use the Nearby library but don't scan for beacons.
Thanks for the feedback about the github example not showing how to scan for beacons. I'll see about adding it.

'openParentApplication(_:reply:)' has been explicitly marked unavailable here - Xcode 7 Beta

After updating to Xcode 7 beta, I receive the following error message: "'openParentApplication(_:reply:)' has been explicitly marked unavailable here", when running the line of code "WKInterfaceController.openParentApplication"
Here is my actual code:
func getData(messageText: String) {
let infoDictionary = ["message" : messageText]
WKInterfaceController.openParentApplication(infoDictionary) {
(replyDictionary, error) -> Void in
if let castedResponseDictionary = replyDictionary as? [String: String],
responseMessage = castedResponseDictionary["message"]
{
print(responseMessage)
}
}
}
+[WKInterfaceController openParentApplication:] is only relevant for WatchKit1 app extensions because with WatchKit1 app extensions, the appex is running on the phone instead of on the watch.
With WatchKit2 app extensions, the appex is running on the watch, so actions such as this are less trivial to accomplish. You probably want to use -[WCSession sendMessageData:replyHandler:errorHandler:] from WatchConnectivity.framework for what you're doing.

How do I exactly use MMWormhole with Swift?

I have an iPhone application and added a WatchKitExtension. From the iPhone App I want to pass a String to the WatchApp which is supposed to change an image on the Watch.
What I already did was to download the source files and import the MMWormhole.m & .h. They are written in Obj-C and so Xcode automatically bridged them for me.
I also added an app group and activated it for my WatchExtension & my iPhone target
In the tutorial on GitHub it says I have to initialize the wormhole with:
self.wormhole = [[MMWormhole alloc] initWithApplicationGroupIdentifier:#"group.com.mutualmobile.wormhole"
optionalDirectory:#"wormhole"];
...and send a message using:
[self.wormhole passMessageObject:#{#"titleString" : title}
identifier:#"messageIdentifier"];
But I have actually no idea where to put that, I am using Swift in my iPhone application and the WatchExtension.
Can anyone please help me there?
I suppose it depends on different applications, but for one application I put the listeners in the didFinishLaunchingWithOptions method of my app delegate in the main iOS app. This was because the user would be using the watch, and they would be relaying information off to the phone
There were multiple listeners...
var wormhole = MMWormhole(applicationGroupIdentifier: "group", optionalDirectory: nil)
wormhole.listenForMessageWithIdentifier("identifier", listener: { (message) -> Void in
//do stuff
})
wormhole.listenForMessageWithIdentifier("identifier2", listener: { (message) -> Void in
//do stuff
})
wormhole.listenForMessageWithIdentifier("identifier3", listener: { (message) -> Void in
//do stuff
})
And then in a WKInterfaceController, I sent a message. Sometimes in an action, sometimes in the willActivate method. It really depends on the flow of your app
var wormhole = MMWormhole(applicationGroupIdentifier: "group", optionalDirectory: nil)
#IBAction func buttonPushed(){
wormhole.passMessageObject("object", identifier: "identifier1")
}
This can work both ways though, I could have very easily put a listener in my watch which would wait for messages initiated by some Interface Controller on the phone.
Here are my instructions. Hopefully they help you with the simplest use case and then you can expand from there. (Remember to structure your code so that it actually makes sense!)
Get MMWormhole (the .h and the .m) added to your project. If you know how to use Cocoapods, do that, but otherwise, just use git submodules. (I use git submmodules)
Because you need the .h to be visible from Swift, you need to use a bridging header.
Set up an App Group, which requires using the Developer Portal. Link is here
In your iPhone build target -> Capabilities -> App Groups and add your group. If all three checkboxes do not go perfectly, go back to the Developer Portal and make sure everything is right or start again.
MMWormhole, iPhone Side
Set up the wormhole somewhere you can reach it. NOTE: your group ID has to be the one from above!
let wormhole = MMWormhole(applicationGroupIdentifier: "group.testMe.now", optionalDirectory: nil)
wormhole.listenForMessageWithIdentifier("wormholeMessageFromWatch", listener: { (message ) -> Void in
if let messageFromWatch = message as? String {
// do something with messageFromWatch
}
})
iPhone App Sends String
wormhole.passMessageObject("message from phone to watch", identifier: "wormholeMessageFromPhone")
iPhone app registers to receive and sends again in the callback via MMWormhole (asynchronous but cool)
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
universe.initWormhole(.phone, messageHandler: { (message) -> () in
universe.wormhole.passMessageObject("the phone got \(message)", identifier: "wormholeMessageFromPhone")
})
return true
}
MMWormhole, Apple Watch Side
Set up the wormhole somewhere you can reach it. NOTE: your group ID has to be the one from above!
let wormhole = MMWormhole(applicationGroupIdentifier: "group.testMe.now", optionalDirectory: nil)
wormhole.listenForMessageWithIdentifier("wormholeMessageFromPhone", listener: { (message ) -> Void in
if let messageFromPhone = message as? String {
// do something with messageFromPhone
}
})
MMWormhole, watch app registers to receive
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
universe.initWormhole(.watch, messageHandler: { (message) -> () in
println("MMWormhole Message Came to Watch: \(message)")
})
}
MMWormhole, watch app sends
// force open the parent application because otherwise the message goes nowhere until the app is opened
WKInterfaceController.openParentApplication(["":""], reply: nil)
universe.wormhole.passMessageObject("[from watch to phone]", identifier: "wormholeMessageFromWatch")

Resources