rn-store-skills 4.0.0 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -3
- package/package.json +2 -2
- package/skills/rn-store-compliance/SKILL.md +10 -1
- package/skills/rn-store-compliance/references/all-apps.md +42 -0
- package/skills/rn-store-compliance/references/features/subscriptions.md +162 -0
- package/skills/rn-store-compliance/references/react-native.md +72 -0
- package/skills/rn-store-compliance/references/rules/app-completeness.md +222 -0
- package/skills/rn-store-compliance/references/rules/copyright-media.md +259 -0
- package/skills/rn-store-compliance/references/rules/design.md +72 -0
- package/skills/rn-store-compliance/references/rules/legal.md +414 -0
- package/skills/rn-store-compliance/references/rules/ota-updates.md +141 -0
- package/skills/rn-store-compliance/references/rules/subscriptions.md +112 -0
package/README.md
CHANGED
|
@@ -4,13 +4,15 @@ React Native store compliance + App Store Connect automation skills for AI codin
|
|
|
4
4
|
|
|
5
5
|
17 skills covering everything from rejection prevention to release automation.
|
|
6
6
|
|
|
7
|
+
> Apple rejected ~1.93 million of ~7.77 million app submissions in 2024 — roughly **25% of all submissions**. Most rejections come from a small set of repeated mistakes. This skill pack helps AI agents catch every one of them before review.
|
|
8
|
+
|
|
7
9
|
## Skills
|
|
8
10
|
|
|
9
11
|
### Store Compliance
|
|
10
12
|
|
|
11
13
|
| Skill | Description |
|
|
12
14
|
|-------|-------------|
|
|
13
|
-
| `rn-store-compliance` | React Native compliance checker — Apple & Google guidelines,
|
|
15
|
+
| `rn-store-compliance` | React Native compliance checker — Apple & Google guidelines, 30+ rejection rules, 10 app-type checklists, RN-specific patterns, copyright/IP, legal compliance, OTA update rules |
|
|
14
16
|
|
|
15
17
|
### App Store Connect CLI (`asc`)
|
|
16
18
|
|
|
@@ -97,7 +99,7 @@ skills/
|
|
|
97
99
|
│ ├── SKILL.md
|
|
98
100
|
│ └── references/
|
|
99
101
|
│ ├── guidelines/ ← Apple & Google guidelines
|
|
100
|
-
│ ├── rules/ ←
|
|
102
|
+
│ ├── rules/ ← 11 detection rule sets
|
|
101
103
|
│ ├── app-types/ ← 7 app category checklists
|
|
102
104
|
│ ├── features/ ← 3 feature checklists
|
|
103
105
|
│ ├── all-apps.md ← Universal checklist
|
|
@@ -133,7 +135,8 @@ skills/
|
|
|
133
135
|
### Store Compliance (rn-store-compliance)
|
|
134
136
|
- Apple App Store Review Guidelines (1.x–5.x) — full index
|
|
135
137
|
- Google Play Store Policies — full index
|
|
136
|
-
-
|
|
138
|
+
- 30+ rejection rules with detection patterns, fixes, and real rejection messages
|
|
139
|
+
- 11 rule categories (metadata, subscriptions, privacy, design, entitlements, performance, permissions, copyright/IP, legal, OTA updates, app completeness)
|
|
137
140
|
- 7 app-type checklists (social, kids, health, games, AI, crypto, VPN)
|
|
138
141
|
- 3 feature checklists (subscriptions, UGC, macOS)
|
|
139
142
|
- React Native / Expo specific patterns and detection
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rn-store-skills",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "React Native store compliance + App Store Connect automation skills for AI coding agents. 17 skills covering rejection prevention, build management, metadata, TestFlight, signing, pricing, and more.",
|
|
3
|
+
"version": "5.0.0",
|
|
4
|
+
"description": "React Native store compliance + App Store Connect automation skills for AI coding agents. 17 skills covering rejection prevention, copyright/IP, legal compliance, OTA updates, subscriptions, build management, metadata, TestFlight, signing, pricing, and more.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent-skill",
|
|
7
7
|
"react-native",
|
|
@@ -14,7 +14,7 @@ description: >
|
|
|
14
14
|
license: MIT
|
|
15
15
|
metadata:
|
|
16
16
|
author: JohnAdib
|
|
17
|
-
version: "
|
|
17
|
+
version: "5.0.0"
|
|
18
18
|
tags:
|
|
19
19
|
- react-native
|
|
20
20
|
- expo
|
|
@@ -91,6 +91,10 @@ When you need detection patterns, fix steps, and example rejection messages:
|
|
|
91
91
|
| Entitlement/capability issues | `references/rules/entitlements.md` |
|
|
92
92
|
| Crashes / performance | `references/rules/performance.md` |
|
|
93
93
|
| Permission problems | `references/rules/permissions.md` |
|
|
94
|
+
| Copyright / IP / media | `references/rules/copyright-media.md` |
|
|
95
|
+
| Legal compliance (GDPR, COPPA, DMA) | `references/rules/legal.md` |
|
|
96
|
+
| OTA / CodePush update violations | `references/rules/ota-updates.md` |
|
|
97
|
+
| App completeness / demo accounts | `references/rules/app-completeness.md` |
|
|
94
98
|
|
|
95
99
|
### Step 5: Submission & Rejection
|
|
96
100
|
|
|
@@ -126,3 +130,8 @@ When you need detection patterns, fix steps, and example rejection messages:
|
|
|
126
130
|
| VPN app | `app-types/vpn.md` |
|
|
127
131
|
| macOS app | `features/macos.md` + `rules/entitlements.md` |
|
|
128
132
|
| Upgrading React Native | `react-native.md` + `rules/performance.md` |
|
|
133
|
+
| Copyright / media licensing | `rules/copyright-media.md` |
|
|
134
|
+
| Legal / GDPR / COPPA / DMA | `rules/legal.md` + `rules/privacy.md` |
|
|
135
|
+
| OTA updates (CodePush/Expo Updates) | `rules/ota-updates.md` + `react-native.md` |
|
|
136
|
+
| App completeness / demo account | `rules/app-completeness.md` |
|
|
137
|
+
| Account deletion requirement | `rules/design.md` + `rules/legal.md` |
|
|
@@ -54,6 +54,28 @@ Master checklist loaded for every app regardless of type or category.
|
|
|
54
54
|
- [ ] POST_NOTIFICATIONS runtime permission handled (Android 13+)
|
|
55
55
|
- [ ] 16 KB page size compatibility for native libraries
|
|
56
56
|
|
|
57
|
+
## Copyright & Intellectual Property
|
|
58
|
+
|
|
59
|
+
- [ ] All images properly licensed (owned, stock licensed, or CC0/permissive)
|
|
60
|
+
- [ ] No copyrighted music or audio without license
|
|
61
|
+
- [ ] No copyrighted video content without distribution rights
|
|
62
|
+
- [ ] Fonts properly licensed for mobile app embedding
|
|
63
|
+
- [ ] Open source licenses complied with (no GPL in App Store without compliance)
|
|
64
|
+
- [ ] AI-generated content does not depict real people without consent
|
|
65
|
+
- [ ] No screenshots or recordings of competitor apps
|
|
66
|
+
- [ ] DMCA / copyright takedown process if app hosts user content
|
|
67
|
+
|
|
68
|
+
## Legal Compliance
|
|
69
|
+
|
|
70
|
+
- [ ] GDPR consent before data collection (EU users)
|
|
71
|
+
- [ ] Account deletion available in-app (if account creation exists)
|
|
72
|
+
- [ ] Export compliance: `ITSAppUsesNonExemptEncryption` set in Info.plist
|
|
73
|
+
- [ ] COPPA compliance if targeting children under 13
|
|
74
|
+
- [ ] Age rating questionnaire completed honestly
|
|
75
|
+
- [ ] Terms of Service accessible in-app and on store listing
|
|
76
|
+
- [ ] Loot box / gacha odds disclosed before purchase (if applicable)
|
|
77
|
+
- [ ] Regional legal requirements checked (China AI terms, Russia data localization)
|
|
78
|
+
|
|
57
79
|
## Design & UX
|
|
58
80
|
|
|
59
81
|
- [ ] Not a copycat of another app
|
|
@@ -79,6 +101,22 @@ Master checklist loaded for every app regardless of type or category.
|
|
|
79
101
|
- [ ] Certificate/signing valid and not expired
|
|
80
102
|
- [ ] Version number incremented above current live version
|
|
81
103
|
|
|
104
|
+
## App Completeness
|
|
105
|
+
|
|
106
|
+
- [ ] Demo account provided in review notes (if login required)
|
|
107
|
+
- [ ] All premium features accessible during review (demo account unlocked or sandbox IAP instructions)
|
|
108
|
+
- [ ] No placeholder content (Lorem ipsum, stock photos as real content, "coming soon")
|
|
109
|
+
- [ ] No debug/staging labels or environment indicators in production
|
|
110
|
+
- [ ] Backend services live and stable during review period (24/7)
|
|
111
|
+
- [ ] All buttons and navigation destinations functional
|
|
112
|
+
- [ ] No hardcoded localhost/staging URLs in production build
|
|
113
|
+
|
|
114
|
+
## OTA Updates
|
|
115
|
+
|
|
116
|
+
- [ ] OTA (CodePush/Expo Updates) used only for bug fixes, not new features
|
|
117
|
+
- [ ] No hidden feature activation via remote config or date triggers
|
|
118
|
+
- [ ] Feature flags only toggle features already present in reviewed binary
|
|
119
|
+
|
|
82
120
|
## Related Rules
|
|
83
121
|
|
|
84
122
|
- See `rules/metadata.md` for metadata rejection patterns
|
|
@@ -88,3 +126,7 @@ Master checklist loaded for every app regardless of type or category.
|
|
|
88
126
|
- See `rules/permissions.md` for permission patterns
|
|
89
127
|
- See `rules/subscriptions.md` if app has subscriptions/IAP
|
|
90
128
|
- See `rules/entitlements.md` for entitlement/capability issues
|
|
129
|
+
- See `rules/copyright-media.md` for copyright/IP/media issues
|
|
130
|
+
- See `rules/legal.md` for legal compliance (GDPR, COPPA, DMA, export)
|
|
131
|
+
- See `rules/ota-updates.md` for OTA/CodePush update violations
|
|
132
|
+
- See `rules/app-completeness.md` for demo accounts, placeholder content, backend readiness
|
|
@@ -52,3 +52,165 @@ Feature checklist — any app type can have subscriptions or in-app purchases.
|
|
|
52
52
|
- Not testing sandbox purchases on real devices before submission.
|
|
53
53
|
- Subscription screen missing required links (privacy policy, terms).
|
|
54
54
|
- Play Billing Library version too old — Google rejects outdated versions.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Auto-Renewal Disclosure (Required Legal Text)
|
|
59
|
+
|
|
60
|
+
### Apple
|
|
61
|
+
Subscription screens must include this disclosure (or equivalent) near the subscribe button:
|
|
62
|
+
- "Payment will be charged to your Apple ID account at confirmation of purchase."
|
|
63
|
+
- "Subscription automatically renews unless it is canceled at least 24 hours before the end of the current period."
|
|
64
|
+
- "Your account will be charged for renewal within 24 hours prior to the end of the current period."
|
|
65
|
+
- "You can manage and cancel your subscriptions by going to your account settings on the App Store after purchase."
|
|
66
|
+
|
|
67
|
+
### Google Play
|
|
68
|
+
- "Your subscription will automatically renew and your payment method will be charged at the start of each billing period."
|
|
69
|
+
- "You can cancel anytime in Google Play Store > Subscriptions."
|
|
70
|
+
|
|
71
|
+
Both stores: the disclosure must be visible without scrolling — not buried in fine print.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Subscription Management Link
|
|
76
|
+
|
|
77
|
+
### Apple
|
|
78
|
+
Include a tappable link to Apple's subscription management page:
|
|
79
|
+
```tsx
|
|
80
|
+
import { Linking, Platform } from 'react-native';
|
|
81
|
+
|
|
82
|
+
const openSubscriptionManagement = () => {
|
|
83
|
+
if (Platform.OS === 'ios') {
|
|
84
|
+
Linking.openURL('https://apps.apple.com/account/subscriptions');
|
|
85
|
+
// Or deep link: itms-apps://apps.apple.com/account/subscriptions
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
```
|
|
89
|
+
Place this in Settings screen and/or subscription management UI.
|
|
90
|
+
|
|
91
|
+
### Google Play
|
|
92
|
+
```tsx
|
|
93
|
+
const openPlaySubscriptions = () => {
|
|
94
|
+
if (Platform.OS === 'android') {
|
|
95
|
+
Linking.openURL('https://play.google.com/store/account/subscriptions');
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Cancellation UX
|
|
103
|
+
|
|
104
|
+
- [ ] Cancellation instructions clearly visible in Settings / Account / Subscription screen
|
|
105
|
+
- [ ] No dark patterns — do not hide the cancel option, require multi-step confirmations, or use confusing language
|
|
106
|
+
- [ ] Do not show misleading "Are you sure?" flows that make it hard to cancel
|
|
107
|
+
- [ ] After cancellation, clearly show when access expires
|
|
108
|
+
- [ ] Apple: you cannot cancel subscriptions programmatically — you must link to Apple's subscription management
|
|
109
|
+
- [ ] Google: you can cancel via Play Billing API server-side, but the standard approach is linking to Play Store subscription settings
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Grace Period and Billing Retry
|
|
114
|
+
|
|
115
|
+
### Apple
|
|
116
|
+
- Apple has automatic billing retry for 60 days after a failed payment
|
|
117
|
+
- Grace period (optional, enable in App Store Connect): keeps subscription active for 6 or 16 days during billing retry
|
|
118
|
+
- Enable grace period in App Store Connect → Subscriptions → Billing Grace Period
|
|
119
|
+
- Your app should check `Transaction.expirationDate` and `Transaction.revocationDate` in StoreKit 2
|
|
120
|
+
|
|
121
|
+
### Google Play
|
|
122
|
+
- Grace period: configurable (3, 7, 14, or 30 days) in Play Console
|
|
123
|
+
- Account hold: after grace period expires, subscription enters hold for up to 30 days
|
|
124
|
+
- Your app should handle `SUBSCRIPTION_ON_HOLD` state — show "update payment method" message
|
|
125
|
+
|
|
126
|
+
### React Native Implementation
|
|
127
|
+
```tsx
|
|
128
|
+
// StoreKit 2 via react-native-iap v12+
|
|
129
|
+
import { getAvailablePurchases, purchaseUpdatedListener } from 'react-native-iap';
|
|
130
|
+
|
|
131
|
+
// Listen for transaction updates (renewals, expirations, revocations)
|
|
132
|
+
purchaseUpdatedListener(async (purchase) => {
|
|
133
|
+
// Validate receipt server-side
|
|
134
|
+
// Check subscription status including grace period
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### RevenueCat
|
|
139
|
+
RevenueCat handles grace period and billing retry automatically:
|
|
140
|
+
- `CustomerInfo.entitlements` reflects active entitlement during grace period
|
|
141
|
+
- Webhooks: `BILLING_ISSUE_DETECTED`, `SUBSCRIPTION_PAUSED`, `EXPIRATION`
|
|
142
|
+
- Check `subscriberInfo.entitlements.active` — it accounts for grace period
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Family Sharing
|
|
147
|
+
|
|
148
|
+
### Apple
|
|
149
|
+
- [ ] Enable Family Sharing for subscriptions in App Store Connect (optional)
|
|
150
|
+
- [ ] If enabled, check entitlements for family members using StoreKit 2 `Transaction.ownershipType`
|
|
151
|
+
- [ ] `Transaction.ownershipType == .familyShared` indicates access via family sharing
|
|
152
|
+
- [ ] Family organizer manages the subscription — individual family members cannot cancel
|
|
153
|
+
|
|
154
|
+
### Google Play
|
|
155
|
+
- [ ] Family Library not available for subscriptions on Google Play
|
|
156
|
+
- [ ] Only one-time purchases can be shared via Family Library
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Offer Codes and Promo Codes
|
|
161
|
+
|
|
162
|
+
### Apple
|
|
163
|
+
- [ ] Offer codes: create in App Store Connect → Subscriptions → Offer Codes
|
|
164
|
+
- [ ] One-time use or multi-use codes
|
|
165
|
+
- [ ] Redeem via `presentCodeRedemptionSheet()` in StoreKit 2
|
|
166
|
+
- [ ] React Native: `react-native-iap` supports `presentCodeRedemptionSheetIOS()`
|
|
167
|
+
|
|
168
|
+
### Google Play
|
|
169
|
+
- [ ] Promo codes: create in Play Console → Monetize → Products → Promo codes
|
|
170
|
+
- [ ] Limited to 500 codes per quarter per app
|
|
171
|
+
- [ ] Redeem via Play Store or deep link
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Price Increase Consent
|
|
176
|
+
|
|
177
|
+
### Apple (StoreKit 2)
|
|
178
|
+
- If you raise the price of an existing subscription, Apple requires user consent
|
|
179
|
+
- Price increases < 50% AND < $5 (or equivalent): Apple auto-consents if user is on auto-renew
|
|
180
|
+
- Price increases above thresholds: Apple shows consent dialog, subscription cancelled if user doesn't accept within 60 days
|
|
181
|
+
- Listen for price consent messages:
|
|
182
|
+
```tsx
|
|
183
|
+
// StoreKit 2 Message listener
|
|
184
|
+
import { Message } from 'StoreKit';
|
|
185
|
+
// In react-native-iap, handle price consent via purchase update listener
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Google Play
|
|
189
|
+
- Google notifies users of price increases automatically
|
|
190
|
+
- Users have 30 days to accept; subscription cancelled if declined
|
|
191
|
+
- Implement `onPriceChangeConfirmationResult` callback
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Subscription Upgrade / Downgrade
|
|
196
|
+
|
|
197
|
+
### Apple
|
|
198
|
+
- [ ] Upgrade: immediate, prorated refund for remaining time on current plan
|
|
199
|
+
- [ ] Downgrade: takes effect at next renewal date
|
|
200
|
+
- [ ] Crossgrade (same tier, different duration): treated as upgrade or downgrade depending on value
|
|
201
|
+
- [ ] Implement `Product.SubscriptionInfo.UpgradePolicy` handling in StoreKit 2
|
|
202
|
+
|
|
203
|
+
### Google Play
|
|
204
|
+
- [ ] Proration modes: `IMMEDIATE_WITH_TIME_PRORATION`, `IMMEDIATE_AND_CHARGE_PRORATED_PRICE`, `DEFERRED`, etc.
|
|
205
|
+
- [ ] Set proration mode when calling `launchBillingFlow` for upgrade/downgrade
|
|
206
|
+
- [ ] `react-native-iap`: pass `prorationModeAndroid` parameter
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Introductory Offer Eligibility
|
|
211
|
+
|
|
212
|
+
- [ ] Check eligibility BEFORE displaying offer pricing — don't show introductory price to ineligible users
|
|
213
|
+
- [ ] Apple: `Product.subscription.isEligibleForIntroOffer` (StoreKit 2)
|
|
214
|
+
- [ ] Google: `SubscriptionOfferDetails.pricingPhases` — check if free trial phase exists for this user
|
|
215
|
+
- [ ] RevenueCat: `offerings.current.availablePackages[0].product.introPrice` — RevenueCat handles eligibility
|
|
216
|
+
- [ ] Displaying intro offer to ineligible users is misleading and can trigger rejection under 3.1.2
|
|
@@ -190,6 +190,78 @@ Validate all parameters. Test from: cold start, background, other apps, Safari/C
|
|
|
190
190
|
### 10. Large App Size
|
|
191
191
|
See `rules/performance.md` for size reduction strategies.
|
|
192
192
|
|
|
193
|
+
### 11. OTA Update Violations (CodePush / Expo Updates)
|
|
194
|
+
Using CodePush or Expo Updates to push new features (not just bug fixes) violates Apple 3.3.2.
|
|
195
|
+
See `rules/ota-updates.md` for what's allowed and what's not.
|
|
196
|
+
|
|
197
|
+
### 12. IPv6-Only Network Failure
|
|
198
|
+
Apple tests on IPv6-only networks. Hardcoded IPv4 addresses or IPv4-only APIs fail.
|
|
199
|
+
See IPv6 section below.
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## IPv6-Only Network Compliance
|
|
204
|
+
|
|
205
|
+
**Apple**: 2.5.6 — IPv6 | **Severity**: REJECTION
|
|
206
|
+
|
|
207
|
+
Apple reviews apps on IPv6-only networks (NAT64/DNS64). If your app uses hardcoded IPv4 addresses, raw IP sockets, or APIs that don't support IPv6, it will fail during review.
|
|
208
|
+
|
|
209
|
+
**Common React Native issues:**
|
|
210
|
+
- Hardcoded IPv4 addresses in API URLs (`http://192.168.1.1`, `http://10.0.0.1`)
|
|
211
|
+
- WebSocket connections to IPv4-only servers
|
|
212
|
+
- Third-party SDKs that use raw sockets (some analytics, game SDKs)
|
|
213
|
+
- Custom native modules using `AF_INET` without `AF_INET6` support
|
|
214
|
+
|
|
215
|
+
**Detection:**
|
|
216
|
+
```bash
|
|
217
|
+
# Check for hardcoded IPv4 addresses
|
|
218
|
+
grep -rnE "\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b" \
|
|
219
|
+
--include="*.tsx" --include="*.ts" --include="*.jsx" --include="*.js" \
|
|
220
|
+
src/ app/ 2>/dev/null | grep -v "node_modules" | grep -v "0\.0\.0\.0" | grep -v "255\.255"
|
|
221
|
+
|
|
222
|
+
# Check native code for IPv4-only socket usage
|
|
223
|
+
grep -rnE "(AF_INET[^6]|inet_addr|SOCK_STREAM.*AF_INET)" \
|
|
224
|
+
--include="*.swift" --include="*.m" --include="*.mm" --include="*.h" \
|
|
225
|
+
ios/ 2>/dev/null
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**Fix:**
|
|
229
|
+
1. Use hostnames (domain names) instead of IP addresses — DNS resolution handles IPv6 automatically.
|
|
230
|
+
2. Use high-level networking APIs (`NSURLSession`, `fetch`, `axios`) — they support IPv6 natively.
|
|
231
|
+
3. Test on an IPv6-only network: Mac → System Preferences → Sharing → Internet Sharing → "Create NAT64 Network."
|
|
232
|
+
4. If using custom native modules with sockets, use `getaddrinfo()` which returns both IPv4 and IPv6 addresses.
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## OTA Updates (CodePush / Expo Updates)
|
|
237
|
+
|
|
238
|
+
React Native's JS-based architecture enables over-the-air updates without store review. This is powerful but strictly regulated.
|
|
239
|
+
|
|
240
|
+
**Key rule**: OTA is allowed ONLY for bug fixes and minor improvements. New features, behavior changes, or anything that changes the app's purpose MUST go through store review.
|
|
241
|
+
|
|
242
|
+
See `rules/ota-updates.md` for complete rules, detection patterns, and what's allowed vs prohibited.
|
|
243
|
+
|
|
244
|
+
**Quick reference:**
|
|
245
|
+
- Bug fix → OTA ✅
|
|
246
|
+
- Text/translation fix → OTA ✅
|
|
247
|
+
- New screen or feature → Store submission required ❌
|
|
248
|
+
- New IAP product → Store submission required ❌
|
|
249
|
+
- Permission change → Store submission required ❌
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## New Architecture (Fabric / TurboModules)
|
|
254
|
+
|
|
255
|
+
React Native's New Architecture (enabled by default in RN 0.76+) changes the native bridge. Compliance implications:
|
|
256
|
+
|
|
257
|
+
- **Bridgeless mode**: Native modules must be rewritten as TurboModules. Verify all third-party libraries support New Architecture before upgrading.
|
|
258
|
+
- **Fabric renderer**: Custom native views need Fabric components. Check library compatibility.
|
|
259
|
+
- **Build size**: New Architecture may slightly increase binary size. Monitor against store limits.
|
|
260
|
+
- **Crash patterns**: New bridge behavior may introduce new crash vectors in release builds. Test thoroughly.
|
|
261
|
+
- **Hermes**: Required with New Architecture. Ensure Hermes-specific compliance (see `rules/performance.md`).
|
|
262
|
+
|
|
263
|
+
Check compatibility: `npx react-native-new-architecture-check` or review the React Native New Architecture compatibility table.
|
|
264
|
+
|
|
193
265
|
---
|
|
194
266
|
|
|
195
267
|
## AI / Generative AI Features
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# App Completeness Rules
|
|
2
|
+
|
|
3
|
+
## Missing Demo Account for Review
|
|
4
|
+
**Apple**: 2.1 — App Completeness | **Google**: Store listing requirements | **Severity**: REJECTION
|
|
5
|
+
|
|
6
|
+
If your app requires login, you MUST provide a demo account in the App Review notes. The account must be pre-populated with realistic data, have all premium features unlocked (if behind paywall), and not require 2FA or external verification.
|
|
7
|
+
|
|
8
|
+
### Detect
|
|
9
|
+
```bash
|
|
10
|
+
# Check if app has login/authentication
|
|
11
|
+
grep -rnE "(login|signIn|sign.?in|auth|authenticate|LogIn|SignIn)" \
|
|
12
|
+
--include="*.tsx" --include="*.ts" --include="*.jsx" --include="*.js" \
|
|
13
|
+
src/ app/ screens/ 2>/dev/null
|
|
14
|
+
|
|
15
|
+
# Check for 2FA / MFA that might block reviewers
|
|
16
|
+
grep -rnE "(two.?factor|2fa|mfa|otp|verification.?code|sms.?code|authenticator)" \
|
|
17
|
+
--include="*.tsx" --include="*.ts" --include="*.jsx" --include="*.js" \
|
|
18
|
+
src/ app/ 2>/dev/null
|
|
19
|
+
|
|
20
|
+
# Check for social-only login (no email/password option)
|
|
21
|
+
grep -rnE "(GoogleSignin|FacebookLogin|AppleAuth)" \
|
|
22
|
+
--include="*.tsx" --include="*.ts" --include="*.jsx" --include="*.js" \
|
|
23
|
+
src/ app/ 2>/dev/null
|
|
24
|
+
|
|
25
|
+
# Check for paywall / premium features
|
|
26
|
+
grep -rnE "(premium|pro|subscribe|paywall|upgrade|locked|gated)" \
|
|
27
|
+
--include="*.tsx" --include="*.ts" --include="*.jsx" --include="*.js" \
|
|
28
|
+
src/ app/ 2>/dev/null
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Fix
|
|
32
|
+
1. Create a dedicated demo account before submission:
|
|
33
|
+
- Username: `demo@yourapp.com` (or similar)
|
|
34
|
+
- Password: a simple, non-expiring password
|
|
35
|
+
- Pre-populate with realistic content (not empty states)
|
|
36
|
+
- Unlock all premium/subscription features on this account
|
|
37
|
+
2. Add credentials in App Store Connect → App Review Information → Notes for Reviewer:
|
|
38
|
+
```
|
|
39
|
+
Demo Account:
|
|
40
|
+
Email: demo@yourapp.com
|
|
41
|
+
Password: DemoPass123!
|
|
42
|
+
|
|
43
|
+
This account has Premium features unlocked for testing.
|
|
44
|
+
To test the subscription flow, navigate to Settings > Subscription.
|
|
45
|
+
```
|
|
46
|
+
3. If 2FA is required: either disable it for the demo account, or provide the 2FA seed/backup codes in the review notes.
|
|
47
|
+
4. If login is social-only (Google/Apple/Facebook), also implement email/password login for the demo account, OR provide detailed instructions for how to create an account.
|
|
48
|
+
5. Test the demo account before every submission — credentials expire, sessions get invalidated, passwords get rotated.
|
|
49
|
+
6. If using Firebase Auth: create the demo user in Firebase Console, not through the app registration flow (to avoid triggering verification emails).
|
|
50
|
+
|
|
51
|
+
### Example Rejection
|
|
52
|
+
> Guideline 2.1 — Performance — App Completeness: We were unable to review your app as it requires login credentials. Please provide a demo account in the App Review notes.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Features Hidden Behind Paywall During Review
|
|
57
|
+
**Apple**: 2.1 — App Completeness | **Google**: App review policy | **Severity**: REJECTION
|
|
58
|
+
|
|
59
|
+
Apple reviewers must be able to access ALL app features. If features are behind a subscription or IAP, the demo account must have them unlocked, or you must provide sandbox IAP testing instructions.
|
|
60
|
+
|
|
61
|
+
### Detect
|
|
62
|
+
```bash
|
|
63
|
+
# Check for subscription gates
|
|
64
|
+
grep -rnE "(isSubscribed|isPremium|isPro|hasPurchased|entitlement|subscription.?status)" \
|
|
65
|
+
--include="*.tsx" --include="*.ts" --include="*.jsx" --include="*.js" \
|
|
66
|
+
src/ app/ 2>/dev/null
|
|
67
|
+
|
|
68
|
+
# Check for feature gates
|
|
69
|
+
grep -rnE "(feature.?locked|premium.?only|upgrade.?required|purchase.?required)" \
|
|
70
|
+
--include="*.tsx" --include="*.ts" --include="*.jsx" --include="*.js" \
|
|
71
|
+
src/ app/ 2>/dev/null
|
|
72
|
+
|
|
73
|
+
# Check for IAP / subscription products
|
|
74
|
+
grep -rnE "(productId|purchaseProduct|requestSubscription|getSubscriptions)" \
|
|
75
|
+
--include="*.tsx" --include="*.ts" --include="*.jsx" --include="*.js" \
|
|
76
|
+
src/ app/ 2>/dev/null
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Fix
|
|
80
|
+
1. **Option A (recommended)**: Grant the demo account full premium access server-side. Add a flag on your backend that bypasses the subscription check for the demo account.
|
|
81
|
+
2. **Option B**: Provide sandbox IAP testing instructions in review notes:
|
|
82
|
+
```
|
|
83
|
+
To test premium features:
|
|
84
|
+
1. Sign out of your personal Apple ID in Settings > Media & Purchases
|
|
85
|
+
2. Use Sandbox account: sandbox@test.com / TestPass123!
|
|
86
|
+
3. Navigate to Settings > Subscription > Subscribe
|
|
87
|
+
4. Complete the sandbox purchase (no real charge)
|
|
88
|
+
```
|
|
89
|
+
3. **Option C**: Temporarily unlock all features for the review build (using a build flag), then remove the flag for the production release. ⚠️ Risky — if Apple notices different behavior between builds, it can trigger a deeper review.
|
|
90
|
+
4. Document ALL premium features and how to access them in the review notes.
|
|
91
|
+
5. If your app has multiple subscription tiers, unlock the highest tier on the demo account.
|
|
92
|
+
|
|
93
|
+
### Example Rejection
|
|
94
|
+
> Guideline 2.1 — Performance: We were unable to access premium features in your app. Please provide a demo account with premium features unlocked or provide instructions for testing in-app purchases.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Placeholder and Incomplete Content
|
|
99
|
+
**Apple**: 2.1 — App Completeness | **Google**: Minimum functionality policy | **Severity**: REJECTION
|
|
100
|
+
|
|
101
|
+
Any visible placeholder content — Lorem ipsum text, stock photo placeholders, empty states that should have data, "coming soon" labels, or debug information — triggers rejection. The app must feel complete and production-ready.
|
|
102
|
+
|
|
103
|
+
### Detect
|
|
104
|
+
```bash
|
|
105
|
+
# Check for Lorem ipsum and placeholder text
|
|
106
|
+
grep -rniE "(lorem ipsum|dolor sit amet|placeholder|dummy|sample|test data|coming soon|under construction|TODO|FIXME|HACK)" \
|
|
107
|
+
--include="*.tsx" --include="*.ts" --include="*.jsx" --include="*.js" --include="*.json" \
|
|
108
|
+
src/ app/ 2>/dev/null
|
|
109
|
+
|
|
110
|
+
# Check for debug/test labels
|
|
111
|
+
grep -rniE "(debug|test|staging|dev|development|beta|alpha|prototype)" \
|
|
112
|
+
--include="*.tsx" --include="*.ts" --include="*.jsx" --include="*.js" \
|
|
113
|
+
src/ app/ 2>/dev/null | grep -viE "(import|require|package|node_modules|\.test\.|\.spec\.|__test__|__mock__)"
|
|
114
|
+
|
|
115
|
+
# Check for placeholder images
|
|
116
|
+
find assets/ src/ -iname "*placeholder*" -o -iname "*dummy*" -o -iname "*sample*" 2>/dev/null
|
|
117
|
+
|
|
118
|
+
# Check for incomplete navigation (screens that go nowhere)
|
|
119
|
+
grep -rnE "(navigation\.navigate.*TODO|console\.log.*not.?implemented|alert.*coming)" \
|
|
120
|
+
--include="*.tsx" --include="*.ts" --include="*.jsx" --include="*.js" \
|
|
121
|
+
src/ app/ 2>/dev/null
|
|
122
|
+
|
|
123
|
+
# Check for hardcoded test URLs
|
|
124
|
+
grep -rnE "(localhost|127\.0\.0\.1|10\.0\.2\.2|staging\.|dev\.|test\.)" \
|
|
125
|
+
--include="*.tsx" --include="*.ts" --include="*.jsx" --include="*.js" \
|
|
126
|
+
src/ app/ 2>/dev/null | grep -v "node_modules" | grep -v "__tests__"
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Fix
|
|
130
|
+
1. Replace all Lorem ipsum with real content — even if it's simple, it must be real.
|
|
131
|
+
2. Remove all "Coming Soon", "Under Construction", and "TODO" labels from the UI.
|
|
132
|
+
3. Remove debug/test/staging labels and environment indicators from the production build.
|
|
133
|
+
4. Ensure all navigation destinations exist and are functional — no buttons that lead nowhere.
|
|
134
|
+
5. Populate empty states with realistic data or show proper empty state UI ("No items yet. Tap + to add one.").
|
|
135
|
+
6. Remove all `console.log`, `console.warn` statements from production (use a Babel plugin):
|
|
136
|
+
```json
|
|
137
|
+
// babel.config.js
|
|
138
|
+
plugins: [
|
|
139
|
+
["transform-remove-console", { exclude: ["error"] }]
|
|
140
|
+
]
|
|
141
|
+
```
|
|
142
|
+
7. Replace hardcoded localhost/staging URLs with production endpoints.
|
|
143
|
+
8. Test on a fresh install — cached data may hide empty states during your testing.
|
|
144
|
+
|
|
145
|
+
### Example Rejection
|
|
146
|
+
> Guideline 2.1 — Performance — App Completeness: Your app includes placeholder content ("Lorem ipsum") on the About screen and a "Coming Soon" label on the Reports tab. Please ensure all content is final.
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Backend Services Unavailable During Review
|
|
151
|
+
**Apple**: 2.1 — App Completeness | **Google**: App functionality policy | **Severity**: REJECTION
|
|
152
|
+
|
|
153
|
+
Apple reviews apps 24/7, including weekends and holidays. If your backend is down during review, the app appears broken and gets rejected. Staging servers with limited uptime, expired API keys, and rate-limited free tiers are common causes.
|
|
154
|
+
|
|
155
|
+
### Detect
|
|
156
|
+
```bash
|
|
157
|
+
# Check API base URL configuration
|
|
158
|
+
grep -rnE "(baseURL|BASE_URL|API_URL|apiUrl|endpoint)" \
|
|
159
|
+
--include="*.tsx" --include="*.ts" --include="*.jsx" --include="*.js" --include="*.env*" \
|
|
160
|
+
src/ app/ 2>/dev/null
|
|
161
|
+
|
|
162
|
+
# Check for environment-specific configs
|
|
163
|
+
grep -rnE "(staging|development|production).*url" \
|
|
164
|
+
--include="*.tsx" --include="*.ts" --include="*.jsx" --include="*.js" --include="*.env*" \
|
|
165
|
+
src/ app/ 2>/dev/null
|
|
166
|
+
|
|
167
|
+
# Check for free-tier services that might hit limits
|
|
168
|
+
grep -E "(firebase|supabase|heroku|render|railway|planetscale|neon|vercel)" \
|
|
169
|
+
package.json 2>/dev/null
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Fix
|
|
173
|
+
1. Point the submission build to production servers (not staging/dev).
|
|
174
|
+
2. Ensure backend services have 99.9%+ uptime during the review period (typically 1-7 days after submission).
|
|
175
|
+
3. If using free-tier hosting (Heroku, Render, Railway): free tiers often sleep after inactivity — upgrade to a paid tier or implement keep-alive pings during the review period.
|
|
176
|
+
4. Check that API keys, tokens, and certificates used in the release build are not expired.
|
|
177
|
+
5. Implement graceful error handling — if the backend is temporarily down, show a retry option, not a crash or blank screen.
|
|
178
|
+
6. If your backend requires VPN or IP whitelisting, add Apple's review team IP ranges or disable IP restrictions during review.
|
|
179
|
+
7. Test the exact build you're submitting against production APIs before uploading.
|
|
180
|
+
8. Include backend status information in review notes if applicable:
|
|
181
|
+
```
|
|
182
|
+
Note: This app requires an internet connection. Our backend services are available 24/7
|
|
183
|
+
at api.yourapp.com. If you experience connectivity issues, please try again or contact
|
|
184
|
+
us at dev@yourapp.com.
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Example Rejection
|
|
188
|
+
> Guideline 2.1 — Performance: Your app was unable to load content during our review. The app displayed an error "Unable to connect to server" on the home screen. Please ensure your backend services are operational and resubmit.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Inadequate App Review Notes
|
|
193
|
+
**Apple**: 2.1 | **Google**: N/A (less structured) | **Severity**: REJECTION (indirect)
|
|
194
|
+
|
|
195
|
+
Poor or missing review notes lead to reviewers being unable to test your app, which results in rejection. Good review notes prevent misunderstandings and speed up the review process.
|
|
196
|
+
|
|
197
|
+
### Fix
|
|
198
|
+
1. Always include in App Review notes:
|
|
199
|
+
- Demo account credentials (if login required)
|
|
200
|
+
- How to access non-obvious features
|
|
201
|
+
- How to test IAP/subscription flows (sandbox accounts)
|
|
202
|
+
- Any required hardware (Bluetooth device, specific location, etc.)
|
|
203
|
+
- If features require specific conditions (e.g., "To test the alarm feature, set an alarm 2 minutes in the future")
|
|
204
|
+
2. If your app uses location: specify a location the reviewer should use, or note that the app works with any location.
|
|
205
|
+
3. If your app requires external hardware (BLE device, smart home device): provide a video demo in the review notes or App Store Connect attachments.
|
|
206
|
+
4. Keep notes concise but complete — reviewers process hundreds of apps. Make it easy.
|
|
207
|
+
5. Example good review notes:
|
|
208
|
+
```
|
|
209
|
+
Demo Account: demo@app.com / Pass123!
|
|
210
|
+
(Premium features are unlocked on this account)
|
|
211
|
+
|
|
212
|
+
Key flows to test:
|
|
213
|
+
1. Home > Search > tap any result > "Add to Cart" > Checkout
|
|
214
|
+
2. Profile > Settings > Notifications (toggle on/off)
|
|
215
|
+
3. Camera tab > Scan any barcode (or use camera to photograph any text)
|
|
216
|
+
|
|
217
|
+
The app requires internet connection. Backend is live 24/7.
|
|
218
|
+
Location features work with any location.
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Example Rejection
|
|
222
|
+
> Guideline 2.1 — Performance: We were unable to complete the review of your app because the demo account credentials provided in the review notes did not work. Please provide valid credentials and resubmit.
|