Skip to content

feat: iOS update check via iTunes Lookup API (checkUpdateIos) - #20

Open
akshaynexus wants to merge 4 commits into
axions-org:productionfrom
akshaynexus:feat/ios-update-check
Open

feat: iOS update check via iTunes Lookup API (checkUpdateIos)#20
akshaynexus wants to merge 4 commits into
axions-org:productionfrom
akshaynexus:feat/ios-update-check

Conversation

@akshaynexus

@akshaynexus akshaynexus commented Jun 18, 2026

Copy link
Copy Markdown

Closes #16

Summary

Adds an iOS equivalent of the Android checkUpdateAndroid() method, so callers can know whether an App Store update is available before triggering any UI.

checkUpdateIos() queries the iTunes Lookup API for the latest published version and compares it against the installed version. It is implemented natively in the existing Swift plugin (over the method channel, mirroring the Android side) — no new Dart packages.

final plugin = InAppUpdateFlutter();

final info = await plugin.checkUpdateIos();
// info.installedVersion — version currently installed
// info.storeVersion     — latest version on the App Store
// info.updateAvailable  — true if storeVersion > installedVersion

if (info.updateAvailable) {
  await plugin.showUpdateForIos(appStoreId: '123456');
}

Why native (vs. a pure-Dart implementation)

Everything needed is already available natively on iOS, so this avoids adding dependencies:

Need Native Swift
Bundle ID Bundle.main.bundleIdentifier
Installed version Bundle.main.infoDictionary["CFBundleShortVersionString"]
Store region Locale.current.region?.identifier (iOS 16+) / regionCode
HTTP request URLSession (10s timeout)
JSON parsing JSONSerialization (targets results[0].version)
Version compare String.compare(_:options: .numeric)

Region handling

The lookup is scoped to the device's region setting via Locale.current, which already returns an ISO 3166-1 alpha-2 code (e.g. us, gb, in) — exactly what the iTunes Lookup API expects, so no lookup table or conversion is needed. This fixes two failure modes of a developer-passed region (hardcoding the wrong store, or defaulting to the US store for apps not listed there), so the iosAppStoreRegion parameter is removed from the public API. No permission prompt, no Info.plist entries — it's the same API every app uses for localization.

Changes

  • Add checkUpdateIos case to InAppUpdateFlutterPlugin (native URLSession + JSONSerialization, .numeric version compare, device region via Locale.current, FlutterResult dispatched on the main thread)
  • Add AppUpdateInfoIos model (storeVersion, installedVersion, updateAvailable, bundleId) with a fromMap factory
  • Wire checkUpdateIos() through the existing platform interface, method-channel implementation, and public API (platform interface kept intact)
  • Drop the iosAppStoreRegion parameter from the public API
  • Remove dependencies: package_info_plus, pub_semver
  • Add Dart method-channel tests (deserialize / null-default / error propagation) and a delegation test
  • Document checkUpdateIos in the README iOS Usage section

Notes

  • .numeric string comparison handles non-semver App Store versions like 1.0 or 2.3.4.5 (which pub_semver would throw on).
  • On lookup failure (network error, missing/invalid listing) the method returns updateAvailable: false with an empty storeVersion rather than throwing — see the open question in feat: iOS update check via iTunes Lookup API (checkUpdateIos) #16 if a different fallback is preferred.

Test status

32/32 Dart tests passing · flutter analyze clean · dart format clean · example iOS app builds (flutter build ios --simulator)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added checkUpdateIos() to perform iOS update checks and return store/installed version, availability, and bundle identifier.
    • iOS update checks automatically use the device’s App Store region via the native iTunes Lookup API—no region parameter required.
  • Bug Fixes
    • Improved iOS store-update prompt handling with stricter argument validation and clearer errors for invalid inputs.
  • Documentation
    • Updated the README with a new iOS “Check for an update” section and detailed returned fields.
  • Tests
    • Added iOS update-check test coverage, including default fallbacks and error propagation.

@akshaynexus

akshaynexus commented Jun 18, 2026

Copy link
Copy Markdown
Author

there are some issues in teh pr will fix and comment here once fixed

Edit: nvm the changes are fine ,just had to cross check with the api that the way im checking for updates is correct

coderabbitai[bot]

This comment was marked as low quality.

@axions-org axions-org deleted a comment from coderabbitai Bot Jun 18, 2026
@axions-org axions-org deleted a comment from coderabbitai Bot Jun 18, 2026

@buildwithpulkit buildwithpulkit left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternative approach: native Swift via method channel (no new packages)

The two new packages (package_info_plus, pub_semver) can be eliminated entirely by moving the implementation into the existing Swift plugin — matching the pattern already used by checkUpdateAndroid() on the Android side.

Everything these packages provide is already natively available in iOS:

Need Current approach Native Swift equivalent
Bundle ID PackageInfo.fromPlatform() Bundle.main.bundleIdentifier
Installed version PackageInfo.fromPlatform() Bundle.main.infoDictionary?["CFBundleShortVersionString"]
Store region developer-passed iosAppStoreRegion arg Locale.current.region?.identifier (iOS 16+) / Locale.current.regionCode (iOS < 16)
HTTP request dart:io HttpClient URLSession.shared.dataTask(...)
JSON parsing regex on raw string JSONSerialization.jsonObject(...)
Version comparison pub_semver Version.parse() v1.compare(v2, options: .numeric)

Region handling

The iosAppStoreRegion parameter should be removed from the public API entirely. Asking the developer to pass a region has two failure modes:

  • Developer hardcodes a region (e.g. "in") — all users globally hit that store, getting wrong results
  • Developer omits it — iTunes Lookup API defaults to the US store, not geo-IP routing. App not listed in the US store silently returns updateAvailable: false for all users

The correct source is Locale.current — this reads the 2-letter ISO alpha-2 region code (e.g. "us", "in", "gb") directly from the device language & region settings. No permission prompt, no Info.plist entries, no App Review concerns — it is the same API every app uses for localization. No lookup table or conversion needed.

Swift side

Add a checkUpdateIos case to InAppUpdateFlutterPlugin.handle():

case "checkUpdateIos":
    let bundleId = Bundle.main.bundleIdentifier ?? ""
    let installedVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? ""

    let regionCode: String
    if #available(iOS 16, *) {
        regionCode = Locale.current.region?.identifier.lowercased() ?? ""
    } else {
        regionCode = Locale.current.regionCode?.lowercased() ?? ""
    }

    let regionPath = regionCode.isEmpty ? "" : "/\(regionCode)"
    let urlString = "https://itunes.apple.com\(regionPath)/lookup?bundleId=\(bundleId)"

    guard let url = URL(string: urlString) else {
        result(["storeVersion": "", "installedVersion": installedVersion, "updateAvailable": false, "bundleId": bundleId])
        return
    }

    let request = URLRequest(url: url, timeoutInterval: 10)
    URLSession.shared.dataTask(with: request) { data, _, _ in
        guard let data = data,
              let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
              let results = json["results"] as? [[String: Any]],
              let storeVersion = results.first?["version"] as? String else {
            DispatchQueue.main.async {
                result(["storeVersion": "", "installedVersion": installedVersion, "updateAvailable": false, "bundleId": bundleId])
            }
            return
        }
        let updateAvailable = storeVersion.compare(installedVersion, options: .numeric) == .orderedDescending
        DispatchQueue.main.async {
            result(["storeVersion": storeVersion, "installedVersion": installedVersion, "updateAvailable": updateAvailable, "bundleId": bundleId])
        }
    }.resume()

Dart side

No region parameter — just a method channel call, identical in shape to checkUpdateAndroid():

@override
Future<AppUpdateInfoIos> checkUpdateIos() async {
    final result = await _methodChannel.invokeMapMethod<String, dynamic>("checkUpdateIos");
    return AppUpdateInfoIos(
        storeVersion: result?["storeVersion"] as String? ?? "",
        installedVersion: result?["installedVersion"] as String? ?? "",
        updateAvailable: result?["updateAvailable"] as bool? ?? false,
        bundleId: result?["bundleId"] as String? ?? "",
    );
}

And the public API simplifies to:

Future<AppUpdateInfoIos> checkUpdateIos() {
    return InAppUpdateFlutterPlatform.instance.checkUpdateIos();
}

Additional benefits

  • Locale.current returns 2-letter alpha-2 directly — no lookup table, no conversion, not deprecated
  • DispatchQueue.main.async ensures FlutterResult is always called on the main thread — URLSession callbacks run on a background thread and calling result() off the main thread causes undefined behavior
  • .numeric string comparison handles non-semver App Store versions like 1.0 or 2.3.4.5 correctly — pub_semver throws FormatException on these
  • URLSession timeout set natively (10 s) with no extra plumbing
  • JSON parsed via JSONSerialization targeting results[0].version — not a regex that could match anywhere in the document
  • Dart method channel test pattern already established in in_app_update_flutter_method_channel_test.dart

@akshaynexus
akshaynexus force-pushed the feat/ios-update-check branch from e5e2bba to 068a1aa Compare June 18, 2026 19:49
@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1db26df3-93e3-41c5-b8f0-9d333c6a19ce

📥 Commits

Reviewing files that changed from the base of the PR and between 39e16bb and a5a5b92.

📒 Files selected for processing (2)
  • ios/in_app_update_flutter/Sources/in_app_update_flutter/InAppUpdateFlutterPlugin.swift
  • test/in_app_update_flutter_method_channel_test.dart
🚧 Files skipped from review as they are similar to previous changes (2)
  • test/in_app_update_flutter_method_channel_test.dart
  • ios/in_app_update_flutter/Sources/in_app_update_flutter/InAppUpdateFlutterPlugin.swift

📝 Walkthrough

Walkthrough

Adds checkUpdateIos() to the plugin: a native Swift implementation queries the iTunes Lookup API using the bundle ID and auto-detects the App Store region from the device locale. A new AppUpdateInfoIos Dart model, platform interface method, method channel wiring, tests, and README documentation are included.

Changes

iOS Update Check Feature

Layer / File(s) Summary
AppUpdateInfoIos model, barrel export, and platform interface contract
lib/src/models/app_update_info_ios.dart, lib/src/models/models.dart, lib/src/platform_interface/in_app_update_flutter_platform_interface.dart
AppUpdateInfoIos is defined with storeVersion, installedVersion, updateAvailable, and bundleId fields, a const constructor, a fromMap factory with null-safe fallbacks, and toString; the model is re-exported via the barrel; InAppUpdateFlutterPlatform declares the abstract checkUpdateIos() method returning AppUpdateInfoIos and throwing UnimplementedError.
Native Swift checkUpdate implementation
ios/in_app_update_flutter/Sources/in_app_update_flutter/InAppUpdateFlutterPlugin.swift
handle(_:result:) is refactored to a switch dispatcher with BAD_ARGS validation for showStoreUpdateIos; a checkUpdateIos branch delegates to a new checkUpdate(result:) that reads the bundle ID and installed version, derives an iTunes region path from the device locale, fetches the iTunes Lookup API via URLSession (10 s timeout), parses the JSON version from the first result, performs numeric comparison, and returns the payload on the main queue with fallback values for failure cases.
Method channel wiring and public Dart API
lib/src/method_channel/in_app_update_flutter_method_channel.dart, lib/in_app_update_flutter.dart
MethodChannelInAppUpdateFlutter.checkUpdateIos() invokes 'checkUpdateIos' via invokeMapMethod and deserializes the result using AppUpdateInfoIos.fromMap, mapping null to an empty map; InAppUpdateFlutter.checkUpdateIos() exposes the public API and forwards to the platform instance.
Tests and README documentation
test/in_app_update_flutter_test.dart, test/in_app_update_flutter_method_channel_test.dart, README.md
_MockPlatform overrides checkUpdateIos() with a fixed AppUpdateInfoIos; tests assert UnimplementedError on the base platform, verify delegation and field values, and cover method channel deserialization, null defaulting, and PlatformException propagation; README gains a features bullet, checkUpdateIos() usage section, AppUpdateInfoIos fields table, and bold iOS emphasis.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 Hop, hop! The iTunes trail is found,
A Swift lookup spins the world around.
BundleId whispers, storefront speaks,
The version diff is what bunny seeks.
updateAvailable: true — ears perk with glee,
No extra packages, just pure native spree! 🍎

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR implements the core requirement from #16: a checkUpdateIos() method returning app update info. However, the implementation deviates from the proposed signature and model structure in the issue. The issue proposed AppUpdateInfoIos with currentVersion/availableVersion/isUpdateAvailable, but the implementation uses installedVersion/storeVersion/updateAvailable. The issue proposed appStoreId parameter but implementation auto-detects via bundleId, removing manual App Store ID specification. Clarify if these design changes intentionally replace the original requirements or if the model/API should match the issue specification.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the primary change: adding iOS update checking via iTunes Lookup API with the checkUpdateIos method.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing iOS update checking. The README updates, model definitions, platform interface extensions, and native Swift implementation all support the checkUpdateIos feature.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
ios/in_app_update_flutter/Sources/in_app_update_flutter/InAppUpdateFlutterPlugin.swift (1)

57-58: 💤 Low value

Consider URL-encoding the bundle ID.

While bundle identifiers typically contain only URL-safe characters (alphanumerics, dots, hyphens), applying addingPercentEncoding(withAllowedCharacters:) would be a defensive safeguard against unexpected characters.

🛡️ Suggested defensive encoding
-    guard !bundleId.isEmpty,
-          let url = URL(string: "https://itunes.apple.com\(regionPath)/lookup?bundleId=\(bundleId)") else {
+    guard !bundleId.isEmpty,
+          let encodedBundleId = bundleId.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
+          let url = URL(string: "https://itunes.apple.com\(regionPath)/lookup?bundleId=\(encodedBundleId)") else {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@ios/in_app_update_flutter/Sources/in_app_update_flutter/InAppUpdateFlutterPlugin.swift`
around lines 57 - 58, The bundle ID is being directly interpolated into the URL
string without URL encoding. Apply
`addingPercentEncoding(withAllowedCharacters:)` to the bundleId variable before
interpolating it into the URL string in the guard statement where URL(string:)
is called. This ensures that any unexpected special characters in the bundle ID
are properly escaped in the URL to prevent potential issues with the iTunes
lookup request.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@ios/in_app_update_flutter/Sources/in_app_update_flutter/InAppUpdateFlutterPlugin.swift`:
- Around line 57-58: The bundle ID is being directly interpolated into the URL
string without URL encoding. Apply
`addingPercentEncoding(withAllowedCharacters:)` to the bundleId variable before
interpolating it into the URL string in the guard statement where URL(string:)
is called. This ensures that any unexpected special characters in the bundle ID
are properly escaped in the URL to prevent potential issues with the iTunes
lookup request.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 22031edf-245d-4259-b15d-69aaa8ca2fff

📥 Commits

Reviewing files that changed from the base of the PR and between e5e2bba and 068a1aa.

⛔ Files ignored due to path filters (1)
  • example/pubspec.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • README.md
  • ios/in_app_update_flutter/Sources/in_app_update_flutter/InAppUpdateFlutterPlugin.swift
  • lib/in_app_update_flutter.dart
  • lib/src/method_channel/in_app_update_flutter_method_channel.dart
  • lib/src/models/app_update_info_ios.dart
  • lib/src/models/models.dart
  • lib/src/platform_interface/in_app_update_flutter_platform_interface.dart
  • test/in_app_update_flutter_method_channel_test.dart
  • test/in_app_update_flutter_test.dart
✅ Files skipped from review due to trivial changes (2)
  • lib/src/models/models.dart
  • README.md

@akshaynexus
akshaynexus force-pushed the feat/ios-update-check branch from 068a1aa to db2a506 Compare June 18, 2026 19:58
@buildwithpulkit

Copy link
Copy Markdown
Member

Alternative approach: native Swift via method channel (no new packages)

The two new packages (package_info_plus, pub_semver) can be eliminated entirely by moving the implementation into the existing Swift plugin — matching the pattern already used by checkUpdateAndroid() on the Android side.

Everything these packages provide is already natively available in iOS:

Need Current approach Native Swift equivalent
Bundle ID PackageInfo.fromPlatform() Bundle.main.bundleIdentifier
Installed version PackageInfo.fromPlatform() Bundle.main.infoDictionary?["CFBundleShortVersionString"]
Store region developer-passed iosAppStoreRegion arg Locale.current.region?.identifier (iOS 16+) / Locale.current.regionCode (iOS < 16)
HTTP request dart:io HttpClient URLSession.shared.dataTask(...)
JSON parsing regex on raw string JSONSerialization.jsonObject(...)
Version comparison pub_semver Version.parse() v1.compare(v2, options: .numeric)

Region handling

The iosAppStoreRegion parameter should be removed from the public API entirely. Asking the developer to pass a region has two failure modes:

  • Developer hardcodes a region (e.g. "in") — all users globally hit that store, getting wrong results
  • Developer omits it — iTunes Lookup API defaults to the US store, not geo-IP routing. App not listed in the US store silently returns updateAvailable: false for all users

The correct source is Locale.current — this reads the 2-letter ISO alpha-2 region code (e.g. "us", "in", "gb") directly from the device language & region settings. No permission prompt, no Info.plist entries, no App Review concerns — it is the same API every app uses for localization. No lookup table or conversion needed.

Swift side

Add a checkUpdateIos case to InAppUpdateFlutterPlugin.handle():

case "checkUpdateIos":
    let bundleId = Bundle.main.bundleIdentifier ?? ""
    let installedVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? ""

    let regionCode: String
    if #available(iOS 16, *) {
        regionCode = Locale.current.region?.identifier.lowercased() ?? ""
    } else {
        regionCode = Locale.current.regionCode?.lowercased() ?? ""
    }

    let regionPath = regionCode.isEmpty ? "" : "/\(regionCode)"
    let urlString = "https://itunes.apple.com\(regionPath)/lookup?bundleId=\(bundleId)"

    guard let url = URL(string: urlString) else {
        result(["storeVersion": "", "installedVersion": installedVersion, "updateAvailable": false, "bundleId": bundleId])
        return
    }

    let request = URLRequest(url: url, timeoutInterval: 10)
    URLSession.shared.dataTask(with: request) { data, _, _ in
        guard let data = data,
              let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
              let results = json["results"] as? [[String: Any]],
              let storeVersion = results.first?["version"] as? String else {
            DispatchQueue.main.async {
                result(["storeVersion": "", "installedVersion": installedVersion, "updateAvailable": false, "bundleId": bundleId])
            }
            return
        }
        let updateAvailable = storeVersion.compare(installedVersion, options: .numeric) == .orderedDescending
        DispatchQueue.main.async {
            result(["storeVersion": storeVersion, "installedVersion": installedVersion, "updateAvailable": updateAvailable, "bundleId": bundleId])
        }
    }.resume()

Dart side

No region parameter — just a method channel call, identical in shape to checkUpdateAndroid():

@override
Future<AppUpdateInfoIos> checkUpdateIos() async {
    final result = await _methodChannel.invokeMapMethod<String, dynamic>("checkUpdateIos");
    return AppUpdateInfoIos(
        storeVersion: result?["storeVersion"] as String? ?? "",
        installedVersion: result?["installedVersion"] as String? ?? "",
        updateAvailable: result?["updateAvailable"] as bool? ?? false,
        bundleId: result?["bundleId"] as String? ?? "",
    );
}

And the public API simplifies to:

Future<AppUpdateInfoIos> checkUpdateIos() {
    return InAppUpdateFlutterPlatform.instance.checkUpdateIos();
}

Additional benefits

  • Locale.current returns 2-letter alpha-2 directly — no lookup table, no conversion, not deprecated
  • DispatchQueue.main.async ensures FlutterResult is always called on the main thread — URLSession callbacks run on a background thread and calling result() off the main thread causes undefined behavior
  • .numeric string comparison handles non-semver App Store versions like 1.0 or 2.3.4.5 correctly — pub_semver throws FormatException on these
  • URLSession timeout set natively (10 s) with no extra plumbing
  • JSON parsed via JSONSerialization targeting results[0].version — not a regex that could match anywhere in the document
  • Dart method channel test pattern already established in in_app_update_flutter_method_channel_test.dart

Adds checkUpdateIos() to check whether an App Store update is available
before triggering any UI, mirroring the Android checkUpdateAndroid()
pattern. Implemented natively in the existing Swift plugin via the method
channel — no new Dart packages.

- Add `checkUpdateIos` case to InAppUpdateFlutterPlugin: reads bundle id
  and installed version from Bundle.main, fetches the latest store version
  via URLSession + JSONSerialization, and compares with String.compare
  using .numeric (handles non-semver versions like "1.0" or "2.3.4.5")
- Scope the lookup to the device's region (`Locale.current`), which is
  already an ISO alpha-2 code — the form the iTunes Lookup API expects, so
  no region parameter and no conversion table are needed. Without a region
  the API defaults to the US store, missing apps not listed there
- Call FlutterResult on the main thread (URLSession callbacks run on a
  background queue)
- Drop the `iosAppStoreRegion` parameter from the public API
- Add AppUpdateInfoIos model (+ fromMap) and wire checkUpdateIos through
  the platform interface, method channel, and public API
- Remove now-unneeded dependencies: package_info_plus, pub_semver
- Add Dart method-channel and delegation tests; document in the README

Closes axions-org#16

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@akshaynexus
akshaynexus force-pushed the feat/ios-update-check branch from db2a506 to 39e16bb Compare June 19, 2026 15:51

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@ios/in_app_update_flutter/Sources/in_app_update_flutter/InAppUpdateFlutterPlugin.swift`:
- Line 35: The `installedVersion` is being defaulted to an empty string when the
bundle version cannot be retrieved, which allows `updateAvailable` to be set to
true even when the installed version is unavailable. At both locations where
`installedVersion` is extracted (the assignment at line 35 and again at line
74), add validation to ensure that `updateAvailable` is only set to true when
both the installed version and store version are available and non-empty. Treat
cases where the installed version is missing as non-comparable scenarios where
no update should be reported, rather than allowing empty string comparisons to
proceed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d9b550a7-0713-4af3-9e19-b42014322827

📥 Commits

Reviewing files that changed from the base of the PR and between db2a506 and 39e16bb.

⛔ Files ignored due to path filters (1)
  • example/pubspec.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • README.md
  • ios/in_app_update_flutter/Sources/in_app_update_flutter/InAppUpdateFlutterPlugin.swift
  • lib/in_app_update_flutter.dart
  • lib/src/method_channel/in_app_update_flutter_method_channel.dart
  • lib/src/models/app_update_info_ios.dart
  • lib/src/models/models.dart
  • lib/src/platform_interface/in_app_update_flutter_platform_interface.dart
  • test/in_app_update_flutter_method_channel_test.dart
  • test/in_app_update_flutter_test.dart
✅ Files skipped from review due to trivial changes (2)
  • lib/src/models/models.dart
  • README.md
🚧 Files skipped from review as they are similar to previous changes (6)
  • lib/src/platform_interface/in_app_update_flutter_platform_interface.dart
  • test/in_app_update_flutter_method_channel_test.dart
  • lib/src/method_channel/in_app_update_flutter_method_channel.dart
  • lib/in_app_update_flutter.dart
  • lib/src/models/app_update_info_ios.dart
  • test/in_app_update_flutter_test.dart

akshaynexus and others added 2 commits June 19, 2026 22:13
- Treat an empty installedVersion as non-comparable so a missing bundle
  version can no longer report updateAvailable: true
- URL-encode the bundle id before building the iTunes Lookup URL
- Add a method-channel regression test asserting lookup failure returns
  updateAvailable: false (the non-throwing contract)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@buildwithpulkit

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5a37a77769

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +58 to +60
regionCode = Locale.current.region?.identifier.lowercased() ?? ""
} else {
regionCode = Locale.current.regionCode?.lowercased() ?? ""

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use the storefront region for lookups

When the user's App Store account/storefront differs from the device Region setting (for example an expat or QA device set to US while the app is only listed in GB), this locale-based country builds the wrong iTunes Lookup URL. The lookup then either returns no result or a different storefront's version, so checkUpdateIos() reports updateAvailable: false even though the user can update from their actual App Store; use the StoreKit storefront or an explicit override instead of Locale.current.

Useful? React with 👍 / 👎.

Codex flagged that scoping the iTunes Lookup solely to Locale.current can
target the wrong App Store when the device region differs from the user's
storefront (e.g. an expat or QA device). SKStorefront.countryCode is the
correct source but only exposes ISO 3166-1 alpha-3, with no clean Foundation
alpha-3->alpha-2 conversion, so deriving it would require a hardcoded table.

Instead, expose an optional `region` parameter on checkUpdateIos() (the
explicit-override path Codex listed as acceptable). It takes an alpha-2 code
and, when omitted, falls back to the device region as before — no lookup
table. Native resolution is centralized in resolveRegion(override:).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@axions-org axions-org deleted a comment from chatgpt-codex-connector Bot Jun 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: iOS update check via iTunes Lookup API (checkUpdateIos)

2 participants