Integration
iOS Integration
Add Reqflow to your iOS app using WKWebView for a native-feeling feedback experience.
Prerequisites
- iOS 14.0+ — Minimum deployment target
- Xcode 14+ — Latest recommended
- Reqflow app — Created in the dashboard
UIKit Implementation
Create a view controller that displays the Reqflow feedback page using WKWebView.
FeedbackViewController.swift
import UIKit
import WebKit
class FeedbackViewController: UIViewController {
private var webView: WKWebView!
// Your app's slug from the Reqflow dashboard
private let appId = "your-app-id"
override func viewDidLoad() {
super.viewDidLoad()
title = "Feedback"
// Configure WebView
let config = WKWebViewConfiguration()
webView = WKWebView(frame: view.bounds, configuration: config)
webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(webView)
loadFeedbackPage()
}
private func loadFeedbackPage() {
// Get user info from your auth system
let userId = getUserId()
let userName = getUserName()
let userEmail = getUserEmail()
var components = URLComponents(
string: "https://reqflow.com/vote/\(appId)"
)!
components.queryItems = [
URLQueryItem(name: "user_id", value: userId),
URLQueryItem(name: "user_name", value: userName),
URLQueryItem(name: "user_email", value: userEmail)
]
if let url = components.url {
webView.load(URLRequest(url: url))
}
}
private func getUserId() -> String {
// Use device identifier or your auth system's user ID
return UIDevice.current.identifierForVendor?.uuidString
?? UUID().uuidString
}
private func getUserName() -> String {
return "User Name" // Get from your auth system
}
private func getUserEmail() -> String? {
return nil // Optional: return user's email
}
}SwiftUI Implementation
For SwiftUI apps, wrap the WebView in a UIViewRepresentable.
FeedbackView.swift
import SwiftUI
import WebKit
struct FeedbackView: UIViewRepresentable {
let appId: String
let userId: String
let userName: String
var userEmail: String?
func makeUIView(context: Context) -> WKWebView {
let webView = WKWebView()
loadFeedbackPage(in: webView)
return webView
}
func updateUIView(_ webView: WKWebView, context: Context) {}
private func loadFeedbackPage(in webView: WKWebView) {
var components = URLComponents(
string: "https://reqflow.com/vote/\(appId)"
)!
var queryItems = [
URLQueryItem(name: "user_id", value: userId),
URLQueryItem(name: "user_name", value: userName)
]
if let email = userEmail {
queryItems.append(URLQueryItem(name: "user_email", value: email))
}
components.queryItems = queryItems
if let url = components.url {
webView.load(URLRequest(url: url))
}
}
}
// Usage
struct ContentView: View {
var body: some View {
NavigationView {
FeedbackView(
appId: "your-app-id",
userId: UIDevice.current.identifierForVendor?.uuidString ?? "",
userName: "John Doe",
userEmail: "john@example.com"
)
.navigationTitle("Feedback")
}
}
}Opening the Feedback Screen
Add a button in your app settings or menu to present the feedback screen.
// Present modally from any view controller
@IBAction func feedbackButtonTapped(_ sender: Any) {
let feedbackVC = FeedbackViewController()
let navController = UINavigationController(rootViewController: feedbackVC)
feedbackVC.navigationItem.rightBarButtonItem = UIBarButtonItem(
barButtonSystemItem: .done,
target: self,
action: #selector(dismissFeedback)
)
present(navController, animated: true)
}
@objc func dismissFeedback() {
dismiss(animated: true)
}Consistent User ID
Always use
identifierForVendor or your auth system's user ID. Don't generate a new UUID each time, or users will lose their votes.Secure Authentication (Optional)
For enhanced security, you can add HMAC signature verification to prevent user impersonation. The signature should be generated by your backend and passed to the app.
SignatureHelper.swift
import CryptoKit
/// Generate HMAC signature for secure authentication (optional)
func generateSignature(userId: String, secret: String) -> (signature: String, timestamp: String) {
let timestamp = String(Int(Date().timeIntervalSince1970))
let payload = "\(userId):\(timestamp)"
let key = SymmetricKey(data: Data(secret.utf8))
let signature = HMAC<SHA256>.authenticationCode(
for: Data(payload.utf8),
using: key
)
let signatureHex = signature.map { String(format: "%02x", $0) }.joined()
return (signatureHex, timestamp)
}
// Usage with WebView
func loadFeedbackPageWithSignature() {
let userId = getUserId()
let secret = "your-secret-from-backend" // Get from your backend, not hardcoded
let (signature, timestamp) = generateSignature(userId: userId, secret: secret)
var components = URLComponents(string: "https://reqflow.com/vote/\(appId)")!
components.queryItems = [
URLQueryItem(name: "user_id", value: userId),
URLQueryItem(name: "user_name", value: getUserName()),
URLQueryItem(name: "signature", value: signature),
URLQueryItem(name: "timestamp", value: timestamp)
]
if let url = components.url {
webView.load(URLRequest(url: url))
}
}Security Note
Don't hardcode the secret in your app. Fetch it from your backend or use iOS Keychain for secure storage. The signature feature is optional and only needed if you enable it on your Reqflow server.
Best Practices
- Loading State — Add a UIActivityIndicatorView while the page loads
- Error Handling — Implement WKNavigationDelegate to handle network errors
- Dark Mode — Reqflow automatically adapts to the system appearance
- Safe Area — The WebView respects safe area insets automatically