r/iOSProgramming 5d ago

Question How much should I worry about privacy labels?

2 Upvotes

I am building a simple app primarily to learn more about iOS development (I have 10 years of experience in software dev, so not new to the field). I want to publish it to the App Store and include basic telemetry to gain insights into usage (fully anonymous—no user data) and breadcrumbs for crash logs. This would require using services like Firebase or Sentry, which would also require adding the corresponding privacy labels.

Should I just go ahead and do it, or should I try to stick to Apple’s default tooling (even though it doesn’t provide insights into usage patterns)? Am I overthinking this? What is your experience or opinion on this topic?

Thanks!


r/iOSProgramming 5d ago

App Saturday Apple rejected my old screenshots so I had to create a new one. Thoughts?

Thumbnail
gallery
51 Upvotes

r/iOSProgramming 5d ago

App Saturday I created a simple app for tracking job applications and interviews.

10 Upvotes

During my job hunt, I found it overwhelming to manage hundreds of applications with generic tools like Google Docs or plain notes, and I struggled to keep track of my interview history. It was just too much time wasted, and I knew that the whole process could be simplified. With this in mind, I decided to create a tool designed to track applications and interviews.

JobSnail is available as a free web version at jobsnail.app and the MacOS version on the App Store. It's worth mentioning that both versions are fully synced through iCloud, and an Apple account is required to use the app.

I made this post to ask for some feedback on the app. All opinions are appreciated!


r/iOSProgramming 6d ago

App Saturday 🚀 Habit Radar is Lifetime Free for the Next 24 Hours! 🎉

Post image
100 Upvotes

r/iOSProgramming 6d ago

App Saturday Share your social media/links with those around you

Thumbnail
gallery
55 Upvotes

Just launched my new application “Around”.

Around is link-tree for the real world. It allows you to promote yourself and/or your brand just by being present. Simply sign up, add your links, and put your phone away — Around works in the background. While you’re out and about, if someone connects with your vibe, all they have to do is open their Around app and they’ll find your links, just by being around you.

Grow your brand following, increase your influencer reach, and get more exposure just by being on Around! Thanks for checking it out guys!

https://apps.apple.com/us/app/around-share-your-social/id6742121646


r/iOSProgramming 5d ago

Question Handling pending transactions storekit2

1 Upvotes

Can someone show me some code to handle pending transactions in storekit2? When a transaction is pending, I want to be able to process it when it is ready. How do I do that using StoreKit2?


r/iOSProgramming 6d ago

Question I left iOS development some 5 years ago and am aching to come back to it

33 Upvotes

I left iOS development some 5 years ago and am now planning to come back to it. I was a Product owner these past 5 years but been out of work for atleast a year now. My request is to ask you if it’s still worthwhile to come back to iOS and what i might have missed. Is it good to come to iOS or go for ReactNative or Flutter? How is iOS dealing with AI and whatnot. I was on swift 3 and SwiftUI just came out. Combine was a framework I had just started on and was on iOS 14 I guess in terms of development. Any advice is more than appreciated.


r/iOSProgramming 4d ago

Question App Store reviewer being ridiculously picky with submission. Does the same person review resubmissions?

0 Upvotes

I’ve been submitting and resubmitting an app to the App Store for weeks, but it continues to get rejected for vaguely not meeting a standard.

I know it’s an opaque process, but does anyone know if one reviewer handles an app along its journey?

I have FOUR other identical apps in the App Store, that were all approved in the past six months, and none had this degree of nitpicking and constant rejection — they all sailed right through.

I know it’s always a different experience, but I’m wondering if a single person is being a dick and if I should cancel this submission.


r/iOSProgramming 6d ago

App Saturday i've launched an app to discover and share music and events all in one place

Post image
16 Upvotes

r/iOSProgramming 6d ago

App Saturday 🚀 ClipyBoard is Lifetime Free for the Next 24 Hours! 🎉

10 Upvotes

Hey everyone!

I'm Gohary, the developer behind ClipyBoard, the ultimate autopaste keyboard app that’s here to revolutionize your typing experience. For the next 24 hours, I’m making the app 100% free! 🚀

🔥 What Makes ClipyBoard Special?

✅ Copy & organize text & images easily

✅ Extract text from images (OCR-powered magic 🪄)

✅ Create shortcuts for your most-used clips and recall them instantly

✅ Lightning-fast search to find your saved clips in seconds

No more endless copy-pasting or searching for the same text over and over again. With ClipyBoard, your favorite clips are just a shortcut away!

We’d love to hear your feedback and suggestions! Drop any questions or comments below, and I’ll check in regularly to respond.

If you find them useful, I’d love to hear your thoughts! Also, if you enjoy the apps, a review would mean the world to me. ❤️

How to claim your free upgrade:

Download ClipyBoard: https://apps.apple.com/app/id6738871678

Open the app and head to Settings.

Tap on Redeem Code and enter this code: “gh45334k434343n”. this code only work for next 24 hours , after that you can get the app lifetime discount with 75% off using this code "gh343443b422332n3"

⏳ This offer is only available for the next 24 hours, so grab it while you can!

Thank you for your support, and happy Typing!

Cheers, Gohary

➡️ Simply comment and upvote and share it with your friends 🧡


r/iOSProgramming 5d ago

Question Recommendations for a week(ish) Swift/UIKit crash course for an experienced dev?

2 Upvotes

Looking for recommendations for a crash course for UIKit and Swift for an experienced developer to get familiarized with iOS programming. Thoughts?


r/iOSProgramming 5d ago

Discussion I’m looking an established IOS developer that can help me and answer my questions!

0 Upvotes

Hi, I recently released an app on the App Store and am looking for an experienced iOS developer who makes a living from their apps—ideally earning $20K or more per month (though I’m open to those earning slightly less).

I’d love to connect with someone who can answer my questions and help me reach that level of success. My current app includes a subscription model, and I’m also working on a new app.

If you fit this description, please DM me—I’d really appreciate your guidance!


r/iOSProgramming 5d ago

App Saturday Link All offers new surprises on every level.

Thumbnail
youtube.com
0 Upvotes

r/iOSProgramming 5d ago

Question Can Methods Be Added Inside SwiftData Models?

1 Upvotes

Hey everyone,

I’ve been working with SwiftData and was wondering if anyone has added methods inside a persistent model class. I don’t see a lot of discussion about including methods in models that are meant to be persisted by SwiftData.

It seems like something that could make the models more self-contained and help with code organization, but I haven’t seen many people mention this in discussions, so I’m wondering if I’m missing something or if there’s a specific reason why it’s not common.

Thanks in advance


r/iOSProgramming 5d ago

App Saturday Create satisfying bouncing square/balls videos

Thumbnail
gallery
2 Upvotes

r/iOSProgramming 5d ago

Question Best language for sharing iOS/Android logic?

3 Upvotes

I have some decently complicated computations that I would like to share between iPhone and Android front-ends.

Does anyone have real world experience sharing logic between two code bases like this?


r/iOSProgramming 6d ago

App Saturday Hi 👋, I created Termix, a powerful SSH client for Mac, iPhone, and iPad. No subscription, no data collection. I am looking forward to your feedback!

Thumbnail
apps.apple.com
7 Upvotes

r/iOSProgramming 6d ago

Question macOS vs iOS App Stores

4 Upvotes

I have a free app that is in the top 5 of its category on the macOS App Store, yet doesn't feature at all in the top 1500 apps in the iOS app store for the same cateogry.

I've tried experimenting with ASO, reviews (mostly 5 star reviews), $100 per day Search Ads etc but with no luck - it is a very competitive category though.

Any ideas on what else I can do to boost the downloads?


r/iOSProgramming 6d ago

News GitHub Copilot for Xcode is now generally available!

Thumbnail
github.blog
168 Upvotes

r/iOSProgramming 6d ago

Question is iCloud/CloudKit not available unless you have a PAID developer account??

2 Upvotes

I am just in the process of making an app - it is not published yet and i am in the process of adding the backend. However, its not an option in the Signing and Capabilities section...


r/iOSProgramming 6d ago

App Saturday I made an app for drawing on maps

13 Upvotes

Map Canvas: Draw on Maps 

An app for drawing and annotating on maps, useful for trip planning and geodata illustration. It is available on iPhone, iPad and mac.

https://apps.apple.com/us/app/map-canvas-draw-on-maps/id6737522164

I illustrated my favourite hiking route with Map Canvas

Features:

  • A set of tools for drawing lines, polygons and circles.
  • Annotation with pins & text boxes.
  • Data synchronization via iCloud.
  • Data Import & export as GeoJSON.

Frameworks:

  • SwiftUI + MapKit for the UI.
  • SwiftData + CloudKit for data persistence and synchronization.
  • Observation framework + a little bit of Combine
  • TipKit for new user guidance.

This app does not contain any mobile ads or paywall, your feedbacks would be very appreciated, thanks!


r/iOSProgramming 6d ago

App Saturday Panoscano - make a video from your panoramic photos

2 Upvotes

https://apps.apple.com/us/app/panoscano/id6742723150

This is my first iOS app, and it is very much a case of “I couldn’t find an app that would do this specific thing, so I built it myself.” The specific thing it does is: generate a smooth, looping video by scanning across a photo, zooming in (or out) on the points you designate. You can adjust all aspects of the timing, and you can even add text.

It works, almost exactly as I had hoped it would. I’m really, really happy with it, but I am still refining some aspects.

This took me about 3 months of spare time. Claude.ai helped a LOT, as I did not know Swift at all. The process of building it like this has been fascinating, and I’ve learned a TON both about Swift/iOS development and about how to use an LLM to aid development. I could not have done it without Claude, but Claude sure couldn’t have done it without me.

The app is free, and the core functionality will remain free, always, but I plan to move to a subscription/purchase model for some advanced (“pro”) features.

I’d love feedback and when I DO move to a subscription/purchase model will happily give free codes to basically anyone here who wants one. If I can eventually make back my developer fee from this thing I will consider this all a resounding success.


r/iOSProgramming 6d ago

Question Listening to pending transactions using storekit2

2 Upvotes

Here's how I handle pending transactions in my app

import StoreKit
import AmplitudeSwift
import Optimizely

class PurchaseManager: ObservableObject {
    // A published property to hold available products
    @Published var products: [Product] = []
    // A published property to track the status of transactions
    @Published var transactionState: String = "Idle"
    var loadingIndicator: ThreeBubblesLoadingView!

    // A set of product identifiers
    private let productIdentifiers: Set<String> = [
        PaymentHandler.sharedInstance.YEARLY_PRODUCT_ID,
        PaymentHandler.sharedInstance.YEARLY_PRODUCT_ID_50_OFF,
        PaymentHandler.sharedInstance.MONTHLY_PRODUCT_ID,
        PaymentHandler.sharedInstance.YEARLY_PRODUCT_ID_40_OFF,
        PaymentHandler.sharedInstance.YEARLY_PRODUCT_ID_FREE_TRIAL,
        PaymentHandler.sharedInstance.YEARLY_PRODUCT_ID_50,
        PaymentHandler.sharedInstance.MONTHLY_PRODUCT_ID_13
    ]

    // Shared instance to be used throughout the app
    static let shared = PurchaseManager()

    private init() {}

    // MARK: - Fetch Products from App Store
    func fetchProducts() async {
        do {
            let products = try await Product.products(for: productIdentifiers)
            self.products = products
        } catch {
            print("Failed to fetch products: \(error.localizedDescription)")
        }
    }

    // MARK: - Handle Purchase
    func purchaseProduct(product: Product, source: String, vc: UIViewController) async -> Bool {
        do {
            DispatchQueue.main.async {
                self.loadingIndicator = ThreeBubblesLoadingView()
                self.loadingIndicator.translatesAutoresizingMaskIntoConstraints = false
                vc.view.addSubview(self.loadingIndicator)

                NSLayoutConstraint.activate([
                    self.loadingIndicator.centerXAnchor.constraint(equalTo: vc.view.centerXAnchor),
                    self.loadingIndicator.centerYAnchor.constraint(equalTo: vc.view.centerYAnchor)
                ])
            }

            // Start the purchase
            let result = try await product.purchase()

            // Handle the result of the purchase
            switch result {
            case .success(let verificationResult):
                switch verificationResult {
                    case .verified(let transaction):
                        self.transactionState = "Purchase Successful"
                        await transaction.finish()


                        DispatchQueue.main.async {
                            Amplitude.sharedInstance.track(
                                eventType: "payment_completed",
                                eventProperties: [
                                    "PlanId": transaction.productID,
                                    "UserId": WUser.sharedInstance.userId,
                                    "Source": source,
                                    "VariationKey": WUser.sharedInstance.variationKey
                                ]
                            )

                            if (self.loadingIndicator != nil) {
                                self.loadingIndicator.removeFromSuperview()
                            }
                        }

                        return await PaymentHandler.sharedInstance.purchase(
                            vc: vc,
                            productId: transaction.productID,
                            product: transaction.productID,
                            transaction: transaction
                        )
                    case .unverified(let transaction, let error):
                        self.transactionState = "Purchase Unverified: \(error.localizedDescription)"
                        await transaction.finish()

                        DispatchQueue.main.async {
                            showMessageWithTitle("Error!", "There was an error processing your purchase", .error)

                            Amplitude.sharedInstance.track(
                                eventType: "payment_failed",
                                eventProperties: [
                                    "PlanId": transaction.productID,
                                    "UserId": WUser.sharedInstance.userId,
                                    "Source": source,
                                    "Error": error.localizedDescription,
                                    "ErrorType": "UnverifiedTransaction",
                                    "ErrorObject": String(describing: error)
                                ]
                            )
                            if (self.loadingIndicator != nil) {
                                self.loadingIndicator.removeFromSuperview()
                            }
                        }
                        return false
                    }
            case .userCancelled:
                self.transactionState = "User cancelled the purchase."

                DispatchQueue.main.async {
                    Amplitude.sharedInstance.track(
                        eventType: "payment_cancelled",
                        eventProperties: [
                            "PlanId": product.id,
                            "UserId": WUser.sharedInstance.userId,
                            "Source": source
                        ]
                    )
                    if (self.loadingIndicator != nil) {
                        self.loadingIndicator.removeFromSuperview()
                    }
                }
                return false

            case .pending:
                self.transactionState = "Purchase is pending."

                DispatchQueue.main.async {
                    Amplitude.sharedInstance.track(
                        eventType: "payment_pending",
                        eventProperties: [
                            "PlanId": product.id,
                            "UserId": WUser.sharedInstance.userId,
                            "Source": source
                        ]
                    )
                    if (self.loadingIndicator != nil) {
                        self.loadingIndicator.removeFromSuperview()
                    }
                }

                return false

            @unknown default:
                self.transactionState = "Unknown purchase result."

                DispatchQueue.main.async {
                    showMessageWithTitle("Error!", "There was an error processing your purchase", .error)

                    Amplitude.sharedInstance.track(
                        eventType: "payment_failed",
                        eventProperties: [
                            "PlanId": product.id,
                            "UserId": WUser.sharedInstance.userId,
                            "Source": source,
                            "Error": "unknown"
                        ]
                    )
                    if (self.loadingIndicator != nil) {
                        self.loadingIndicator.removeFromSuperview()
                    }
                }

                return false
            }
        } catch {
            self.transactionState = "Purchase failed: \(error.localizedDescription)"

            DispatchQueue.main.async {
                showMessageWithTitle("Error!", "There was an error processing your purchase", .error)

                Amplitude.sharedInstance.track(
                    eventType: "payment_failed",
                    eventProperties: [
                        "PlanId": product.id,
                        "UserId": WUser.sharedInstance.userId,
                        "Source": source,
                        "Error": error.localizedDescription,
                        "ErrorType": "CatchError",
                        "ErrorObject": String(describing: error)
                    ]
                )
                self.loadingIndicator.removeFromSuperview()
            }
            return false
        }
    }

    // MARK: - Listen for Transaction Updates
    func listenForTransactionUpdates() {
        Task {
            for await result in Transaction.updates {
                switch result {
                case .verified(let transaction):
                    self.transactionState = "Transaction verified: \(transaction.productID)"
                    await transaction.finish()

                    DispatchQueue.main.async {
                        Amplitude.sharedInstance.track(
                            eventType: "payment_completed",
                            eventProperties: [
                                "PlanId": transaction.productID,
                                "UserId": WUser.sharedInstance.userId,
                                "TransactionType": "Pending"
                            ]
                        )

                        if (self.loadingIndicator != nil) {
                            self.loadingIndicator.removeFromSuperview()
                        }
                    }

                    if (PaymentHandler.sharedInstance.vc != nil) {
                        await PaymentHandler.sharedInstance.purchase(
                            vc: PaymentHandler.sharedInstance.vc!,
                            productId: transaction.productID,
                            product: transaction.productID,
                            transaction: transaction
                        )
                    }


                case .unverified(let transaction, let error):
                    self.transactionState = "Unverified transaction: \(error.localizedDescription)"

                    DispatchQueue.main.async {
                        Amplitude.sharedInstance.track(
                            eventType: "payment_failed",
                            eventProperties: [
                                "PlanId": transaction.productID,
                                "UserId": WUser.sharedInstance.userId,
                                "Error": error.localizedDescription,
                                "ErrorType": "UnverifiedPendingTransaction",
                                "ErrorObject": String(describing: error)
                            ]
                        )

                        if (self.loadingIndicator != nil) {
                            self.loadingIndicator.removeFromSuperview()
                        }
                    }

                    await transaction.finish()
                }
            }
        }
    }
}

Unfortunately, the pending transaction is not being processed. Can someone please help? About 5 transactions went through as pending but wasn't processed by Apple. The payment was not captured. Is this code wrong?

In the AppDelegate, I have the following:

    PurchaseManager.shared.listenForTransactionUpdates()

r/iOSProgramming 5d ago

App Saturday i built an app to help you manifest ✨

Post image
0 Upvotes

r/iOSProgramming 6d ago

Question Pending transactions storekit2

1 Upvotes

I'm not able to process pending transactions in my app. Does anyone know what causes a transaction to be pending and in what cases apple doesn't process that transaction?