Axle works with Enode to provide access to a wide array of EVs, chargers, heat pumps, and batteries.Axle will call the Enode API directly on your behalf to read from and control assets. We provide a pre-built integration
to help you gather credentials from your users, access assets, and confer the ability to control them to Axle.Enode host their own onboarding flow - LinkUI. This guide
will demonstrate how to use Axle Components and LinkUI to onboard and connect an asset.If you’re developing in another platform, get in touch to discuss how we can provide a native integration.
This is a helper component, which will automatically generate and return correctly
scoped Enode tokens.The end user will see a loading indicator, and you’ll need to listen to messages to correctly
show the Native Enode SDK.
Example component view
Copy
import SwiftUIimport WebKitstruct WebView: UIViewRepresentable { let url: String func makeUIView(context: Context) -> WKWebView { let webView = WKWebView() return webView } func updateUIView(_ webView: WKWebView, context: Context) { guard let url = URL(string: url) else { return } let request = URLRequest(url: url) webView.load(request) }}struct AxleEnodeIntegration: View { var body: some View { NavigationView { WebView(url: "https://app.axle.energy/form/enode/vehicle") } }}
Step 2: Listen for the Enode token from the component
You’ll need to listen for the Enode token once the component has authenticated and fetched from Axle. The Enode
component automatically sends this token using WKWebView message handlers on iOS.We’ll first register the message handlers in the WebView. This example is using SwiftUI,
but it’s also easy to do this in UIKit by implementing the WKScriptMessageHandler delegate.
Register message handler in the WebView
Copy
// In EnodeWebView struct// Two way communication with parent view@Binding var messageHandler: ((String, Any?) -> Void)?func makeUIView(context: Context) -> WKWebView { let webView = WKWebView() // Register a message listener in the webview let userContentController = webView.configuration.userContentController userContentController.add(context.coordinator, name: "axleEnode") return webView}// Called automatically by SwiftUI when instantiating the viewfunc makeCoordinator() -> Coordinator { Coordinator(self)}class Coordinator: NSObject, WKScriptMessageHandler { var parent: WebView init(_ parent: WebView) { self.parent = parent } func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { parent.messageHandler?(message.name, message.body) }}
Step 3: Handle the Enode token and trigger LinkSDK
Once you receive the Enode token from the Axle component, you’ll need to present the LinkSDK to complete the asset connection. First, import LinkKit and add the necessary state variables.
Import LinkKit and add state variables
Copy
import SwiftUIimport LinkKitstruct AxleEnodeIntegration: View { @State private var isLinkKitPresented = false @State private var linkToken: String? = nil @State private var messageHandler: ((String, Any?) -> Void)? // ... rest of the view}
Next, update your message handler to extract the link token from the response and trigger the LinkSDK:
Handle token and trigger LinkSDK
Copy
private func setupMessageHandler() { messageHandler = { messageName, messageBody in DispatchQueue.main.async { switch messageName { case "handoff": // Extract link token from the response if let responseData = messageBody as? [String: Any], let token = responseData["linkToken"] as? String { linkToken = token isLinkKitPresented = true } default: print("Unknown message: \(messageName)") } } }}
Finally, add the LinkKit sheet to your view and handle the results:
Add LinkKit sheet
Copy
var body: some View { NavigationView { WebView(url: "https://app.axle.energy/form/enode/vehicle", messageHandler: $messageHandler) } .onAppear { setupMessageHandler() } .linkKitSheet(isPresented: $isLinkKitPresented, linkToken: linkToken) { linkResult in switch linkResult { case .success(let success): handleLinkSuccess(success) case .failure(let error): handleLinkError(error) } }}
Add the success and error handlers:
Handle LinkSDK results
Copy
private func handleLinkSuccess(_ success: LinkSuccessMetadata) { print("LinkKit success: \(success)") // Move to the next stage in your onboarding!}private func handleLinkError(_ error: LinkError) { print("LinkKit error: \(error)") // Handle LinkKit error // Show error message to user or retry flow}