How to do Code Push on Flutter(2.0)?

Chimera
10 min readMar 17, 2021
Flutter Code Push
Photo by Sigmund on Unsplash

As you know, till now, Flutter does not support code push for iOS/Android app patching.

Google flutter team has announced that flutter would not support the code push function in their engine.

So Chimera flutter CodePush was initialized and developed at that moment: Chimera CodePush is a cloud service that enables flutter developers to deploy mobile app updates directly to their users’ devices. It works by acting as a central repository that developers can publish updates to and that apps can query for updates from. This allows you to have a more deterministic and direct engagement model with your userbase when addressing bugs and/or adding small features that don’t require you to re-build a binary and re-distribute it through the respective app stores.

  • How to integrate Chimera Code Push SDK to your flutter App??

I will show you how to do it now:

Dev Setup

Now let’s start the journey:

🚩 First of all, you may need to be an excellent Flutter programmer or a flutter programming enthusiast, like me :-), mainly needs to be familiar with Flutter programming, and has a heart that likes to study and learn.

Set up Flutter ENV:here.

You need a good IDE, Android Studio or VSCODE are recommended.

Remember to install http-server, because subsequent work requires http-server:

brew install http-server

The big killer is here, our compiler! This compiler is the main tool to serve Chimera CodePush.

# Compilation tool download link

https://github.com/Waytoon/chimera_flutter_code_push/releases/download/v1.0.0/rust_compile

The important thing: The compiler needs to be connected to the Internet while it is running. Full support for Mac, including M1.

🏁 Please check the runtime environment on your computer. Chimera is based on the latest stable version of Flutter. And the SDK will continue to support the latest stable Flutter version in the future.

https://flutter.dev/docs/development/tools/sdk/releases?tab=macos(opens new window)

The flutter version we use (stable version)

 ~/Desktop/tool  flutter --version                      
Flutter 1.22.6 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 9b2d32b605 (6 weeks ago) • 2021-01-22 14:36:39 -0800
Engine • revision 2f0af37152
Tools • Dart 2.10.5

If you are using flutter 2 now, please switch to flutter 1.22.6 stale

Switching method : Please run flutter downgrade in the terminal

Use CodePush SDK

First, run mkdir test to create a test folder. As shown below:

cd test enter the test directory and create a hello project: flutter create hello.

hello directory structure is as follows:

.hello folder
├── README.md
├── android
├── hello.iml
├── ios
├── lib
├── pubspec.lock
├── pubspec.yaml
└── test

Open the hello project with IDE:

Be careful here! ! Use the IDE to debug the hello project, whether using the simulator or the real phone, below we use the simulator as an example demonstration.

Very important step Download our compiler, link:

https://github.com/Waytoon/chimera_flutter_code_push/releases/download/v1.0.0/rust_compile

Please pay attention to check and pay attention to the release of the release file in the release section. In the recent period, we will update the compiler every night.

Download to a designated directory, give a name at will, let’s use tool:

Then open the terminal, enter the directory of the compiler, and run the command chmod 777 rust_compile to make the compiler have permission to run.

The first time you run the compiler, the configuration file config.yaml will be generated.

After running, you will be prompted to configure config.yaml, as shown in the figure above.

Open config.yaml and configure it as following:

# Project path
projectPath: /Users/ryanliu/Desktop/test/hello #Modify the directory of hello
# Flutter SDK
flutterSdkPath: /Users/ryanliu/development/flutter #Modify the SDK directory of the current flutter environment
# Compile cache path
buildCachePath: /Users/ryanliu/Desktop/temp/dart_compile_cache #Set up a directory to save dart_compile_cache
# FTP
#ftpConfig: 192.168.80.141|root|123456 ignore this optional setting

Then run ./rust_compile again in the terminal to execute our compilation process. In about 2-5 minutes, you can get the following screen results. The compiled product hello.bin is in the project hello/assets/ directory, and there are more wtbase Library directory.

We can see that the directory of the hello folder has been changed, notice that there are two new folders assets and wtbase in the directory:

├── README.md
├── android
├── assets
├── build
├── hello.iml
├── ios
├── lib
├── pubspec.lock
├── pubspec.yaml
├── test
└── wtbase

The next step is very important! Configure wtbase/pubspec.yaml in dependencies to modify the boot path of flutter_code_push as follows:

flutter_code_push:
git:
url: https://github.com/Waytoon/chimera_flutter_code_push.git
path: flutter_code_push

Original configuration:

After modification:

Remember to click pub get above, or type flutter pub get in the terminal.

Then modify `hello/pubspec.yaml` and add the following in `dependencies`:

wtbase:
path: ./wtbase

And cut and copy other dependent libraries under dependencies to dependencies under wtbase/pubspec.yaml, the final effect is as follows:hello/pubspec.yaml:

hello/wtbase/pubspec.yaml:

Remember to run flutter pub get, or click the Pub get button.

Note: Please run Pub get of the wtbase directory first, and then run Pub get of the hello project. The purpose of this is to ensure that the version numbers of the dependent libraries of the project remain consistent.Up to this point, the preliminary SDK configuration work has been completed. Below we explain how to use and implement hot updates in our source code.

Now create MyApp.dart in hello/libDirectory,Source code :

import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
void initApp() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
// This makes the visual density adapt to the platform that you run
// the app on. For desktop platforms, the controls will be smaller and
// closer together (more dense) than on mobile platforms.
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
String _response;
void _incrementCounter() {
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
}
void _getHttp() async {
try {
Response response = await Dio().get("http://www.google.com");
setState(() {
String temp = '$response';
for (var i = 0; i < 10; ++i) {
temp = '$i' + temp;
}
_response = temp.substring(0, 100);
});
} catch (e) {
print(e);
}
}
@override
void initState() {
_getHttp();
super.initState();
}
@override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
// Column is also a layout widget. It takes a list of children and
// arranges them vertically. By default, it sizes itself to fit its
// children horizontally, and tries to be as tall as its parent.
//
// Invoke "debug painting" (press "p" in the console, choose the
// "Toggle Debug Paint" action from the Flutter Inspector in Android
// Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
// to see the wireframe for each widget.
//
// Column has various properties to control how it sizes itself and
// how it positions its children. Here we use mainAxisAlignment to
// center the children vertically; the main axis here is the vertical
// axis because Columns are vertical (the cross axis would be
// horizontal).
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
Text(
'Server Response:\n$_response'
)
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}

After adding this file, remember to run flutter pub get to ensure that the dependencies are imported correctly.

import 'package:hello/MyApp.dart';
import 'package:wtbase/wtbase.dart';
import 'package:flutter/material.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
bool isNative = false;
if (isNative) {
initApp();
} else {
String downloadUrl = "http://yourlocalhost/hello.bin";
readCode = WTAnalysisReadCode();
await readCode.loadFile(downloadUrl);
readCode.executeMethod(
'package:hello/MyApp.dart', 'initApp');
}
}

Please note that downloadUrl now only supports intranet testing. downloadUrl needs to start with http://192.168.

If you need to support extranet requests, please contact flupush@gmail.com.

Another crucial step:

Open the terminal and enter the hello/assets directory:

Then type in the terminal: http-server -c -1

The results are as follows:

Copy the link below http-server, mine is http://192.168.80.115:8080, used to modify main.dart

String downloadUrl = "http://yourlocalhost/hello.bin";

Change to:

String downloadUrl = "http://192.168.80.115:8080/hello.bin";

So far, the entire access process has come to an end..

Run App with Code Push

The next thing is to run your APP from the IDE by clicking on the green bug.

No surprises, IDE compilation will not cause any problems. The display on the simulator is like this.

IDE’s debug console log is as follows:

Launching lib/main.dart on Android SDK built for x86 in debug mode...
Running Gradle task 'assembleDebug'...
✓ Built build/app/outputs/flutter-apk/app-debug.apk.
Installing build/app/outputs/flutter-apk/app.apk...
Waiting for Android SDK built for x86 to report its views...
Debug service listening on ws://127.0.0.1:65046/r1MGSW-wdg4=/ws
Syncing files to device Android SDK built for x86...
W/m.example.hell( 6898): Accessing hidden method Lsun/misc/Unsafe;->getUnsafe()Lsun/misc/Unsafe; (greylist,core-platform-api, linking, allowed)
W/m.example.hell( 6898): Accessing hidden method Lsun/misc/Unsafe;->objectFieldOffset(Ljava/lang/reflect/Field;)J (greylist,core-platform-api, linking, allowed)
W/m.example.hell( 6898): Accessing hidden method Lsun/misc/Unsafe;->compareAndSwapObject(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z (greylist, linking, allowed)
W/m.example.hell( 6898): Accessing hidden method Lsun/misc/Unsafe;->putObject(Ljava/lang/Object;JLjava/lang/Object;)V (greylist, linking, allowed)
D/EGL_emulation( 6898): eglMakeCurrent: 0xd7a8e900: ver 3 0 (tinfo 0xdaf0f820)
D/eglCodecCommon( 6898): setVertexArrayObject: set vao to 0 (0) 1 0
I/flutter ( 6898): download file!
I/flutter ( 6898): vmClassName: MyApp className: WTStatelessWidget1
I/flutter ( 6898): vmClassName: MyHomePage className: WTStatefulWidget1
I/flutter ( 6898): vmClassName: _MyHomePageState className: WTState1

The next thing is to let you do it yourself. For example, let’s modify the code in MyApp.dart and try it. Try modifying the icon of floatingActionButton:

floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),

Modify Icons.add to Icons.home. It looks like this after completion:

floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.home),
),

Save the changes you made, then go back to the terminal, enter your compiler directory, and run ./rust_compile:

After running this command, wait for a while, the final effect is as follows:

Please pay attention here, we don’t need an IDE to do anything at this point, just close the currently running app in the simulator, reopen it, and you will find that it becomes the following:

Once again, we have not used any functions of the IDE in this step of the operation so far. We just compiled the new hello.bin file with our own compiler, and then loaded the bin file remotely through the simulator. .

Photo by Daniels Joffe on Unsplash

This is an APP that can be fully updated.

So far, you have developed an App with hot update function, isn’t it amazing? ! You can try to modify some code at will, and remember to compile again after changing your code (repeat step 10).

If you like, please give us a star ✨!

--

--