فهرست منبع

Added support for Touch ID to unlock app (closes #13378)

Felix Paul Kühne 9 سال پیش
والد
کامیت
0ad1be617e

+ 1 - 0
NEWS

@@ -9,6 +9,7 @@
 * Added support for system-wide search "CoreSpotlight"
 * Added improved UI support for Right-to-Left languages
 * Added support for the split-screen appearance in iOS 9 (#14840)
+* Added support for Touch ID to unlock app (#13378)
 * Added option to configure playback continuation (#14340, #14590)
 * Added option to configure gestures (#15449) 
 * Added support for music albums with more than 1 disk (#14650)

+ 10 - 0
Resources/Settings.bundle/Root.inApp.plist

@@ -22,6 +22,16 @@
 		</dict>
 		<dict>
 			<key>DefaultValue</key>
+			<string>YES</string>
+			<key>Key</key>
+			<string>AllowTouchID</string>
+			<key>Title</key>
+			<string>SETTINGS_PASSCODE_LOCK_ALLOWTOUCHID</string>
+			<key>Type</key>
+			<string>PSToggleSwitchSpecifier</string>
+		</dict>
+		<dict>
+			<key>DefaultValue</key>
 			<true/>
 			<key>Key</key>
 			<string>MLDecrapifyTitles</string>

BIN
Resources/Settings.bundle/en.lproj/Root.strings


BIN
Resources/en.lproj/Localizable.strings


+ 1 - 0
Sources/VLCAppDelegate.m

@@ -62,6 +62,7 @@ NSString *const VLCDropboxSessionWasAuthorized = @"VLCDropboxSessionWasAuthorize
         skipLoopFilterDefaultValue = kVLCSettingSkipLoopFilterNonRef;
 
     NSDictionary *appDefaults = @{kVLCSettingPasscodeKey : @"",
+                                  kVLCSettingPasscodeAllowTouchID : @(1),
                                   kVLCSettingContinueAudioInBackgroundKey : @(YES),
                                   kVLCSettingStretchAudio : @(NO),
                                   kVLCSettingTextEncoding : kVLCSettingTextEncodingDefaultValue,

+ 1 - 0
Sources/VLCConstants.h

@@ -17,6 +17,7 @@
 
 #define kVLCSettingPasscodeKey @"Passcode"
 #define kVLCSettingPasscodeOnKey @"PasscodeProtection"
+#define kVLCSettingPasscodeAllowTouchID @"AllowTouchID"
 #define kVLCSettingContinueAudioInBackgroundKey @"BackgroundAudioPlayback"
 #define kVLCSettingStretchAudio @"audio-time-stretch"
 #define kVLCSettingStretchAudioOnValue @"1"

+ 60 - 0
Sources/VLCKeychainCoordinator.m

@@ -14,6 +14,7 @@
 #import "PAPasscodeViewController.h"
 #import "VLCAppDelegate.h"
 #import "SSKeychain.h"
+#import <LocalAuthentication/LocalAuthentication.h>
 
 NSString *const VLCPasscodeValidated = @"VLCPasscodeValidated";
 
@@ -23,6 +24,8 @@ NSString *const VLCPasscode = @"org.videolan.vlc-ios.passcode";
 {
     PAPasscodeViewController *_passcodeLockController;
     NSDictionary *_passcodeQuery;
+    BOOL _inValidation;
+    BOOL _inTouchID;
 }
 
 @end
@@ -41,6 +44,32 @@ NSString *const VLCPasscode = @"org.videolan.vlc-ios.passcode";
     return sharedInstance;
 }
 
+- (instancetype)init
+{
+    self = [super init];
+    if (!self)
+        return nil;
+
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(appInForeground:)
+                                                 name:UIApplicationDidBecomeActiveNotification
+                                               object:nil];
+    return self;
+}
+
+- (void)dealloc
+{
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+- (void)appInForeground:(NSNotification *)notification
+{
+    /* our touch ID session is killed by the OS if the app moves to background, so re-init */
+    if (_inValidation) {
+        [self _touchIDQuery];
+    }
+}
+
 - (NSString *)_obtainPasscode
 {
     NSString *passcode = [SSKeychain passwordForService:VLCPasscode account:VLCPasscode];
@@ -71,6 +100,11 @@ NSString *const VLCPasscode = @"org.videolan.vlc-ios.passcode";
 
 - (void)validatePasscode
 {
+    /* we may be called repeatedly as Touch ID uses an out-of-process dialog */
+    if (_inValidation)
+        return;
+    _inValidation = YES;
+
     NSString *passcode = [self _obtainPasscode];
     if ([passcode isEqualToString:@""]) {
         [[NSNotificationCenter defaultCenter] postNotificationName:VLCPasscodeValidated object:self];
@@ -88,8 +122,32 @@ NSString *const VLCPasscode = @"org.videolan.vlc-ios.passcode";
     UINavigationController *navCon = [[UINavigationController alloc] initWithRootViewController:_passcodeLockController];
     navCon.modalPresentationStyle = UIModalPresentationFullScreen;
     [appDelegate.window.rootViewController presentViewController:navCon animated:NO completion:nil];
+
+    if (SYSTEM_RUNS_IOS8_OR_LATER) {
+        if ([[NSUserDefaults standardUserDefaults] boolForKey:kVLCSettingPasscodeAllowTouchID]) {
+            [self _touchIDQuery];
+        }
+    }
 }
 
+- (void)_touchIDQuery
+{
+    /* don't launch multiple times */
+    if (_inTouchID)
+        return;
+    _inTouchID = YES;
+    LAContext *myContext = [[LAContext alloc] init];
+    if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:nil]) {
+        [myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
+                  localizedReason:NSLocalizedString(@"TOUCHID_UNLOCK", nil)
+                            reply:^(BOOL success, NSError *error) {
+                                if (success) {
+                                    [self PAPasscodeViewControllerDidEnterPasscode:nil];
+                                } else if (error.code == LAErrorSystemCancel)
+                                    _inTouchID = NO;
+                            }];
+    }
+}
 
 - (void)PAPasscodeViewControllerDidEnterPasscode:(PAPasscodeViewController *)controller
 {
@@ -97,6 +155,8 @@ NSString *const VLCPasscode = @"org.videolan.vlc-ios.passcode";
 
     VLCAppDelegate *appDelegate = (VLCAppDelegate *)[UIApplication sharedApplication].delegate;
     [appDelegate.window.rootViewController dismissViewControllerAnimated:YES completion:nil];
+    _inValidation = NO;
+    _inTouchID = NO;
 }
 
 - (void)PAPasscodeViewController:(PAPasscodeViewController *)controller didFailToEnterPasscode:(NSInteger)attempts

+ 1 - 0
Sources/VLCMenuTableViewController.m

@@ -249,6 +249,7 @@ static NSString *WiFiCellIdentifier = @"VLCMenuWiFiCell";
             settingsVC.showCreditsFooter = NO;
 
             viewController = settingsVC;
+            [self.settingsController willShow];
         } else if (itemIndex == 1)
             viewController = [[VLCAboutViewController alloc] init];
     } else {

+ 2 - 0
Sources/VLCSettingsController.h

@@ -16,4 +16,6 @@
 
 @property (nonatomic, retain) IASKAppSettingsViewController *viewController;
 
+- (void)willShow;
+
 @end

+ 20 - 1
Sources/VLCSettingsController.m

@@ -39,6 +39,22 @@
     [[NSNotificationCenter defaultCenter] removeObserver:self];
 }
 
+- (void)willShow
+{
+    [self filterCellsWithAnimation:NO];
+}
+
+- (void)filterCellsWithAnimation:(BOOL)shouldAnimate
+{
+    NSMutableSet *hideKeys = [[NSMutableSet alloc] init];
+
+    VLCKeychainCoordinator *keychainCoordinator = [VLCKeychainCoordinator defaultCoordinator];
+    if (![keychainCoordinator passcodeLockEnabled])
+        [hideKeys addObject:kVLCSettingPasscodeAllowTouchID];
+
+    [self.viewController setHiddenKeys:hideKeys animated:shouldAnimate];
+}
+
 - (void)settingDidChange:(NSNotification*)notification
 {
     if ([notification.object isEqual:kVLCSettingPasscodeOnKey]) {
@@ -61,7 +77,10 @@
 }
 
 
-- (void)didChangePasscodeStatus:(BOOL)passcodeEnabled {
+- (void)didChangePasscodeStatus:(BOOL)passcodeEnabled
+{
+    [self filterCellsWithAnimation:YES];
+
     BOOL spotlightEnabled = !passcodeEnabled;
     [[MLMediaLibrary sharedMediaLibrary] setSpotlightIndexingEnabled:spotlightEnabled];
     if (!spotlightEnabled) {

+ 4 - 0
VLC for iOS.xcodeproj/project.pbxproj

@@ -142,6 +142,7 @@
 		7D74177A1AE2D3CE001F1997 /* VLCNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D7417791AE2D3CE001F1997 /* VLCNavigationController.m */; };
 		7D84E4C61B41AB2800EA7D1F /* VideoToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7D84E4C51B41AB2800EA7D1F /* VideoToolbox.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
 		7D84E4C91B41ABCE00EA7D1F /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7D84E4C81B41ABCE00EA7D1F /* CoreMedia.framework */; };
+		7D8968711BD3058800F4EAAD /* LocalAuthentication.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7D8968701BD3058800F4EAAD /* LocalAuthentication.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
 		7D89786F185DED88009BAB5D /* VLCDownloadViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7D89786E185DED88009BAB5D /* VLCDownloadViewController.xib */; };
 		7D89787D185DF794009BAB5D /* VLCOpenNetworkStreamViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7D89787C185DF794009BAB5D /* VLCOpenNetworkStreamViewController.xib */; };
 		7D9289751877459B009108FD /* VLCFirstStepsThirdPageViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D9289731877459B009108FD /* VLCFirstStepsThirdPageViewController.m */; };
@@ -612,6 +613,7 @@
 		7D8139CD1865211900D65504 /* ms */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ms; path = ms.lproj/Localizable.strings; sourceTree = "<group>"; };
 		7D84E4C51B41AB2800EA7D1F /* VideoToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = VideoToolbox.framework; path = System/Library/Frameworks/VideoToolbox.framework; sourceTree = SDKROOT; };
 		7D84E4C81B41ABCE00EA7D1F /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; };
+		7D8968701BD3058800F4EAAD /* LocalAuthentication.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = LocalAuthentication.framework; path = System/Library/Frameworks/LocalAuthentication.framework; sourceTree = SDKROOT; };
 		7D89786E185DED88009BAB5D /* VLCDownloadViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = VLCDownloadViewController.xib; path = Resources/VLCDownloadViewController.xib; sourceTree = SOURCE_ROOT; };
 		7D89787C185DF794009BAB5D /* VLCOpenNetworkStreamViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = VLCOpenNetworkStreamViewController.xib; path = Resources/VLCOpenNetworkStreamViewController.xib; sourceTree = SOURCE_ROOT; };
 		7D8E19271B6BC186000D7C74 /* VLC WatchKit App.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = "VLC WatchKit App.entitlements"; sourceTree = "<group>"; };
@@ -847,6 +849,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				7D8968711BD3058800F4EAAD /* LocalAuthentication.framework in Frameworks */,
 				DD2789E41B67A88600CED769 /* WatchConnectivity.framework in Frameworks */,
 				7D2DF7C31B67777D00FB78AB /* libc++.tbd in Frameworks */,
 				7D2DF7C11B67760100FB78AB /* libGTLTouchStaticLib.a in Frameworks */,
@@ -1352,6 +1355,7 @@
 		7D94FCDD16DE7D1000F2623B /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
+				7D8968701BD3058800F4EAAD /* LocalAuthentication.framework */,
 				7DC71D0D1BC81F70001FACAA /* AVFoundation.framework */,
 				7DF28AE41BA31D9C0030C944 /* libSystem.tbd */,
 				7DF28AE21BA31D770030C944 /* libcommonCrypto.tbd */,