×
Community Blog Flutter Analysis and Practice: Evolution and Innovation of Xianyu Technologies

Flutter Analysis and Practice: Evolution and Innovation of Xianyu Technologies

A thorough overview of Xianyu's systems, projects, developments and how to deploy and debug them discussed over 5 sections.

With the booming development of mobile smart devices, a mobile multi-terminal development framework has become a general trend. Download the Flutter Analysis and Practice: Evolution and Innovation of Xianyu Technologies eBook for step-by-step analyses based on real-life problems, as well as clear explanations of the important concepts of Flutter.

1. Hybrid Projects

1.1 Flutter Project System

1.1.1 Introduction to the Hybrid Project Development System

The project development system focuses on the following points:

  • Flutter development flow in hybrid project mode from a global perspective.
  • Project structure, for example, how to introduce Flutter into the existing native project, organize the project structure, manage the Flutter environment, and compile, integrate, and package builds.
  • Build optimization, for example, how to debug and optimize builds based on the Flutter toolchain (such as flutter_tools and the Flutter plug-in for IntelliJ IDEA.)
  • Separate debugging: Unlike integrated debugging mode where developers start a project and debug it in Flutter, in separate debugging mode, developers start a project in the native environment, for example, in Xcode or Android Studio or by clicking the app icon, but debug it in Flutter. Separate debugging can simplify flutter_tools operations and improve the stability and flexibility of debugging.
  • Flutter hot reload upon native startup.
  • Joint debugging: In this mode, developers debug a project in both Flutter and native Android and iOS environments.
  • Continuous integration: We can integrate a compiled Flutter project to an Android project as an Android Archive (AAR) or to an iOS project as a pod library.

1.1.2 Flutter Development in Hybrid Project Mode

As shown in Figure 1-1, in this project development system, developers can obtain engine dependencies and make appropriate modifications based on the official Flutter repository to meet the customization requirements. After developing each module, publish it to a private pub repository, which can be depended and integrated in business code though pubspec.yaml. During building, compile Dart code into a product (App.framework or Snapshot) and integrate it into an iOS App Store Package (IPA) as a standard iOS pod dependency or as an Android Package Kit (APK) as an Android Gradle dependency. Native developers do not need to focus on Flutter details. Flutter developers can start the Flutter project for debugging or access the Flutter page and use Dart remote connection for debugging after the native project is started (Observatory monitoring starts.)

1
Figure 1-1

1.1.3 Project Structure

The core logic is how to run Flutter with minimal changes to the existing iOS or Android projects. As shown in Figure 1-2, Flutter can serve as a module. It can be embedded into the main project of your existing Android app piecemeal, as a source code Gradle subproject or as an AAR. For the main project of your existing iOS app, Flutter can be embedded as a CocoaPods dependency or iOS pod library.

2
Figure 1-2

1.1.4 Build Optimization

Problem: The Android project is slowly built when it is started in Flutter.

Cause: In the logic of flutter_tools, when android/app/build.gradle is not found, gradle builds other than gradle assembleDebug is run to build multiple configurations.

Solution: Rebuild the Android project so that build.gradle of the project module is in the android/app directory, to match the logic of flutter_tools.

The debugging method of flutter_tools is:

1) Modify flutter_tools.dart to enable parameter printing.

import 'package:flutter_tools/executable.dart' as executable;

void main(List<String> args) {
  print('[KWLM]:${args.join(' ')}');
  executable.main(args);
}

2) Delete flutter/bin/cache/fluttertools.stamp so flutter_tools can be rebuilt.

  # Invalidate cache if:
  #  * SNAPSHOT_PATH is not a file, or
  #  * STAMP_PATH is not a file with nonzero size, or
  #  * Contents of STAMP_PATH is not our local git HEAD revision, or
  #  * pubspec.yaml last modified after pubspec.lock
  if [[ ! -f "$SNAPSHOT_PATH" || ! -s "$STAMP_PATH" || "$(cat "$STAMP_PATH")" != "$revision" || "$FLUTTER_TOOLS_DIR/pubspec.yaml" -nt "$FLUTTER_TOOLS_DIR/ pubspec.lock" ]]; then
    rm -f "$FLUTTER_ROOT/version"
    touch "$FLUTTER_ROOT/bin/cache/.dartignore"
    "$FLUTTER_ROOT/bin/internal/update_dart_sdk.sh"
    VERBOSITY="--verbosity=error"

    echo Building flutter tool...
    if [[ "$CI" == "true" || "$BOT" == "true" || "$CONTINUOUS_INTEGRATION" == "true" || "$CHROME_HEADLESS" == "1" ]]; then
      PUB_ENVIRONMENT="$PUB_ENVIRONMENT:flutter_bot"
      VERBOSITY="--verbosity=normal"
    fi
    export PUB_ENVIRONMENT="$PUB_ENVIRONMENT:flutter_install"

    if [[ -d "$FLUTTER_ROOT/.pub-cache" ]]; then
      export PUB_CACHE="${PUB_CACHE:-"$FLUTTER_ROOT/.pub-cache"}"
    fi

    retry_upgrade

    "$DART" $FLUTTER_TOOL_ARGS --snapshot="$SNAPSHOT_PATH" --packages= "$FLUTTER_TOOLS_DIR/.packages" "$SCRIPT_PATH"
    echo "$revision" > "$STAMP_PATH"
  fi

3) Build a flutter_tools project in Flutter and obtain its input parameters.

Building flutter tool...
[KWLM]:--no-color run --machine --track-widget-creation --device-id= GWY7N16A31002764 --start-paused lib/main.dart
Running "flutter packages get" in hello_world...                    0.4s
Launching lib/main.dart on MHA AL00 in debug mode...
Initializing gradle...
Resolving dependencies...

4) Use IntelliJ IDEA (or Android Studio) to start the flutter_tools project, create the Dart Command Line App, and configure Program arguments based on the input parameters obtained in Step (3), as shown in Figure 1-3.

3
Figure 1-3

5) Start to debug the flutter_tools project, as shown in Figure 1-4.

4
Figure 1-4

1.1.5 Project Debugging in Flutter upon Native Startup

In Flutter mode, the Flutter plug-in runs the xcodebuild command to build an iOS project or the Gradle script to build an Android project. For developers with the native background, this method is not suitable and causes repeated compilation due to parameters problems of commands, such as xcodebuild. This is especially complicated for a large native project. To solve this problem, we can debug and hot reload the project in Flutter either when it is started in Flutter or the native environment, as shown in Figure 1-5.

5
Figure 1-5

1.1.5.1 Debugging and Hot Reload in Flutter upon Flutter Startup

In fact, when the native project is configured with Flutter support and is started in Flutter, the main work to be done is:

  1. Check whether flutter_tools.snapshot needs to be regenerated.
  2. Run the pub packages to get command to obtain the dependency based on pubspec.yaml and generate the plug-in description files flutter-plugins and pubspec.lock.
  3. Generate the Generated.xcconfig file for iOS and the local.properties file for Android based on Flutter configurations, such as the framework path, debug. or release mode, and whether to enable Dart 2.
  4. Build an app based on Gradle and xcodebuild.
  5. Start the app based on Android Debug Bridge (ADB) and LLDB Debugger (LLDB.)
  6. After Flutter in the app has started, locate the Observatory port and connect Dart Debugger to it for debugging.
  7. Synchronize the dependency files of hot reload and implement full restart or hot reload through the daemon listening command (for example, clicking the plug-in button.)

If Dart debugging and hot reload upon native startup can be implemented, the slow compilation caused by flutter_tools and the unstability of the debugging environment can be solved. When starting an iOS app that contains Flutter content in debug mode in Xcode (or the Android app in Android Studio), follow steps (1), (2), (3), (6), and (7). Repeat steps (1), (2), and (3) only when the configurations of flutter_tools, pubspec.yaml, or Flutter are modified. Steps (6) and (7) are required for development personnel to complete the debugging and hot reload. We need to consider how to support them in this mode.

1.1.5.2 Debugging and Hot Reload in Flutter upon Native Startup

Locate the Observatory port on an iOS device. Run the idevicesyslog command to obtain the required command line. This involves the libimobiledevice library, including the idevicesyslog and iproxy commands.

kylewong@KyleWongdeMacBook-Pro ios % idevicesyslog | grep listening
Aug 26 14:07:18 KyleWongs-iPhone Runner(Flutter)[686] <Notice>: flutter: Observatory listening on http://127.0.0.1:56486/oB7rB0DQ3vU=/

The Observatory on the iOS device starts port x (with a random port number) and the authentication code is y.

Run the iproxy command to map port x on the iOS device to the local port z.

kylewong@KyleWongdeMacBook-Pro ios % iproxy 8101 56486 your-ios-device-uuid

The "waiting for connection" message is displayed. Then, you can visit http://127.0.0.1:z/ y/#/vm and access the Observatory, as shown in Figure 1-6.

6
Figure 1-6

You can use the Observatory to check Dart-related memory and debugging information.

You can also use the IDE link to debug and configure Dart Remote Debug, as shown in Figure 1-7.

7
Figure 1-7

Be sure to use port z that was just forwarded to the device and search the root directory of the Flutter project for source code.

To avoid a connection failure due to the authentication code, '--disable-service-auth-codes' must be passed during app startup.

After Dart Remote Debug is configured, click the debug button to connect to the debug port, as shown in Figure 1-8.

8
Figure 1-8

After the operation succeeds, "Connected" is displayed on the Debugger tab. If it is not displayed, click the debug button again, as shown in Figure 1-9.

9
Figure 1-9

Then, you can use the IDE to set breakpoints and debug Dart (Flutter) code, as shown in Figure 1-10.

10
Figure 1-10

1.1.6 Hot Reload in Flutter upon Native Startup

Start the app. On the Flutter page, locate the Observatory port x and authentication code y.

In the directory of the Flutter project, run the flutter attach --debug-uri=http:// 127.0.0.1:x/y/ command.

kylewong@KyleWongdeMacBook-Pro fwn_idlefish % flutter/bin/flutter attach --debug-uri=http://127.0.0.1:63515/2T0iU5TV0As=/
[KWLM]: [attach, --debug-uri=http://127.0.0.1:63515/2T0iU5TV0As=/]
Syncing files to device KyleWong's iPhone...

🔥 To hot reload changes while running, press "r". To hot restart (and rebuild state), press "R".
An Observatory debugger and profiler on KyleWong's iPhone is available at: http://127.0.0.1:63515/2T0iU5TV0As=/
For a more detailed help message, press "h", To detach, press "d"; to quit, press "q".

Modify Dart source code, and enter r on the device (following 'to quit,press"q"').

      new Padding(
        padding: new EdgeInsets.only(left: 22.0),
        child: createButton(
            videoIsFullScreen,
            {
              'foreground': 'fundetail_superfavor_white',
              'background': 'super_favor_unhighlight'
            },
            'super_favor_highlight',
            '赞',
            buttonSelectedStatus['superfavor'], () {
          superLikeComponent.clickV2(widget.itemInfo.itemId, widget.itemInfo.userId, widget.itemInfo.fishPoolId,
              widget.itemInfo.superFavorInfo.superFavored, widget.itemInfo.trackParams);
        }),
      )

Here, "Superb" is changed to "Like." "Initializing hot reload...Reloaded..." is displayed on the device. After the operation is completed, modification on the device takes effect and the text in the lower-left corner becomes "Like," as shown in Figure 1-11.

The debugging and hot reload of Android projects in Flutter are similar, but for Android, you can run IDE Logcat or ADB Logcat | grep Observatory to obtain the port number and run ADB forward to forward the port.

11
Figure 1-11

1.1.7 Joint Debugging of Native and Flutter

Your app can be debugged in Flutter at any time after startup. You can also run the Attach Debugger to the Android Process of Android Studio to debug an Android app, implementing the joint debugging of Android and Flutter. Similarly, you can run the Attach to Process of Xcode to implement joint debugging of iOS and Flutter.

1.1.8 Continuous Integration

The Xianyu team has native developers and Flutter developers, so they make development separately in Flutter mode and native mode. The Flutter environment has been installed on a public device (Mac Mini) for Flutter-related building. The compiled Flutter projects are integrated into a native project (Flutter-related code is considered as a module) as an AAR or a pod library. The Continuous Integration (CI) platform used to build the final APK or IPA also integrates and packages Flutter as a compiled product.

0 0 0
Share on

XianYu Tech

56 posts | 4 followers

You may also like

Comments