Skip to content

Commit

Permalink
NFC Tag Reading support added (#4331)
Browse files Browse the repository at this point in the history
* NFC Tag Reading support added

* Cahneg record to type uri

* restyled

Co-authored-by: Rob Walker <[email protected]>
  • Loading branch information
2 people authored and pull[bot] committed Jan 26, 2021
1 parent 521a5ee commit 4874019
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 7 deletions.
9 changes: 9 additions & 0 deletions src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
4 changes: 4 additions & 0 deletions src/darwin/CHIPTool/CHIPTool.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
B232D8B92514BD0800792CB4 /* CHIPUIViewUtils.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CHIPUIViewUtils.m; sourceTree = "<group>"; };
B243A6672513A73600E56FEA /* RootViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RootViewController.h; sourceTree = "<group>"; };
B243A6682513A73600E56FEA /* RootViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RootViewController.m; sourceTree = "<group>"; };
B27FAB67255D4B980038F0D2 /* CHIPTool.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = CHIPTool.entitlements; sourceTree = "<group>"; };
B2946A4024C99D53005C87D0 /* WifiViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WifiViewController.h; sourceTree = "<group>"; };
B2946A4124C99D53005C87D0 /* WifiViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WifiViewController.m; sourceTree = "<group>"; };
B2946A9924C9A7BF005C87D0 /* DefaultsUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DefaultsUtils.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -152,6 +153,7 @@
B204A61E244E1D0600C7C0E1 /* CHIPTool */ = {
isa = PBXGroup;
children = (
B27FAB67255D4B980038F0D2 /* CHIPTool.entitlements */,
B204A62B244E1D0700C7C0E1 /* Assets.xcassets */,
B2F53AE9245B0D140010745E /* LaunchScreen.storyboard */,
B204A630244E1D0700C7C0E1 /* Info.plist */,
Expand Down Expand Up @@ -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 = "";
Expand All @@ -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 = "";
Expand Down
5 changes: 5 additions & 0 deletions src/darwin/CHIPTool/CHIPTool/CHIPTool.entitlements
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict/>
</plist>
2 changes: 2 additions & 0 deletions src/darwin/CHIPTool/CHIPTool/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NFCReaderUsageDescription</key>
<string>To read a setup payload code via NFC code</string>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>Used to connect to the peripheral</string>
<key>NSCameraUsageDescription</key>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@

#import <AVFoundation/AVFoundation.h>
#import <CHIP/CHIP.h>
#import <CoreNFC/CoreNFC.h>
#import <UIKit/UIKit.h>

@interface QRCodeViewController
: UIViewController <AVCaptureMetadataOutputObjectsDelegate, CHIPDeviceControllerDelegate, CHIPDevicePairingDelegate>
@interface QRCodeViewController : UIViewController <AVCaptureMetadataOutputObjectsDelegate, CHIPDeviceControllerDelegate,
CHIPDevicePairingDelegate, NFCNDEFReaderSessionDelegate>

@end
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -66,6 +69,8 @@ @interface QRCodeViewController ()

@property (readwrite) CHIPDeviceController * chipController;
@property (readonly) CHIPToolPersistentStorageDelegate * persistentStorage;

@property (strong, nonatomic) NFCNDEFReaderSession * session;
@end

@implementation QRCodeViewController {
Expand Down Expand Up @@ -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];
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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];
Expand Down Expand Up @@ -243,6 +275,8 @@ - (void)addResultsUIToStackView:(UIStackView *)stackView
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
[_session invalidateSession];
_session = nil;
}

- (void)dismissKeyboard
Expand Down Expand Up @@ -270,6 +304,57 @@ - (void)viewDidLoad
[self qrCodeInitialState];
}

// MARK: NFCNDEFReaderSessionDelegate

- (void)readerSession:(nonnull NFCNDEFReaderSession *)session didDetectNDEFs:(nonnull NSArray<NFCNDEFMessage *> *)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
{
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 4874019

Please sign in to comment.