<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: SENEKA App</title>
    <description>The latest articles on DEV Community by SENEKA App (@seneka_app).</description>
    <link>https://dev.to/seneka_app</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4242169%2F2ff679c8-528f-48ff-a495-47754e0c08b2.png</url>
      <title>DEV Community: SENEKA App</title>
      <link>https://dev.to/seneka_app</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/seneka_app"/>
    <language>en</language>
    <item>
      <title>Apple rejected our Flutter app update for one sentence in the paywall fine print</title>
      <dc:creator>SENEKA App</dc:creator>
      <pubDate>Fri, 13 Nov 2026 04:57:37 +0000</pubDate>
      <link>https://dev.to/seneka_app/apple-rejected-our-flutter-app-update-for-one-sentence-in-the-paywall-fine-print-309i</link>
      <guid>https://dev.to/seneka_app/apple-rejected-our-flutter-app-update-for-one-sentence-in-the-paywall-fine-print-309i</guid>
      <description>&lt;p&gt;Small one, but it cost us a full review cycle, so maybe it saves someone else a week.&lt;/p&gt;

&lt;p&gt;Full disclosure: we make SENEKA, a game of everyday dilemmas, and this is about our own app. We build it in Flutter and ship one codebase to Google Play and the App Store. An iOS update came back from App Review with three issues. None of them was a crash.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Guideline 2.3.10: "remove Google Play references"
&lt;/h2&gt;

&lt;p&gt;Our subscription fine print under the paywall said:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Payment is charged to your Apple ID or Google Play account at confirmation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One shared string for both platforms. It's accurate, and Apple doesn't care. An iOS binary can't mention another store, even in legal small print.&lt;/p&gt;

&lt;p&gt;The fix is boring: a separate iOS string, picked at runtime.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s1"&gt;'dart:io'&lt;/span&gt; &lt;span class="n"&gt;show&lt;/span&gt; &lt;span class="nc"&gt;Platform&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Platform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isIOS&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s1"&gt;'paywall.legalIos'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'paywall.legal'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The annoying part was doing it in all 16 languages we ship. Before you submit, grep your localisation files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;grep -rniE &lt;span class="s2"&gt;"google|play store|android"&lt;/span&gt; assets/l10n lib
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every hit that can reach an iOS screen is a possible 2.3.10.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Guideline 2.1(b): "we couldn't complete the purchase"
&lt;/h2&gt;

&lt;p&gt;The screenshot attached to the rejection showed Apple's own system alert, "Account Not In This Store". The reviewer device was on the Singapore storefront and the sandbox account was from the US. Nothing in our code was involved.&lt;/p&gt;

&lt;p&gt;What we did:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replied in App Store Connect explaining the storefront mismatch, politely, without arguing.&lt;/li&gt;
&lt;li&gt;Attached a screen recording of the full purchase flow running in Xcode's StoreKit test mode, from the paywall to the unlocked content.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your app is available in many storefronts, it's worth saying in the review notes that purchases were tested with a sandbox account of the same storefront as the device.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Guideline 2.1(b): "we can't find the in-app purchases"
&lt;/h2&gt;

&lt;p&gt;Our paywall only shows up in a few places: a locked pack, the end of a free journey, and settings. "It's in settings" wasn't enough. They want exact steps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Launch the app and finish onboarding (2 taps).
2. Tap the "Explore" tab.
3. Tap any pack with a lock icon.
4. The paywall opens with the yearly and monthly plans.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Write it like the reviewer has never seen your app, because they haven't.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus bug we found on the way
&lt;/h2&gt;

&lt;p&gt;While re-testing the paywall we noticed the yearly plan's "per month" price didn't always match the store's own price formatting (currency symbol position, decimals). We were using a ready-made per-month string from our purchases SDK. Now we divide the yearly price by 12 ourselves and write it in the same format as the store's own yearly price string, with a small unit test so it can't drift again. Small, but a paywall that shows two price formats side by side looks broken.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checklist before the next submission
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] No "Google", "Play" or "Android" in any string an iOS user can see, in every language&lt;/li&gt;
&lt;li&gt;[ ] Review notes have tap-by-tap steps to each in-app purchase&lt;/li&gt;
&lt;li&gt;[ ] A short recording of a sandbox purchase, ready to attach&lt;/li&gt;
&lt;li&gt;[ ] Prices on the paywall all come from the store, in one format&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The update is resubmitted and waiting for review. If you want to see what the app is: one everyday dilemma a day, two defensible answers, and you can compare your choices with a partner or friends, who can answer in the browser without installing anything. &lt;a href="https://seneka.pages.dev/?c=devto" rel="noopener noreferrer"&gt;Try it in the browser&lt;/a&gt; or get the &lt;a href="https://play.google.com/store/apps/details?id=no.ck.seneka.seneka&amp;amp;referrer=utm_source%3Ddevto" rel="noopener noreferrer"&gt;Android app&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>ios</category>
      <category>appstore</category>
      <category>mobile</category>
    </item>
  </channel>
</rss>
