diff --git a/src/README.md b/src/README.md index ff9157b798b2f9..edf63ac6ff9c88 100644 --- a/src/README.md +++ b/src/README.md @@ -20,3 +20,12 @@ The CHIP src directory is structured as follows: | setup_payload | QR code setup data encode / decode library | | system | System Layer -- common APIs for mem, work, etc. | | test_driver | Framework for on-device testing | + +#### Darwin + +##### Near Field Communication Tag Reading + +NFC Tag Reading is disabled by default because a paid Apple developer account is +requird to have it enabled. If you want to enable it and you have a paid Apple +developer account, go to the CHIPTool iOS target and turn on Near Field +Communication Tag Reading under the Capabilities tab. diff --git a/src/darwin/CHIPTool/CHIPTool.xcodeproj/project.pbxproj b/src/darwin/CHIPTool/CHIPTool.xcodeproj/project.pbxproj index fe0d2fc3e9bfd2..3676673fb42d03 100644 --- a/src/darwin/CHIPTool/CHIPTool.xcodeproj/project.pbxproj +++ b/src/darwin/CHIPTool/CHIPTool.xcodeproj/project.pbxproj @@ -69,6 +69,7 @@ B232D8B92514BD0800792CB4 /* CHIPUIViewUtils.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CHIPUIViewUtils.m; sourceTree = ""; }; B243A6672513A73600E56FEA /* RootViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RootViewController.h; sourceTree = ""; }; B243A6682513A73600E56FEA /* RootViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RootViewController.m; sourceTree = ""; }; + B27FAB67255D4B980038F0D2 /* CHIPTool.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = CHIPTool.entitlements; sourceTree = ""; }; B2946A4024C99D53005C87D0 /* WifiViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WifiViewController.h; sourceTree = ""; }; B2946A4124C99D53005C87D0 /* WifiViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WifiViewController.m; sourceTree = ""; }; B2946A9924C9A7BF005C87D0 /* DefaultsUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DefaultsUtils.h; sourceTree = ""; }; @@ -152,6 +153,7 @@ B204A61E244E1D0600C7C0E1 /* CHIPTool */ = { isa = PBXGroup; children = ( + B27FAB67255D4B980038F0D2 /* CHIPTool.entitlements */, B204A62B244E1D0700C7C0E1 /* Assets.xcassets */, B2F53AE9245B0D140010745E /* LaunchScreen.storyboard */, B204A630244E1D0700C7C0E1 /* Info.plist */, @@ -477,6 +479,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = CHIPTool/CHIPTool.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = ""; @@ -499,6 +502,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = CHIPTool/CHIPTool.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = ""; diff --git a/src/darwin/CHIPTool/CHIPTool/CHIPTool.entitlements b/src/darwin/CHIPTool/CHIPTool/CHIPTool.entitlements new file mode 100644 index 00000000000000..0c67376ebacb41 --- /dev/null +++ b/src/darwin/CHIPTool/CHIPTool/CHIPTool.entitlements @@ -0,0 +1,5 @@ + + + + + diff --git a/src/darwin/CHIPTool/CHIPTool/Info.plist b/src/darwin/CHIPTool/CHIPTool/Info.plist index f8649206b381ae..5b93c4638b2824 100644 --- a/src/darwin/CHIPTool/CHIPTool/Info.plist +++ b/src/darwin/CHIPTool/CHIPTool/Info.plist @@ -20,6 +20,8 @@ 1 LSRequiresIPhoneOS + NFCReaderUsageDescription + To read a setup payload code via NFC code NSBluetoothAlwaysUsageDescription Used to connect to the peripheral NSCameraUsageDescription diff --git a/src/darwin/CHIPTool/CHIPTool/View Controllers/QRCode/QRCodeViewController.h b/src/darwin/CHIPTool/CHIPTool/View Controllers/QRCode/QRCodeViewController.h index 127098305c7810..d0143134ea2fbb 100644 --- a/src/darwin/CHIPTool/CHIPTool/View Controllers/QRCode/QRCodeViewController.h +++ b/src/darwin/CHIPTool/CHIPTool/View Controllers/QRCode/QRCodeViewController.h @@ -17,9 +17,10 @@ #import #import +#import #import -@interface QRCodeViewController - : UIViewController +@interface QRCodeViewController : UIViewController @end diff --git a/src/darwin/CHIPTool/CHIPTool/View Controllers/QRCode/QRCodeViewController.m b/src/darwin/CHIPTool/CHIPTool/View Controllers/QRCode/QRCodeViewController.m index ea12c83c870741..04f1d46d94f344 100644 --- a/src/darwin/CHIPTool/CHIPTool/View Controllers/QRCode/QRCodeViewController.m +++ b/src/darwin/CHIPTool/CHIPTool/View Controllers/QRCode/QRCodeViewController.m @@ -50,6 +50,9 @@ @interface QRCodeViewController () @property (strong, nonatomic) UITextField * manualCodeTextField; @property (strong, nonatomic) UIButton * doneManualCodeButton; +@property (strong, nonatomic) UIButton * nfcScanButton; +@property (readwrite) BOOL sessionIsActive; + @property (strong, nonatomic) UIView * setupPayloadView; @property (strong, nonatomic) UILabel * manualCodeLabel; @property (strong, nonatomic) UIButton * resetButton; @@ -66,6 +69,8 @@ @interface QRCodeViewController () @property (readwrite) CHIPDeviceController * chipController; @property (readonly) CHIPToolPersistentStorageDelegate * persistentStorage; + +@property (strong, nonatomic) NFCNDEFReaderSession * session; @end @implementation QRCodeViewController { @@ -100,6 +105,19 @@ - (void)setupUI // Title UILabel * titleLabel = [CHIPUIViewUtils addTitle:@"QR Code Parser" toView:self.view]; + // stack view + UIStackView * stackView = [UIStackView new]; + stackView.axis = UILayoutConstraintAxisVertical; + stackView.distribution = UIStackViewDistributionFill; + stackView.alignment = UIStackViewAlignmentLeading; + stackView.spacing = 15; + [self.view addSubview:stackView]; + + stackView.translatesAutoresizingMaskIntoConstraints = false; + [stackView.topAnchor constraintEqualToAnchor:titleLabel.bottomAnchor constant:30].active = YES; + [stackView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:30].active = YES; + [stackView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-30].active = YES; + // Manual entry view _manualCodeTextField = [UITextField new]; _doneManualCodeButton = [UIButton new]; @@ -108,19 +126,34 @@ - (void)setupUI _manualCodeTextField.keyboardType = UIKeyboardTypeNumberPad; [_doneManualCodeButton setTitle:@"Go" forState:UIControlStateNormal]; UIView * manualEntryView = [CHIPUIViewUtils viewWithUITextField:_manualCodeTextField button:_doneManualCodeButton]; - [self.view addSubview:manualEntryView]; + [stackView addArrangedSubview:manualEntryView]; manualEntryView.translatesAutoresizingMaskIntoConstraints = false; [manualEntryView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:30].active = YES; [manualEntryView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-30].active = YES; [manualEntryView.topAnchor constraintEqualToAnchor:titleLabel.bottomAnchor constant:30].active = YES; + _nfcScanButton = [UIButton new]; + [_nfcScanButton setTitle:@"Scan NFC Tag" forState:UIControlStateNormal]; + [_nfcScanButton addTarget:self action:@selector(startScanningNFCTags:) forControlEvents:UIControlEventTouchDown]; + _nfcScanButton.titleLabel.font = [UIFont systemFontOfSize:17]; + _nfcScanButton.titleLabel.textColor = [UIColor blackColor]; + _nfcScanButton.layer.cornerRadius = 5; + _nfcScanButton.clipsToBounds = YES; + _nfcScanButton.backgroundColor = UIColor.systemBlueColor; + [stackView addArrangedSubview:_nfcScanButton]; + + _nfcScanButton.translatesAutoresizingMaskIntoConstraints = false; + [_nfcScanButton.leadingAnchor constraintEqualToAnchor:stackView.leadingAnchor].active = YES; + [_nfcScanButton.trailingAnchor constraintEqualToAnchor:stackView.trailingAnchor].active = YES; + [_nfcScanButton.heightAnchor constraintEqualToConstant:40].active = YES; + // Results view _setupPayloadView = [UIView new]; [self.view addSubview:_setupPayloadView]; _setupPayloadView.translatesAutoresizingMaskIntoConstraints = false; - [_setupPayloadView.topAnchor constraintEqualToAnchor:manualEntryView.bottomAnchor constant:10].active = YES; + [_setupPayloadView.topAnchor constraintEqualToAnchor:stackView.bottomAnchor constant:10].active = YES; [_setupPayloadView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:30].active = YES; [_setupPayloadView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-30].active = YES; [_setupPayloadView.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor constant:-30].active = YES; @@ -141,7 +174,7 @@ - (void)setupUI [self.view addSubview:_qrCodeViewPreview]; _qrCodeViewPreview.translatesAutoresizingMaskIntoConstraints = false; - [_qrCodeViewPreview.topAnchor constraintEqualToAnchor:manualEntryView.bottomAnchor constant:30].active = YES; + [_qrCodeViewPreview.topAnchor constraintEqualToAnchor:_nfcScanButton.bottomAnchor constant:30].active = YES; [_qrCodeViewPreview.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:30].active = YES; [_qrCodeViewPreview.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-30].active = YES; [_qrCodeViewPreview.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor constant:-50].active = YES; @@ -151,12 +184,11 @@ - (void)setupUI _errorLabel.text = @"Error Text"; _errorLabel.textColor = UIColor.blackColor; _errorLabel.font = [UIFont systemFontOfSize:17]; - [self.view addSubview:_errorLabel]; + [stackView addArrangedSubview:_errorLabel]; _errorLabel.translatesAutoresizingMaskIntoConstraints = false; [_errorLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:30].active = YES; [_errorLabel.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-30].active = YES; - [_errorLabel.topAnchor constraintEqualToAnchor:manualEntryView.bottomAnchor constant:40].active = YES; // Reset button _resetButton = [UIButton new]; @@ -243,6 +275,8 @@ - (void)addResultsUIToStackView:(UIStackView *)stackView - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; + [_session invalidateSession]; + _session = nil; } - (void)dismissKeyboard @@ -270,6 +304,57 @@ - (void)viewDidLoad [self qrCodeInitialState]; } +// MARK: NFCNDEFReaderSessionDelegate + +- (void)readerSession:(nonnull NFCNDEFReaderSession *)session didDetectNDEFs:(nonnull NSArray *)messages +{ + [_session invalidateSession]; + NSString * errorMessage; + if (messages.count == 1) { + for (NFCNDEFMessage * message in messages) { + if (message.records.count == 1) { + for (NFCNDEFPayload * payload in message.records) { + NSString * payloadType = [[NSString alloc] initWithData:payload.type encoding:NSUTF8StringEncoding]; + if ([payloadType isEqualToString:@"U"]) { + NSURL * payloadURI = [payload wellKnownTypeURIPayload]; + NSLog(@"Payload text:%@", payloadURI); + if (payloadURI) { + /* CHIP Issue #415 + Once #415 goes in, there will b no need to replace _ with spaces. + */ + NSString * qrCode = [[payloadURI absoluteString] stringByReplacingOccurrencesOfString:@"_" + withString:@" "]; + NSLog(@"Scanned code string:%@", qrCode); + [self scannedQRCode:qrCode]; + } + } else { + errorMessage = @"Record must be of type text."; + } + } + } else { + errorMessage = @"Only one record in NFC tag is accepted."; + } + } + } else { + errorMessage = @"Only one message in NFC tag is accepted."; + } + if ([errorMessage length] > 0) { + NSError * error = [[NSError alloc] initWithDomain:@"com.chiptool.nfctagscanning" + code:1 + userInfo:@{ NSLocalizedDescriptionKey : errorMessage }]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, DISPATCH_TIME_NOW), dispatch_get_main_queue(), ^{ + [self showError:error]; + }); + } +} + +- (void)readerSession:(nonnull NFCNDEFReaderSession *)session didInvalidateWithError:(nonnull NSError *)error +{ + NSLog(@"If no NFC reading UI is appearing, target may me missing the appropriate capability. Turn on Near Field Communication " + @"Tag Reading under the Capabilities tab for the project’s target. A paid developer account is needed for this."); + _session = nil; +} + // MARK: CHIPDeviceControllerDelegate - (void)deviceControllerOnConnected { @@ -591,6 +676,7 @@ - (void)scannedQRCode:(NSString *)qrCode { dispatch_async(dispatch_get_main_queue(), ^{ [self->_captureSession stopRunning]; + [self->_session invalidateSession]; }); CHIPQRCodeSetupPayloadParser * parser = [[CHIPQRCodeSetupPayloadParser alloc] initWithBase41Representation:qrCode]; NSError * error; @@ -650,6 +736,16 @@ - (IBAction)resetView:(id)sender [self qrCodeInitialState]; } +- (IBAction)startScanningNFCTags:(id)sender +{ + if (!_session) { + _session = [[NFCNDEFReaderSession alloc] initWithDelegate:self + queue:dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT) + invalidateAfterFirstRead:NO]; + } + [_session beginSession]; +} + - (IBAction)enteredManualCode:(id)sender { NSString * decimalString = _manualCodeTextField.text;