跳转至

16 Platform-Specific App Assets

So far, you’ve built Flutter apps for the Flutter toolkit using the Dart language and the various Flutter idioms. You then built and deployed those apps to iOS and Android devices without having to do anything special. It’s almost magical.

However, sometimes you’ll need to add platform-specific code to cater to the needs of the particular store or operating system.

For example, you might need to change how you specify the app icon, the launch assets and the splash screen to suit each platform.

In this chapter, you’ll go through the process of setting up some important parts of your app to look great regardless of which platform your users choose. You’ll continue using the Recipe Finder app from the previous section.

Note: You can also start fresh by opening this chapter’s starter project. If you choose to do this, remember to click the Get dependencies button or execute flutter pub get from Terminal. You’ll also need to add your API Key and ID in lib/network/recipe_service.dart.

You’ll want to use native development tools when working with platform-specific assets, so you’ll need to install Xcode 13 to complete the deployment of the iOS app in this chapter. Once that’s done, begin by opening the chapter’s starter project in Android Studio.

Setting the app icon

The app icon is one of the most important pieces of any app’s branding. It’s what shows up on the store page and the home screen as well as in notifications and settings. It’s the avatar for the app, so it must look just right.

To do this, you need to use constraints. Android and iOS not only use different constraints, but they also specify them differently, which means you need to tweak your icon for each platform.

By default, when you create a new Flutter project with the flutter tool, it sets the Flutter F logo as the project’s icon:

img

Not only is this not branded to your recipe app, but the app stores aren’t likely to approve it. Your first task will be to update to a custom image that looks great on each platform.

Optimizing the app icon for Android

With the project open in Android Studio, open android/app/src/main/AndroidManifest.xml. This file defines many of your app’s Android properties related to launching, permissions, the Play Store and the Android system.

One of the properties under application defines the launcher screen icon:

android:icon="@mipmap/ic_launcher"

The @mipmap part means that it resolves to a mipmap-{resolution} folder to load a graphic of the correct device’s screen scale. ic_launcher is the filename of the icon.

Under android/app/src/main/res, you’ll find the various mipmap- subfolders.

In Finder, open assets/icons/android from the chapter materials. Copy the res folder from Finder and replace android/app/src/main/res in Android Studio.

If you receive a pop-up confirming you want to copy the folders to the specified directories, click Refactor or OK, depending on your Android Studio version.

img

Expand the android/app/src/main/res folder and verify you’ve pasted the res folder in the correct place. It should be at the same level as the java and kotlin folders, not inside the existing res folder.

img

Hot reload doesn’t update the launcher icon (hot restart doesn’t, either). For these changes to take effect, you need to stop the app and run it again.

On the home screen, you’ll now see the new launcher icon. Run the app on an Android device or emulator to see the following:

img

Great, you’ve just swapped the default assets for some cool custom ones. If you need to adjust the icon fill size, or if you’re working on your own app later and want to import Android images, you’ll need to import and resize the artwork. That’s next!

Personalizing the app icon for Android

When you work with your own custom artwork, there are a few more steps you need to take, beyond just copying and pasting from a folder. You need to work in the Android portion of your app and not within the Flutter project.

Open the Android folder directly from the Android Studio menu, choose File ▸ Open and navigate to your project’s android folder. Finally, click Open.

img

Wait until the Gradle sync is complete. The time it takes your project to finish might vary.

img

Navigate to the app folder, right-click on res and choose New ▸ Image Asset.

img

The Configure Image Asset pop-up window will display. Click the folder icon to open the custom image.

img

Locate your master artwork image. In this case, you’ll find it in the assets/. Select the IconArtwork_1024x1024.png image and click on Open.

img

The loaded image will appear like this.

img

If the cook figure is outside the safe zone, use the Resize slider to adjust the size. Make sure the cook figure is inside the circle, which is the safe zone, as shown below. When done click Next.

img

The next screen displays the path where you’ll save the assets. Keep in mind this is for the Android project, not your Flutter project, so the folder layers look different from what you’ve worked with so far.

Leave the defaults and click Finish.

img

Close this Android project and go back to your Flutter project.

img

You’ve now seen how to resize custom artwork for your Android app. What’s great is that after you finish these updates, your Flutter app updates automatically!

As before, for these changes to take effect, you need to stop the app and run it again. You’ll see the same launcher icon. Run the app on an Android device or emulator to see the following:

img

Next, you’ll work on the iOS app icon.

Optimizing the app icon for iOS

When you create a Flutter project that supports iOS, Flutter generates an ios subfolder in the project at the same level as the android folder. This contains the libraries and support files to run on iOS. In that folder is an Xcode workspace, Runner.xcworkspace.

Note: iOS developers, Flutter apps use Runner.xcworkspace instead of the traditional Runner.xcodeproj.

There are a couple ways to open the Xcode project. You can use Finder or the IDE.

In Finder, open starter/ios from the chapter materials and double-click Runner.xcworkspace. If you have Xcode open, you can also navigate to the folder and open it.

img

If you’re using Android Studio/IntelliJ right-click on the ios folder and naviagate to Flutter and you’ll see Open iOS Module in Xcode. Below you’ll see the Android Studio menu.

img

VSCode is a little different. When you right-click on the ios folder you’ll see Open in Xcode.

img

Flutter uses a workspace to build the app because, under the hood, it uses Cocoapods to manage iOS-specific dependencies required to build and deploy iOS apps. The workspace contains the main runner project and the Cocoapods project as well as all the supporting files to build and deploy an iOS app.

This project contains a lot of boilerplate and helpers to run the app within the iOS app context. Don’t worry about building the app from the project. Continue to use Android Studio or the command line to build and deploy to a simulator.

Viewing the app icon

To see the app icon, open Runner ▸ Runner ▸ Assets.xcassets. This is an asset catalog, a way of organizing assets in an Xcode project in a configuration-aware way.

Inside, you’ll see AppIcon and LaunchImage.

img

Click AppIcon to see all the devices and resolutions supported by the default Flutter icon.

img

In Finder, open assets/icons/ios from the chapter materials. Drag each of the images inside into the asset catalog, grabbing the right one for each size. You can tell which is which by the name.

Don’t worry if you grab the wrong one: A yellow warning triangle will appear next to any image that isn’t the right size.

img

Save these changes and return to Android Studio.

Perform a full stop and run again on an iOS simulator to see the new icon on the Home Screen. You may have to refresh the screen on your device.

img

Setting the app’s name

Now that you have a shiny new icon on the device launch screens, you’ll notice that the app’s name isn’t always formatted nicely, which detracts from the experience.

Setting the launcher name is an easy fix, but you also have to do it for each platform.

Return to android/app/src/main/AndroidManifest.xml. Find the android:label property of the application node and change the text to:

Recipe 🔎

Build and run the app on Android. By choosing a shorter label, the name will fit on more Android launchers.

img

You can do the same on iOS as well. Go back to Xcode and open Runner ▸ Runner ▸ Info.plist. This file is similar to AndroidManifest.xml in that it contains information about your app for the OS to use.

Under Information Property List, change the Bundle display name to Recipe 🔎 as well.

Back in Android Studio, build and run the app for iOS.

img

There, that looks better!

Adding a launch screen

The next finishing touch you’ll put on your app is a launch screen. It takes a few moments for the Dart VM to spin up when users launch the app, so you’ll add polish by giving them something to look at other than a white screen. Once again, you need to set this up separately for iOS and Android.

Setting a launch image in iOS

On iOS, setting a launch image is straightforward.

In Xcode, open ios/Runner.xcworkspace again, select Assets.xcassets, and this time select LaunchImage.

You’ll see three boxes to represent the image at 1x, 2x and 3x resolution. Because you’ve only defined one version of the image, you need to tell iOS to scale it for the other high-resolution screens.

To do that, select one of the boxes. Then in the Attributes inspector select from the Scalesdrop-down: Single Scale.

img

This setting lets the system know there’s just one version of the image. This is preferred for images like photographs, which have a native resolution.

Find splash.png under assets/launch image from the chapter materials, then drag it onto the Allsquare for the launch image.

img

The user will see this image from the time when the app launches until the main screen is ready. Since the image has text in it, you’d normally supply high-resolution images as well, but in this case, you’ll modify it later.

Build and run on iOS from Android Studio again.

img

On some simulators it’s a little squished and on others it doesn’t even show up, but you’ll fix that now.

Showing a more sophisticated launch UI

A good image can go a long way toward making your app look sophisticated. However, the one you just used is problematic because the built-in text is hard to get right across a wide variety of device sizes and resolutions. This adds a layer of complexity to the translation.

Right now, UIImageView in LaunchScreen.storyboard uses the launch image you added to the asset catalog earlier. The app loads this storyboard when it launches and displays it until it finishes loading. In Xcode, open the storyboard from Runner ▸ Runner ▸ LaunchScreen.storyboard.

Adding constraints

Your first step is to make the image fill the screen without distorting its contents. That will make it look good on all device sizes.

Expand View Controller Scene ▸ View Controller ▸ View and select LaunchImage.

img

Then, click the Add New Constraints button at the bottom.

img

Set all four constraints to 0 and make sure Constrain to margins isn’t selected. Then, click Add 4 Constraints to set the constraints. This forces the image to fill its superview.

img

Next, in the Attributes inspector, change the Content Mode to Aspect Fill. This will resize the image to fill the image view, but keep the aspect ratio intact, truncating it as necessary.

img

Replacing the title with a label

It’s not ideal to have text attached to the image, so you’ll replace it with a label that has its own constraints, instead. To do that, you’ll need a new image.

Returning to Runner ▸ Runner ▸ Assets.xcassets open LaunchImage in the asset catalog. In the same assets folder as the original splash image, you’ll also find alloo.jpg. Drag this to the catalog to replace the existing image.

img

Back in LaunchScreen.storyboard, drag a Label from the Library onto the view. If it’s not already visible, you can access the Library from View ▸ Show Library.

Add constraints to the label, as you did for the image, but this time, add these three constraints:

  • Top to 140.
  • Leading and Trailing space to 0.
  • Leave the bottom constraint unset.

Then, in the Attribute inspector, set the following values:

  • Text to Recipe Finder.
  • Color to White Color.
  • Font to System, Style to Heavy and Size to 100.
  • Alignment to Center.
  • Lines to 2.
  • Line Break to Word Wrap.
  • Shadow to Dark Grey Color and Shadow Offset to a Height of 2 and a Width of 2.

Hold your breath for one last finishing step in the name of aesthetics.

With the label still selected, at the top of the right pane, click on the triangle ruler icon to show the Size inspector.

img

Double-click the Vertical constraint to open the constraint in the editor.

img

Change the Second Item from Top.Layout Guide.Bottom to Superview.Top.

img

This changes the anchor for the label’s top from the layout guide, which changes during launch, to the top of the screen. This ensures consistent placement of the label.

Phew… that was a lot of settings, but the result really makes a statement. When you’re done, the storyboard will look like this:

img

In Android Studio, if your app is still running perform a full stop. Build and run again to see the new launch screen.

img

Now, the image is no longer squished, the text is readable and your launch screen looks great.

Setting a launch image in Android

As of Android 12, there is a default splash screen that animates from the launcher, showing the app icon and then fading into the first activity of the app once the main Flutter widget is ready to go.

img

You get this all for free and is actually a nice experience. You can customize this animation, but this requires specialized assets and additional skills. For more information, see the Raywenderlich.com Splash Screen Tutorial for Android or the Android Animations by Tutorials book.

Key points

  • Flutter generates app projects for iOS and Android, which you can edit to brand your app.
  • These projects contain resources and code related to launching the app and preparing to start the Flutter main view.
  • You need to set assets related to app launch separately for each platform.

Where to go from here?

You may have seen other apps with more dynamic or animated splash screens. These are generally created as a whole-screen stateful widget that displays for a predetermined time between the Flutter VM load and launching your main screen widget.

Dynamic splash screens give your app launch a little more flair, but you should still include an image-based launch screen to show before the splash loads. The splashscreen package is a good place to start if you want to implement one in your app: https://pub.dev/packages/splashscreen.