How to access Camera, Calendar, Photos, Microphone, Location, Media Library, Motion, Speech Recognition, SiriKit, TV Provider in iOS 10 - camera

I am developing my app for iOS 10, but my default iOS functionality extensions not working well. Like am not able to access camera, Microphone and media Library. Every time it got crashed. I have written all, but nothing working.
case .Authorized:
picker!.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
if UIDevice.currentDevice().userInterfaceIdiom == .Phone
{
self.presentViewController(picker!, animated: true, completion: nil)
}
break
//handle authorized status
case .Denied, .Restricted :
print("Denied")
let alertController = UIAlertController (title: appName, message: "Go to Settings?", preferredStyle: .Alert)
let settingsAction = UIAlertAction(title: "Settings", style: .Default) { (_) -> Void in
let settingsUrl = NSURL(string: UIApplicationOpenSettingsURLString)
if let url = settingsUrl {
UIApplication.sharedApplication().openURL(url)
}
}
let cancelAction = UIAlertAction(title: "Cancel", style: .Default, handler: nil)
alertController.addAction(settingsAction)
alertController.addAction(cancelAction)
presentViewController(alertController, animated: true, completion: nil)
break

A significant change in iOS 10 is that you must declare ahead of time any access to private data or your App will crash. The fix is quick but easy to overlook if the usage is not a major feature of an App so here is your reminder if you are planning an iOS 10 migration.
Don’t Forget Your Purpose Strings
Once you link with iOS 10 you must declare access to any user private data types. You do this by adding a usage key to your app’s Info.plist together with a purpose string. The list of frameworks that count as private data is a long one:
Contacts, Calendar, Reminders, Photos, Bluetooth Sharing, Microphone, Camera, Location, Health, HomeKit, Media Library, Motion, CallKit, Speech Recognition, SiriKit, TV Provider.
If you are using one of these frameworks and fail to declare the usage your app will crash when it first makes the access. The crash log helpfully tells you which key you are missing. For example, this is the result of accessing the camera without adding the key to Info.plist:
This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app’s Info.plist must contain an NSCameraUsageDescription key with a string value explaining to the user how the app uses this data.
To avoid the crash we need to add the suggested key to ‘Info.plist’ (Xcode 8 already contains the full list of possible keys):
The system shows the purpose string when asking the user to allow access (so you may want to localize it):
The direction from Apple is clear. If you access private data declare your intentions up front or expect your App to crash.
You can check all privacy settings key for apple documentation : Privacy setting keys for iOS10

Related

Change the default camera app in Windows 10 desktop

How to change the default camera app in Windows 10 desktop ? The option is available from Settings in Phones but not from Desktops
If you want to make 'advanced' photo capture, then you can use MediaCapture class. Everything about this you will find at MSDN. There are also quite nice samples at GitHub.
It also seems that my old post for WinRT is still quite relevant. You will find there that I'm using GetCameraID:
private static async Task<DeviceInformation> GetCameraID(Windows.Devices.Enumeration.Panel desired)
{
DeviceInformation deviceID = (await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture))
.FirstOrDefault(x => x.EnclosureLocation != null && x.EnclosureLocation.Panel == desired);
if (deviceID != null) return deviceID;
else throw new Exception(string.Format("Camera of type {0} doesn't exist.", desired));
}
to choose a device to be used to capture the photo. In your app you can enumerate devices and choose the one that suits you.

How do I intercept downloads from a WKWebView?

I am making a Cocoa app that involves users selecting pictures from online for use within the app. I am also looking to collect contextual metadata from those downloads, such as the host the image came from, the website the user was visiting, the exact MIME type in the response headers, etc.
Basically I want to curate my user across the internet, downloading images and metadata into that user's account as I go. Until today I thought this would be impossible.
But just recently I was toying with a WKWebView and I tried right clicking on an image. I saw this...
Is there any way I could connect to that Download Image button, and get notifications when its clicked?
I did figure out how to make "Download Linked File" work and its a doozy that will not fit in a SO answer: https://github.com/kfix/MacPin/commit/9e5f925819f7f54ef29baff1e90783b820e683a3
However implementing those private delegate functions doesn't seem to allow "Download Image" to signal my WkWebView app in any way.
You can intercept those non-working "Download Image" and "Download Linked File" menu items by subclassing the WKWebView class and implementing the willOpenMenu method like this:
class MyWebView: WKWebView {
override func willOpenMenu(_ menu: NSMenu, with event: NSEvent) {
for menuItem in menu.items {
if menuItem.identifier == "WKMenuItemIdentifierDownloadImage" ||
menuItem.identifier == "WKMenuItemIdentifierDownloadLinkedFile" {
menuItem.action = #selector(menuClick(sender:))
menuItem.target = self
}
}
}
func menuClick(sender: AnyObject) {
if let menuItem = sender as? NSMenuItem {
Swift.print("Menu \(menuItem.title) clicked")
}
}
}
Instead of this you can also simply hide the menu items with menuItem.isHidden = true
Detecting the chosen menu item is one thing, but knowing what the user actually clicked in the WKWebView control is the next challenge :)

Can I preload the web content for Safari View Controller?

I can create Safari View Controller without problem:
let svc = SFSafariViewController(URL: NSURL(string: remote_url)!, entersReaderIfAvailable: true)
self.presentViewController(svc, animated: true, completion: nil)
Is there any way I can preload the URL before I present the view controller to the user?
For example, I can preload the URL (web content) in the background first, and after the user clicks on something, I can show the Safari View Controller with the content right away. The user will feel the page loading is faster or instant.
P.S. Workarounds/hacks are also acceptable. For example, using cache or starting the view controller in background, etc.
EDIT: please consider SFSafariViewController only.
Here is a solution.
Obviously, if you click on the button right away you'll see the loading.
But basically, I load the Browser and put the view behind another one and I put a button in this other view.
When you press the button, the browser is bring to the front, already loaded.
The only problem here is that I'm not using any transition but that's one solution at least.
import UIKit
import SafariServices
class ViewController: UIViewController {
var svc = SFSafariViewController(URL: NSURL(string: "https://microsoft.com/")!, entersReaderIfAvailable: true)
var safariView:UIView?
let containerView = UIView()
let btn = UIButton()
override func viewDidLoad() {
super.viewDidLoad()
//let tmpView = svc.view
addChildViewController(svc)
svc.didMoveToParentViewController(self)
svc.view.frame = view.frame
containerView.frame = view.frame
containerView.backgroundColor = UIColor.redColor()
safariView = svc.view
view.addSubview(safariView!)
view.addSubview(containerView)
btn.setTitle("Webizer", forState: UIControlState.Normal)
btn.titleLabel!.textColor = UIColor.blackColor()
btn.addTarget(self, action: "buttonTouched:", forControlEvents: .TouchUpInside)
btn.frame = CGRectMake(20, 50, 100, 100)
containerView.addSubview(btn)
view.sendSubviewToBack(safariView!)
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func buttonTouched(sender: AnyObject) {
view.bringSubviewToFront(safariView!)
//self.presentViewController(svc, animated: true, completion: nil)
}
}
Sadly this behaviour is not supported with the current implementation of SFSafariViewController. I would encourage filing a radar with Apple to add support for this behaviour but like others have suggested your best bet is to use WKWebView and start loading before its added to the hierarchy.
I came across a lovely radar from Twitter that actually mentions exactly what you're asking for. I think you might find the following requests useful:
High Priority:
- Ability to warm the SFSafariViewController before actually presenting it with a URL, URL request, HTML data or file on disk
- Currently, are investing heavily into warming the shared URL cache for high priority Tweets so that if the user hits that Tweet we
will open UIWebView (sadly not WKWebView) with that pre-cached web
page. If we could just warm an SFSafariViewController with the
desired link, this would eliminate an enormous amount of effort on our
end.
You can see in their implementation they simply cache responses using UIWebView since WKWebView seems to obfuscate the caching semantics a bit. The only risk is that UIWebView is a likely candidate for deprecation as you see in their docs "In apps that run in iOS 8 and later, use the WKWebView class instead of using UIWebView."
So unfortunately it seems that their are many hoops you need to jump through to get this all going so your best bet for now is to just pester Apple and dupe Twitters radar.
You could try using a http cache, but I don't think it would work as the Safari View Controller is working as a separate process (probably the same as Safari), so that's why it e.g. circumvents ATS.
The only way I can think of this working is to somehow force the user's Safari to load it? openURL: or adding to Reading List maybe? This doesn't sound like a viable solution.
You can always experiment with custom presentation of the view controller, attach it the view hierarchy, trigger appearance events, but set its frame to CGRectMake(0,0,1,1) or attach it somewhere off-screen, then wait a while and represent it with a correct frame.
you can download the web page using the following code . and represent it with the help of svc
let data:NSData?
do {
let weatherData = try NSData(contentsOfURL: NSURL(string: remote_url)!, options: NSDataReadingOptions())
data = weatherData
print(weatherData)
} catch {
print(error)
}
and load it when you needed in the svc
While it's technically possible to use the solution above to achieve what you're asking, this may not pass App Store review. Per the SFSafariViewController docs:
In accordance with App Store Review Guidelines, this view controller must be used to visibly present information to users; the controller may not be hidden or obscured by other views or layers. Additionally, an app may not use SFSafariViewController to track users without their knowledge and consent.

AVCaptureDevice - iphone/ipad as video source

Can AVCaptureDevice be used (objective-c or Swift) to access an iOS device as a camera source, when it is connected via a lightning cable, very much like Quicktime does for OSX Yosemite?
Quicktime select camera source image
If not, is there any other way to capture it?
I'm using AVCaptureDevice.devices() (in swift) but it only lists the built-in Mac camera and mic.
Found the solution for this (thanks Chris Adamson), after looking at a presentation on WWDC where Apple announced this capability - fast forward to 4:09.
The following CMI property needs to be set before AVCaptureDevice can detect the iOS device as a camera/capture device (example in Swift):
var prop : CMIOObjectPropertyAddress = CMIOObjectPropertyAddress(
mSelector: CMIOObjectPropertySelector(kCMIOHardwarePropertyAllowScreenCaptureDevices),
mScope: CMIOObjectPropertyScope(kCMIOObjectPropertyScopeGlobal),
mElement: CMIOObjectPropertyElement(kCMIOObjectPropertyElementMaster))
var allow:UInt32 = 1
CMIOObjectSetPropertyData( CMIOObjectID(kCMIOObjectSystemObject),
&prop,
0,
nil,
UInt32(sizeofValue(allow)),
&allow)
After this is done (e.g. in your AppDelegate), the standard registration of observers can be done, and the iOS camera will show up in the list of available devices
// register for notifications when a new device is connected
notifications.registerObserver(AVCaptureSessionDidStartRunningNotification, forObject: session, block: {note in
var devices = AVCaptureDevice.devicesWithMediaType(AVMediaTypeMuxed)
+ AVCaptureDevice.devicesWithMediaType(AVMediaTypeVideo) as! [AVCaptureDevice]
for device in self.devices {
if device.modelID == "iOS Device" {
// device is your AVCaptureDevice... use it as usual
}
}
})

Dropping files onto the app's dock icon works except for proxy icons

I want to be able to accept drops on my app's dock icon from files, URLs, and text. Since files (public.file-url) are a subtype of URL (public.url), I added just two Services entries to my Info.plist:
Services
Item 0 (processURL)
Instance method Name = processURL
Send Types
Item 0 = public.url
Menu
Menu item title = Process URL
Item 1 (processString)
Instance method Name = processString
Send Types
Item 0 = public.plain-text
Menu
Menu item title = Process Text
Then I made my -applicationDidFinishLaunching call [NSApp setServicesProvider: self], and wrote a couple methods (-processString:userData:error and -processURL:userData:error) there in my application delegate. The app icon now accepts drops of all three types. In the -processURL:... method, it's easy to check if it's a local file or not, so that handles both of those cases.
One case still eludes me, though. When I try dragging a window's proxy icon to the app, it highlights the icon as if it can accept the drop, but then my method isn't called.
I tried dropping proxy icons from Xcode, Terminal, Preview, and some third-party apps: none would call my services method. But strangely, a proxy icon dropped from the Finder worked fine.
I tried changing public.url to public.item (the base type of the physical hierarchy), but my method is still not called for non-Finder proxy icons.
When the Finder successfully drops a proxy icon on my app, the pboard -types it provides are:
"public.file-url",
"CorePasteboardFlavorType 0x6675726C",
"dyn.ah62d4rv4gu8y6y4grf0gn5xbrzw1gydcr7u1e3cytf2gn",
NSFilenamesPboardType,
"dyn.ah62d4rv4gu8yc6durvwwaznwmuuha2pxsvw0e55bsmwca7d3sbwu",
"Apple URL pasteboard type"
I tried using each of these directly as the "Send Types". "public.file-url" and "NSFilenamesPboardType" highlight the icon as if it'll accept the drop, but don't. The others, unsurprisingly, don't even highlight the dock icon.
I can't find any reference to proxy icons having a different UTI than normal files. Do they? That would be weird.
I know this must be possible, because I can drag proxy icons from any window onto a Terminal window. What am I missing?
UPDATE: From an NSView, if I -registerForDraggedTypes including "public.url", I do get drops of proxy icons from all apps, with exactly the same -types list as from the Finder, listed above. So it's clearly something special to receiving drops via the dock icon. This should still be possible somehow: you can drag a proxy icon from a (non-Finder) window (e.g., an .xcworkspace from Xcode) onto the Terminal dock window, and it catches that just fine.
Swift 4 for your app delegate
func application(_ sender: NSApplication, openFile: String) -> Bool {
Swift.print("sender \(sender) file \(openFile)")
return true
}
func application(_ sender: NSApplication, openFiles: [String]) {
Swift.print("sender \(sender) list \(openFiles)")
// Create a FileManager instance
let fileManager = FileManager.default
for path in openFiles {
do {
let files = try fileManager.contentsOfDirectory(atPath: path)
for file in files {
_ = self.application(sender, openFile: file)// void return
}
}
catch let error as NSError {
print("Yoink \(error.localizedDescription)")
}
}
}
If you implement dragging files to your dock icon using application:openFile: in your NSApplicationDelegate, then dragging proxy icons should work too. The trick to accepting all files is adding a Document Type with extensions of '*'.