[Newbie] Chapter 1. Flutter overview
[Newbie] Chapter 2. Flutter getting started
Content
- Config to App Center
- CI config
- App splash screen
- App launcher
- App version and env
Config to App Center
- Create an account on https://appcenter.ms/apps
- Create a new app.
- With Flutter, you need to create two apps separately for android and ios
- Update dependencies at
pubspec.yaml
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^0.1.2
appcenter:
git:
url: git://github.com/nhancv/flutter_plugin_appcenter.git
path: src/appcenter
appcenter_crashes:
git:
url: git://github.com/nhancv/flutter_plugin_appcenter.git
path: src/appcenter_crashes
appcenter_analytics:
git:
url: git://github.com/nhancv/flutter_plugin_appcenter.git
path: src/appcenter_analytics
- Modify
lib/main.dart
to integrate App center
import 'package:flutter/material.dart';
import 'package:appcenter/appcenter.dart';
import 'package:appcenter_analytics/appcenter_analytics.dart';
import 'package:appcenter_crashes/appcenter_crashes.dart';
import 'package:flutter/foundation.dart' show defaultTargetPlatform;
import 'package:flutter/foundation.dart' show TargetPlatform;
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// @nhancv 10/23/2019: Config app center
final ios = defaultTargetPlatform == TargetPlatform.iOS;
String appSecret = ios
? "4cb4478e-9803-92cf-02ef-00f272f9768d"
: "7bf557b6-6739-028f-b83e-ba192d3f7972";
await AppCenter.start(
appSecret, [AppCenterAnalytics.id, AppCenterCrashes.id]);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: CrashHome(),
);
}
}
class CrashHome extends StatefulWidget {
@override
_CrashHomeState createState() => _CrashHomeState();
}
class _CrashHomeState extends State<CrashHome> {
String _installId = 'Unknown';
bool _areAnalyticsEnabled = false, _areCrashesEnabled = false;
@override
initState() {
super.initState();
initPlatformState();
}
initPlatformState() async {
if (!mounted) return;
var installId = await AppCenter.installId;
var areAnalyticsEnabled = await AppCenterAnalytics.isEnabled;
var areCrashesEnabled = await AppCenterCrashes.isEnabled;
setState(() {
_installId = installId;
_areAnalyticsEnabled = areAnalyticsEnabled;
_areCrashesEnabled = areCrashesEnabled;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Appcenter plugin example app'),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text('Install identifier:\n $_installId'),
Text('Analytics: $_areAnalyticsEnabled'),
Text('Crashes: $_areCrashesEnabled'),
RaisedButton(
child: Text('Generate test crash'),
onPressed: AppCenterCrashes.generateTestCrash,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text('Send events'),
IconButton(
icon: Icon(Icons.map),
tooltip: 'map',
onPressed: () {
AppCenterAnalytics.trackEvent("map");
},
),
IconButton(
icon: Icon(Icons.casino),
tooltip: 'casino',
onPressed: () {
AppCenterAnalytics.trackEvent("casino", {"dollars": "10"});
},
),
],
),
],
),
);
}
}
- For iOS, you may face with pod install error, just make a little change at
ios/Podfile
: put comment#
onuse_frameworks!
line, then run it again.
target 'Runner' do
# use_frameworks!
- For Android, add internet permission to
android/app/src/main/AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET"/>
- Run app
- Click on ‘Generate test crash’ and go to App center to check crash report
CI config
- Download
appcenter-post-clone.sh
config build for Android at https://github.com/microsoft/appcenter/tree/master/sample-build-scripts/flutter/android-build and place it inproject/android/app/
- Download
appcenter-post-clone.sh
config build for iOS at https://github.com/microsoft/appcenter/tree/master/sample-build-scripts/flutter/ios-build and place it inproject/ios/
- For the Android project to be detected by AppCenter, remove
gradle-wrapper.jar
,gradlew
andgradlew.bat
from the.gitignore
file created by flutter with the new project. - Config Keystore for Android
- Copy
<User>/.android/debug.keystore
toandroid/app/keystores/keystore-debug.jks
- Clone
keystore-debug.jks
tokeystore-release.jks
- Update
android/app/build.gradle
- Copy
signingConfigs {
debug {
keyAlias 'androiddebugkey'
keyPassword 'android'
storeFile file("keystores/keystore-debug.jks")
storePassword 'android'
}
release {
keyAlias 'androiddebugkey'
keyPassword 'android'
storeFile file("keystores/keystore-release.jks")
storePassword 'android'
}
}
buildTypes {
debug {
debuggable true
signingConfig signingConfigs.debug
}
release {
debuggable false
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
}
- Commit these script to remote
- Go to
Appcenter dashboard -> Build -> Connect to your source -> Config -> Save & Build
- Wait for building
- After build successful, you can Download or Distribute it
- iOS build status
- After distributed, collaborators will get an email
App launcher
- Prepare app icon: https://jgilfelt.github.io
- Get the biggest icon, rename it to
app-icon.png
and place it toassets/icons/app-icon.png
- Update
pubspec.yaml
dev_dependencies:
flutter_launcher_icons: ^0.7.3
flutter_icons:
image_path: "assets/icons/app-icon.png"
android: true
ios: true
image_path_android: "assets/icons/app-icon.png"
image_path_ios: "assets/icons/app-icon.png"
adaptive_icon_background: "assets/icons/app-icon.png"
adaptive_icon_foreground: "assets/icons/app-icon.png"
- Generate icon
flutter pub get
flutter pub run flutter_launcher_icons:main
- Stop and Run the app again
App splash screen
Android
- Update
android\app\src\main\res\drawable\launch_background.xml
(remember using the resource in drawable, not in mipmap)
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<item>
<bitmap
android:gravity="center"
android:src="@drawable/ic_launcher_background" />
</item>
</layer-list>
- Update
android\app\src\main\res\values\styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
Flutter draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
<item name= "android:windowFullscreen">true</item>
</style>
</resources>
- Update android native MainActivity at
src\main\...
Kotlin
import android.os.Build
import android.os.Bundle
import android.view.ViewTreeObserver
import android.view.WindowManager
import io.flutter.app.FlutterActivity
import io.flutter.plugins.GeneratedPluginRegistrant
class MainActivity : FlutterActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//make transparent status bar
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.statusBarColor = 0x00000000
}
GeneratedPluginRegistrant.registerWith(this)
//Remove full screen flag after load
val vto: ViewTreeObserver = flutterView.viewTreeObserver
vto.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
flutterView.viewTreeObserver.removeOnGlobalLayoutListener(this)
window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
}
})
}
}
Java
import android.os.Build
import android.os.Bundle
import android.view.ViewTreeObserver
import android.view.WindowManager
import io.flutter.app.FlutterActivity
import io.flutter.plugins.GeneratedPluginRegistrant
public class MainActivity extends FlutterActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//make transparent status bar
getWindow().setStatusBarColor(0x00000000);
GeneratedPluginRegistrant.registerWith(this);
//Remove full screen flag after load
ViewTreeObserver vto = getFlutterView().getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
getFlutterView().getViewTreeObserver().removeOnGlobalLayoutListener(this);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
});
}
}
iOS

Open Runner.xcworkspace -> Runner -> Runner -> Assets.scassets -> LaunchImage -> Upload 3 type res