Appcelerator iOS 12 Location - location

Are there new code changes to be made for iOS 12 when it comes to location services, as opposed to iOS 11?
I have the following code that works perfectly in iOS 11, but in iOS 12, even though it asks for the prompts as far as always/when in use, and I see the GPS icon, I get undefined on my e.coords.
var hasLocationPermission = Ti.Geolocation.hasLocationPermissions(Ti.Geolocation.AUTHORIZATION_ALWAYS);
if (hasLocationPermission) {
//this just calls the function, but it the e.coords comes back as undefined in iOS 12, fine in iOS 11
getLocation();
}
function getLocation() {
Ti.Geolocation.addEventListener('location', function (e) {
try {
longitude = e.coords.longitude;
latitude = e.coords.latitude;
} catch (err) {
console.log('err', err)
}
});
}

Make sure to include the iOS 11+ NSLocationAlwaysAndWhenInUseUsageDescription key in your plist, which became more important in iOS 12, because the prompt will suggest to use the less critical "when in use" permission if you do not include the above key. In addition, make sure to always first ask for the "when in use" permission and then upgrade to "always" later.
See the Ti.Geolocation docs for details.

Related

Unable to connect WKExtensionDelegate in Xcode 14 watch app

In the Apple developer docs chapter "There and Back Again" the watch app's App is written like this:
#main
struct MyWatchApp: App {
#WKExtensionDelegateAdaptor(ExtensionDelegate.self) var extensionDelegate
#SceneBuilder var body: some Scene {
WindowGroup {
NavigationView {
ContentView()
}
}
}
}
Unfortunately I get a purple runtime warning on my var declaration that says
#WKExtensionDelegateAdaptor should only be used within an extension based process
There must be something in Xcode that explicitly defines the App structure as "extension-based" but I can't find it!
Edit: More clarification... I am trying to handle the special method that gets called after you run the HealthKit method startWatchApp(with:completion:)
The special method for watch extensions is func handle(_ workoutConfiguration: HKWorkoutConfiguration)
I cannot seem to find a way to link this function on the new App structure for watch apps.
Ok, I found it. The solution is to simply replace WKExtensionDelegate with the new WKApplicationDelegate!
You can try this solution, it is simple and universal.
import WatchKit
class ExtensionDelegate: NSObject, WKExtensionDelegate {
static var current: ExtensionDelegate? {
return (WKExtension.shared().delegate as? ExtensionDelegate)
}
...
}
Then access this current instance like below, because it is Singleton, you can access it in the entire project scope.
ExtensionDelegate.current?.dosomething()

Xcode 12. Value of type 'AVCapturePhotoOutput' has no member 'supportedFlashModes'

In new Xcode 12, there is an error: Value of type 'AVCapturePhotoOutput' has no member 'supportedFlashModes' when i try to reach https://developer.apple.com/documentation/avfoundation/avcapturephotooutput/1648766-supportedflashmodes
Any suggestions?
Seems to be a bug on Xcode 12, but you can workaround it using macro conditions:
#if !targetEnvironment(simulator)
guard stillImageOutput?.supportedFlashModes.contains(mode) == true else { return }
//rest of your code
#endif
As #Andy Heard wrote:
Our apologies. For apps using Swift 3.2 or Swift 4.0, several
AVFoundation capture APIs (public extensions on external protocol)
were inadvertently marked private in Xcode 9.
The following AVFoundation API are temporarily unavailable:
AVCaptureDevice.Format.supportedColorSpaces
AVCaptureDevice.supportedFlashModes
AVCapturePhotoOutput.availablePhotoPixelFormatTypes
AVCapturePhotoOutput.availableRawPhotoPixelFormatTypes
AVCapturePhotoSettings.availablePreviewPhotoPixelFormatTypes
As a workaround you can use the SwiftPrivate versions of these API by
prepending each API with double underscore (__). For example, change
AVCaptureDevice.Format.supportedColorSpaces to
AVCaptureDevice.Format.__supportedColorSpaces.
For the XCode 12 regression (sigh), you can use the __ version like so
var flashModesSupported: [AVCaptureDevice.FlashMode] {
#if targetEnvironment(simulator)
return self.photoOutput.__supportedFlashModes.compactMap { AVCaptureDevice.FlashMode.init(rawValue: $0.intValue) }
#else
return self.photoOutput.supportedFlashModes
#endif
}
There was a report this did not trigger SPI (so, safe to submit to app store)
You can try this:
let device2 = AVCapturePhotoOutput()
if (device2.supportedFlashModes.contains(.auto)){
} else {
}

Xamarin iOS 13 check bluetooth permission without triggering a native popup

iOS 13 started to request Bluetooth permission. When bluetooth permission isn't granted yet, I want to show a custom screen to explain why I need the Bluetooth and suggest to give the app an access to it. Before that I have to check if bluetooth permission is granted or not.
This function immediately shows native popup and asks for the permission:
public bool NeedsBluetoothPermission()
{
if (UIDevice.CurrentDevice.CheckSystemVersion(13, 0))
{
return CBCentralManager.Authorization != CBManagerAuthorization.AllowedAlways;
}
else
{
return false;
}
}
Question: How to check if the app needs to request bluetooth permissions without triggering native popup first?
This answer doesn't work for me, as I don't create any instance of CBCentralManager yet, I only use its static property.
Native iOS developers, please chime in too. I guess it's not Xamarin problem only...
Another way is to use CBCentralInitOptions, where you can set "ShowPowerAlert" as false.
When you create the instance of CBCentralManager, pass the init option and it won't show a native popup
Finally, I figured this out.
This behavior was actual for iOS 13.0 beta.
For the latest iOS 13.2 I don't observe this issue.
I'm able to check CBCentralManager.Authorization property silently.
The system pop-up shows up when I create an instance of CBCentralManager.
In my case, CBCentralManager.Authorization does not exist. But CBPeripheralManager.authorization is a static class var that works with iOS 13+. Apple's documentation
- (void)checkBluetoothPermissionStatus:(CDVInvokedUrlCommand *)command
{
if (#available(iOS 13.1, *)) {
switch(CBPeripheralManager.authorization) {
case CBPeripheralManagerAuthorizationStatusAuthorized:
NSLog(#"CBP BLE allowedAlways");
[self requestBluetoothPermission: command]; // Further get the BLE on/off status once the permission is granted
break;
case CBPeripheralManagerAuthorizationStatusDenied:
NSLog(#"CBP BLE denied");
[self sendMessage:#"Denied" error:true command:command];
break;
case CBPeripheralManagerAuthorizationStatusNotDetermined:
NSLog(#"CBP BLE notDetermined");
[self sendMessage:#"Undetermined" error:true command:command];
break;
case CBPeripheralManagerAuthorizationStatusRestricted:
NSLog(#"CBP BLE restricted");
[self sendMessage:#"Restricted" error:true command:command];
break;
}
} else {
// Fallback on earlier versions
NSLog(#"CBP BLE unknown");
[self sendMessage:#"Unknown" error:true command:command];
}
}

Mac: Notification Center doesn't parse `loc-key` from my Push Notification Payload

I'm sending this to my Mac
{"aps":
{
"alert":{"loc-key":"F"},
"sound":"s"
}
}
and for whatever reason, the loc-key isn't parsed. I know it's in the Localizable, because if I call NSLocalizedString(userInfo["aps"]["alert"]["loc-key"]) it works perfectly, saying (for example) Hello World.
Also, if I have simply "alert":"F", the Notification says F. There's something I might be doing wrong with that loc-key. I can't find anywhere an information that would suggest loc-key only works on iOS.
The documentation from Apple mentions it on the Mac Developer Library just like on iOS.
A workaround for this Apple bug is to add an empty "loc-args" array when using "loc-key".
An example JSON string that works for both iOS and OSX is as follows:
{
"aps" : {
"alert" : {
"loc-key" : "contact_request",
"loc-args" : []
},
"badge": 8
}
}

Titanium : Camera crashes the application

I am using Titanium sdk's openCamera function to capture an image and storing it to sdcard.
function captureImage() {
var capturedImg;
Titanium.Media.showCamera({
success : function(event) {
/* Holds the captured image */
capturedImg = event.media;
/* Condition to check the selected media */
if (event.mediaType == Ti.Media.MEDIA_TYPE_PHOTO) {
var window1 = Project.AddDocumentSaveView.init(capturedImg, docImgModel);
window1.oldWindow = win;
Project.UI.Common.CommonViews.addWindowToTabGroup(window1);
activityInd.hide();
}
},
cancel : function() {
},
error : function(error) {
/* called when there's an error */
var a = Titanium.UI.createAlertDialog({
titleid : Project.StringConstant.IMP_DOCS_CAMERA
});
if (error.code == Titanium.Media.NO_CAMERA) {
a.setMessage(Project.StringConstant.IMP_DOCS_ERROR_WITH_CAMERA);
} else {
a.setMessage(Project.StringConstant.UNEXPECTED_ERROR + error.message);
}
a.show();
}
});
}
It works fine in iphone and even samsung galaxy s2. But on one device, Motorola Milestone device, the application crashes when the picture is accepted after capturing.
Here is the log while the device was attached : Log for camera crash
I tried so many times but couldnt find the issue .I think its some memory issue but i am not sure.
Could someone look into it and help me find what the issue is.
Any help/suggestions will be appreciated.
Thanks
everything in this block should be done after the camera is close
if (event.mediaType == Ti.Media.MEDIA_TYPE_PHOTO) {
}
the camera is memory intensive and you are opening new windows and doing a bunch of other stuff... not good.
This is an aging issue on Titanium (TIMOB-12848
On some devices the native camera app (Titanium calls it using an Intent) cause Android to destroy our app.
When it tries to restart it, there's no recovering of the previous state so the intent callback is not called.
I've found a simple workaround to minimize this issue but doesn't resolve it. It just "mask" it somehow.
The workaround is discussed in the previous link and the full example code is here

Resources