If you already have a website up and running, you are closer to having a mobile app than you think. You do not need to rebuild everything from scratch in Swift or Kotlin. You do not need to hire a mobile developer or learn an entirely new stack. What you already have — a live website — is enough to get started.
A lot of businesses sit on a fully functional website and never make it to mobile simply because native app development feels too heavy. It is expensive, it takes time, and it requires skills that most web-focused teams do not have in-house. But there is a middle ground that works surprisingly well — wrapping your website inside a Flutter app using a WebView. Your website runs inside the app, it looks and feels native to the user, and you can ship it to both the Google Play Store and the Apple App Store from a single codebase.
That is exactly what this guide covers. We will go through the full process — setting up Flutter from scratch, writing the code, testing on a device, and building the final app files ready for submission. No steps skipped, no assumed knowledge.
If you have your website URL ready, let's get into it.
Before we write any code, let's make sure everything is in place. You do not need a lot, but you do need the right things set up before moving forward.
Here is what you will need:
That is genuinely all you need. No prior mobile development experience required.
Let's get everything installed. We will go through this step by step so nothing gets missed.
Go to the official Flutter website at flutter.dev and click on Get Started. Select your operating system — Windows, macOS, or Linux — and download the Flutter SDK zip file.
Once downloaded, extract the zip file to a location on your computer. A good place is:
C:\flutter~/flutterNow you need to add Flutter to your system PATH so you can run Flutter commands from anywhere in the terminal.
On Windows:
Search for Environment Variables in the Start menu. Under System Variables, find the Path variable, click Edit, and add the full path to the flutter\bin folder. For example: C:\flutter\bin
On macOS/Linux:
Open your terminal and add this line to your .bashrc, .zshrc, or .bash_profile file:
export PATH="$PATH:$HOME/flutter/bin"
Then run:
source ~/.zshrc
Or whichever file you edited. To confirm Flutter is installed, open a new terminal window and run:
flutter --version
If you see the Flutter version printed out, you are good to move on.
Go to developer.android.com/studio and download Android Studio for your operating system. Run the installer and follow the setup wizard — the default options are fine for most cases.
Once Android Studio is open, go to Plugins from the welcome screen and search for Flutter. Install the Flutter plugin. It will also prompt you to install the Dart plugin — install that too.
After that, go to Settings → Android SDK and make sure you have at least one Android SDK version installed. Android 13 or above is recommended.
Inside Android Studio, go to Device Manager from the welcome screen or from the toolbar inside a project. Click Create Device.
Pick a device from the list — a Pixel 6 or Pixel 7 works well. Click Next, select a system image (pick one with the Recommended tag), and download it if it is not already there. Finish the setup and your emulator will appear in the Device Manager.
Click the Play button next to it to launch the emulator and make sure it boots up correctly before moving on.
This is the most important step before writing any code. Open your terminal and run:
flutter doctor
Flutter will scan your system and tell you exactly what is set up correctly and what still needs attention. You will see something like this:
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable)
[✓] Android toolchain - develop for Android devices
[✓] Android Studio
[✓] Connected device
Work through any items marked with [✗] or [!] until everything you need shows a [✓]. The output is clear and usually tells you exactly what command to run to fix each issue.
Once Flutter Doctor shows no critical issues, you are ready to create your project.
With the environment ready, let's scaffold a new Flutter project. There are two ways to do this — via the terminal or directly inside Android Studio. We will cover both.
Open your terminal and navigate to the folder where you want to create the project. Then run:
flutter create my_web_app
Replace my_web_app with whatever you want to name your project. Once it is done, navigate into the project folder:
cd my_web_app
Then open it in Android Studio by running:
studio .
If you prefer to skip the terminal entirely, you can create the project directly from Android Studio.
com.yourname.mywebapp. Click NextAndroid Studio will generate the project and open it automatically.
Either way, you will end up with a folder structure that looks like this:
my_web_app/
├── android/
├── ios/
├── lib/
│ └── main.dart
├── pubspec.yaml
└── ...
Most of the work happens inside the lib folder. The main.dart file is where we will write the code. The pubspec.yaml file is where we manage dependencies.
Before touching any code, make sure your emulator is running and then execute:
flutter run
You should see the default Flutter counter app launch on the emulator. If it runs without errors, your setup is solid and we are ready to move forward.
Now let's add the WebView package. We will be using flutter_inappwebview — it is one of the most capable WebView packages available for Flutter and gives us a lot of control over how the web content behaves inside the app. You can find the package and always check for the latest version at flutter_inappwebview on pub.dev.
Open your pubspec.yaml file and add the dependency under dependencies:
dependencies:
flutter:
sdk: flutter
flutter_inappwebview: ^6.1.5
Save the file and run:
flutter pub get
This will download and install the package into your project.
Now there are a couple of platform-specific configurations we need to take care of before writing the code.
Android Configuration
Open android/app/build.gradle and make sure the minSdkVersion is set to at least 19:
android {
defaultConfig {
minSdkVersion 19
}
}
Then open android/app/src/main/AndroidManifest.xml and add internet permission inside the <manifest> tag:
<uses-permission android:name="android.permission.INTERNET"/>
iOS Configuration
Open ios/Runner/Info.plist and add the following inside the <dict> tag to allow your app to load web content:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Once both configurations are done, you are ready to write the actual code.
This is the part everything has been building toward. Open lib/main.dart, delete everything that is already there, and replace it with the following:
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
title: 'My Web App',
home: WebViewScreen(),
);
}
}
class WebViewScreen extends StatefulWidget {
const WebViewScreen({super.key});
@override
State<WebViewScreen> createState() => _WebViewScreenState();
}
class _WebViewScreenState extends State<WebViewScreen> {
final GlobalKey webViewKey = GlobalKey();
InAppWebViewController? webViewController;
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: InAppWebView(
key: webViewKey,
initialUrlRequest: URLRequest(
url: WebUri('https://your-website.com'),
),
initialSettings: InAppWebViewSettings(
javaScriptEnabled: true,
domStorageEnabled: true,
useWideViewPort: true,
loadWithOverviewMode: true,
supportZoom: false,
),
onWebViewCreated: (controller) {
webViewController = controller;
},
onLoadStart: (controller, url) {
debugPrint('Page started loading: $url');
},
onLoadStop: (controller, url) {
debugPrint('Page finished loading: $url');
},
onReceivedError: (controller, request, error) {
debugPrint('Error: ${error.description}');
},
),
),
);
}
}
Replace https://your-website.com with your actual website URL. That is the only change you need to make.
Here is a quick breakdown of what the key settings do:
javaScriptEnabled — allows your website to run JavaScript normally inside the appdomStorageEnabled — enables localStorage and sessionStorage so your website can store datauseWideViewPort — makes sure the page renders at the correct width rather than zooming outsupportZoom — set to false so the user cannot pinch-zoom the page, which gives it a more native app feelSafeArea — keeps the WebView within the safe boundaries of the screen, avoiding notches and system UI overlapsSave the file and let's make sure it runs.
Before building the final app files, let's make sure everything works correctly on both an emulator and a real device.
Make sure your emulator is running from Android Studio's Device Manager. Then go to your terminal and run:
flutter run
Flutter will compile the app and launch it on the emulator. Your website should load inside the app within a few seconds. Check the following before moving on:
If you see any errors in the terminal, the onReceivedError callback we added in the code will also print the error description to the debug console, which makes it easier to track down what went wrong.
Testing on an emulator is good but testing on a real device is always better. Real devices give you a much more accurate feel of how the app actually performs.
For Android, connect your phone to your computer via USB. Make sure USB Debugging is enabled on your device — you can find this under Settings → Developer Options. If Developer Options is not visible, go to Settings → About Phone and tap Build Number seven times to unlock it.
Once your device is connected, run:
flutter devices
You should see your device listed. Then run:
flutter run
Flutter will detect your connected device and install the app on it directly.
For iOS, you will need a Mac with Xcode installed. Connect your iPhone, trust the connection when prompted, and make sure your device is registered in your Apple Developer account. Then run the same flutter run command and Flutter will build and install the app on your device.
Once you are happy with how everything looks and behaves on both platforms, it is time to build the final app files.
Once testing is done and everything looks good, it is time to generate the final build files that you will submit to the stores.
There are two file formats for Android — APK and AAB.
An APK is a standalone installable file. It is useful for sharing the app directly or testing on a device without going through the Play Store.
An AAB (Android App Bundle) is what Google Play requires for store submission. It is a more optimized format that lets Google Play generate smaller, device-specific APKs for each user.
To generate an APK, run:
flutter build apk --release --no-tree-shake-icons
Your APK file will be available at:
build/app/outputs/flutter-apk/app-release.apk
To generate an AAB for Play Store submission, run:
flutter build appbundle --release --no-tree-shake-icons
Your AAB file will be available at:
build/app/outputs/bundle/release/app-release.aab
We are using --no-tree-shake-icons in both commands. Flutter's tree shaking can sometimes strip out icons it considers unused during a release build, which leads to missing icons in the final app. This flag prevents that from happening with no downside.
Before building for release, you will need to sign your app with a keystore. Without a valid signature, Google Play will not accept your submission. To generate a keystore, run:
keytool -genkey -v -keystore ~/my-release-key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias my-key-alias
Then create a key.properties file in the android folder with the following:
storePassword=your-store-password
keyPassword=your-key-password
keyAlias=my-key-alias
storeFile=/path/to/my-release-key.jks
And update your android/app/build.gradle to reference it:
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
android {
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}
Now when you run flutter build appbundle --release --no-tree-shake-icons, the output will be properly signed and ready for Play Store submission.
Building for iOS requires a Mac with Xcode installed and an active Apple Developer account.
First, open the project in Xcode by running:
open ios/Runner.xcworkspace
Inside Xcode, go to Runner → Signing & Capabilities and select your development team from your Apple Developer account. Make sure the bundle identifier matches what you set when creating the project.
Then go back to your terminal and run:
flutter build ipa --release --no-tree-shake-icons
Your IPA file will be available at:
build/ios/ipa/my_web_app.ipa
You can then upload this file to App Store Connect using Xcode, Transporter, or the altool command line tool for review and submission.
You now have a signed, release-ready build file for Android and iOS. The next step is getting them live on the stores.
Submitting to the Google Play Store and the Apple App Store are two separate processes. Each has its own requirements — things like store listings, screenshots, privacy policy, app categories, and review guidelines. Both take a bit of time to get through the first time, but once you know the steps it becomes straightforward.
Rather than cramming both submission processes into the tail end of this guide, we have covered each one in its own dedicated article with full step-by-step instructions:
Follow whichever applies to your build, or both if you are publishing to both platforms.
Setting up Flutter, configuring Android Studio, dealing with signing certificates, and managing platform-specific settings is a real amount of work. For developers who just want their website live as a mobile app without going through all of that, there is a simpler path.
Appilix is a no-code platform that converts any website into a mobile app for both Android and iOS. You paste your website URL, configure your app name and icon, and Appilix handles the build process on the backend. No local development environment, no terminal, no Xcode, no Android Studio. You get a ready-to-submit app file at the end of it.
And it goes beyond just wrapping your URL. Appilix gives you access to native features that you can plug straight into your existing website without touching any native code:
If the Flutter route felt like too much overhead for what you need, Appilix is worth a look. You can get started at appilix.com.
Not really. The code in this guide is minimal and self-contained — you mostly just need to paste your website URL in one place and the rest stays as is. That said, having a basic understanding of how Flutter projects are structured will help if something goes wrong during setup or if you want to customize the app further down the line.
Yes. The flutter_inappwebview package handles cookies and sessions the same way a regular browser does. Users can log in through the app and their session will persist as long as the cookie is valid. We also enabled domStorageEnabled in the settings which makes sure localStorage works correctly inside the WebView.
Yes, and this is one of the biggest advantages of this approach. Since the app just loads a URL, any changes you make to your website show up in the app immediately. You do not need to rebuild or resubmit to the stores for content or design changes.
It depends on the content. Both stores have policies against apps that simply wrap a website with no real value added. As long as your app offers genuine, useful content or functionality and does not feel like a bare browser window, it will generally pass review. Make sure your app has a proper icon, a clear purpose, and a clean store listing. Apps that get rejected are usually ones that feel empty or offer nothing beyond what a browser already provides.
Yes. It does not matter how your website was built or what platform it runs on. As long as your website has a publicly accessible URL that loads correctly in a browser, it will load correctly inside the app. WordPress, Shopify, Webflow, custom-built — all of them work the same way here.
An APK is a standalone installable file that you can share directly or install on a device without going through the Play Store. An AAB is what Google Play requires for store submission — it is a more optimized format that allows the Play Store to generate smaller, device-specific downloads for each user. For testing and direct sharing, use APK. For Play Store submission, use AAB.
Yes. Building for iOS requires a Mac with Xcode installed. There is no official way around this — Apple's build tools only run on macOS. If you do not have a Mac, you can still build and publish the Android version of your app without one. For iOS, you will either need access to a Mac or look into cloud-based Mac services.
Appilix can help. Let's start!