Category: Xcode

Xcode is Apple’s integrated development environment for macOS, used to develop software for macOS, iOS, iPadOS, watchOS, and tvOS.

  • Essential App Store Checklist: Launch Your App with Confidence

    Essential App Store Checklist: Launch Your App with Confidence

    This blog post “Essential App Store Checklist: Launch Your App with Confidence” provides a comprehensive guide for developers preparing to launch their mobile app on various app stores. It emphasizes the importance of thorough preparation to ensure a smooth launch and successful visibility.

    Key elements:

    • App Design and Functionality: Ensuring that the app is user-friendly and meets the needs of the target audience.
    • App Store Optimization (ASO): Tips on keywords, engaging descriptions, and attractive visuals to enhance discoverability.
      Beta Testing: The significance of testing the app with real users to gather feedback and identify bugs.
    • Compliance and Guidelines: Adhering to the specific submission guidelines set by different app stores to avoid rejections.
    • Marketing Strategy: Planning a promotion strategy that includes social media, content marketing, and engaging press releases.
    • The post concludes with encouragement to follow the checklist diligently, which will help developers launch their apps confidently and improve their chances of success in a competitive marketplace.

    AppStore Listing

    App General Info

    1. App Preview & Screenshots – Screenshots must be in the JPG or PNG format, and in the RGB color space. App previews must be in the M4V, MP4, or MOV format and can’t exceed 500 MB.
    2. Promotional Text – Promotional text lets you inform your App Store visitors of any current app features without requiring an updated submission. This text will appear above your description on the App Store for customers with devices running iOS 11 or later, and macOS 10.13 or later.
    3. Description – A description of your app, detailing features and functionality.
    4. What’s New in This Version – Describe what’s new in this version of your app, such as new features, improvements, and bug fixes.
    5. Keywords – Include one or more keywords that describe your app. Keywords make App Store search results more accurate. Separate keywords with an English comma, Chinese comma, or a mix of both.
    6. Support URL – A URL with support information for your app. This appears on your app’s product page once you release your app on the App Store.
    7. Marketing URL – A URL with marketing information about your app. This URL will be visible on the App Store.
    8. Version – The version of the app you are adding. Numbering should follow software versioning conventions.
    9. Copyright – The name of the person or entity that owns the exclusive rights to your app, preceded by the year the rights were obtained (for example, “2008 Acme Inc.”). Do not provide a URL.
    10. Build – Build of your app version from Xcode
    11. App Icon – Xcode should have it already
    12. App Review Information – If your app has a login window, otherwise you don’t need it.
    13. App Store Version Release – Choose to automatically release this version. Also, you can choose to manually release it or release on a specific date.

    App Information

    1. Name – The name will be reviewed with the next submission of your app.
    2. Subtitle –  A summary of your app that will appear under your app’s name on your App Store product page. This can’t be longer than 30 characters.
    3. Category Primary – The category that best describes this app.
    4. Category Secondary – The category you want after the primary category

    Note: Some of these can be auto populated by Xcode

    App Privacy

    1. Privacy Policy URL – A URL that links to your privacy policy. A privacy policy is required for all apps.
    2. Data collection declaration – Just say the app doesn’t collect any data.

    Pricing and Availability

    1. Prices – Leave it to Free or set your Price.
    2. App Availability – All Countries or you can make it available for only a few countries.

    Xcode

    Set the bundle ID

    When you create your Xcode project from a template, the bundle ID (CFBundleIdentifier), which uniquely identifies your app throughout the system, defaults to the organization ID appended to the app name that you enter in reverse-DNS format—for example, the bundle ID becomes com.example.mycompany.HelloWorld.

    1. Choose the target.
    2. Click the Signing & Capabilities pane.
    3. Expand Signing.
    4. Enter the bundle ID in the Bundle Identifier text field.

    2. Set the supported destinations

    Indicate which devices and platforms your app supports. In the project editor:

    1. Choose the target.
    2. Select the General pane.
    3. Expand the Supported Destinations section.
    4. Click the Add button (+), choose a device and platform. To remove a destination, select it and click the Remove button (-).

    3. Set the app category

    Categories help customers discover your app on the App Store. In App Store Connect, you set the primary and secondary categories that you want your app to appear under in the App Store. For macOS apps, you also set a category for your app in your project.

    Select a category that matches or closely relates to the primary category you set in App Store Connect:

    1. Choose the target.
    2. Select the General pane.
    3. Expand the Identity section.
    4. Choose a category from the App Category pop-up menu.

    For guidance with choosing the most accurate and effective categories, see Choosing a category.

    4. Edit deployment info settings

    For iOS and iPadOS apps, choose the device orientations your app supports.

    5. Add an app icon and App Store icon

    Create icon https://www.candyicons.com/free-tools/app-icon-assets-generator

    Add an icon to represent your app in various locations on a device and on the App Store.

    A project created from a template already contains the image set for app icons. The App Icons and Launch Images section of the General pane displays the name of the asset. Open the asset in the asset catalog to configure the icon ass

    Spread the love
  • Sync your Macs with iCloud

    Sync your Macs with iCloud

    As a software developer, I always strive to streamline my workflow and maximize the tools at my disposal. One of the challenges I faced was synchronizing my Macs with various Integrated Development Environments (IDEs) and editors I used for different projects, especially all the snippets I have been collecting for the last 10 years.

    Mainly I use Xcode, Android Studio, and VS Code. VSCode for Laravel or Django, most of the time.

    I always used two different Macs one for home and one for when I’m away. When I travel I always use my Macbook Air, and Macbook Pro when not traveling. Whenever I open my other Mac I always have the latest code snippets and configuration files.

    Here are a few tips to sync different tools between your Macs using iCloud. I don’t use any other file-sharing stuff on my Mac.

    Change {USERNAME} with your username.

    Sync AndroidStudio

    ln -s /Users/{USERNAME}/Desktop/android/AndroidStudio/AndroidStudio2023.2 /Users/{USERNAME}/Library/Application\ Support/Google

    Sync Xcode

    ln -s /Users/{USERNAME}/Desktop/Xcode/UserData /Users/{USERNAME}/Library/Developer/Xcode/

    DBeaver Community Edition

    ln -s /Users/{USERNAME}/Desktop/mysql/General /Users/{USERNAME}/Library/DBeaverData/workspace6/

    Bookmark this page for the future I might sync more stuff in my Macs.

    How to make TextEdit Start with a blank file. (Log out require)

    defaults write com.apple.TextEdit NSShowAppCentricOpenPanelInsteadOfUntitledFile -bool false

    Spread the love
  • Auto-renewable subscriptions with SwiftUI

    Auto-renewable subscriptions with SwiftUI

    Auto-renewable subscriptions with SwiftUI

    Read about App Store Server Integration in Laravel

    Auto-renewable subscriptions provide access to content, services, or premium features in your app on an ongoing basis. They automatically renew at the end of their duration until the user chooses to cancel. Subscriptions are available on iOS, iPadOS, macOS, watchOS, and tvOS.

    Great subscription apps justify the recurring payment by providing ongoing value and continually innovating the app experience. If you’re considering implementing the subscription model, plan to regularly update your app with feature enhancements or expanded content.

    To offer subscriptions, youʼll need to configure them in App Store Connect and use StoreKit APIs in your app. You’ll also need to assign each subscription to a subscription group (a group of subscriptions with different access levels, prices, and durations that people can choose from), then add details such as a name, price, and description. This information displays in the In-App Purchases section of your app’s product page on the App Store. Ensure that the subscriptions are available across all device types that your app supports. Consider allowing a way for subscribers to see the status of their subscription within your app, along with upgrade, crossgrade, and downgrade options, as well as a way to easily manage or turn off their auto-renewable subscription. Make sure to follow our design and review guidelines.

    To get ready:

    Before creating any subscription make sure you have done all these steps and all are showing Active status. 

    Auto-renewable subscriptions with SwiftUI

    Go here https://appstoreconnect.apple.com/agreements/#

    Creating subscriptions

    Go to app detail page and click on the In-App purchase link under Feature. 

    Select Auto-Renewable Subscription and click the Create button.

    Auto-renewable subscriptions with SwiftUI

    SwiftUI View-Model

    //
    //  AppStoreManager.swift
    //  ARSubscription
    //
    //  Created by Smin Rana on 2/1/22.
    //
    
    import SwiftUI
    import StoreKit
    import Combine
    
    class AppStoreManager: NSObject, ObservableObject, SKProductsRequestDelegate, SKPaymentTransactionObserver {
    
        @Published var products = [SKProduct]()
        
        override init() {
            super.init()
            
            SKPaymentQueue.default().add(self)
        }
        
        func getProdcut(indetifiers: [String]) {
            print("Start requesting products ...")
            let request = SKProductsRequest(productIdentifiers: Set(indetifiers))
            request.delegate = self
            request.start()
        }
        
        func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
            print("Did receive response")
                    
            if !response.products.isEmpty {
                for fetchedProduct in response.products {
                    DispatchQueue.main.async {
                        self.products.append(fetchedProduct)
                    }
                }
            }
            
            for invalidIdentifier in response.invalidProductIdentifiers {
                print("Invalid identifiers found: \(invalidIdentifier)")
            }
        }
        
        func request(_ request: SKRequest, didFailWithError error: Error) {
            print("Request did fail: \(error)")
        }
        
        // Transaction
        
        @Published var transactionState: SKPaymentTransactionState?
        
        func purchaseProduct(product: SKProduct) {
            if SKPaymentQueue.canMakePayments() {
                let payment = SKPayment(product: product)
                SKPaymentQueue.default().add(payment)
            } else {
                print("User can't make payment.")
            }
        }
        
        struct PaymentReceiptResponseModel: Codable {
            var status: Int
            var email: String?
            var password: String?
            var message: String?
        }
        
        func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
            for transaction in transactions {
                switch transaction.transactionState {
                case .purchasing:
                    self.transactionState = .purchasing
                case .purchased:
                    print("===============Purchased================")
                    UserDefaults.standard.setValue(true, forKey: transaction.payment.productIdentifier)
                    if let appStoreReceiptURL = Bundle.main.appStoreReceiptURL,
                        FileManager.default.fileExists(atPath: appStoreReceiptURL.path) {
    
                        do {
                            let receiptData = try Data(contentsOf: appStoreReceiptURL, options: .alwaysMapped)
                            let receiptString = receiptData.base64EncodedString(options: [])
                            
                            // TODO: Send your receiptString to the server and verify with Apple
                            // receiptString should be sent to server as JSON
                            // {
                            //    "receipt" : receiptString
                            // }
                            
                            self.transactionState = .purchased // only if server sends successful response
                        }
                        catch { print("Couldn't read receipt data with error: " + error.localizedDescription) }
                    }
                case .restored:
                    UserDefaults.standard.setValue(true, forKey: transaction.payment.productIdentifier)
    
                    queue.finishTransaction(transaction)
                    print("==================RESTORED State=============")
                    self.transactionState = .restored
                case .failed, .deferred:
                    print("Payment Queue Error: \(String(describing: transaction.error))")
                    queue.finishTransaction(transaction)
                    self.transactionState = .failed
                default:
                    print(">>>> something else")
                    queue.finishTransaction(transaction)
                }
            }
        }
        
        func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
            print("===============Restored================")
            if let appStoreReceiptURL = Bundle.main.appStoreReceiptURL,
                FileManager.default.fileExists(atPath: appStoreReceiptURL.path) {
    
                do {
                    let receiptData = try Data(contentsOf: appStoreReceiptURL, options: .alwaysMapped)
                    let receiptString = receiptData.base64EncodedString(options: [])
                    
                    // TODO: Send your receiptString to the server and verify with Apple
                    // receiptString should be sent to server as JSON
                    // {
                    //    "receipt" : receiptString
                    // }
                    
                    
                    self.transactionState = .purchased // only if server sends successful response
                }
                catch { print("Couldn't read receipt data with error: " + error.localizedDescription) }
            }
        }
        
        func restorePurchase() {
            SKPaymentQueue.default().restoreCompletedTransactions()
        }
    }
    
    

    Testing with .storekit file on simulator:

    https://youtu.be/e7Tflo6AUH4

    Server side with PHP and Laravel:

    Create app specific shared secret

    Auto-renewable subscriptions with SwiftUI

    PHP and Laravel

    <?php 
    
    // Laravel and GuzzleHTTP\Client
    
    function verifyReceiptWithApple() {
            $input = file_get_contents('php://input');
            $request = json_decode($input);
    
            $d = $request->receipt;
            $secret = 'your_app_purchase_secret';
    
            //$url = 'https://sandbox.itunes.apple.com/verifyReceipt';
            $url = 'https://buy.itunes.apple.com/verifyReceipt';
    
            // Replace with curl if you are not using Laravel
            $client = new Client([
                'headers' => [ 'Content-Type' => 'application/json' ]
            ]);
            
            $response = $client->post($url,
                ['body' => json_encode(
                    [
                        'receipt-data' => $d,
                        'password' => $secret,
                        'exclude-old-transactions' => false
                    ]
                )]
            );
    
            $json = json_decode($response->getBody()->getContents());
            if ($json->status == 0) {
    
                $email = "";
    
                // Get original transaction id
                $receipts = $json->receipt->in_app;
                if (!empty($receipts) && count($receipts) > 0) {
                    $first_receipt = $receipts[0];
                    if ($first_receipt->in_app_ownership_type == "PURCHASED") {
                        $original_transaction_id = $first_receipt->original_transaction_id;
    
                        // Create email address with transaction id 
                        // Create new user if not exists
                        $email = $original_transaction_id.'@domain.com';
                        $have_user = "check_with_your_database";
                        if (!$have_user) {
                            // New purchase -> user not found
                        } else {
                            // Restore purchase -> user found 
                            
                        }
                    }
                }
    
                return response()->json(["status" => 1, "message" => "Receipt is verified"]);
            } else {
                return response()->json(["status" => 0, "message" => "Invalid receipt"]);
            }
        }

    Things to include in-app purchase

    • Value proposition
    • Call to action
    • Clear terms
    • Signup
    • Multiple tiers
    • Log in
    • Restore
    • Terms and conditions

    Read more

    App store distribution and marketing: https://developer.apple.com/videos/app-store-distribution-marketing

    Auto-Renewable Subscriptions: https://developer.apple.com/design/human-interface-guidelines/in-app-purchase/overview/auto-renewable-subscriptions/

    Architecting for subscriptions: https://developer.apple.com/videos/play/wwdc2020/10671/

    Download full source code

    Spread the love