Skip to content

Integrated encrypted links functionality, tracking conversions, destination url #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
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
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ let sdk = ShortIOSDK()

let parameters = ShortIOParameters(
domain: "your_domain",
originalURL: "https://yourdomain.com"
originalURL: "https://{your_domain}"
)

let apiKey = "your_api_key"
Expand All @@ -98,6 +98,28 @@ Task {
}
```

### 🔐 Secure Short Links (Encrypted)

If you want to encrypt the original URL, the SDK provides a `createSecure` function that uses AES-GCM encryption.

#### 🔧 Example

```swift
Task {
do {
let result = try shortLinkSDK.createSecure(originalURL: "https://{your_domain}")
print("result", result.securedOriginalURL, result.securedShortUrl)
} catch {
print("Failed to create secure URL: \(error)")
}
}
```
#### 🧾 Output Format

- **`securedOriginalURL:`** An encrypted URL like `shortsecure://<Base64EncodedData>?<Base64IV>`

- **`securedShortUrl:`** A Base64-encoded decryption key to be appended as a fragment (e.g. `#<key>`)

## 🌐 Handling Universal Links

### SwiftUI Implementation
Expand Down
18 changes: 16 additions & 2 deletions StoryboardProject/ShortIOApp/SceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,22 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
print("Invalid universal link or URL components")
return
}
sdk.handleOpen(incomingURL) { result in
print("Host: \(result?.host), Path: \(result?.path)")
Task{
await sdk.handleOpen(incomingURL) { result,destinationUrl, error in
if let error = error {
print("Error: \(error)")
return
}

if let components = result {
print("Host: \(components.host ?? "nil")")
print("Path: \(components.path)")
print("QueryParams: \(result?.queryItems)")
print("DestinationUrl: \(destinationUrl ?? "nil")")
} else {
print("No components returned")
}
}
}
}

Expand Down
187 changes: 145 additions & 42 deletions StoryboardProject/ShortIOApp/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class ViewController: UIViewController {
return label
}()

private let createButton: UIButton = {
private let createShortLinkButton: UIButton = {
let button = UIButton(type: .system)
button.setTitle("Create Short Link", for: .normal)
button.titleLabel?.font = .systemFont(ofSize: 18, weight: .semibold)
Expand All @@ -24,9 +24,21 @@ class ViewController: UIViewController {
return button
}()

private let activityIndicator = UIActivityIndicatorView(style: .medium)
private let createSecureShortLinkButton: UIButton = {
let button = UIButton(type: .system)
button.setTitle("Create Secure Short Link", for: .normal)
button.titleLabel?.font = .systemFont(ofSize: 18, weight: .semibold)
button.backgroundColor = .systemBlue
button.tintColor = .white
button.layer.cornerRadius = 10
button.addTarget(self, action: #selector(createSecureShortLink), for: .touchUpInside)
return button
}()

private let shortLinkActivityIndicator = UIActivityIndicatorView(style: .medium)
private let secureLinkActivityIndicator = UIActivityIndicatorView(style: .medium)

private let loadingLabel: UILabel = {
private let loadingShortLinkLabel: UILabel = {
let label = UILabel()
label.text = "Creating Short Link..."
label.textAlignment = .center
Expand All @@ -35,28 +47,68 @@ class ViewController: UIViewController {
label.isHidden = true
return label
}()

private let loadingSecuredShortLinkLabel: UILabel = {
let label = UILabel()
label.text = "Creating Secured Short Link..."
label.textAlignment = .center
label.textColor = .gray
label.font = .systemFont(ofSize: 14)
label.isHidden = true
return label
}()

private let resultLabel: UILabel = {
private let resultShortLinkLabel: UILabel = {
let label = UILabel()
label.textAlignment = .center
label.numberOfLines = 0
label.textColor = .systemGreen
return label
}()

private let copyButton: UIButton = {
private let resultSecureShortLinkLabel: UILabel = {
let label = UILabel()
label.textAlignment = .center
label.numberOfLines = 0
label.textColor = .systemGreen
return label
}()

private let copyShortLinkButton: UIButton = {
let button = UIButton(type: .system)
button.setTitle("Copy Short Link", for: .normal)
button.titleLabel?.font = .systemFont(ofSize: 16, weight: .medium)
button.backgroundColor = .systemGray
button.tintColor = .white
button.layer.cornerRadius = 8
button.isHidden = true
button.addTarget(self, action: #selector(copyToClipboard), for: .touchUpInside)
button.tag = 1
button.addTarget(self, action: #selector(copyToClipboard(_:)), for: .touchUpInside)
return button
}()

private let errorLabel: UILabel = {
private let copySecureShortLinkButton: UIButton = {
let button = UIButton(type: .system)
button.setTitle("Copy Secure Short Link", for: .normal)
button.titleLabel?.font = .systemFont(ofSize: 16, weight: .medium)
button.backgroundColor = .systemGray
button.tintColor = .white
button.layer.cornerRadius = 8
button.isHidden = true
button.tag = 2
button.addTarget(self, action: #selector(copyToClipboard(_:)), for: .touchUpInside)
return button
}()

private let errorShortLinkLabel: UILabel = {
let label = UILabel()
label.textAlignment = .center
label.numberOfLines = 0
label.textColor = .systemRed
return label
}()

private let errorSecureShortLinkLabel: UILabel = {
let label = UILabel()
label.textAlignment = .center
label.numberOfLines = 0
Expand All @@ -71,21 +123,33 @@ class ViewController: UIViewController {
}

private func layoutUI() {
let loaderStack = UIStackView(arrangedSubviews: [activityIndicator, loadingLabel])
loaderStack.axis = .vertical
loaderStack.alignment = .center
loaderStack.spacing = 8
let shortLinkLoaderStack = UIStackView(arrangedSubviews: [shortLinkActivityIndicator, loadingShortLinkLabel])
shortLinkLoaderStack.axis = .vertical
shortLinkLoaderStack.alignment = .center
shortLinkLoaderStack.spacing = 8

let secureLinkLoaderStack = UIStackView(arrangedSubviews: [secureLinkActivityIndicator, loadingSecuredShortLinkLabel])
secureLinkLoaderStack.axis = .vertical
secureLinkLoaderStack.alignment = .center
secureLinkLoaderStack.spacing = 8

let stackView = UIStackView(arrangedSubviews: [
titleLabel,
createButton,
loaderStack,
resultLabel,
copyButton,
errorLabel

createShortLinkButton,
shortLinkLoaderStack,
resultShortLinkLabel,
copyShortLinkButton,
errorShortLinkLabel,

createSecureShortLinkButton,
secureLinkLoaderStack,
resultSecureShortLinkLabel,
copySecureShortLinkButton,
errorSecureShortLinkLabel,
])
stackView.axis = .vertical
stackView.spacing = 20
stackView.spacing = 10
stackView.alignment = .center
stackView.translatesAutoresizingMaskIntoConstraints = false

Expand All @@ -95,39 +159,57 @@ class ViewController: UIViewController {
stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
createButton.widthAnchor.constraint(equalTo: stackView.widthAnchor),
copyButton.widthAnchor.constraint(equalTo: stackView.widthAnchor)

createShortLinkButton.widthAnchor.constraint(equalTo: stackView.widthAnchor),
copyShortLinkButton.widthAnchor.constraint(equalTo: stackView.widthAnchor),
createSecureShortLinkButton.widthAnchor.constraint(equalTo: stackView.widthAnchor),
copySecureShortLinkButton.widthAnchor.constraint(equalTo: stackView.widthAnchor),
])
}

@objc private func copyToClipboard() {
guard let text = resultLabel.text?.replacingOccurrences(of: "Short URL: ", with: "") else { return }
UIPasteboard.general.string = text

let alert = UIAlertController(title: "Copied", message: "Short URL copied to clipboard.", preferredStyle: .alert)
@objc private func copyToClipboard(_ sender: UIButton) {
let text: String?
let message: String

switch sender.tag {
case 1:
text = resultShortLinkLabel.text?.replacingOccurrences(of: "Short URL: ", with: "")
message = "Short URL copied to clipboard."
case 2:
text = resultSecureShortLinkLabel.text?.replacingOccurrences(of: "Secured Short URL: ", with: "")
message = "Secured Short URL copied to clipboard."
default:
return
}

guard let copiedText = text, !copiedText.isEmpty else { return }

UIPasteboard.general.string = copiedText

let alert = UIAlertController(title: "Copied", message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default))
present(alert, animated: true)
}

@objc private func createShortLink() {
resultLabel.text = nil
errorLabel.text = nil
copyButton.isHidden = true
activityIndicator.startAnimating()
loadingLabel.isHidden = false
createButton.isEnabled = false
resultShortLinkLabel.text = nil
errorShortLinkLabel.text = nil
copyShortLinkButton.isHidden = true
shortLinkActivityIndicator.startAnimating()
loadingShortLinkLabel.isHidden = false
createShortLinkButton.isEnabled = false

let parameters: ShortIOParameters
do {
parameters = try ShortIOParameters(
domain: "your_domain",
originalURL: "your_original_url"
originalURL: "{https://{your_domain}"
)
} catch {
activityIndicator.stopAnimating()
loadingLabel.isHidden = true
createButton.isEnabled = true
errorLabel.text = "Invalid input: \(error.localizedDescription)"
shortLinkActivityIndicator.stopAnimating()
createShortLinkButton.isEnabled = true
errorShortLinkLabel.text = "Invalid input: \(error.localizedDescription)"
return
}

Expand All @@ -138,18 +220,39 @@ class ViewController: UIViewController {
let result = try await shortLinkSDK.createShortLink(parameters: parameters, apiKey: apiKey)
switch result {
case .success(let response):
resultLabel.text = "Short URL: \(response.shortURL)"
copyButton.isHidden = false
resultShortLinkLabel.text = "Short URL: \(response.shortURL)"
copyShortLinkButton.isHidden = false
case .failure(let errorResponse):
errorLabel.text = "Error: \(errorResponse.message)"
errorShortLinkLabel.text = "Error: \(errorResponse.message)"
}
} catch {
errorLabel.text = "Error: \(error.localizedDescription)"
errorShortLinkLabel.text = "Error: \(error.localizedDescription)"
}
activityIndicator.stopAnimating()
loadingLabel.isHidden = true
createButton.isEnabled = true
shortLinkActivityIndicator.stopAnimating()
createShortLinkButton.isEnabled = true
loadingShortLinkLabel.isHidden = true
}
}
}

@objc private func createSecureShortLink() {
resultSecureShortLinkLabel.text = nil
errorSecureShortLinkLabel.text = nil
copySecureShortLinkButton.isHidden = true
secureLinkActivityIndicator.startAnimating()
loadingSecuredShortLinkLabel.isHidden = false
createSecureShortLinkButton.isEnabled = false

Task { @MainActor in
do {
let result = try await shortLinkSDK.createSecure(originalURL: "https://{your_domain}")
resultSecureShortLinkLabel.text = "Secured Short URL: \(result.securedShortUrl)"
copySecureShortLinkButton.isHidden = false
} catch {
errorSecureShortLinkLabel.text = "Error: \(error.localizedDescription)"
}
secureLinkActivityIndicator.stopAnimating()
createSecureShortLinkButton.isEnabled = true
loadingSecuredShortLinkLabel.isHidden = true
}
}
}
19 changes: 19 additions & 0 deletions SwiftUIProject/ShortIOApp/AppDelegate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import Foundation
import SwiftUI
import ShortIOSDK


class AppDelegate: NSObject, UIApplicationDelegate {

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {

let sdk = ShortIOSDK.shared

sdk.initialize(apiKey: "your-api-key-here", domain: "your-domain-here")

// Override point for customization after application launch.
return true
}

}

Loading