What Nowa adds to your code
Everything you build in Nowa ends up as ordinary Flutter code in your project, and this page shows you where it lives. Look up a feature to see the files, classes, packages and platform settings Nowa added when you turned it on, and what goes away when you turn it off. You never need any of this to build your app with Nowa AI and the board: it's here for the moments you open the code yourself, in code mode or VS Code.
Project files
For a map of the whole project, see What's in your project. Code that Nowa owns carries the @NowaGenerated tag, explained in How code and design stay in sync.
lib/main.dart
A new project's main() looks like this:
@NowaGenerated()
main() async {
WidgetsFlutterBinding.ensureInitialized();
sharedPrefs = await SharedPreferences.getInstance();
runApp(const MyApp());
}
- Nowa writes this
main()itself. It rebuilds it from that template plus the start-up lines your integrations need, which it keeps in.nowa/settings.jsonundermainand places between thesharedPrefsline andrunApp. Lines you add to it by hand don't last. - A
main()you write yourself, without@NowaGenerated, stays exactly as you wrote it. Nowa adds start-up lines only to its ownmain(), so with yours, add them from the table below. sharedPrefsis a top-levelSharedPreferencesinstance that Nowa's code uses to save values on the device. See Actions and popups.MyAppbuilds aMaterialApp.routerinside aMultiProviderthat provides your global states. ItsthemeisAppState.of(context).theme, and itsrouterConfigisappRouterfromlib/globals/router.dart.- If a start-up line is missing from the list, Problems says
Setup statement in main.dart for "<key>" is required but not found., and Fix adds it back.
| Feature | Start-up line in main() |
|---|---|
| Firebase | await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); |
| Supabase | await SupabaseService().initialize(); |
| Push notifications | await NotificationService.instance.initialize(); |
| RevenueCat | await RevenuecatService().configureRevenuecat(); |
| AdMob | await MobileAds.instance.initialize(); |
| Stripe | Stripe.publishableKey = AppConstants.stripePublishableKey;, plus Stripe.merchantIdentifier = '<merchant ID>'; once you deploy with Apple Pay on |
| Remove # in URLs | usePathUrlStrategy(); |
Each line brings its own import, and they all run before runApp, so Firebase, Supabase and the rest are ready before your first screen opens.
You can't delete lib/main.dart. If it goes missing anyway, or loses its main(), Problems offers Fix, which opens Reset main file. Reset writes a fresh lib/main.dart and replaces everything in the old one. That file uses Flutter's Navigator (a MaterialApp with initialRoute and routes), expects a HomePage class in lib/pages/home_page.dart, and its MultiProvider lists only AppState. So afterwards:
- In a GoRouter project, make
MyAppreturnMaterialApp.router(routerConfig: appRouter, ...)again and importglobals/router.dart, yourself or with Nowa AI. Don't use Enable GoRouter in the Router panel for this: it replaceslib/globals/router.dartwith a single route for the home screen. - Attach your other global states again (Global state).
pubspec.yaml
| Entry | What Nowa puts there |
|---|---|
name | The Package Name. For a new local project Nowa builds it from the project name: lowercase, spaces become underscores, and a leading digit is spelled out, so 1project becomes one_project. An imported project keeps the name it has. |
version | Build version and Build number together, as in 1.3.4+7. Flutter passes them to iOS as CFBundleShortVersionString and CFBundleVersion, and to Android as versionName and versionCode. New projects start at 1.0.0+1. |
dependencies | Your packages. See Packages. |
flutter: → assets: and fonts: | Rebuilt from your assets/ folder. See Images and other assets and Fonts and icons. Nowa also keeps uses-material-design: true. |
Platform files Nowa rebuilds
Nowa generates these files from its own templates plus your settings, and writes each one whole when a setting that feeds it changes:
| File | Rebuilt when you change |
|---|---|
android/app/src/main/AndroidManifest.xml | The App Name, an Android permission (including one an integration turns on, such as Boot Completed for push notifications), the AdMob Android App ID, the Google Maps Android API Key or the Deep Links Host |
android/app/build.gradle.kts | The Bundle Identifier, the Firebase connection or push notifications |
android/settings.gradle.kts | The Firebase connection |
ios/Runner/Info.plist | The App Name, an iOS permission or its message (including one an integration turns on, such as Camera for a Stripe deploy), the AdMob iOS App ID, the Google Sign-In iOS Client ID, the Firebase Google or Phone sign-in provider, or the Deep Links URL Scheme |
ios/Podfile | An integration that needs a newer iOS version: platform :ios, '...' is set to the highest one |
ios/Runner/AppDelegate.swift | The Google Maps iOS API Key |
web/index.html | The Google Maps Web API Key. The App Name changes only its <title> line. |
Turning one of those integrations off rebuilds its files too. And when you open a project whose web/index.html still uses Flutter's older web loader (it doesn't load flutter_bootstrap.js), Nowa replaces that file with its own template.
A rebuilt file keeps only what Nowa's template and your settings put in it. Anything you added by hand, or that an imported project already had, is gone at the next rebuild. The one exception is permissions: the first time Nowa opens a project, it records the Android permissions in the manifest, and the iOS ones on its own list, and keeps writing those. Commit your project with Git before you change permissions, the App Name, the Bundle Identifier or an integration, so you can compare and put back what you need.
A few more changes happen outside those files:
- Bundle Identifier also sets every
PRODUCT_BUNDLE_IDENTIFIERline inios/Runner.xcodeproj/project.pbxprojto the new ID (test and extension targets included) and updatesmacos/Runner/Configs/AppInfo.xcconfigandlinux/CMakeLists.txt. On Android it deletes the deepest folder underandroid/app/src/main/kotlin/that the old and new IDs share, with every Kotlin file in it:com.example.apptocom.acme.appdeletes all ofkotlin/com/, and a change in the first part deletes all ofkotlin/. Then it writes a freshMainActivity.kt, aFlutterFragmentActivity. It doesn't touchInfo.plist. - App Name also updates the app name in the macOS, Linux and Windows runner files.
- Permissions are stored under
permissionsin.nowa/settings.json, and Nowa writes them into the manifest andInfo.plist. See Set permissions. - Integrations edit a few more files, such as
MainActivity.ktandios/Runner/Runner.entitlements. Their sections below list them. - Nowa AI can edit any project file,
pubspec.yamland platform files included, and create new ones. Its edits to the files in the table last only until Nowa rebuilds them. A connected external agent can't editInfo.plistorAndroidManifest.xmlat all: Nowa refuses the edit and points it to itsset_permissionstool.
The .nowa folder
| Path | What it holds |
|---|---|
.nowa/settings.json | The settings Nowa keeps for the project: the app name and bundle ID, permissions, the start-up lines for main(), experimental flags, the integration keys that go into platform files (under packages), and your Firebase and Stripe setup. |
.nowa/assistant_instructions.md | Your Nowa AI Custom Instructions, so they travel with the project. |
.nowa/temp/ | Nowa AI checkpoints. They're an undo button, not a backup: .nowa/.gitignore keeps this folder out of Git. |
.nowa/thumbnail.png | Your project's cover in the projects list: a screenshot of the board, taken when Nowa saves while a board is open, or the image you picked. .nowa/.gitignore keeps it out of Git too. |
.nowa/icon.<ext> | The last image you picked as your app icon, which Nowa makes the platform icons from. |
The Files tree in code mode doesn't list folders whose names start with a dot, so open .nowa in VS Code or your file manager.
Boards, the Library and Run
- Boards are
.boardfiles in theboardsfolder, subfolders included, named in lowercase with underscores: Login flow becomeslogin_flow.board. They're for Nowa only and aren't part of your app's code. - A loose widget, one you drop straight onto a board, is saved only in its board file. It isn't part of your app until you place it inside a screen.
- The Library's Project chip shows the folders of
lib/and what they declare. Rename renames the file too when it's named after the widget, Delete removes the file when the widget is the only thing in it, and dragging a row onto a folder moves the file. Files inlibstay inlib, and assets stay inassets. See Manage project files. - Locate folder, for a local project Nowa can't find, accepts only a folder that contains a
pubspec.yaml. - The Run preview builds your app as a web app, so it needs
lib/main.dartand aweb/folder. Nothing to run means Nowa found nolib/main.dartor no Dart package. Web support is missing offers Add web support, which generates the missing files (withflutter createin a local project). See Fix a preview that won't start.
Screens and routes
To add and set up screens, see Create and set up screens.
- Files. A screen is a widget class in its own Dart file. When you add one from a template, the naming dialog (titled after the template, such as New Empty Page) shows the Class name and the file Path: screens go in
lib/pages/and components inlib/components/. New projects start withHomePageinlib/pages/home_page.dart. - Screen or component. Nowa treats a widget class as a screen when its
buildreturns aScaffold, on its own or inside wrappers. Every other widget class is a component. - Rename updates every place that uses the screen. It also renames the file when the file is named after the screen, and always when you rename from Details.
- Add description writes a doc comment (
///) above the class. The Library's details card and the widget picker show it. - Copy as new widget creates a separate class in a new file.
- Remove takes the screen off the board. Its file stays in your project.
- Routes in GoRouter projects, which new projects are (one saved from the Simple app playground uses
Navigator): a screen you add from a single-file template gets a route inlib/globals/router.dart, its class name in lowercase with hyphens, soHomePagegets/home-page. Screens from multi-file templates, such as the Authentication Template, start without one. See Navigation. - Routes in older Navigator projects: Nowa keeps the
routesmap ofMaterialAppinlib/main.dart, with one entry per public screen inlib/whose constructor has no required parameters, keyed by its class name ('HomePage'). The home screen is theinitialRoute.
Components
To build and reuse components, see Build reusable components.
- Create component saves the component as a Dart file directly in
lib/, named after it:ProductCardgoes inlib/product_card.dart. Components you add from a template (New Widget...) go inlib/components/. - Adding the first variable turns the component into a
StatefulWidgetwith aStateclass that holds its variables. There's nothing to set up. - Copy as new widget, on an instance's right-click menu, creates a separate component in its own file.
- Rename updates every use and renames the file when it's named after the component. Delete removes the file when the component is the only thing in it.
- Flutter's
@Previewannotation adds variants that show under the component. See Preview a widget in several states.
Themes
To create and edit themes, see Create and edit themes.
- Where themes live. Each theme is a top-level
ThemeDatavariable inlib/globals/themes.dart, and the Themes panel writes your edits there. New projects havelightThemeanddarkTheme, built onColorScheme.light()andColorScheme.dark(). AThemeDatavariable that a function builds is listed too; variables of other types aren't. Open in New Tab opens your themes as code. - New themes you create in the panel are named
newThemeat first and useColorScheme.fromSeed(seedColor: Color(0xFF673AB7)). If you open a theme that sets no color scheme, Nowa adds the sameColorScheme.fromSeed(seedColor: Color(0xFF673AB7)), Material's deep purple. - The applied theme. In new projects
MaterialAppreadsAppState.of(context).theme, so Apply sets the starting value of_themeinAppState(lib/globals/app_state.dart), andAppState.changeTheme(theme)switches themes while the app runs. In a project without that setup, Apply setstheme:on theMaterialAppinlib/main.dart. - Default Font and the Default Theme tab appear for themes written as
ThemeData(...). A theme that a function orcopyWithbuilds shows only its extension tabs. - Theme extensions are classes that extend
ThemeExtension. A widget reads an extension color asAppColors.of(context).brand, or asTheme.of(context).extension<AppColors>()!.brandwhen the class has noof. A color that points to another color, such asAppColors.primary, shows as the color it reads. - Figma. With the Figma connector on, Nowa AI writes theme files under
lib/globals/, such asapp_colors.dartandapp_text.dart, and reloads your themes. - Create Theme Setup, for a project that has no
lib/globals/themes.dart, creates that file (withlightThemeanddarkTheme) andlib/globals/app_state.dart, and skips a file that already exists. Its dialog listslib/global/theme.dartandlib/global/app_state.dart, but the files it creates are the two above.
Fonts and icons
To pick fonts and icons, see Fonts and icons.
- Google Fonts download into your project when you pick one: Nowa saves the family's regular file as
assets/fonts/<Font Name>.ttfand registers it inpubspec.yaml. - Your own font files go in
assets/fonts/, registered and selected. Imported by you lists the font files inassets/, including Google Fonts you've already used. - Nowa AI downloads Google Fonts into
assets/fonts/<name>.ttftoo, instead of using thegoogle_fontspackage, so its text styles usefontFamily: '<name>'. - Declare fonts yourself, for example a family made of several files: list your families, weights and styles under
flutter:→fonts:inpubspec.yaml. Nowa keeps your declarations and drops only those whose files no longer exist. For each font file inassets/you haven't declared, it adds a family named after the file. The board shows each family under the name you declared, but the Fonts popup lists font files by file name. google_fonts. If your own code uses the package, such asGoogleFonts.poppins(), the board runs it. It's one of the built-in packages.- Icons you pick are Flutter's Material icons, written as
Icons.<name>, such asIcons.home_outlined.uses-material-design: trueinpubspec.yamlships the icon font with your app.
Images and other assets
To add and use files, see Images, videos and other files.
- Where files go. Imported files go in
assets/, or in the subfolder ofassets/you clicked last (for a file, the folder it's in). Upload assets..., on a folder's right-click menu, uploads straight into that folder. Dragging a row onto another folder insideassets/moves the file. - Upload Image, when you choose an asset for a widget, saves the file in
assets/and selects it. - A pasted image is saved as
assets/pasted_image_<id>, with its own file extension, and Nowa places an Image widget where your pointer is. - Images from AI. Images that Nowa AI saves from your chat attachments, and images a connected external agent adds with
add_image_assets, go inassets/images/. pubspec.yaml. Nowa writes theflutter:→assets:list for you, with one entry for each folder that isn't empty,assets/itself and the folders in it at any depth, such asassets/images/. It rebuilds the whole list whenever you import a file, pick a font or add, update or remove a package, so entries for files outsideassets/don't last. Fonts go underfonts:, as in Fonts and icons.
Translations
To make your app speak several languages, see Languages and right-to-left text.
- Nowa AI can't add the
flutter_localizationspackage. Its package tool refuses it and tells the agent to use a different approach. - If your
pubspec.yamlalready listsflutter_localizations: {sdk: flutter}, Nowa counts it as installed, so Problems no longer says it's missing from the pubspec. Like everysdk:package, the board doesn't load it, and Nowa AI still doesn't add it for you. - The board runs localization delegates written in your project: a
LocalizationsDelegatewhoseloadreturns your own translations class, which widgets read withLocalizations.of(context, YourClass). If a delegate fails to load, the board keeps drawing, and Logs saysCould not load <DelegateClass>: <error>.
Variables and functions
To work with logic, see Store data in variables, Create functions and Build logic in Circuit.
- Variables of a screen or component are fields of its
Stateclass, which Nowa adds with the first variable (see Components). - Circuit edits real Dart code. What you change in Circuit changes the function in its file, and code you save shows up in Circuit. An open Circuit panel rebuilds when the file is read again, and shows "Function was modified in code and could not find it" when the function is gone.
- await. Turning on await for a step, under Future Options, makes the enclosing function
asyncand wraps its return type inFuture. Turning the last one off undoes it. This happens in InitState Function too, which becomesFuture<void> initState() async, and Flutter rejects that in debug builds, the kind Run makes. Put the waiting steps in a separate function and call that frominitStatewithout await. See Run logic when a screen opens or closes. - What Circuit can draw. Circuit draws a function only when its body sticks to these statements: expression statements, local variables,
if/else,try/catch(onecatchclause shown),whileandreturn. It can't draw a function that uses others, such asfor,switch,breakorcontinue, so keep functions you want to edit visually within that list. - Values in text. The
$menu writes Dart string interpolation,${name}. When you type code yourself,$nameworks for a plain variable, and anything with a dot or a call needs braces:${textController.text},${getName()}.
Global state
To share data across your app, see Share data across your app.
- The class. A global state is a class that extends Flutter's
ChangeNotifier, with a factoryofconstructor, such asfactory AppState.of(BuildContext context, {bool listen = true}), which returnsProvider.of<AppState>(context, listen: listen). CallingnotifyListeners()tells every widget that reads it to rebuild. - Attaching adds
ChangeNotifierProvider<YourState>(create: (context) => YourState())to theMultiProviderinMyApp, inlib/main.dart, so every screen can read it. Detaching removes it. - Where the file goes. New Global State... in the Library creates it in
lib/globals/and attaches it. Create global state, in the Variables panel with nothing selected, under Globals, creates it directly inlib/. Pick global state attaches one that already exists inlib. - AppState. New projects include
AppStateinlib/globals/app_state.dart: a privateThemeData _themethat starts aslightTheme, athemegetter, andchangeTheme(ThemeData theme), which callsnotifyListeners(). - How Nowa reads it. Inside a
buildmethod, Nowa writesAppState.of(context), which listens, so the widget rebuilds when the state changes. In functions and events it writesAppState.of(context, listen: false), which reads the state without listening.
Data models
To create models, see Data models.
- Files. New Model... creates the model in
lib/models/. Nowa fills in the class and file names from what you type: "task model" becomes the classTaskModelintask_model.dart. - Generated members. Each model has a constructor,
factory TaskModel.fromJson({required Map<String, dynamic> json})andMap<String, dynamic> toJson(), so you writeTaskModel.fromJson(json: data). Nowa rewrites all three each time you change the fields, and View Code shows the result. Models from Supabase templates take the map as a plain argument instead:TodosModel.fromJson(data). - JSON keys. By default each field reads and writes the JSON key with its own name. A field whose type is another model, or a list of models, goes through that model's
fromJsonandtoJson. ADateTimefield is read withDateTime.tryParseand written withtoIso8601String(), so it expects dates as text. - Generate Models From Json puts every class it creates in one file named after the main class, in
lib/models/by default, soRootbecomeslib/models/root.dart. The folder must be insidelib. Generate Model for a REST API request uses the same dialog. - Edit in code. Open a model's file (in the Library, right-click it and choose Show in code, or click View Code in the model editor) and add or change fields. Nowa reads them back into the model editor.
- Models from integrations. Supabase templates save a model per table as
<Table>Modelinlib/models/, such asTodosModelinlib/models/todos_model.dart, and Use Existing Model lists the models in your project'smodelsfolders. Firestore collections are models too, inlib/firebase/collections.dart: see Firebase.
Navigation
To move between screens, see Navigate between screens and Set up routes in the Router panel.
- The router. New projects use the
go_routerpackage. The router is a top-levelGoRoutervariable inlib/globals/router.dart, namedappRouterin new projects (Nowa uses the firstGoRoutervariable in that file, whatever its name).MyApppasses it toMaterialApp.router(routerConfig: appRouter). - Routes. Each route is a
GoRoute, such asGoRoute(path: '/home-page', builder: (context, state) => const HomePage()), and sub-routes go in itsrouteslist. A path parameter, such as:idin/product/:id, is read in the builder withstate.pathParameters['id']and passed to the screen's constructor. A query parameter is read withstate.uri.queryParameters['q']. - Router Configuration. Initial Location is the router's
initialLocation, the path your app opens first. Redirect Logic, on the router or on one route, adds aredirectfunction that takescontextandstateand starts by returningnull, which lets everyone through. Remove # in URLs addsusePathUrlStrategy();tomain()and theflutter_web_pluginsSDK package. - Navigation steps. The GoRouter step writes
GoRouter.of(context).push('/path'), and its Type is the method, such aspush,goorpop. The Navigator step writesNavigator.of(context).push(MaterialPageRoute(builder: ...)). - Older projects, and one saved from the Simple app playground, use Flutter's
Navigator, with theroutesmap inMaterialAppdescribed under Screens and routes. To move one to GoRouter, see Switch an older project to GoRouter.
Actions and popups
To add these steps, see Use ready-made actions and Show dialogs, sheets, snackbars and pickers.
| Step | What it writes or does in code |
|---|---|
| GLOBALS → Show snackbar | ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Hello World'))). Store result keeps the ScaffoldFeatureController<SnackBar, SnackBarClosedReason> it returns, whose closed future completes when the bar goes away. |
| GLOBALS → checkPlatform | NPlatform.isWeb, from nowa_runtime. NPlatform also has isMacOs, isWindows, isLinux, isAndroid, isIOS, isDesktop and currentPlatform. |
| GLOBALS → Media Query | MediaQuery.of(context). |
| SHARED PREFERENCES steps | Calls on the sharedPrefs that main() creates. set writes setString(key, value), or setInt, setDouble, setBool or setStringList to match the Type. get writes the matching getter, such as getString(key). remove key writes remove(key), and clear writes clear(). |
openUrl | Calls launchUrl(Uri.parse(url)) from the url_launcher package. |
showMediaPicker | Returns a Future<List<XFile>>. XFile comes from the image_picker package and has the file's path, name and readAsBytes(). When nothing is picked, the list is empty. |
print | Dart's print(). In the editor, Nowa sends its messages to Logs. When you run the app from VS Code or another IDE, they show in its debug console. |
In code you can combine platform checks, as in NPlatform.isAndroid || NPlatform.isIOS.
The categories in Circuit's + menu hold more than the pages show:
- MATERIAL also has
showMenu,showSearch(it needs aSearchDelegate, which you write in code) andshowAboutDialog. - DART:ASYNC has
Timer,unawaitedandscheduleMicrotask. - PACKAGE: followed by your package name, such as
PACKAGE:MY_APP, lists your own functions, classes with public static members, such asAppConstants, and singletons, classes with one shared instance (a static_instanceand a factory constructor), such asSupabaseServiceand your API collections. - A package you add brings its own category, listing its functions and the same kinds of classes. To make an object from any other class, use Create....
REST APIs
To connect an API, see Connect a REST API.
- Files. Each collection is a Dart file in
lib/api/, named after it: a collection named Cats islib/api/cats.api.dart. Renaming the collection (Name) renames the file, and Nowa finds collections by that.api.dartending. - The class. A collection is a singleton class named after it. It holds a
Dioclient, from thediopackage, whoseBaseOptionscarry the Base URL and the collection's headers. Each request is a method that returns aFutureof Dio'sResponse, or of your model once the request returns one. Headers you add to a single request are written into its method. Everything you type there ships inside your app, a token in a header value included. - Auth Key adds an interceptor to the collection's constructor. Before each request it sets the
Authorizationheader to'Bearer ${sharedPrefs.getString('<Auth Key>')}', the token your app saved on the device under that name. - File uploads. If a body has a file field (MultipartFile), Upload File picks a file to test with. For the test only, Nowa puts its bytes into the request's
Uint8ListorList<int>parameters. - Models from Generate Model go in
lib/modelsby default. See Data models. - Import. A Postman file needs both an
infoand anitemsection, or Nowa shows an error that starts withInvalid Postman collection format. See Import an API.
Keys and constants
To manage your keys, see Keys and constants.
-
AppConstants. Constants live in theAppConstantsclass inlib/globals/app_constants.dart. Each one is aString, read asAppConstants.<name>, such asAppConstants.supabaseUrl. The file is part of your app's code, so the values ship inside your app. -
From integrations. These integrations add constants. RevenueCat, Stripe and Google Sign-In add theirs empty when you turn them on, and Supabase fills in its two when you connect:
Integration Constants Supabase supabaseUrl,supabaseAnonKeyRevenueCat revenueCatAppleApiKey,revenueCatAndroidApiKey,revenueCatWebApiKeyStripe stripePublishableKey,stripeMerchantName,stripeMerchantCountryCodeGoogle Sign-In, and the Firebase Google provider, which installs the same package webClientId -
When you turn an integration off, its constants stay, listed under Custom Constants. Turning RevenueCat, Stripe or Google Sign-In on again sets theirs back to empty, so note your keys before you switch one off and on.
-
Platform keys aren't constants. Keys that only platform files need (the Google Maps API keys, the AdMob App IDs, the Deep Links URL Scheme and Host, and the Google Sign-In iOS Client ID) are stored under
packagesin.nowa/settings.json, and Nowa writes them into your Android, iOS or web files. They live on their own pages under Settings → Integrations. -
In Circuit,
AppConstantsis in the PACKAGE: category of the + menu. See Use a constant.
Supabase
To set it up, see Connect Supabase.
What connecting adds
| What | Where | What it's for |
|---|---|---|
supabase_flutter | pubspec.yaml | Supabase's Flutter package. |
SupabaseService | lib/integrations/supabase_service.dart | A singleton class (SupabaseService() always returns the same instance) with initialize(), signIn(email, password), signUp(email, password) and signOut(). Every function you add later, from a template, from Nowa AI or through the Supabase connector, goes into this class. |
| Start-up line | main() in lib/main.dart | await SupabaseService().initialize();, which calls Supabase.initialize(url: AppConstants.supabaseUrl, anonKey: AppConstants.supabaseAnonKey). |
supabaseUrl, supabaseAnonKey | AppConstants | Your project URL and anon key. |
Functions in SupabaseService
-
signIncallsSupabase.instance.client.auth.signInWithPassword(...)andsignUpcallsauth.signUp(...), both returning aFuture<AuthResponse>.signOutcallsauth.signOut(). -
There's no ready-made "is someone signed in" function. Check
Supabase.instance.client.auth.currentSession != null, as the redirect example does, or ask Nowa AI to add a function toSupabaseServicethat tells you. -
A generated function is ordinary Dart code. Change it with Edit Code in its test panel (Change a function's code) or in code mode.
-
The Supabase panel sorts the functions of
SupabaseServiceby what their code contains:.from(without.rpc,.storage,.realtimeor.functions) goes under Queries,.auth.s, as in.auth.signIn...,.auth.signUpand.auth.signOut, under Authentication,.storageunder Storage,.rpcunder RPC and.functionsunder Other Functions. Functions you write yourself are sorted the same way, and one that matches none of these, such as a function that only calls.auth.resetPasswordForEmail(...), doesn't show in the panel. -
A live query returns a
Stream, and no template creates one. Here's a minimal one (Live queries covers turning on Realtime for the table):Stream<List<Map<String, dynamic>>> streamTodos() {return Supabase.instance.client.from('todos').stream(primaryKey: ['id']);} -
When Nowa AI builds something with the Supabase connector, it also writes the matching functions into
SupabaseService, so your screens can use what it built. Models from templates go inlib/models/: see Data models.
Your backend in the supabase/ folder
Pull Backend Files, in the panel's ⋮ menu, copies your backend into the project, so you can commit it:
| Path | What it holds |
|---|---|
supabase/migrations/ | One .sql file for each migration in your Supabase project's history. |
supabase/functions/<function name>/index.ts | The code of each deployed edge function. |
supabase/nowa_setup.json | The list of your storage buckets, plus a setup note. Set up Backend shows that note. |
- It replaces what's already in
supabase/migrations,supabase/functionsandsupabase/nowa_setup.json. Other files insupabase/, such as a Supabase CLIconfig.toml, stay. The folder follows the Supabase CLI's layout, so the files work with the CLI too. - It needs recorded migrations. Without them, Nowa says the project "has no migration history, so its schema cannot be captured". Your table data, the files in your buckets, your auth provider settings and your secrets aren't copied.
Disconnect Supabase
Nowa deletes lib/integrations/supabase_service.dart, removes supabase_flutter and takes the start-up line out of main(). Every function in SupabaseService goes with it, including ones you edited or wrote, so screens and events that call them stop working. Your Supabase project, your models in lib/models/, the supabaseUrl and supabaseAnonKey constants and the supabase/ folder stay. Connecting again creates a fresh SupabaseService. See Disconnect Supabase.
Firebase
To set it up, see Connect Firebase.
What connecting adds
| File or change | What it's for |
|---|---|
android/app/google-services.json, ios/Runner/GoogleService-Info.plist | The Firebase config files for your Android and iOS apps, downloaded from Firebase. |
lib/firebase_options.dart | DefaultFirebaseOptions.currentPlatform, with the connection options for the web, Android and iOS. macOS apps use the iOS options, and other platforms get null. |
lib/firebase/firebase.dart | FirebaseService, a singleton that holds your sign-in functions and a firestore getter for FirebaseFirestore.instance. |
lib/firebase/collections.dart, lib/firebase/queries.dart | Your Cloud Firestore collections, and the FirestoreService class that holds your queries. Both start empty. |
Start-up line in main() | await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); |
pubspec.yaml | firebase_core and cloud_firestore, even if you only use sign-in. |
android/app/build.gradle.kts, android/settings.gradle.kts | The com.google.gms.google-services Gradle plugin (version 4.3.15 in settings.gradle.kts). |
ios/Podfile | platform :ios, '15.0' at least, which cloud_firestore needs. |
.nowa/settings.json | Your Firebase project and app IDs, under firebase. |
- Nowa AI can't connect Firebase for you. Its package tool refuses
firebase_coreand points to Settings → Integrations → Firebase, so the configuration is set up correctly. - Refresh/Update apps and config files, next to Project ID, downloads the config files again and rebuilds
lib/firebase_options.dart. - In Nowa 3.13, if you reload the page or close Nowa soon after Connect Apps, the connection can be lost before it's saved. The Firebase files are then gone,
lib/main.dartstill points at the missingfirebase_options.dart, so the project doesn't compile, and the Firebase page asks for your project again. See Known issues.
Authentication
Nowa puts the sign-in functions in FirebaseService, in lib/firebase/firebase.dart:
| Switch | Functions it adds | Package |
|---|---|---|
| Authentication | signOut(), isUserSignedIn(), currentUser, sendVerificationEmail() | firebase_auth |
| Email/Password | signUpWithEmailAndPassword(email, password), signInWithEmailAndPassword(email, password), sendPasswordResetEmail(email) | |
signInWithGoogle(), which opens a popup on the web (signInWithPopup) and uses the google_sign_in package everywhere else | google_sign_in | |
| Phone | verifyPhoneNumber(phoneNumber), signInWithPhoneNumber(verificationId, smsCode) |
- iOS URL schemes. Google adds a
CFBundleURLTypesentry toInfo.plistwith your reversed client ID. Phone needs its own scheme,app-plus your iOS app ID with dashes, but it's only added while Google is on too: both come from thegoogle_sign_inpackage's settings, and Phone doesn't add that package. A scheme you add by hand is lost when Nowa next rebuildsInfo.plist. See Functions Nowa adds. - Google and
google_sign_in7.x. In Nowa 3.13,signInWithGoogle()is written for an older version ofgoogle_sign_in(it callsGoogleSignIn().signIn()) than the 7.x version Nowa installs. If your build reports errors aboutGoogleSignIninlib/firebase/firebase.dart, this is the cause. Turning Google off removes the function and the package. - Turning Authentication off removes every function in the table except
sendPasswordResetEmail(), which stays inFirebaseService. Nowa also switches the providers off and removesfirebase_auth, andgoogle_sign_inif Google was on. The leftover function still callsFirebaseAuth.instance, so it breaks your build: delete it in code mode. Turning only Email/Password off leaves it behind too, which is harmless while Authentication stays on.
Cloud Firestore
- Collections. Every class in
lib/firebase/collections.dartis a collection: a model withfromJsonandtoJsonthat your queries use. A main collection carries@NowaGenerated({'fbCollectionType': 'fbMainCollection'}), and a sub collectionfbSubCollectionplusfbParent. Select Collection in the query builder lists main collections only, so a class you or Nowa AI write without that metadata doesn't show there. - Field types. A collection's
fromJsonandtoJsonuse each field's name as the document key, and aDateTimefield is read withDateTime.tryParseand written withtoIso8601String(). It expects dates as text, not FirestoreTimestampvalues. - Queries. Each query is a method of
FirestoreService, a singleton inlib/firebase/queries.dart. Select Firestore Query and Circuit's FIREBASE category list every method of that class except constructors, after Refresh/Update apps and config files. - Adding them in Nowa 3.13. The designer has no button for adding collections or queries, so edit the two files in code mode, then click Refresh/Update apps and config files so Nowa's lists match your code. To add, set or delete documents, write the function in
lib/firebase/queries.dartyourself, withoutwithConverter: the builder'saddanddocsteps don't work in 3.13. See Add collections and queries in Nowa 3.13.
Push notifications
| What | Where |
|---|---|
firebase_messaging, flutter_local_notifications | pubspec.yaml |
NotificationService | lib/firebase/notification_service.dart |
| Start-up line | await NotificationService.instance.initialize(); in main() |
| Android | Core library desugaring in android/app/build.gradle.kts (isCoreLibraryDesugaringEnabled = true and coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.4")), and the Boot Completed permission, which flutter_local_notifications needs. The permission stays when you turn notifications off. |
| iOS | The fetch and remote-notification background modes (UIBackgroundModes) for Info.plist. Turning notifications on doesn't rebuild that file by itself, so they're written at its next rebuild, for example when you change an iOS permission. Check ios/Runner/Info.plist before an iOS build. |
initialize()asks for permission to show notifications, shows messages that arrive while the app is open as local notifications (Android channelhigh_importance_channel), keeps the device's token infcmTokenand subscribes to the topicall, which Nowa's test notifications go to.- When someone taps a notification that arrived while your app was open,
onNotificationTapgets the message data as JSON, so set it to react. A tap that opens the app from the background, or starts it, calls_handleBackgroundMessage, which Nowa leaves empty for your code. - Nowa writes no
aps-environmententitlement. Add the Push Notifications capability in Xcode, under Signing & Capabilities. In the macOS desktop app, the Open Xcode Workspace link under the switch opensios/Runner.xcworkspacefrom the project's folder, so it works for local projects. See Set up notifications for iPhone. - Turning off Push Notifications (FCM) removes
lib/firebase/notification_service.dart, the two packages and the start-up line. The background modes leaveInfo.plistonly at its next rebuild.
Disconnect Firebase
Nowa removes FirebaseService, the config files, lib/firebase_options.dart, the sign-in functions and notification code, the Firebase packages and the start-up line, and rebuilds the Gradle files. Keep Files keeps collections.dart and queries.dart so you can reuse them with another project. Your queries show errors until you connect again.
In Nowa 3.13, disconnecting leaves the google_sign_in package in place if the Google provider was on. If you don't need it, turn Enabled off on the Google Sign-In page.
Stripe
To set it up, see Accept payments with Stripe.
Turn on Stripe
- Enabled adds the
flutter_stripepackage, the start-up lineStripe.publishableKey = AppConstants.stripePublishableKey;and the constantsstripePublishableKey,stripeMerchantNameandstripeMerchantCountryCode. After a Deploy Configuration with Apple Pay on and a merchant ID,main()also setsStripe.merchantIdentifier. - Your other choices (purchase types, table and column mapping, currency and wallets) are stored under
stripe_integrationin.nowa/settings.json. - Secret Key and Webhook Secret don't go into your app. Nowa stores them in your Supabase project as the edge function secrets
STRIPE_SECRET_KEYandSTRIPE_WEBHOOK_SECRET. - Every key is saved exactly as typed, without trimming spaces.
Deploy Configuration
Deploy Configuration creates these in your Supabase project, for the purchase types you chose:
| Purchase type | Table | Edge functions |
|---|---|---|
| One-Time | nowa_stripe_one_time_payments | stripe-one-time-payment-intent |
| Consumable | nowa_stripe_consumable_payments | stripe-consumable-payment-intent |
| Subscription | nowa_stripe_subscriptions | stripe-create-subscription, stripe-cancel-subscription |
| Every deploy | stripe-webhook |
In your project, it generates StripePaymentService in lib/integrations/stripe_payment_service.dart, a class of static methods that call those functions through your Supabase client:
| Purchase type | Methods |
|---|---|
| One-Time | processPayment(recordId: ...), which opens Stripe's payment sheet, plus getPaymentStatus(recordId) and getPaymentDetails(recordId). With Consumable on too, the names include OneTime, as in processOneTimePayment. |
| Consumable | The same three, with Consumable in the names when One-Time is on too. |
| Subscription | subscribe(priceId: ...), getSubscriptionStatus(), getSubscriptionDetails() and cancelSubscription(). |
- Each deploy regenerates the class. It rewrites every method, including the private
_initPaymentSheetand_presentPaymentSheet, and deletes any other member, so a hand edit or a Nowa AI edit, or a helper method you added, is lost on the next deploy. - Google Pay is set up in
_initPaymentSheetasPaymentSheetGooglePay(merchantCountryCode: AppConstants.stripeMerchantCountryCode, testEnv: true), Google's test environment. When Google approves your app, change it totestEnv: falseafter your last deploy, because each deploy putstrueback. - The functions pin
apiVersion: '2025-12-15.clover'and loadstripe@17.5.0from esm.sh.stripe-webhookchecks each event withstripe.webhooks.constructEventAsyncand readsevent.data.object, so your Stripe event destination must send snapshot events, not thin ones. - Amounts are sent as
Math.round(amount * 100)for every currency. Stripe expects zero-decimal currencies, such as JPY, without that multiplication, so those would be charged 100 times the price (Stripe: zero-decimal currencies). A Fixed Currency is lowercased for you; a Currency Column value is sent as stored, and Stripe wants lowercase codes. - Subscription periods.
stripe-create-subscriptionandstripe-webhookread the subscription'scurrent_period_startandcurrent_period_end, andstripe-webhookalso readsinvoice.subscription. Stripe removed these fields in API version2025-03-31.basil(subscription periods, invoices). The functions call Stripe with the pinned2025-12-15.clover, so the subscriptions they create or fetch never have the period fields, and webhook events have them only when your event destination uses an older API version than basil (Stripe: event destinations). So the period columns can stay empty, and on basil or later theinvoice.*branches find no subscription. The status still follows thecustomer.subscription.*events.
Platform changes, written at the end of each successful deploy:
| Platform | Change |
|---|---|
| Android | Rewrites MainActivity.kt as a FlutterFragmentActivity, writes android/app/proguard-rules.pro with Stripe's rules (replacing an existing file), and sets NormalTheme in res/values/styles.xml and res/values-night/styles.xml to Theme.MaterialComponents. |
| iOS | Turns on the Camera permission. With Apple Pay on and a merchant ID, writes ios/Runner/Runner.entitlements whole with com.apple.developer.in-app-payments, which replaces any other entitlement in that file, such as aps-environment for push. |
Remove Stripe
Turning Enabled off deletes the Stripe settings, the start-up lines and lib/integrations/stripe_payment_service.dart. The Camera permission, your constants and everything in Supabase stay.
It also undoes the platform changes, but in Nowa 3.13 only if a Deploy Configuration finished since you last opened the project. Otherwise they stay, and you undo them yourself (or ask Nowa AI to):
- Delete
android/app/proguard-rules.pro. - Set
NormalThemeback to@android:style/Theme.Light.NoTitleBarin bothstyles.xmlfiles. - Switch
MainActivityfromFlutterFragmentActivitytoFlutterActivity. If you also use RevenueCat, leave it aFlutterFragmentActivity, which Nowa set up for RevenueCat. (When Nowa undoes it, it doesn't check, so look atMainActivity.ktafterwards.) - Remove the
com.apple.developer.in-app-paymentskey fromios/Runner/Runner.entitlements, and the file if nothing else is left in it.
RevenueCat
To set it up, see In-app purchases with RevenueCat.
| What | Where |
|---|---|
purchases_flutter | pubspec.yaml. The RevenueCat Paywall widget also needs purchases_ui_flutter, which Add Missing Dependencies adds when you click Add. |
RevenuecatService | lib/integrations/revenuecat_service.dart, a singleton class. |
| Start-up line | await RevenuecatService().configureRevenuecat(); in main(). |
| Your keys | revenueCatAppleApiKey, revenueCatAndroidApiKey and revenueCatWebApiKey in AppConstants. They're public keys, so shipping them inside your app is expected. |
| iOS | platform :ios, '14.0' at least in ios/Podfile. |
| Android | MainActivity.kt rewritten as a FlutterFragmentActivity, which new Nowa projects already use. |
| Method | What it does |
|---|---|
configureRevenuecat() | Picks the key for the platform (Apple, Android or web) and calls Purchases.configure(PurchasesConfiguration(apiKey)). |
fetchOfferings() | Returns your offerings as a Future<Offerings?>, or null if the request fails. |
purchasePackage(PurchaseParams purchase) | Buys a package through Purchases.purchase. |
- These work with RevenueCat's own types, so for purchase flows beyond the paywall, ask Nowa AI or write the code yourself (Write your own code).
- Nowa doesn't add Apple's In-App Purchase capability to your iOS project. See Before you publish.
- Turning Enabled off removes the package,
lib/integrations/revenuecat_service.dartand the start-up line. Your keys stay in Constants, andMainActivitystays aFlutterFragmentActivity. Remove any logic that callsRevenuecatService, and any RevenueCat Paywall widgets, first.
AdMob
To set it up, see Show ads with AdMob.
| What | Where |
|---|---|
nowa_mobile_ads | pubspec.yaml. Nowa's package around google_mobile_ads, which it also exports, with NowaAdBannerWidget (the Admob Banner) and loadAndShowInterstitialAd(). |
| Start-up line | await MobileAds.instance.initialize(); in main(). |
| Android App ID | AndroidManifest.xml, as <meta-data android:name="com.google.android.gms.ads.APPLICATION_ID" .../>. |
| iOS App ID | Info.plist, as GADApplicationIdentifier, together with Google's SKAdNetworkItems list. |
- Both App IDs are stored under
packagesin.nowa/settings.jsonand must start withca-app-pub-. - The banner takes
androidUnitID,iosUnitIDandshowTestAds, andloadAndShowInterstitialAd()takes the same three. WhileshowTestAdsistrue, the default (Show Test Ads), both use Google's sample ad units instead of yours. - Turning Enabled off removes the package, your App IDs with their manifest and
Info.plistentries, and the start-up line. Remove your banners andloadAndShowInterstitialAdcalls first.
Google Maps
To set it up, see Add Google Maps.
Turning on Enabled adds the google_maps_flutter package and sets platform :ios, '14.0' at least in ios/Podfile. Nowa puts each key where its platform needs it:
| Key | Where Nowa writes it |
|---|---|
| Android API Key | AndroidManifest.xml, as <meta-data android:name="com.google.android.geo.API_KEY" .../>. |
| iOS API Key | ios/Runner/AppDelegate.swift, as GMSServices.provideAPIKey("...") at app launch, with import GoogleMaps. |
| Web API Key | A Google Maps <script> tag in the head of web/index.html. |
- The keys are stored under
packagesin.nowa/settings.json. - Turning Enabled off removes the package, your keys and their platform entries.
Google sign-in
To set it up, see Google Sign-In.
Turning on Enabled adds the google_sign_in package. Nowa doesn't generate sign-in code for this setup: your code, or the flow Nowa AI builds, does the signing in.
| Field | Used for | What Nowa does with it |
|---|---|---|
| iOS Client ID | Required for Google sign-in without Firebase. | Writes it to Info.plist as GIDClientID and adds the reversed ID as an iOS URL scheme (a CFBundleURLTypes entry). It's stored under packages in .nowa/settings.json. |
| Web Client ID | Also used as the server client ID on Android. | Saves it as the constant AppConstants.webClientId. It isn't written to any platform file, and Nowa doesn't pass it to Google for you: your sign-in code reads it. |
- When Firebase manages Google sign-in, Nowa builds the same URL scheme from Firebase's client ID.
- If you also set a Deep Links URL Scheme, check
Info.plist, as Deep links explains: both write aCFBundleURLTypesentry. - Turning Enabled off removes the package and the iOS entries Nowa added. The Web Client ID stays in Constants, under Custom Constants as
webClientId.
Deep links
To set them up, see Deep links.
Turning on Enabled adds the app_links package. From then on, each time Nowa rebuilds Info.plist or the Android manifest, it switches off Flutter's built-in deep link handling there: FlutterDeepLinkingEnabled is false in Info.plist, and the manifest's activity gets flutter_deeplinking_enabled set to false. Turning on Enabled doesn't rebuild either file by itself; saving the fields below does. Your settings take effect in a built app.
| Field | Opens your app from | Where Nowa writes it |
|---|---|---|
| URL Scheme | Links like myapp://... | Info.plist, as a CFBundleURLTypes entry, as soon as you save it. The Android manifest, as an intent filter for the scheme with the host open.my.app, only at the manifest's next rebuild (see below). |
| Host | Links like https://example.com/... | The Android manifest only, as an App Links intent filter with android:autoVerify="true". A path after the domain, as in example.com/app, becomes android:pathPrefix="/app". |
- Check the Android manifest. Saving URL Scheme rebuilds only
Info.plist. To get your scheme into the manifest, save Host, which rebuilds it; without a host, save any Host and clear it again. Before you test on Android, openandroid/app/src/main/AndroidManifest.xmland look for your scheme. - No iOS Universal Links. Nowa doesn't add the associated-domains entitlement, so web links open your app on Android only until you set up Universal Links yourself (Apple's guide). On Android,
autoVerifymakes the system check that you own the domain, so your site must serve the verification file (Android's guide). - Two URL types. Google sign-in, standalone or through Firebase, also writes a
CFBundleURLTypesentry once its client ID is saved. With both,Info.plistholds two separateCFBundleURLTypeskeys, and since a property list should hold that key once, one of them may not take effect on iOS. Merging them by hand, or with Nowa AI, doesn't last: Nowa rebuilds the whole file whenever one of its settings changes (see Platform files Nowa rebuilds). See Use deep links with Google Sign-In. - Reading the link is up to your code. Nowa registers the links and adds
app_links, but it doesn't generate code that reads an incoming link. Your app's logic has to read it and open the right screen. - Turning Enabled off removes the package and the entries Nowa added to the Android and iOS files.
Publishing
To publish your app, see Get ready to publish.
Code checks
Publishing to the web starts with a code check, flutter analyze, and stops when it finds errors: the deployment fails with Analysis Failed, and the findings go to Logs. You can run the same check any time: in Problems, switch to From Code Analysis and click Run Code Check. See Find and fix problems.
Cloud builds and codemagic.yaml
Cloud builds run the workflows in your project's codemagic.yaml:
| Workflow | What it does |
|---|---|
android-debug-workflow | flutter build apk --debug. The artifact is build/**/outputs/flutter-apk/*.apk. |
android-workflow | Release flutter build appbundle and flutter build apk, signed with the keystore from the android_key_info variable group: CM_KEYSTORE (the keystore, base64-encoded), CM_KEYSTORE_PASSWORD, CM_KEY_ALIAS and CM_KEY_PASSWORD. |
web-workflow | flutter build web --release, zipped into build/web.zip. |
ios-workflow | Signs with the ios_credentials variable group, runs flutter build ipa --release and uploads the build to App Store Connect (publishing: app_store_connect). |
- If the file breaks, the error bar in code mode offers Reset to default, which writes the default content back. See What runs behind the scenes.
- Android signing in
android/app/build.gradle.kts. Release builds use thereleasesigning config. On Codemagic, whereCIis set, it reads the keystore decoded to$CM_BUILD_DIR/codemagic.keystoreand theCM_*passwords. Anywhere else it readsandroid/key.properties(storeFile,storePassword,keyAlias,keyPassword), so create that file to build a signed release on your own computer. - iOS signing. The
ios_credentialsgroup holdsAPP_STORE_CONNECT_PRIVATE_KEY,APP_STORE_CONNECT_KEY_IDENTIFIER,APP_STORE_CONNECT_ISSUER_ID,CERTIFICATE_PRIVATE_KEY(your distribution certificate's private key) andBUNDLE_ID(the Bundle Identifier saved with your App Store Connect credentials). The signing step runskeychain initialize,app-store-connect fetch-signing-files "$BUNDLE_ID" --type IOS_APP_STORE --create,keychain add-certificatesandxcode-project use-profiles. - What
--createdoes. It registers your bundle ID if it's missing, and when no Apple Distribution certificate matchesCERTIFICATE_PRIVATE_KEY, it creates one from that key. That new certificate counts toward Apple's limit, as Add a distribution certificate explains.
Use a key from a Mac certificate
Certificate Private Key must be your certificate's private key as PEM text, a text file that starts with -----BEGIN. Nowa reads the file you pick as text, so a binary .p12 exported from Keychain Access fails, even though the picker only lists .p12 files. The key file Nowa gives you with Download Certificate is already in the right format. To reuse a certificate made on a Mac, follow Codemagic's steps for the same key:
-
On the Mac that created the certificate, open Keychain Access, right-click your iOS distribution certificate and choose Export.
-
Choose the Personal Information Exchange (.p12) format, save the file, for example as
IOS_DISTRIBUTION.p12, and leave the password empty. -
In Terminal, in the folder where you saved it, run the command below. When it asks for the import password, press Enter. The key is written to a text file named
ios_distribution_private_key.openssl pkcs12 -in IOS_DISTRIBUTION.p12 -nodes -nocerts | openssl rsa -out ios_distribution_private_keyIf your
opensslis OpenSSL 3 and the first command fails with anunsupportedalgorithm error, add-legacyafterpkcs12: OpenSSL 3 loads the older algorithms some.p12files use only in its legacy mode (OpenSSL: pkcs12). -
Rename that file so it ends in
.p12, such asios_distribution_private_key.p12, so Nowa's file picker shows it. -
In the Distribution Certificate card, click Browse next to Certificate Private Key, pick the file and click Save. See Use a key you already have.
Before you upload to the App Store
- Export compliance. Nowa's
Info.plisttemplate doesn't setITSAppUsesNonExemptEncryption, so App Store Connect asks the encryption questions for each build (Apple: export compliance). You can add the key yourself, but Nowa rebuildsInfo.plistwhole when one of its settings changes (Platform files Nowa rebuilds), so check that it's still there before each upload. - App icon transparency. Nowa generates the iOS icons without removing transparency (
remove_alpha_iosisn't set), and the icon generator it uses warns that "Icons with alpha channel are not allowed in the Apple App Store". Use an icon image without transparency for iOS. - Version numbers. Build version and Build number come from
version:inpubspec.yaml. See Project files.
Packages
To add, update or remove packages yourself, see Add packages.
New projects start with nowa_runtime, provider, shared_preferences, dio and go_router, plus flutter_lints as a dev dependency. When you turn on an integration with its Enabled switch, Nowa adds the newest version of its package from pub.dev. Connecting Supabase or Firebase, and the packages Nowa adds for a widget, use versions fixed in your Nowa release, and so does Nowa AI when it adds a package that Nowa has its own setup for.
That setup runs however the package arrives, from an integration, the Packages page or Nowa AI: it adds the package's start-up line, files, constants and permissions. Adding geolocator, for example, asks first in Add Missing Dependencies, then turns on the Fine Location and Coarse Location permissions on Android and Location When In Use on iOS, which rebuilds the manifest and Info.plist.
nowa_runtime is Nowa's helper package. It holds @NowaGenerated, NPlatform, openUrl, showMediaPicker and widgets such as CustomButton, which the Library lists before Nowa's own Button when you search for button in a new project. It brings url_launcher, flutter_inappwebview, markdown_widget, video_player, chewie, audioplayers, image_picker, intl and web into your app with it. Each time Nowa loads your project, it sets nowa_runtime, and nowa_mobile_ads if you use AdMob, back to the versions your Nowa release works with, so a different version you write for either doesn't last.
| Feature | Packages Nowa adds |
|---|---|
| Supabase | supabase_flutter |
| Firebase | firebase_core, cloud_firestore; firebase_auth with Authentication; google_sign_in with the Google provider; firebase_messaging and flutter_local_notifications with push notifications |
| Stripe | flutter_stripe |
| RevenueCat | purchases_flutter, plus purchases_ui_flutter for the paywall |
| AdMob | nowa_mobile_ads |
| Google Maps | google_maps_flutter |
| Google Sign-In | google_sign_in |
| Deep links | app_links |
| Remove # in URLs | flutter_web_plugins, an SDK package |
| Widget | Package it needs |
|---|---|
| SVG | flutter_svg |
| Lottie | lottie |
| Rive | rive |
| YouTube Player | youtube_player_flutter |
| Swipeable Stack | flutter_card_swiper. The widget also creates a swiperController variable. |
| Pin Code Field | pin_code_fields. The widget also creates a pinCode variable. |
| Page View dots | smooth_page_indicator, which nowa_runtime no longer includes. See Handle the Page indicator migration. |
| Html | flutter_html. Nowa doesn't add it when you place the widget: click Fix on the Problems message. |
| Admob Banner, Google Maps, RevenueCat Paywall | The integration's packages above, plus your keys in Settings → Integrations. |
- The Library's Packages chip lists the packages in your
pubspec.yamlwith their versions (workspace for a local path), and the widgets and classes they bring. '<package>' is imported but is not in the pubspec.in Problems means your code imports a package yourpubspec.yamldoesn't list. Fix adds the package at its latest version. A package listed withsdk:,git:orpath:doesn't cause this problem. If the package is a dev dependency, Problems says so instead, with no Fix: Nowa doesn't load dev dependencies, so move it todependenciesto use it inlib/.- Nowa AI won't add
firebase_core(see Firebase) orflutter_localizations(see Translations).