Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# SPDX-FileCopyrightText: Estonian Information System Authority
# SPDX-License-Identifier: LGPL-2.1-or-later

name: Build NFC library

on:
push:
pull_request:

permissions:
contents: read

jobs:
build:
runs-on: macos-26
steps:
- uses: actions/checkout@v6
- name: Build for iOS device
run: swift build --triple arm64-apple-ios18.0 --sdk "$(xcrun --sdk iphoneos --show-sdk-path)"
- name: Build for iOS simulator
run: swift build --triple arm64-apple-ios18.0-simulator --sdk "$(xcrun --sdk iphonesimulator --show-sdk-path)"

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 27 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// swift-tools-version: 6.0
// SPDX-FileCopyrightText: Estonian Information System Authority
// SPDX-License-Identifier: LGPL-2.1-or-later

import PackageDescription

let package = Package(
name: "IdCardLib",
platforms: [.iOS(.v18)],
products: [
.library(name: "IdCardLib", targets: ["nfclib"])
],
dependencies: [
.package(url: "https://github.com/leif-ibsen/BigInt.git", from: "1.15.0"),
.package(url: "https://github.com/leif-ibsen/SwiftECC", from: "5.1.0")
],
targets: [
.target(
name: "nfclib",
dependencies: [
.product(name: "BigInt", package: "BigInt"),
.product(name: "SwiftECC", package: "SwiftECC")
]
)
],
swiftLanguageModes: [.v5]
)
32 changes: 7 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
- [Application Requirements](#application-requirements)
- [Enable NFC Capability](#enable-nfc-capability)
- [Update Info.plist](#update-infoplist)
- [Build the Library](#build-the-library)
- [Add the Library to the Application](#add-the-library-to-the-application)
- [Add the Library as a Swift Package](#add-the-library-as-a-swift-package)
- [Library Interfaces for ID Card Communication](#library-interfaces-for-id-card-communication)
- [Logging](#logging)
- [Enabling Sensitive Logs (Debug Only)](#enabling-sensitive-logs-debug-only)
Expand All @@ -19,7 +18,7 @@ The NFC-ID library is not intended for public use. It is a low-level technical l
The NFC-ID library was originally developed within the m-valimiste project, based on the need to use the ID card inside the m-Voting client application.

# Demo Application Run Guide
- Open **mvtng-nfc-demo.xcworkspace**. This workspace includes both the demo app and the `nfclib` library.
- Open **mvoting-nfc/nfc-demo.xcodeproj**. The demo app uses the Swift package at the repository root.
- Wait until **Swift Package Manager** dependencies are fully downloaded.
- Select **Product → Run**.

Expand All @@ -43,27 +42,10 @@ You must declare NFC usage in your **Info.plist** file to explain why the applic
- Add a new key: **Privacy – NFC Scan Usage Description** (`NFCReaderUsageDescription`).
- Set its value to a string explaining why the app requires NFC access. This text will be displayed to the user the first time the app attempts to use NFC.

### Build the Library
The goal is to build an `.xcframework` bundle that can be added as a dependency to other projects.

- Run the script `build_xcframework.sh`, located at `nfc-lib/nfc-lib/build_xcframework.sh`. It takes two optional arguments – the build configuration (`Debug` or `Release`, default `Release`) and whether to compile in sensitive logging (`YES` or `NO`, default `NO`):

```sh
./build_xcframework.sh # Release, no sensitive logging – for production / App Store
./build_xcframework.sh Release YES # Release with sensitive logging
./build_xcframework.sh Debug YES # Debug with sensitive logging – for local debugging
```

- After execution, the **build** folder will contain **nfclib.xcframework** in a `<Configuration>-universal` subfolder.
- Pass `YES` only for builds where you need sensitive logs. The production framework must be built with the default `NO`, which strips the sensitive-logging code from the binary.

### Add the Library to the Application
- Open the project where you want to integrate the `nfclib` library.
- Select the project, then under **TARGETS**, choose the correct target.
- In the **General** tab of the target, find the **Frameworks and Libraries** section.
- Click **+ → Add Other… → Add Files… → Select nfclib.xcframework**.

The NFC library is now integrated into your application.
### Add the Library as a Swift Package
- In Xcode, choose **File → Add Package Dependencies… → Add Local…** and select this repository's root directory. For a remote dependency, use the repository URL and select a revision containing `Package.swift`.
- Add the `IdCardLib` product to your app target. Import the library in Swift with `import nfclib`.
- Set the app's minimum deployment target to iOS 18 or later.

# Library Interfaces for ID Card Communication
The library provides the following operation classes for ID card communication:
Expand Down Expand Up @@ -134,6 +116,6 @@ NFCLibLogging.isEnabled = true // Default is false

Set it back to `false` to turn them off again. The demo already wires this up in `nfc_demoApp.swift` (`mvoting-nfc/nfc-demo`), so the quickest way to try it is to switch that line to `true`.

This only has an effect when the library was built with sensitive logging compiled in. For a framework built via the script, that's the `YES` argument (see [Build the Library](#build-the-library)); if you build the library from source instead (for example the demo workspace), add `-D ENABLE_LOGGING` to the `nfclib` target's **Other Swift Flags** (`OTHER_SWIFT_FLAGS`). Both default to off, so a production build has the code stripped and cannot log it regardless of this flag – but your app should still never set it to `true` in production.
This only has an effect when the library was built with sensitive logging compiled in. For local package debugging, add `.define("ENABLE_LOGGING")` to the `nfclib` target's `swiftSettings` in `Package.swift`. Remove it before a production build so the sensitive logging code is stripped from the binary. Your app should also leave `NFCLibLogging.isEnabled` set to `false` in production.

Once enabled, the sensitive logs appear under the same subsystem as everything else.
122 changes: 38 additions & 84 deletions mvoting-nfc/nfc-demo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,57 +3,37 @@
archiveVersion = 1;
classes = {
};
objectVersion = 56;
objectVersion = 70;
objects = {

/* Begin PBXBuildFile section */
13176D752B3193F70093D806 /* CardInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13176D742B3193F70093D806 /* CardInfoView.swift */; };
1319EBC32B330BB500F69C0E /* nfclib.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1319EBC22B330BB500F69C0E /* nfclib.framework */; };
1319EBC42B330BB500F69C0E /* nfclib.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 1319EBC22B330BB500F69C0E /* nfclib.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
139195AC2AFA29CC00EDA022 /* nfc_demoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 139195AB2AFA29CC00EDA022 /* nfc_demoApp.swift */; };
139195AE2AFA29CC00EDA022 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 139195AD2AFA29CC00EDA022 /* ContentView.swift */; };
139195B02AFA29CD00EDA022 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 139195AF2AFA29CD00EDA022 /* Assets.xcassets */; };
139195B32AFA29CD00EDA022 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 139195B22AFA29CD00EDA022 /* Preview Assets.xcassets */; };
1A0AA6F32E8EB4D2000B11FA /* CardOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A0AA6F22E8EB4D2000B11FA /* CardOperations.swift */; };
1A0AA6F42E8EB4D2000B11FA /* Operator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A0AA6F12E8EB4D2000B11FA /* Operator.swift */; };
B73A95A32F7C4F59A4123720 /* IdCardLib in Frameworks */ = {isa = PBXBuildFile; productRef = B73A95A22F7C4F59A4123720 /* IdCardLib */; };
/* End PBXBuildFile section */

/* Begin PBXCopyFilesBuildPhase section */
1319EBC52B330BB500F69C0E /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
1319EBC42B330BB500F69C0E /* nfclib.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
13176D742B3193F70093D806 /* CardInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardInfoView.swift; sourceTree = "<group>"; };
1319EBC22B330BB500F69C0E /* nfclib.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = nfclib.framework; sourceTree = BUILT_PRODUCTS_DIR; };
137E71132B04FAC90065282B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
139195A82AFA29CC00EDA022 /* nfc-demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "nfc-demo.app"; sourceTree = BUILT_PRODUCTS_DIR; };
139195AB2AFA29CC00EDA022 /* nfc_demoApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = nfc_demoApp.swift; sourceTree = "<group>"; };
139195AD2AFA29CC00EDA022 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
139195AF2AFA29CD00EDA022 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
139195B22AFA29CD00EDA022 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
1392583F2B04B06A00AD38EA /* nfc-demo.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "nfc-demo.entitlements"; sourceTree = "<group>"; };
1A0AA6F12E8EB4D2000B11FA /* Operator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Operator.swift; sourceTree = "<group>"; };
1A0AA6F22E8EB4D2000B11FA /* CardOperations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardOperations.swift; sourceTree = "<group>"; };
5A2C028B2B060E9D00C6D249 /* SkSigningLib.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SkSigningLib.framework; sourceTree = BUILT_PRODUCTS_DIR; };
5A9969882B03B9A4002A1060 /* nfc_lib.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = nfc_lib.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */

/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
4E7CD94E306AF90B009D43BD /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
Info.plist,
);
target = 139195A72AFA29CC00EDA022 /* nfc-demo */;
};
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */

/* Begin PBXFileSystemSynchronizedRootGroup section */
4E7CD944306AF90A009D43BD /* nfc-demo */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (4E7CD94E306AF90B009D43BD /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = "nfc-demo"; sourceTree = "<group>"; };
/* End PBXFileSystemSynchronizedRootGroup section */

/* Begin PBXFrameworksBuildPhase section */
139195A52AFA29CC00EDA022 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
1319EBC32B330BB500F69C0E /* nfclib.framework in Frameworks */,
B73A95A32F7C4F59A4123720 /* IdCardLib in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -63,9 +43,8 @@
1391959F2AFA29CC00EDA022 = {
isa = PBXGroup;
children = (
139195AA2AFA29CC00EDA022 /* nfc-demo */,
139195A92AFA29CC00EDA022 /* Products */,
5A9969872B03B9A4002A1060 /* Frameworks */,
4E7CD944306AF90A009D43BD /* nfc-demo */,
);
sourceTree = "<group>";
};
Expand All @@ -77,40 +56,6 @@
name = Products;
sourceTree = "<group>";
};
139195AA2AFA29CC00EDA022 /* nfc-demo */ = {
isa = PBXGroup;
children = (
137E71132B04FAC90065282B /* Info.plist */,
1392583F2B04B06A00AD38EA /* nfc-demo.entitlements */,
139195AB2AFA29CC00EDA022 /* nfc_demoApp.swift */,
139195AD2AFA29CC00EDA022 /* ContentView.swift */,
13176D742B3193F70093D806 /* CardInfoView.swift */,
139195AF2AFA29CD00EDA022 /* Assets.xcassets */,
139195B12AFA29CD00EDA022 /* Preview Content */,
1A0AA6F12E8EB4D2000B11FA /* Operator.swift */,
1A0AA6F22E8EB4D2000B11FA /* CardOperations.swift */,
);
path = "nfc-demo";
sourceTree = "<group>";
};
139195B12AFA29CD00EDA022 /* Preview Content */ = {
isa = PBXGroup;
children = (
139195B22AFA29CD00EDA022 /* Preview Assets.xcassets */,
);
path = "Preview Content";
sourceTree = "<group>";
};
5A9969872B03B9A4002A1060 /* Frameworks */ = {
isa = PBXGroup;
children = (
1319EBC22B330BB500F69C0E /* nfclib.framework */,
5A2C028B2B060E9D00C6D249 /* SkSigningLib.framework */,
5A9969882B03B9A4002A1060 /* nfc_lib.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
Expand All @@ -121,14 +66,17 @@
139195A42AFA29CC00EDA022 /* Sources */,
139195A52AFA29CC00EDA022 /* Frameworks */,
139195A62AFA29CC00EDA022 /* Resources */,
1319EBC52B330BB500F69C0E /* Embed Frameworks */,
);
buildRules = (
);
dependencies = (
);
fileSystemSynchronizedGroups = (
4E7CD944306AF90A009D43BD /* nfc-demo */,
);
name = "nfc-demo";
packageProductDependencies = (
B73A95A22F7C4F59A4123720 /* IdCardLib */,
);
productName = "mvoting-nfc";
productReference = 139195A82AFA29CC00EDA022 /* nfc-demo.app */;
Expand All @@ -150,7 +98,7 @@
};
};
buildConfigurationList = 139195A32AFA29CC00EDA022 /* Build configuration list for PBXProject "nfc-demo" */;
compatibilityVersion = "Xcode 14.0";
compatibilityVersion = "Xcode 15.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
Expand All @@ -159,6 +107,7 @@
);
mainGroup = 1391959F2AFA29CC00EDA022;
packageReferences = (
B73A95A12F7C4F59A4123720 /* XCLocalSwiftPackageReference ".." */,
);
productRefGroup = 139195A92AFA29CC00EDA022 /* Products */;
projectDirPath = "";
Expand All @@ -174,8 +123,6 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
139195B32AFA29CD00EDA022 /* Preview Assets.xcassets in Resources */,
139195B02AFA29CD00EDA022 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -186,11 +133,6 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
139195AE2AFA29CC00EDA022 /* ContentView.swift in Sources */,
139195AC2AFA29CC00EDA022 /* nfc_demoApp.swift in Sources */,
1A0AA6F32E8EB4D2000B11FA /* CardOperations.swift in Sources */,
1A0AA6F42E8EB4D2000B11FA /* Operator.swift in Sources */,
13176D752B3193F70093D806 /* CardInfoView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -335,7 +277,6 @@
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 18.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand Down Expand Up @@ -368,7 +309,6 @@
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 18.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand Down Expand Up @@ -404,6 +344,20 @@
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */

/* Begin XCLocalSwiftPackageReference section */
B73A95A12F7C4F59A4123720 /* XCLocalSwiftPackageReference ".." */ = {
isa = XCLocalSwiftPackageReference;
relativePath = ..;
};
/* End XCLocalSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
B73A95A22F7C4F59A4123720 /* IdCardLib */ = {
isa = XCSwiftPackageProductDependency;
productName = IdCardLib;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 139195A02AFA29CC00EDA022 /* Project object */;
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions mvoting-nfc/nfc-demo/CardOperations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
/// This protocol defines a set of operations for interacting with a card,
/// including NFC support checking, reading card information, and performing
/// authentication and signing operations.
import Foundation
import Security
import nfclib

public protocol CardOperations {
Expand Down
2 changes: 1 addition & 1 deletion mvoting-nfc/nfc-demo/nfc_demoApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import nfclib
@main
struct mvoting_nfcApp: App {
init() {
// Set to true (and add -D ENABLE_LOGGING to the nfclib target's Other Swift Flags) to see sensitive logs.
// Set to true (and enable ENABLE_LOGGING in the nfclib package target) to see sensitive logs.
NFCLibLogging.isEnabled = false
}

Expand Down
10 changes: 0 additions & 10 deletions mvtng-nfc-demo.xcworkspace/contents.xcworkspacedata

This file was deleted.

This file was deleted.

This file was deleted.

Loading
Loading