# Remove Widget and Notification Features URL: https://easyapp.site/en/docs/FQA/removeWidgetNoti Remove all widget and notification features *** title: Remove Widget and Notification Features description: Remove all widget and notification features icon: FileQuestionIcon ---------------------- If you temporarily don't need widget and notification features, you can follow the steps below to remove related code and configurations ### Remove Widgets * Delete the `EasyAppWidget` folder, select `Move to Trash` ![removeWidget1](/media/fqa/removeWidget1.png) * Right-click to delete `EasyAppWidgetExtension` ![removeWidget2](/media/fqa/removeWidget2.png) * Uncheck `widget` in `App Group`, as shown in step 3 of the image below ![removeWidget3](/media/fqa/removeWidget3.png) * Delete the `App -> Developer -> SubPages -> LiveActivity` folder, select `Move to Trash` ![removeWidget4](/media/fqa/removeWidget4.png) * Go to `App -> Developer -> View -> DeveloperView.swift` file, delete the code ![removeWidget5](/media/fqa/removeWidget5.png) ![removeWidget6](/media/fqa/removeWidget6.png) ![removeWidget7](/media/fqa/removeWidget7.png) ![removeWidget8](/media/fqa/removeWidget8.png) * Go to `EasyAppSwiftUIApp.swift` file, delete the following `widget` related code ```swift #if DEBUG @State private var showLiveActivityDemo = false @State private var showWidgetMicrophoneDemo = false @State private var showWidgetCameraDemo = false #endif ``` ```swift // live activity .onOpenURL { url in devLogger.info("onOpenURL: \(url)") let liveActivityValue = url.getEaspAppDeepLinkUrlParam( hostKey: "live-activity", name: "path") let widgetMicrophoneValue = url.getEaspAppDeepLinkUrlParam( hostKey: "microphone", name: "path") let widgetCameraValue = url.getEaspAppDeepLinkUrlParam( hostKey: "camera", name: "path") if let liveActivityValue, liveActivityValue == "live-activity" { showLiveActivityDemo.toggle() } if let widgetMicrophoneValue, widgetMicrophoneValue == "microphone" { showWidgetMicrophoneDemo.toggle() } if let widgetCameraValue, widgetCameraValue == "camera" { showWidgetCameraDemo.toggle() } } // widget .sheet(isPresented: $showWidgetMicrophoneDemo) { OpenWidgetMicrophoneDemo() } .sheet(isPresented: $showWidgetCameraDemo) { OpenWidgetCameraDemo() } ``` ### Remove Notification Features * Remove the dependency on `EasyAppNotifyKit` library ![removeNot0](/media/fqa/removeNot0.png) Select `EasyAppNotifyKit`, click the `-` button (might fail, try multiple times) ![removeNot0\_1](/media/fqa/removeNot0_1.png) * Delete notification permissions Uncheck `Notifications` permission ![delete-remoteN](/media/fqa/delete-remoteN.png) ![delete-remoteN2](/media/fqa/delete-remoteN2.png) * Search and delete the following imported libraries in the `EasyAppSwiftUI` project ```swift import EasyAppNotifyKit import OneSignalFramework ``` * Delete/comment out the related code in the `EasyAppSwiftUI/Lib/Auth/AuthManager.swift` file ```swift title="EasyAppSwiftUI/Lib/Auth/AuthManager.swift" PushManager.shared.loginUser(userId) ``` ```swift title="EasyAppSwiftUI/Lib/Auth/AuthManager.swift" PushManager.shared.logoutUser() ``` * Delete the following content, select `Move to Trash` ![removeNot](/media/fqa/removeNot.png) ![removeNot3](/media/fqa/removeNot3.png) ![removeNot4](/media/fqa/removeNot4.png) * Go to `EasyAppSwiftUI/App/Developer/View/DeveloperView.swift`, delete the code ![removeNot5](/media/fqa/removeNot5.png) ![removeNot6](/media/fqa/removeNot6.png) ![removeNot7](/media/fqa/removeNot7.png) * Uncheck ![removeNot2](/media/fqa/removeNot2.png) * Go to `EasyAppSwiftUIApp.swift` file, delete the following `notification` related code ```swift #if DEBUG @State private var showDeepLinkTest = false #endif ``` ```swift // Show the deep link test view when the notification is clicked #if DEBUG .sheet(isPresented: $showDeepLinkTest) { OSDeepLinkTargetTestView() } .onReceive( NotificationCenter.default.publisher( for: EasyAppNotifyKit.Notifications.osNotificationClicked) ) { notification in let deeplink = notification.userInfo?["deeplink"] as? String if let deeplink, deeplink == "EasyApp://notifykit?screen=osTests" { withAnimation(.spring(response: 0.5, dampingFraction: 0.8)) { showDeepLinkTest = true } } } #endif ``` ```swift if Constants.OneSignal.isEnabledNotification { let oneSignalService = OneSignalService() PushManager.shared.configure(with: oneSignalService) let configuration: PushServiceConfiguration = PushServiceConfiguration( appId: Constants.OneSignal.appId, launchOptions: launchOptions ) PushManager.shared.initialize(with: configuration) OneSignal.Notifications.addClickListener(self) OneSignal.Notifications.addForegroundLifecycleListener(self) } ``` ```swift extension AppDelegate: OSNotificationClickListener, OSNotificationLifecycleListener { func onClick(event: OSNotificationClickEvent) { devLogger.info("Notification clicked: \(event.jsonRepresentation())") self.handleViewTap(additionalData: event.notification.additionalData) } func onWillDisplay(event: OSNotificationWillDisplayEvent) { devLogger.info("Foreground notification: \(event.notification.title ?? "No Title")") event.preventDefault() guard let notifTitle = event.notification.title, let notifMessage = event.notification.body, let additionalData = event.notification.additionalData, let symbol = additionalData["symbolImage"] as? String else { event.notification.display() // Show notification as usual return } var notifHaptics: UINotificationFeedbackGenerator.FeedbackType = .warning if let size = additionalData["status"] as? String { if size == "error" { notifHaptics = .error } else if size == "success" { notifHaptics = .success } UINotificationFeedbackGenerator().notificationOccurred(notifHaptics) } ShowNotification.showInAppNotification( title: notifTitle, message: notifMessage, isSuccess: notifHaptics == .success, duration: .seconds(seconds: 5), systemImage: symbol, handleViewTap: { self.handleViewTap(additionalData: event.notification.additionalData) } ) } /// Handle the view tap /// - Parameter additionalData: the additional data private func handleViewTap(additionalData: [AnyHashable: Any]? = nil) { // Parse the additional data let ad = JSON(additionalData ?? [:]) // Get the deeplink let deeplink = ad["deeplink"].stringValue if !deeplink.isEmpty { // Broadcast click to allow host views to react (e.g., navigate) NotificationCenter.default.post( name: EasyAppNotifyKit.Notifications.osNotificationClicked, object: nil, userInfo: [ "deeplink": deeplink ] ) } } } ``` Finally, run the `Cmd + B` command to check for any other errors. # RevenueCat Related URL: https://easyapp.site/en/docs/FQA/revenueCat RevenueCat Common Errors *** title: RevenueCat Related description: RevenueCat Common Errors icon: FileQuestionIcon ---------------------- ### RevenueCat Common Errors ![reCat\_err](/media/fqa/reCat_err.png) Usually, this is because your App Store Connect agreement is not signed or has issues. You need to check [https://appstoreconnect.apple.com/business/atb/95c7eacb-a537-4036-9c21-ff4c032d3f94](https://appstoreconnect.apple.com/business/atb/95c7eacb-a537-4036-9c21-ff4c032d3f94) Check if the paid app agreement is valid ![reCat\_err1](/media/fqa/reCat_err1.png) # AI Features URL: https://easyapp.site/en/docs/Integrations/AI Learn how to use Supabase Edge Function to call AI APIs in EasyAppSwiftUI *** title: AI Features description: Learn how to use Supabase Edge Function to call AI APIs in EasyAppSwiftUI icon: Brain ----------- # AI Feature Integration Guide This document provides a detailed guide on how to use **Supabase Edge Function** to call AI APIs in EasyAppSwiftUI, using receipt analysis functionality as an example to demonstrate the complete implementation process. ## Why Choose Supabase Edge Function? Using Supabase Edge Function as an intermediate layer for AI services offers the following significant advantages:

No additional server maintenance costs, pay-as-you-go model

API Keys are securely stored on the server side, avoiding client-side packet capture risks

Easy access to user information for permission control and data management

**Strongly Recommended**: Store API Keys on the server side rather than the client side. Network requests from mobile apps are easily intercepted by packet capture tools, leading to API Key leakage. ### Related Resources Want to learn more about Supabase Edge Function? Please refer to the official documentation: * [Supabase Edge Functions Official Guide](https://supabase.com/docs/guides/functions) For more information on how to integrate Supabase Edge Function, please refer to: } href="/docs/Integrations/supabaseEdgeFuncton">

Introduction to Supabase Edge Function

We can combine with in-app purchases to provide different AI analysis counts, such as 10 free, 100 paid, 1000 paid, etc. This feature is currently under development, stay tuned. ## System Architecture Overview The AI feature adopts the following architecture design: ``` SwiftUI App → Supabase Storage → Supabase Edge Function → OpenAI API → Streaming Response → SwiftUI ``` ## Demo
Go back to the `Supabase` console and check the `Users` table, you can see the user information from your Apple Sign In. ![SignAppleSuccess](/media/Integrations/SignAppleSuccess.png) Congratulations 🎉🎉🎉, you have successfully integrated the Apple Sign In function. ### Support Email Verification Function Supabase enables email authentication by default, and EasyApp of course supports it. But you need to configure Deep Linking. The configuration process is very simple. 1. Set `URL Type` in Xcode ![urlType](/media/Integrations/urlType.png) In the screenshot, you need to fill in `identifier` and `URL Schemas` - `identifier` is recommended to use Bundle Identifier. - `URL Schemas` is recommended to use your App name. 2. Configure `Deep Linking` in Supabase Next, go to the Supabase `Authentication` page and click the `URL Configuration` button. ![urlConfirm](/media/Integrations/urlConfirm.png) Click the `Add URL` button and enter your App's URL. When filling in Deep Linking, we recommend using the format `YourAppName://user?type=sign_up`. Let me explain why we set it up this way, where `user` represents the module name, `type` represents the type, and `sign_up` represents email verification. The user module has the following types: - `sign_up`: email verification - `reset_password`: password reset So we use `type` to distinguish. In `SwiftUI`, we distinguish through module name + `type`. ```swift .onOpenURL { url in let value = url.getEaspAppDeepLinkUrlParam(hostKey: "user", name: "type") guard value == "reset_password" else { return } /// Handle password reset logic } ``` ```swift .onOpenURL { url in let value = url.getEaspAppDeepLinkUrlParam(hostKey: "user", name: "type") guard value == "sign_up" else { return } /// Handle email verification logic } ``` Add URL filling rules: URL Schemas + :// The EasyApp template has already configured the email verification/password reset Deep Linking rules. You need to configure `identifier` and `URL Schemas` in Xcode. Then configure `Deep Linking` in your `Supabase` as shown in the figure. If you have other needs later, just follow this rule to configure At this point, you can normally use Email authentication function. Process: User registration successful -> Supabase sends email -> User clicks link in email -> Directly returns to the App -> Login successful. 3. Resend verification email For user experience, we have made the following optimizations: - After successful user registration, assuming the user does not verify the email in time, when they reopen the app at some point, we will check whether the current user has verified the email If the user has not verified the email, we will prompt the user to verify the email. So we provide a `VerifyEmailView` This component will automatically pop up when the user has not verified the email and supports users to resend verification emails. The Supabase platform provides a default email sending service for you to try. This service is limited to 2 emails per hour and only provides best-effort availability. For production use, we recommend configuring a custom SMTP server. For specific operation guidelines, please refer to [Custom SMTP Configuration Guide](https://supabase.com/docs/guides/auth/auth-smtp) ### Disable Email Verification Function If you don't plan to use Email authentication function, you can disable them. ![email](/media/signUp/email.png) ![emailNoComfirm](/media/signUp/emailNoComfirm.png) If you disable the email verification function, after user registration is completed, to optimize the shortest login process: we will let the user log in directly successfully. */} # Configure Supabase URL and API Key ### Step 1: Get Supabase URL and API Key * Get Supabase URL. Click the "Connect" button in the top navigation bar. In the popup, select Mobile Framework, select Swift from Framework. Copy supabaseURL. ![connnect](/media/Integrations/connect.png) ![copySupabaseUrl](/media/Integrations/copySupabaseUrl.png) * Get Supabase API key. Click the "Project Settings" button in the sidebar, click the "API Keys" button. Click the "Copy" button. ![copyAKey](/media/Integrations/copyAKey2.png) ### Step 2: Configure Supabase URL and API Key in the `EasyAppSwiftUI/Constants/Constants.swift` file Forgot? No problem, let's review again. } href="/docs/configuration/supabase">

Supabase URL and API key

Paste the URL and API key we just obtained into the `EasyAppSwiftUI/Constants/Constants.swift` file. ```swift enum Supabase { #if DEBUG /// Development supabase url static let url = "http://192.168.124.134:54321" /// The anon key static let key = "your_local_anon_key" #else /// Production supabase url /// WARNING: Replace with your production supabase url, only test environment static let url = "your_production_supabase_url" /// The anon key /// WARNING: Replace with your production supabase anon key, only test environment static let key = "your_production_supabase_anon_key" #endif } ``` Here we can see there is environment judgment, `#if DEBUG` means development environment, `#else` means production environment. For better understanding, you should replace the content in both `#if DEBUG` and `#else` here. That is: ```swift #if DEBUG static let url = "your_production_supabase_url" static let key = "your_production_supabase_anon_key" #else static let url = "your_production_supabase_url" static let key = "your_production_supabase_anon_key" #endif ``` Replace all with your Supabase online url and api key.
{/* # Test Your Results ### Registration You can use a real device/simulator to run the EasyApp application. Open the Xcode project and press "Command + R". On the registration page, you can enter your email and password, then click the "Sign Up" button.
![signUp](/media/signUp/signUp.png)
After successful registration, we can see your user information in Supabase's "Users" table. ![signUpSuccess](/media/signUp/signUpSuccess.png) ### Login Next, let's perform the login operation
![signUp](/media/signUp/signIn.png) ![signUp](/media/signUp/setting.png)
Congratulations 🎉🎉, you have successfully integrated Supabase user authentication service.
*/} ### Step 3: Deploy Supabase Backend Service At this point, you have completed the integration of the Supabase service on the app side. Next, you need to configure the Supabase backend service, because the Supabase backend service includes user authentication, database, storage service, backend API, etc. All functions in the App depend on the Supabase backend service. } href="/docs/Integrations/supabaseEdgeFuncton" /> # How to Register Apple Developer Account URL: https://easyapp.site/en/docs/quickstart/appleDeveloper Learn how to quickly register an Apple Developer account *** title: How to Register Apple Developer Account description: Learn how to quickly register an Apple Developer account icon: Apple ----------- The registration tutorial reference [official documentation](https://developer.apple.com/programs/enroll/) Without a developer account, there are the following limitations. (This is an Apple requirement, not related to the template). * Cannot use Apple Sign-In * Cannot use in-app purchases * Cannot use push notifications Other features have no restrictions for now. Solutions: You can first run it on the simulator. For login, use regular email/password login. Remember to turn off Supabase email authentication, as email verification logic is difficult to test on the simulator. How to disable email verification functionality is documented in the Supabase integration chapter. } href="/docs/Integrations/Supabase#disable-email-verification">

Disable email verification functionality

There's no need to comment out the code for now. First, complete your core business development, and when you're about to launch, pay for a developer account and integrate Apple Sign-In and in-app purchases. After development is complete, you can directly delete template code for features you don't need, which can also reduce some issues encountered during review. If you still encounter other problems, you can contact us on [Discord](https://discord.gg/36UQMU6yKw) or [GitHub](https://github.com/FastEasyApp/easyapp-swiftui).
# Apple Login/Email Login URL: https://easyapp.site/en/docs/quickstart/appleLogin Learn how EasyAppSwiftUI project integrates Apple Login/Email Login *** title: Apple Login/Email Login description: Learn how EasyAppSwiftUI project integrates Apple Login/Email Login icon: Apple ----------- # Set up Apple Sign In (Recommended) We recommend you use Apple Sign In. Compared to traditional registration and login processes, Apple Sign In provides a better overall user experience. of course, if you don't plan to use Apple Sign In, you can skip this step. ### Configure Apple Sign In First, make sure you have an available Apple Developer account. If you haven't registered yet, please refer to the [official documentation](https://developer.apple.com/cn/help/account/membership/enrolling-in-the-app) to register. After registration, log in to your developer account and go to the [`Identifiers`](https://developer.apple.com/account/resources/identifiers/list) page, click the `+` button #### Step 1: Register Services ID ![Identifiers](/media/Integrations/Identifiers.png) ![addIdentifiers](/media/Integrations/addIdentifiers.png) Select `Services IDs` and click the `Continue` button ![ServicesIDs](/media/Integrations/ServicesIDs.png) `Description` can be named using your app name + Services ID. `Identifier` is recommended to be named as bundleID.ServicesID. Where bundleID is your app's unique identifier. Click the `Continue` button ![RServicesIDs](/media/Integrations/RServicesIDs.png) You can find bundleID in your Xcode project here. ![XcodeBundleID](/media/Integrations/XcodeBundleID.png) Click the `Register` button ![registerIdent](/media/Integrations/registerIdent.png) After completion, return to the `Identifiers` page and click the `Services IDs` we just created ![successRegisterIdent](/media/Integrations/successRegisterIdent.png) If you can't find the `Services IDs` we just created, filter as shown below ![filterIdns](/media/Integrations/filterIdns.png) Enable `Sign in with Apple` function and click the `Configure` button ![configIdns](/media/Integrations/configIdns.png) In the popup window, you need to configure the following options: Please replace `SUPABASE_PROJECT_ID` with your Supabase project ID. You can find it here ![findSupabaseProjectID](/media/Integrations/findSupabaseProjectID.png) In the documentation example, our `SUPABASE_PROJECT_ID` is `mutkgdbrerijqhqccalu`. 1. In `Primary App ID`, select your App's `Bundle Identifier` from the dropdown. 2. In the `Domains and Subdomains` field, enter `supabase.co,SUPABASE_PROJECT_ID.supabase.co` 3. In the `Return URLs` field, enter `https://SUPABASE_PROJECT_ID.supabase.co/auth/v1/callback` 4. Click the `Next` button and `Done` button ![WebAuthConfig](/media/Integrations/WebAuthConfig.png) Click the `Continue` button and click the `Save` button ![saveWebAuthConfig](/media/Integrations/saveWebAuthConfig.png) ![saveWebAuthConfig2](/media/Integrations/saveWebAuthConfig2.png) #### Step 2: Create .p8 Authentication Key for Apple Sign In Go to the [`Keys`](https://developer.apple.com/account/resources/authkeys/list) page and click the `+` button ![CreateKeys](/media/Integrations/CreateKeys.png) 1. Enter your `Key Name`, for easier identification later, we recommend naming it with your app name + Keys. 2. Select `Sign in with Apple` function and click the `Configure` button. 3. After clicking the `Configure` button, select your `App ID` from the `Primary App ID` dropdown. 4. Click the `Save` button ![RNewKey](/media/Integrations/RNewKey.png) ![CKeys](/media/Integrations/CKeys.png) Then click the `Continue` button and click the `Register` button ![NewKeyCon](/media/Integrations/NewKeyCon.png) ![NewKeyReg](/media/Integrations/NewKeyReg.png) #### Step 3: Integrate Apple Sign In with Supabase Go to your [`Supabase`](https://supabase.com/dashboard/project/mutkg233333dbrerijqhq22ccalu/auth/providers) project, click the sidebar `Authentication`, click `Sign In/Providers`, click the `Apple` button. ![SupabaseSignApple](/media/Integrations/SupabaseSignApple.png) In the popup window, you need to configure the following information: 1. Enable `Enable Sign in with Apple` function 2. In the `Client IDs` field, enter your `Services ID` and your app's unique identifier `bundleID`. (separated by commas, no spaces) ![AppleModalSave](/media/Integrations/AppleModalSave.png) The `Secret Key (for OAuth)` field can be left empty. 3. Click save Forgot `Services ID` and `bundleID`? No problem, let's review again. 1. On the [`Identifiers`](https://developer.apple.com/account/resources/identifiers/list) page, find the `Services IDs` we just created. ![successRegisterIdent](/media/Integrations/successRegisterIdent.png) 2. In your Xcode project, find `Bundle Identifier`. ![XcodeBundleID](/media/Integrations/XcodeBundleID.png) Or on the [`Identifiers`](https://developer.apple.com/account/resources/identifiers/list) page, you can also find it ![IdensBIds](/media/Integrations/IdensBIds.png) #### Step 4: Test Apple Sign In Apple Sign In testing needs to be done on a real device.