I am working on a project to pass data from an Apple Watch App to the iPhone App using Appgroups. My code is not working and I am not sure why. Hopefully someone can help me out! :)
Sending Data Apple Watch
#IBAction func senddata() {
let group = "group.pairedapp"
let shared = UserDefaults(suiteName: group)
let ok = "works"
shared!.setValue(ok, forKey: "status")
shared!.synchronize()
}
Getting Data on iPhone
#IBAction func getWatchData(_ sender: Any) {
let group = "group.pairedapp"
let shared = UserDefaults(suiteName: group)
let get = shared!.value(forKey: "status")
if get != nil {
print("works")
}
else{
print("OO NO!")
}
}
Since the introduction of watchOS2, watchOS apps are no longer considered just extensions of their iOS counterpart and hence you cannot use AppGroups to share data between the two.
You should use the WatchConnectivity framework on watchOS2+ to share data between your watchOS and iOS apps.
For more information, see the Sharing Data part of the WatchKit Programming Guide.
Related
In my scenario, I'm sharing data between the parent iOS app and notification service extension. I'm using Xcode 10.2.1, iOS Deployment Target 10.0
We have tried the NSUserDefaults and Keychain group it's working as expected. Is any other way to save the values(Store Model or datatypes) from notification service extension(TargetB) to MainApp(TargetA).
We have appended the values into the model once the app is in terminated state and save it in the keychain.
For saving to Keycahin:
NotificationAPI.shared.NotificationInstance.append(Notifications(title: messageTitle, message: messageBody,date: Date()))
let notification = NotificationAPI.shared.NotificationInstance
let value = keychain.set(try! PropertyListEncoder().encode(notification), forKey: "Notification")
For USerDefault :
var defaults = NSUserDefaults(suiteName: "group.yourappgroup.example")
I want to transfer the data from Target B to Target A. when the app is in an inactive state? Another to transfer or saving data? Please help me?
Maybe I didn't get the question correctly.
You can share data between the app through CoreData:
Here it is explained.
In general, you need to add the extension and the main app in a group and to add your xcdatamodeled file in the target of the extension.
I think UserDefaults, Keychain, CoreData, iCloud, and storing data to your backend from where the other app take it is all the options that you have.
Add below property in your VC.
var typeArray = [DataModelType]()
let path = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.ABC.app")?.appendingPathComponent("type.plist")
DataModel which you want to share
struct DataModelType: Codable {
//define properties which you wanna use.
}
Add Extention to ViewController
extension ViewController {
fileprivate func saveData() {
let encoder = PropertyListEncoder()
do{
let dataEncode = try encoder.encode(typeArray)
try dataEncode.write(to:path!)
}
catch{
print("Error")
}
}
fileprivate func loadData() {
if let data = try? Data(contentsOf: path!) {
let decoder = PropertyListDecoder()
do {
typeArray = try decoder.decode([DataModelType].self, from: data)
}
catch {
print("Error")
}
}
}
func fetchDataModel() -> DataModelType {
loadData()
return typeArray
}
}
In your extension add below code wherever you wanna access data.
let viewController = ViewController()
let currentDataModel = viewController.fetchDataModel()
When I open the iOS Facebook app with
fb://profile/44083897053
the app opens and goes to the proper page as expected.
When I use
fb://profile/philamuseum
the app opens, but I am taken to my timeline.
Can anyone explain why this is happening?
The code being used is:
#IBAction func gotoFacebook(_ sender: Any) {
UIApplication.tryURL(urls:["fb://profile/\(self.facebookUser)/", "https://www.facebook.com/\(self.facebookUser)"])
}
. . . .
extension UIApplication {
class func tryURL(urls: [String]) {
let application = UIApplication.shared
for url in urls {
if application.canOpenURL(URL(string: url)!) {
application.open(URL(string: url)!)
return
}
}
}
I've looked at number of questions re opening facebook from an iOS app here and elsewhere and have not found any recent answer that bears on this issue.
I need to store data that's controlled by the main Watch app (and the iPhone app) and displayed in a complication.
The official Apple documentation says
If you need to fetch or compute the data for your complication, do it
in your iOS app or in other parts of your WatchKit extension (for
example, by scheduling a background app refresh task), and cache the
data in a place where your complication data source can access it.
What do they have in mind when they tell you to cache the data in a place where the complication can access it? What is the best practice/standard way to achieve this?
You could store some data in UserDefaults, and access that from your complication data source.
ie.
//In a background task
func getComplicationData(){
let yourData = someNetworkCall()
/*
yourData = [
"complicationHeader": "Some string",
"complicationInner": "Some other stirng"
]
*/
UserDefaults.standard.set(yourData, forKey: "complicationData")
}
Then in your ComplicationDataSource
func getCurrentTimelineEntry(for complication: CLKComplication, withHandler handler: #escaping (CLKComplicationTimelineEntry?) -> Void) {
if let yourData = UserDefaults.standard.dictionary(forKey: "complicationData") as? [String: String] {
//Handle setting up templates for complications
}
}
i am trying to access the mobile data/ cellular data setting page which lists all the apps that have access to mobile/cellular data or internet.
I tried the below code:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let currentCell = featuresTable.cellForRow(at: indexPath)! as! HomeTableViewCell
if(currentCell.featureName!.text == "Internet Permissions")
{
// The code to enter the mobile data settings
let url = URL(string: "App-Prefs:root=MOBILEDATA")
let app = UIApplication.shared
app.openURL(url!)
}
}
Here the Output i want:
It is possible.! but the standard approach is to always open your App Setting Screen which is done by below code.All the Apps like Uber,Facebook etc use the below approach.
the below code is written in
Swift 3
Plus the Code also checks the ios version and does the job for all versions, Also a little bit Explanatory
if let url = URL(string: UIApplicationOpenSettingsURLString){
if #available(iOS 10.0, *){
UIApplication.shared.open(url, completionHandler: nil)
print("\n--- in ios 10 ")
} else{
UIApplication.shared.openURL(url)
print("\n--- in ios other than 10 ")
}
}
UIApplicationOpenSettingsURLString : Basically opens your app's settings, Also It shows all the Services being used by app Including Locations Services,Mobile Data, Photo Library etc...
Now to add Cocoa Keys to your app i.e. in plist file
Here are some url's
Cocoa keys for iOS 10, Cocoa Keys from developer.apple
Hope it helps...
i am not sure about mobile data.
you can open app settings as follow
UIApplication.shared.openURL(URL(String:UIApplicationOpenSettingsURLString))
I wonder if we can share datas between apps with the new iOS 8 feature : App groups (using NSUserDefaults) - Or if App Groups only share datas between the main app and its extension?
I actually enabled the App Groups feature on both of the apps that should share datas between them (they belong the same company). They also have the same App Groups thing (like group.com.company.myApp).
Here's the code on the first one (in Swift)
NSUserDefaults.standardUserDefaults().setBool(true, forKey:"Bool")
NSUserDefaults.standardUserDefaults().synchronize()
And here's the code on the second one (in Objective-C)
NSUserDefaults *datas = [[NSUserDefaults alloc] initWithSuiteName:#"group.com.company.myApp"];
NSLog(#"%#", [datas boolForKey:#"Bool"]);
Sadly, the Bool always returns nil.
If anyone has a solution :)
Thanks
Check out this thread on the Apple Developer Forums:
https://devforums.apple.com/message/977151#977151
I believe that both instances need to use the group ID (initializing with initWithSuiteName:) or else they are reading/writing to different user defaults sets.
So your Swift code would change to:
var userDefaults = NSUserDefaults(suiteName: "group.com.company.myApp")
userDefaults.setBool(true, forKey: "Bool")
userDefaults.synchronize()
App Groups no longer work in WatchOS2. You must use the watch connectivity Framework.
in your iOS App:
import UIKit
import WatchConnectivity
class ViewController: UIViewController, WCSessionDelegate {
override func viewDidLoad() {
super.viewDidLoad()
if (WCSession.isSupported()) {
let session = WCSession.defaultSession()
session.delegate = self
session.activateSession()
}
do {
let applicationDict = ["key" : "value"]
try WCSession.defaultSession().updateApplicationContext(applicationDict)
} catch {
// Handle errors here
}
}
}
In your Watch OS2 App:
import WatchKit
import WatchConnectivity
import Foundation
class InterfaceController: WKInterfaceController, WCSessionDelegate {
func session(session: WCSession, didReceiveApplicationContext applicationContext: [String : AnyObject]) {
print(applicationContext)
}