Posts

Post not yet marked as solved
2 Replies
2.1k Views
I am trying to send a simple JSON to a connected Bluetooth peripheral but getting some problems in the process.The properties read from the peripheral in the didDiscoverCharacteristicsFor method are the following:po characteristic.properties ▿ CBCharacteristicProperties - rawValue : 10Which as this is a mask and if I am not mistaken this states that I can read (2) and write (8) from/to the device.I am writing the data as soon as I discover a new characteristic that matches the requirements in the following wayfunc peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService,error: Error?) { for characteristic in service.characteristics! { let characteristic = characteristic as CBCharacteristic print(characteristic.uuid) if characteristic.uuid.isEqual(RX_UUID) { // Received only support for writing with response, writing without response is not allowed if characteristic.properties.contains(CBCharacteristicProperties.write) { self.writeJsonStringToPeripheral(peripheral: peripheral, characteristic: characteristic, writeType: .withResponse) } else if characteristic.properties.contains(CBCharacteristicProperties.writeWithoutResponse) { self.writeJsonStringToPeripheral(peripheral: peripheral, characteristic: characteristic, writeType: .withoutResponse) } } } } func writeJsonStringToPeripheral(peripheral: CBPeripheral, characteristic: CBCharacteristic, writeType: CBCharacteristicWriteType) { do { let msgDictionary = ["SSID": self.wiFiCredentials.SSID, "Password": self.wiFiCredentials.Password] let jsonData = try JSONSerialization.data(withJSONObject: msgDictionary, options: []) //let data = "".data(using: .utf8) peripheral.writeValue(jsonData, for: characteristic, type: writeType) } catch let error as NSError { debugPrint("Error in auth message JSON: \(error.description)") This snippet calls the function at line 10 indicating the possibility of writing with a response and after callign it the didWriteValueFor delegate method is called.func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) { if let error = error { print(error) } else { print("Value writen sucessfully.") } }Printing the following error.Error Domain=CBATTErrorDomain Code=3 "Writing is not permitted." UserInfo={NSLocalizedDescription=Writing is not permitted.}I've made myself sure that the device is connected and I can also see it in the Settings.app. I am a bit lost and I don't know what could be going on here.On the other side if I force the writing to be withoutResponse I get another console log2020-03-25 22:23:50.286662+0100 Cloudy[2595:1232291] [CoreBluetooth] WARNING: Characteristic does not specify the "Write Without Response" property - ignoring response-less writeAfter sending the specified JSON to the device it should start a sequence to connect to the specified WiFi SSID. I am sure the hardware works because I can set those values using the console on the device itself and the process works so there must be something I am missing here that causes this to fail.This test has been done using an iPhone 6S running ios 13.3.1.
Posted Last updated
.
Post not yet marked as solved
4 Replies
1.3k Views
I am querying heart rate samples taken during a workout. For all of the mentioned cases below I'm wearing an Apple Watch and using the stock Workouts.app in the watch. If I query heart rate samples for a recent workout, it being yesterday or the past month for example, I get the full samples. If I query a workout let's say, two/three months in the past the samples I get back look "choppy" with a lot of missing data. (See attached image) imgur.com/a/FbMSBoa How am I getting the heart rate samples? swift extension HKHealthStore: HKHealthStoreCombine {     public func getT(sample: T, start: Date, end: Date, limit: Int = HKObjectQueryNoLimit) - AnyPublisher[HKQuantitySample], Error where T: HKObjectType {         let subject = PassthroughSubject[HKQuantitySample], Error()                 let sampleType = HKSampleType.quantityType(forIdentifier: HKQuantityTypeIdentifier(rawValue: sample.identifier))!         let predicate = HKQuery.predicateForSamples(withStart: start, end: end)                  let query = HKSampleQuery(sampleType: sampleType, predicate: predicate, limit: limit, sortDescriptors: nil, resultsHandler: { (query, samples, error) in             guard error == nil else {                 logger.error("Error fetching samples of type \(sample.description) from \(start) to \(end) with a limit of \(limit): \(error!.localizedDescription)")                 subject.send(completion: .failure(error!))                 return             }             let samples = samples as? [HKQuantitySample] ?? []             logger.log("Successfully fetched \(samples.count) samples of type \(sample.description) from \(start) to \(end) with a limit of \(limit)")             subject.send(samples)             subject.send(completion: .finished)         })         self.execute(query)         return subject.eraseToAnyPublisher()     } } swift healthStore.get(sample: HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.heartRate)!, start: workout.startDate, end: workout.endDate)             .map({                 $0.compactMap({ $0.quantity.doubleValue(for: UserUnits.shared().heartCountUnits) })             })             .replaceError(with: [])             .receive(on: DispatchQueue.main)             .sink(receiveValue: {                 self.heartRate = $0             })             .store(in: &bag) Is this some kind of wrong way that I am working with HealthKit? I don't know what the issue can be but it looks like accessing heart samples in the "past" are somewhat archived and I don't get the full resolution.
Posted Last updated
.
Post not yet marked as solved
2 Replies
1.7k Views
I am trying to read the [appStoreReceiptURL](https://developer.apple.com/documentation/foundation/bundle/1407276-appstorereceipturl#) to read the receipt in hopes to find the initial date of purchase or initial version the user has. The plan to use this is to migrate from a paid upfront version to a free + IAP as many might have done over the years. I know I am under a sandbox environment, while I develop this, so the path is file:///.../StoreKit/sandboxReceipt. Currently, I don't require neither local or remote validation of the receipt for the time being so I only need to read the file. Checking if it exists using the FileManager it says that it doesn't so I start a SKReceiptRefreshRequest to retrieve a copy of the receipt from Apple's servers. I know that receipt won't have the exact data I am looking for but as far as I know it will give me an initial install version field for this environment that's 1.0 so it'd work for testing purposes. After setting the SKRequestDelegate and starting the request when the receipt is not found neither the requestDidFinish nor didFailWithError delegate methods are called. Currently I am not able to retrieve any copy of even a "sample" receipt for the sandbox environment. This sample code I am using it's pretty simple so far and is as follows, import StoreKit @objc class ReceiptFetcher : NSObject, SKRequestDelegate { 	let receiptRefreshRequest = SKReceiptRefreshRequest() 	 	override init() { 		super.init() 		receiptRefreshRequest.delegate = self 	} 	 	@objc 	func fetchReceipt() { 		guard let receiptUrl = Bundle.main.appStoreReceiptURL else { 			print("unable to retrieve receipt url") 			return 		} 		 		do { 			// if the receipt does not exist, start refreshing 			let reachable = try receiptUrl.checkResourceIsReachable() 			 			// the receipt does not exist, start refreshing 			if reachable == false { 				receiptRefreshRequest.start() 			} 		} catch { 			print("error: \(error.localizedDescription)") 			/* 			 error: The file “sandboxReceipt” couldn’t be opened because there is no such file 			 */ 			DispatchQueue.main.async { 				self.receiptRefreshRequest.start() 			} 		} 	} 	 	// MARK: SKRequestDelegate methods 	func requestDidFinish(_ request: SKRequest) { 		print("request finished successfully") 	} 	 	func request(_ request: SKRequest, didFailWithError error: Error) { 		print("request failed with error \(error.localizedDescription)") 	} } This is being called from the AppDelegate to first of all request a fresh receipt or load one if it's not present. Currently I am testing this using an iPad with my Apple ID logged in but under Settings.app --> App Store --> Sandbox Account I've logged in with a sandbox account created inside the development team which this app is published under that account. Do I need to enable IAP in the AppStore Connect account so I am able to retrieve receipts? Is receipt validation strictly necessary in this case? I wouldn't need to validate against some third party as the initial purchase has been through the App Store. I would want to only read the fields of the receipt that show information on the initial purchase date/version. I remember did this some time ago with another app that was free but with an IAP. And AFAIK every app, either paid or free, has a receipt attached with this kind of information but being currently on a sandbox environment I am a bit confused. I haven't found anything so far that's relevant and can point me towards what's going on. Running iOS 14b3 and Xcode 12b3.
Posted Last updated
.
Post not yet marked as solved
0 Replies
419 Views
I am running several cron jobs on a Mac server. Some time ago I don't know why I deactivated the cron logs into the local mail of the system. I now am getting errors running those cronjobs and I am not able to take a look at the logs as they are not generated.Is there a way to reactivate this behavior?I tried adding this line on top of the cronjob definition file, cronjob -eMAILTO="/var/mail/MY_USERNAME"With no result, previously whenever a cron ran I was getting on the console a message indicating that I had new mail as the result has been appended to the mail. I can't seem to reactivate this behavior and when I open `mail` from console the inbox is empty.
Posted Last updated
.
Post not yet marked as solved
3 Replies
1.3k Views
While implementing a VPN using the Packet Tunnel Network Extension framework I've stumbled upon different problems I cannot see well documented.I am monitoring the changes in the interface and its status observing defaultPath. How should I react to the interface changes.Should I reset my tunnel when I go from WiFi to Cellular? Or should I reconnect it? I want to guarantee that when I perform an interface change my Internet traffic goes out using the tunnel interface.What should I do when the status changes in NWPathStatus changes? I am having trouble when my status changes from WiFi (satisfied) to WiFi (satisfied). The VPN is still up but the outgoing traffic doesn't use the tunnel interface. I don't want to cancelTunnelWithError(_:) every time I see an interface change. While this solves the problem and forces the traffic to go out using the tunnel interface as it's reestablishing the tunnel again and again it drains the battery and it's not the correct approach. Specially when at home there are constant WiFi (satisfied) to WiFi (satisfied) network changes that I don't wrap my head around what they can mean.How should I manage these changes when the device goes to and from sleep? There's a property, reasserting that specifies when the tunnel starts to reconnect, should I modify it when the device goes to sleep or when it wakes? And should I cancel or reconnect the tunnel when the device comes from sleep?I haven't found much information on this so if someone could guide me a bit on how to solve this it'd be great.
Posted Last updated
.
Post marked as solved
4 Replies
2.2k Views
I have been working on a Packet Tunnel Network Extension that establishes a VPN connection with a server. The main purpose is to block websites that the VPN server considers safe websites when resolving the DNS. If the website is considered as safe it will resolve the website and allow traffic.This solution is implemented by establishing a VPN tunnel using the OpenVPN protocol.As per reading the documentation I see there is a difference being made between always on VPN and on demand VPN. What I can see is that I can implement an on demand VPN for example by distributing my app in the App Store. What I can't do is implement an always on VPN if it's not by managing devices. This coulnd't be an option for us.I would like to know if there are specifications or part in the documentation that can answer some of these questions:* Are the VPN connections shut down when the device goes to sleep? I can see this because my device does it but haven't seen this in the documentation.* Can I establish an always on VPN without having supervised devices? I can reset my VPN when my network interface changes and try to have my "always on" implementation.* In some part of the documentation they mention that for iOS devices there are two virtual interfaces, one for Cellular and the other for Wi-Fi. My NEPacketTunnelProvider does not differentiate between two `tun` interfaces, so is this only for managed devices?* Are the VPN tunnels time restricted? I don't know if I am having too many problems with this or this is something hard to work with but the tunnel seems to disconnect after a while when the device goes to sleep.* If I cannot establish an always on and I cannot force my traffic to go out of my tun interface, would establishing an IPSec tunnel another viable option? AFAIK an IPSec tunnel would not have to touch anything below the network layer so we wouldn't have a problem when the traffic is not routed via the tunnel interface.There are several apps in the App Store like Bear Tunnel and NordVPN and they have/sell an always on service. Is this some kind of special entitlement we have to get to have this capabilities?Thank you.
Posted Last updated
.
Post marked as solved
1 Replies
877 Views
I am working on a VPN Packet Tunnel Network Extension. When I run it from Xcode 11b5 it works perfectly but if I run it from Xcode 10.2.1 the Tunnel Extension crashes. I have to check the Console for the device to see that is has crashed because Xcode does not point a crash has occured. What I see in the console is this (all is from the Network Extension, another target),NEProvider objects cannot be instantiated from non-extension processes *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSDictionaryM setObject:forKey:]: object cannot be nil (key: A8EDB519-3197-4907-92E2-17DCE552D3A1)' *** First throw call stack: (0x21357a98c 0x2127539f8 0x2134f43f8 0x213469228 0x213f98dd4 0x213f98644 0x212fb8a38 0x212fb97d4 0x212f62324 0x212f62e40 0x212f6b4ac 0x21319a114 0x21319ccd4) Failed to start extension com.me.MyApp.tunnel-extension: Error Domain=NSCocoaErrorDomain Code=4097 "connection to service named com.me.MyApp.tunnel-extension.apple-extension-service" UserInfo={NSDebugDescription=connection to service named com.me.MyApp.tunnel-extension.apple-extension-service} Extension com.me.MyApp.tunnel-extension died unexpectedlyI have set up an Exception Breakpoint but it does not trigger and I am a bit stuck on what to do. As per I have read it might be related to an issue in the entitlements but I don't know if it runs on Xcode 11b5 why it shouldn't in Xcode 10?Entitlements for my app<dict> <key>com.apple.developer.networking.networkextension</key> <array> <string>packet-tunnel-provider</string> </array> <key>com.apple.security.application-groups</key> <array> <string>group.com.me.MyApp</string> </array></dict></plist>And for my extension<dict> <key>com.apple.developer.networking.networkextension</key> <array> <string>packet-tunnel-provider</string> </array> <key>com.apple.security.application-groups</key> <array> <string>group.com.me.MyApp</string> </array></dict></plist>
Posted Last updated
.
Post not yet marked as solved
0 Replies
550 Views
I am tunnelling my traffic through a server. In some cases it has to block determinate websites, e.g. gambling sites. The tunnel works without a problem if I start the tunnel with WiFi or Cellular. When I change the network to the opposite the VPN reconnects automatically as I am using on demand VPN but the VPN doesn't block the websites it did before. My main supposition is that after changing the interface, WiFi to Cellular or vice versa, the outgoing traffic from the device it is not routed through the tunnel interface (utun) but the VPN is still up.How could I check or "force" the outgoing traffic through my tunnel interface?I can detect when the interface changes and I could force restart the tunnel but I shouldn't do it. That should be the tunnel's task and I prefer not to force the tunnel's state.As I see in Session 717 from 2015 WWDC the VPN connnection is stablished and then goes down level by level in the Internet stack until the interface level. When the VPN has been stablished it uses the utun0 interface. My fear is when I stablish, for example, a tunnel using Wi-Fi connection it correctly routes the traffic out using the utun0 interface but when I change to the Cellular connection it uses another interface therefore my tunnel is still up but it doesn't apply the content blocking because the packets are not routed using the utun0 interface.EDIT, I've just discovered defaultPath. Using KVO I am able to monitor interface changes. When I detect a interface change I try to reconnect the tunnel. In some cases I am able to solve the issues I had before and the blocking is applied but in other cases it does not. I'm trying to monitor the cases in which the interface changes and if the connection is established but I cannot wrap my head around all the possible cases.
Posted Last updated
.
Post marked as solved
1 Replies
1.3k Views
Currently working on a Network Extension that lets me stablish a connection using a .ovpn file using a library. I have saved correcly my configuration to the System settings and when running the extension to perform debug my extension status changes from disconnected, stays in connecting for a while and then disconnects. Further inspecting the console logs for the device anf filtering by the network extension I get three main error messages.Log message from provider: TUN Error: cannot acquire tun interface socket SIOCGIFMTU failed: Device not configured NEVirtualInterfaceAdjustReadBufferSize: interface_get_mtu failed (6), defaulting to max mtu
Posted Last updated
.