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
4 changes: 2 additions & 2 deletions Knock.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |spec|
spec.name = "Knock"
spec.version = "0.2.0"
spec.version = "1.0.0"
spec.summary = "An SDK to build in-app notifications experiences in Swift with Knock.."

spec.description = <<-DESC
Expand All @@ -16,6 +16,6 @@ Pod::Spec.new do |spec|
spec.author = { "Knock" => "support@knock.app" }
spec.source = { :git => "https://github.com/knocklabs/knock-swift.git", :tag => "#{spec.version}" }
spec.ios.deployment_target = '16.0'
spec.swift_version = '5.0'
spec.swift_version = '5.3'
spec.source_files = "Sources/**/*"
end
144 changes: 41 additions & 103 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,28 @@
# Swift SDK

## Features

* Preferences
* getAllUserPreferences
* getUserPreferences
* setUserPreferences
* Channels
* registerTokenForAPNS
* getUserChannelData
* updateUserChannelData
* Messages
* getMessage
* updateMessageStatus
* deleteMessageStatus
* batchUpdateStatuses
* Users
* getUser
* updateUser

## Installation
# Offical Knock iOS SDK

[![GitHub Release](https://img.shields.io/github/v/release/knocklabs/knock-swift?style=flat)](https://github.com/knocklabs/knock-swift/releases/latest)
[![CocoaPods](https://img.shields.io/cocoapods/v/Knock.svg?style=flat)](https://cocoapods.org/)
[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
[![Swift Package Manager compatible](https://img.shields.io/badge/Swift%20Package%20Manager-compatible-4BC51D.svg?style=flat)](https://swift.org/package-manager/)

![min swift version is 5.3](https://img.shields.io/badge/min%20Swift%20version-5.3-orange)
![min ios version is 16](https://img.shields.io/badge/min%20iOS%20version-16-blue)
[![GitHub license](https://img.shields.io/badge/license-MIT-lightgrey.svg?style=flat)](https://github.com/knocklabs/ios-example-app/blob/main/LICENSE)



---

Knock is a flexible, reliable notifications infrastructure that's built to scale with you. Use our iOS SDK to engage users with in-app feeds, setup push notifications, and manage notification preferences.

You can include the SDK in a couple of ways:
---

1. Swift Package Manager
2. Carthage
3. Cocoapods
4. Manually
## Documentation

See the [documentation](https://docs.knock.app/notification-feeds/bring-your-own-ui) for usage examples.

## Installation

### Swift Package Manager

Expand All @@ -42,59 +38,20 @@ There are two ways to add this as a dependency using the Swift Package Manager:
<img width="422" alt="Screenshot 2023-06-27 at 19 41 32" src="https://github.com/knocklabs/knock-swift/assets/952873/31bb67de-5272-445a-a5c4-5df3bcfa3c8b">

2. Search for `https://github.com/knocklabs/knock-swift.git` and then click `Add Package`
*Note: We recommend that you set the Dependency Rule to Up to Next Major Version. While we encourage you to keep your app up to date with the latest SDK, major versions can include breaking changes or new features that require your attention.*

<img width="900" alt="Screenshot 2023-06-27 at 19 42 09" src="https://github.com/knocklabs/knock-swift/assets/952873/d947cc7f-8da6-4814-aa75-3e41ffe72ff4">

3. Ensure that the Package is selected and click `Add Package`

<img width="900" alt="Screenshot 2023-06-27 at 19 42 23" src="https://github.com/knocklabs/knock-swift/assets/952873/c6053b06-73dc-43c8-8a68-40fbc2298f7c">

4. Wait for Xcode to fetch the dependencies and you should see the SDK on your Package Dependencies on the sidebar

<img width="505" alt="Screenshot 2023-06-27 at 19 42 45" src="https://github.com/knocklabs/knock-swift/assets/952873/9f314c9d-2525-4357-8da0-6ce4508b6db0">

#### Manually via `Package.swift`

If you are managing dependencies using the `Package.swift` file, just add this to you dependencies array:

``` swift
dependencies: [
.package(url: "https://github.com/knocklabs/knock-swift.git", .upToNextMajor(from: "0.2.0"))
.package(url: "https://github.com/knocklabs/knock-swift.git", .upToNextMajor(from: "1.0.0"))
]
```

### Carthage

1. Add this line to your Cartfile:

```
github "knocklabs/knock-swift" ~> 0.2.0
```

2. Run `carthage update`. This will fetch dependencies into a Carthage/Checkouts folder, then build each one or download a pre-compiled framework.
3. Open your application targets’ General settings tab. For Xcode 11.0 and higher, in the "Frameworks, Libraries, and Embedded Content" section, drag and drop each framework you want to use from the Carthage/Build folder on disk. Then, in the "Embed" section, select "Do Not Embed" from the pulldown menu for each item added. For Xcode 10.x and lower, in the "Linked Frameworks and Libraries" section, drag and drop each framework you want to use from the Carthage/Build folder on disk.
4. On your application targets’ Build Phases settings tab, click the + icon and choose New Run Script Phase. Create a Run Script in which you specify your shell (ex: /bin/sh), add the following contents to the script area below the shell:
```
/usr/local/bin/carthage copy-frameworks
```
5. Create a file named `input.xcfilelist` and a file named output.xcfilelist
6. Add the paths to the frameworks you want to use to your input.xcfilelist. For example:
```
$(SRCROOT)/Carthage/Build/iOS/Knock.framework
```
7. Add the paths to the copied frameworks to the `output.xcfilelist`. For example:
```
$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Result.framework
```
8. Add the `input.xcfilelist` to the "Input File Lists" section of the Carthage run script phase
9. Add the `output.xcfilelist` to the "Output File Lists" section of the Carthage run script phase

This script works around an [App Store submission bug](http://www.openradar.me/radar?id=6409498411401216) triggered by universal binaries and ensures that necessary bitcode-related files and dSYMs are copied when archiving.

With the debug information copied into the built products directory, Xcode will be able to symbolicate the stack trace whenever you stop at a breakpoint. This will also enable you to step through third-party code in the debugger.

When archiving your application for submission to the App Store or TestFlight, Xcode will also copy these files into the dSYMs subdirectory of your application’s .xcarchive bundle.

### Cocoapods

Add the dependency to your `Podfile`:
Expand All @@ -108,6 +65,14 @@ target 'MyApp' do
end
```

### Carthage

1. Add this line to your Cartfile:

```
github "knocklabs/knock-swift" ~> 0.2.0
```

### Manually

As a last option, you could manually copy the files inside the `Sources` folder to your project.
Expand All @@ -119,47 +84,20 @@ You can now start using the SDK:
``` swift
import Knock

knockClient = try! Knock(publishableKey: "your-pk", userId: "user-id")

knockClient.getUser{ result in
switch result {
case .success(let user):
print(user)
case .failure(let error):
print(error.localizedDescription)
}
}
```
// Setup the shared Knock instance as soon as you can.
try? Knock.shared.setup(publishableKey: "your-pk", pushChannelId: "user-id")

## Using the SDK
// Once you know the Knock UserId, sign the user into the shared Knock instance.
await Knock.shared.signIn(userId: "userid", userToken: nil)

The functions of the sdk are encapsulated and managed in a client object. You first have to instantiate a client with your public key and a user id. If you are running on production with enhanced security turned on (recommended) you have to also pass the signed user token to the client constructor.

``` swift
import Knock

knockClient = try! Knock(publishableKey: "your-pk", userId: "user-id")

// on prod with enhanced security turned on:
knockClient = try! Knock(publishableKey: "your-pk", userId: "user-id", userToken: "signed-user-token")
```

## Notes for publishing

When releasing a new version of this SDK, please note:

* You should update the version in a couple of places:
* in the file `Sources/KnockAPI.swift`: `clientVersion = "..."`
* in the file `Knock.podspec`: `spec.version = "..."`
* in this `README.md`, in the installation instructions for all the package managers
* in git, add a tag, preferably to the commit that includes this previous changes






## How to Contribute

Community contributions are welcome! If you'd like to contribute, please read our [contribution guide](CONTRIBUTING.md).

## License

This project is licensed under the MIT license.

See [LICENSE](LICENSE) for more information.
43 changes: 24 additions & 19 deletions Sources/Knock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,44 +28,49 @@ public class Knock {
Returns a new instance of the Knock Client

- Parameters:
- publishableKey: your public API key
- publishableKey: Your public API key
- options: [optional] Options for customizing the Knock instance.
*/
public func setup(publishableKey: String, pushChannelId: String?, options: Knock.KnockStartupOptions? = nil) async throws {
logger.loggingDebugOptions = options?.loggingOptions ?? .errorsOnly
try await environment.setPublishableKey(key: publishableKey)
await environment.setBaseUrl(baseUrl: options?.hostname)
await environment.setPushChannelId(pushChannelId)
}

@available(*, deprecated, message: "Use async setup() method instead for safer handling.")
public func setup(publishableKey: String, pushChannelId: String?, options: Knock.KnockStartupOptions? = nil) throws {
logger.loggingDebugOptions = options?.debuggingType ?? .errorsOnly
try environment.setPublishableKey(key: publishableKey)
environment.setBaseUrl(baseUrl: options?.hostname)
environment.pushChannelId = pushChannelId
logger.loggingDebugOptions = options?.loggingOptions ?? .errorsOnly
Task {
try await environment.setPublishableKey(key: publishableKey)
await environment.setBaseUrl(baseUrl: options?.hostname)
await environment.setPushChannelId(pushChannelId)
}
}

/**
Reset the current Knock instance entirely.
After calling this, you will need to setup and signin again.
*/
public func resetInstanceCompletely() {
Knock.shared = Knock()
}
}

public extension Knock {
struct KnockStartupOptions {
public init(hostname: String? = nil, debuggingType: DebugOptions = .errorsOnly) {
public init(hostname: String? = nil, loggingOptions: LoggingOptions = .errorsOnly) {
self.hostname = hostname
self.debuggingType = debuggingType
self.loggingOptions = loggingOptions
}
var hostname: String?
var debuggingType: DebugOptions
var loggingOptions: LoggingOptions
}

enum DebugOptions {
enum LoggingOptions {
case errorsOnly
case errorsAndWarningsOnly
case verbose
case none
}
}

public extension Knock {
var userId: String? {
get { return environment.userId }
}

var apnsDeviceToken: String? {
get { return environment.userId }
}
}
20 changes: 13 additions & 7 deletions Sources/KnockAPIService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,22 @@ internal protocol KnockAPIService {
}

extension KnockAPIService {
private var apiBaseUrl: String {
return "\(Knock.shared.environment.baseUrl)/v1"

func apiBaseUrl() async -> String {
let base = await Knock.shared.environment.getBaseUrl()
return "\(base)/v1"
}

func makeRequest<T:Codable>(method: String, path: String, queryItems: [URLQueryItem]?, body: Encodable?) async throws -> T {
let sessionConfig = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfig, delegate: nil, delegateQueue: nil)

let loggingMessageSummary = "\(method) \(apiBaseUrl)\(path)"
let baseUrl = await apiBaseUrl()

let loggingMessageSummary = "\(method) \(baseUrl)\(path)"

guard var URL = URL(string: "\(apiBaseUrl)\(path)") else {
let networkError = Knock.NetworkError(title: "Invalid URL", description: "The URL: \(apiBaseUrl)\(path) is invalid", code: 0)
guard var URL = URL(string: "\(baseUrl)\(path)") else {
let networkError = Knock.NetworkError(title: "Invalid URL", description: "The URL: \(baseUrl)\(path) is invalid", code: 0)
Knock.shared.log(type: .warning, category: .networking, message: loggingMessageSummary, status: .fail, errorMessage: networkError.localizedDescription)
throw networkError
}
Expand All @@ -52,8 +56,10 @@ extension KnockAPIService {

request.addValue("knock-swift@\(Knock.clientVersion)", forHTTPHeaderField: "User-Agent")

request.addValue("Bearer \(try Knock.shared.environment.getSafePublishableKey())", forHTTPHeaderField: "Authorization")
if let userToken = Knock.shared.environment.userToken {
let publishableKey = try await Knock.shared.environment.getSafePublishableKey()
request.addValue("Bearer \(publishableKey)", forHTTPHeaderField: "Authorization")

if let userToken = await Knock.shared.environment.getUserToken() {
request.addValue(userToken, forHTTPHeaderField: "X-Knock-User-Token")
}

Expand Down
Loading