Guideline 4.2

Guideline 4.2 - Design: WebView-Only App With No Native Functionality

High RiskMedium DifficultyTypical Fix: 1-2 weeks0 Reports
Also known as:Entire app is a single WKWebView pointing to a website URLApp wraps a responsive web app with a navigation bar but adds no native featuresContent is loaded from a CMS via web views with no offline capabilityApp is a PhoneGap/Cordova wrapper with no native pluginsLogin screen is native but all other content is web-basedTab bar or navigation exists but each tab loads a different web page

Our Take

Apple rejected your app under Guideline 4.2 because it is essentially a wrapper around a website with no meaningful native iOS functionality. The app’s primary content is displayed through WKWebView or embedded web pages, and it does not leverage native iOS capabilities like push notifications, offline storage, camera, Siri, widgets, or other platform features. Apple considers such apps better suited as websites or Safari bookmarks rather than standalone App Store listings.

Resolution Guide

01

**Rewrite core screens in native SwiftUI or UIKit** — At minimum, convert the primary user-facing screens to native code. The home screen, navigation, lists, and detail views should all be native:

```swift

// Instead of loading a URL in WKWebView, build native views

List(articles) { article in

NavigationLink(destination: ArticleDetailView(article: article)) {

ArticleRowView(article: article)

}

}

```

02

**Add push notifications** — Register for remote notifications and send timely, relevant alerts. This is one of the clearest signals that an app is native:

```swift

UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound])

```

03

**Implement offline functionality** — Cache content locally so the app is useful without an internet connection:

  • Use SwiftData or Core Data for structured content
  • - Cache images with URLCache or a library like Kingfisher

    - Show cached content with a “last updated” indicator when offline

    04

    **Add native iOS features** that a website cannot provide:

  • Widgets: Show quick-glance information on the Home Screen
  • - Camera/photo integration: Let users capture or select images natively

    - Haptic feedback: Add tactile responses to interactions

    - Shortcuts/Siri: Enable voice-driven actions

    - Share extension: Let users share content from other apps into yours

    05

    **Use native navigation** — Replace web-based navigation with UINavigationController or NavigationStack. Users should feel iOS-native transitions, swipe-back gestures, and standard navigation patterns.


    06

    **If some web content is necessary**, use it selectively — It’s acceptable to use WKWebView for specific content like terms of service, help articles, or rich HTML emails. The key is that the majority of the app must be native.


    07

    **Test the “airplane mode test”** — Put your phone in airplane mode and open your app. If it’s completely blank or unusable, you haven’t added enough native functionality.


    Example Rejection Email

    From:Apple App Review Team
    Subject:Guideline 4.2 - Design: WebView-Only App With No Native
    Guideline 4.2 - Minimum Functionality Your app only includes links, images, or content aggregated from the Internet with limited or no native iOS functionality. Although this content may be useful, it would be more appropriate as a Safari bookmark, web clip, or web app. Specifically, your app appears to be a repackaged version of a website. The primary interface is a web view that loads content from [your-domain.com] with no additional native features. Next Steps: We encourage you to build your app using native iOS frameworks and technologies to create a more engaging, responsive user experience that takes advantage of iOS platform capabilities.

    Consider Appealing

    Appeals are very unlikely to succeed if your app truly is a web view wrapper. Apple’s policy is firm on this. If your app uses web views for specific content but has substantial native features the reviewer missed, reply with a detailed feature list and screenshots of the native components. Otherwise, invest the time in rebuilding core screens natively.

    Generate Appeal

    Before & After

    Before — Rejected

    // Entire app: a single WKWebView

    struct ContentView: View {

    var body: some View {

    WebView(url: URL(string: "https://mysite.com")!)

    }

    }


    struct WebView: UIViewRepresentable {

    let url: URL

    func makeUIView(context: Context) -> WKWebView {

    let webView = WKWebView()

    webView.load(URLRequest(url: url))

    return webView

    }

    func updateUIView(_ uiView: WKWebView, context: Context) {}

    }

    After — Approved

    // Native app with tabs, offline, and push notifications

    @main

    struct MyApp: App {

    @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate


    var body: some Scene {

    WindowGroup {

    TabView {

    HomeView() // Native SwiftUI list + search

    .tabItem { Label("Home", systemImage: "house") }

    FavoritesView() // Locally persisted favorites

    .tabItem { Label("Saved", systemImage: "bookmark") }

    NotificationsView() // Push notification history

    .tabItem { Label("Alerts", systemImage: "bell") }

    SettingsView() // Native preferences

    .tabItem { Label("Settings", systemImage: "gear") }

    }

    }

    }

    }


    // AppDelegate handles push notification registration

    // SwiftData models for offline content caching

    // WidgetBundle for Home Screen widget

    What changed: The single WKWebView was replaced with a fully native TabView-based architecture. Each tab renders native SwiftUI views. Push notifications, offline caching via SwiftData, and a Home Screen widget demonstrate native platform integration that a website cannot replicate.

    Before — Rejected

    // Web-based content loading — no offline, no native features

    func loadContent() {

    webView.load(URLRequest(url: URL(string: "https://api.mysite.com/feed")!))

    }

    // If offline: blank white screen

    After — Approved

    // Native content loading with offline cache

    @Observable

    class FeedViewModel {

    var articles: [Article] = []


    func loadContent() async {

    // Try network first

    if let remote = try? await APIClient.fetchArticles() {

    articles = remote

    try? SwiftDataStore.cache(remote) // persist for offline

    } else {

    // Offline fallback — load cached content

    articles = SwiftDataStore.loadCached()

    }

    }

    }


    // Native list rendering

    struct FeedView: View {

    @State var viewModel = FeedViewModel()


    var body: some View {

    List(viewModel.articles) { article in

    ArticleRow(article: article)

    }

    .refreshable { await viewModel.loadContent() }

    .task { await viewModel.loadContent() }

    }

    }

    What changed: Content is fetched via a native API client and rendered in a SwiftUI List instead of a web view. Articles are cached locally with SwiftData so the app works offline. Pull-to-refresh provides a native interaction pattern that web views cannot match.

    Community Solutions · 0

    Sign in to share your solution.

    More Guideline 4 (Design) rejections

    View all Guideline 4 rejections