Skip to content
This repository has been archived by the owner on Feb 11, 2024. It is now read-only.

Flutter support #18

Merged
merged 22 commits into from
Aug 4, 2021
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
cf87c48
flutter support: initial commit
unsuitable001 Jul 27, 2021
11e8c11
implement: android support
unsuitable001 Jul 27, 2021
d0ea739
CI: exclude flutter sample from dart analyze
unsuitable001 Jul 27, 2021
1b6a8a2
flutter: add linux support
unsuitable001 Jul 28, 2021
6094162
update tools/setup for android
unsuitable001 Jul 28, 2021
bafdd35
flutter: add windows support
unsuitable001 Jul 28, 2021
bd49741
update readme for android support
unsuitable001 Jul 28, 2021
875cc3a
str interpolate -> package:path join & adding constants
unsuitable001 Jul 29, 2021
a631548
remove circular ref in map
unsuitable001 Jul 29, 2021
0488e0e
make androidPath final
unsuitable001 Jul 29, 2021
2481e54
add flutter platform keys for desktops
unsuitable001 Aug 1, 2021
e0bdfb8
readme fixes and CI from Dart -> Flutter
unsuitable001 Aug 2, 2021
3870e67
update ci
unsuitable001 Aug 4, 2021
9fa8327
remove boilerplate widget_test
unsuitable001 Aug 4, 2021
edb24bd
ci check success on each step
unsuitable001 Aug 4, 2021
59da4ee
ci: remove successs check at wrong place
unsuitable001 Aug 4, 2021
3adf06f
change exit code in case of build failure
unsuitable001 Aug 4, 2021
3a4c1d7
remove linking with dart.lib (windows) and int -> size_t for strlen
unsuitable001 Aug 4, 2021
3dbaf29
add `flutter create` boilerplate modification notes
unsuitable001 Aug 4, 2021
d26ed08
Network -> network
unsuitable001 Aug 4, 2021
5c58ed6
yet another typo :sweat:
unsuitable001 Aug 4, 2021
4cdcc6c
change download url
unsuitable001 Aug 4, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ doc/api/
.history
.vscode
compile_commands.json
*.log

# IntelliJ
*.iml
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.0.4

* Added support for Android and Flutter Desktops (Windows/Linux).

## 0.0.3

* Using `package:args` for handling CLI arguments.
Expand Down
35 changes: 33 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ This is a [GSoC 2021 project](https://summerofcode.withgoogle.com/projects/#4757

## Supported Platforms

Currently, 64 bit Desktop Platforms (Linux, Windows and MacOS) are supported.
Currently, Android and 64 bit Desktop Platforms (Linux, Windows and MacOS) are supported.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about x86 Android when using the Android Emulator from Android studio?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those binaries are added too, both x86 and x86_64. (I'll try to test on the emulator).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not working on x86 emulator :( Getting HttpException with some negative long random value as error status code. Maybe we should mention this and probably need to do some modifications in the wrapper to support 32 bit systems overall.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please file an issue to track this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue: #20


## Requirements

1. Dart SDK 2.12.0 or above.
2. CMake 3.15 or above. (If on windows, Visual Studio 2019 with C++ tools)
3. C++ compiler. (g++/clang/msvc)
4. Android NDK if targeting Android.

## Usage

Expand All @@ -27,6 +28,22 @@ Currently, 64 bit Desktop Platforms (Linux, Windows and MacOS) are supported.
dart run cronet:setup # Downloads the cronet binaries.
```

**Flutter**

```bash
flutter pub get
flutter run cronet:setup # Downloads the cronet binaries.
```

***Note for Android:** Remember to add the following permissions in `AndroidManifest.xml` file.
unsuitable001 marked this conversation as resolved.
Show resolved Hide resolved

```xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
```

You may also like to enable cleartext traffic by adding `android:usesCleartextTraffic="true"` to `AndroidManifest.xml` file.
unsuitable001 marked this conversation as resolved.
Show resolved Hide resolved

3. Import

```dart
Expand Down Expand Up @@ -56,8 +73,20 @@ Currently, 64 bit Desktop Platforms (Linux, Windows and MacOS) are supported.

## Run Example

### Flutter

```bash
cd example
cd example/flutter
flutter pub get
flutter run cronet:setup # Downloads the cronet binaries.
unsuitable001 marked this conversation as resolved.
Show resolved Hide resolved
flutter run
```

### Dart CLI

```bash
cd example/cli
dart pub get
dart run cronet:setup # Downloads the cronet binaries.
dart run
```
Expand Down Expand Up @@ -98,3 +127,5 @@ Note: Test results may get affected by: <https://github.com/google/cronet.dart/i
2. Run `dart run cronet:setup build` from the root of your project.

**Note for Windows:** Run `step 2` from `x64 Native Tools Command Prompt for VS 2019` shell.

**Note for Android:** Copy the produced jar files in `android/libs` and `.so` files in `android/src/main/jniLibs` subdirectory from the root of this package.
1 change: 1 addition & 0 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
include: package:lints/recommended.yaml

analyzer:
exclude: [example/flutter/**]
strong-mode:
implicit-casts: false
implicit-dynamic: false
Expand Down
8 changes: 8 additions & 0 deletions android/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
50 changes: 50 additions & 0 deletions android/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
group 'dev.google.cronet'
version '1.0-SNAPSHOT'

buildscript {
ext.kotlin_version = '1.3.50'
repositories {
google()
jcenter()
}

dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}

rootProject.allprojects {
repositories {
google()
jcenter()
}
}

apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'

android {
compileSdkVersion 30

sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}

externalNativeBuild {
// Encapsulates your CMake build configurations.
cmake {
// Provides a relative path to your CMake build script.
path "../src/CMakeLists.txt"
}
}

defaultConfig {
minSdkVersion 16
}
}

dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation files(fileTree(dir: 'libs', includes: ['*.jar']))
}
3 changes: 3 additions & 0 deletions android/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true
5 changes: 5 additions & 0 deletions android/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
1 change: 1 addition & 0 deletions android/settings.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rootProject.name = 'cronet'
5 changes: 5 additions & 0 deletions android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="dev.google.cronet">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>
41 changes: 41 additions & 0 deletions android/src/main/kotlin/dev/google/cronet/CronetPlugin.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package dev.google.cronet

import androidx.annotation.NonNull

import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.PluginRegistry.Registrar

import org.chromium.base.ContextUtils

/** CronetPlugin */
class CronetPlugin: FlutterPlugin, MethodCallHandler {
/// The MethodChannel that will the communication between Flutter and native Android
///
/// This local reference serves to register the plugin with the Flutter Engine and unregister it
/// when the Flutter Engine is detached from the Activity
private lateinit var channel : MethodChannel

override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
System.loadLibrary("cronet.86.0.4240.198")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we loading these in Kotlin rather than using DynamicLibrary.open?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we do not load it using Kotlin first, we get this error -

F/chromium(17045): [0418/210141.455792:FATAL:jni_android.cc(96)] Check failed: g_jvm. 

Though we're not using Platform Channel from our side in our package itself. Loading the library via Kotlin first then doing DynamicLibrary.open on Dart side fixes the issue. (I'm yet to figure out why this is happening though.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It sounds similar to this: flutter/flutter#73318

Lets just keep it for now and file an issue to look at it later.

System.loadLibrary("wrapper")
ContextUtils.initApplicationContext(flutterPluginBinding.applicationContext)
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "cronet")
channel.setMethodCallHandler(this)
}

override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
if (call.method == "getPlatformVersion") {
result.success("Android ${android.os.Build.VERSION.RELEASE}")
} else {
result.notImplemented()
}
}

override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
}
}
60 changes: 47 additions & 13 deletions bin/setup.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'package:args/command_runner.dart';
import 'package:cli_util/cli_logging.dart' show Ansi, Logger;
import 'package:cronet/src/constants.dart';
import 'package:cronet/src/third_party/ffigen/find_resource.dart';
import 'package:path/path.dart';

// Extracts a tar.gz file.
void extract(String fileName, [String dir = '']) {
Expand All @@ -28,13 +29,37 @@ void extract(String fileName, [String dir = '']) {
}
}

/// Places downloaded mobile binaries to proper location.
void placeMobileBinaries(String platform, String fileName) {
Directory(androidPaths['cronet.jar']!).createSync(recursive: true);
Directory(tempAndroidDownloadPath['cronet.jar']!).listSync().forEach((jar) {
if (jar is File) {
jar.renameSync(join(androidPaths['cronet.jar']!, basename(jar.path)));
}
});
Directory(androidPaths['cronet.so']!).createSync(recursive: true);
Directory(tempAndroidDownloadPath['cronet.so']!)
.listSync(recursive: true)
.forEach((cronet) {
if (cronet is File) {
Directory(join(androidPaths['cronet.so']!, basename(cronet.parent.path)))
.createSync(recursive: true);
cronet.renameSync(join(androidPaths['cronet.so']!,
basename(cronet.parent.path), basename(cronet.path)));
}
});
}

/// Places downloaded binaries to proper location.
void placeBinaries(String platform, String fileName) {
final logger = Logger.standard();
final ansi = Ansi(Ansi.terminalSupportsAnsi);
logger.stdout('${ansi.yellow}Extracting Cronet for $platform${ansi.none}');
Directory(binaryStorageDir).createSync(recursive: true);
extract(fileName, binaryStorageDir);
if (mobilePlatforms.contains(platform)) {
placeMobileBinaries(platform, fileName);
}
logger.stdout('Done! Cleaning up...');

File(fileName).deleteSync();
Expand Down Expand Up @@ -75,9 +100,10 @@ Future<void> downloadCronetBinaries(String platform) async {
String _makeBuildOutputPath(String buildFolderPath, String fileName,
{bool isDebug = false}) {
if (Platform.isWindows) {
return '$buildFolderPath\\out\\${Platform.operatingSystem}\\${isDebug ? "Debug" : "Release"}\\$fileName';
return join(buildFolderPath, 'out', Platform.operatingSystem,
isDebug ? 'Debug' : 'Release', fileName);
} else if (Platform.isMacOS || Platform.isLinux) {
return '$buildFolderPath/out/${Platform.operatingSystem}/$fileName';
return join(buildFolderPath, 'out', Platform.operatingSystem, fileName);
} else {
throw Exception('Unsupported Platform.');
}
Expand All @@ -95,7 +121,7 @@ void buildWrapper() {
final result = Process.runSync('cmake', [
'CMakeLists.txt',
'-B',
'out/${Platform.operatingSystem}',
join('out', Platform.operatingSystem),
'-DCMAKE_BUILD_TYPE=Release'
]);
print(result.stdout);
Expand All @@ -111,16 +137,20 @@ void buildWrapper() {
}
return;
}
var result = Process.runSync('cmake',
['--build', 'out/${Platform.operatingSystem}', '--config', 'Release']);
var result = Process.runSync('cmake', [
'--build',
join('out', Platform.operatingSystem),
'--config',
'Release'
]);
print(result.stdout);
print(result.stderr);
if (result.exitCode != 0) return;
Directory.current = pwd;
final moveLocation = '$binaryStorageDir${Platform.operatingSystem}64';
Directory(moveLocation).createSync(recursive: true);
final buildOutputPath = _makeBuildOutputPath(wrapperPath, getWrapperName());
File(buildOutputPath).copySync('$moveLocation/${getWrapperName()}');
File(buildOutputPath).copySync(join(moveLocation, getWrapperName()));
logger.stdout(
'${ansi.green}Wrapper moved to $moveLocation. Success!${ansi.none}');
return;
Expand All @@ -141,7 +171,7 @@ void verifyCronetBinary() {
final logger = Logger.standard();
final ansi = Ansi(Ansi.terminalSupportsAnsi);
final sampleSource = findPackageRoot()
.resolve('third_party/cronet_sample')
.resolve(join('third_party', 'cronet_sample'))
.toFilePath(windows: Platform.isWindows);
final buildName = _getCronetSampleBuildName();
final pwd = Directory.current;
Expand All @@ -153,29 +183,30 @@ void verifyCronetBinary() {

logger.stdout('Building Sample...');
var result = Process.runSync('cmake', [
'$sampleSource/CMakeLists.txt',
join(sampleSource, 'CMakeLists.txt'),
'-B',
'$sampleSource/out/${Platform.operatingSystem}'
join(sampleSource, 'out', Platform.operatingSystem)
], environment: {
'CURRENTDIR': pwd.path
});
print(result.stdout);
print(result.stderr);
result = Process.runSync(
'cmake', ['--build', '$sampleSource/out/${Platform.operatingSystem}'],
'cmake', ['--build', join(sampleSource, 'out', Platform.operatingSystem)],
environment: {'CURRENTDIR': pwd.path});
print(result.stdout);
print(result.stderr);
final buildOutputPath =
_makeBuildOutputPath(sampleSource, buildName, isDebug: true);

logger.stdout('Copying...');
final sample = File(buildOutputPath)
.copySync('.dart_tool/cronet/${Platform.operatingSystem}64/$buildName');
final sample = File(buildOutputPath).copySync(
join('.dart_tool', 'cronet', Platform.operatingSystem + '64', buildName));

logger.stdout('Verifying...');
result = Process.runSync(
'.dart_tool/cronet/${Platform.operatingSystem}64/$buildName', []);
join('.dart_tool', 'cronet', Platform.operatingSystem + '64', buildName),
[]);
if (result.exitCode == 0) {
logger.stdout('${ansi.green}Verified! Cronet is working fine.${ansi.none}');
} else {
Expand Down Expand Up @@ -238,6 +269,9 @@ Future<void> main(List<String> args) async {
if (validPlatforms.contains('${Platform.operatingSystem}64')) {
await downloadCronetBinaries('${Platform.operatingSystem}64');
}
if (Directory('android').existsSync()) {
await downloadCronetBinaries('android');
}
} else {
await runner.run(args);
}
Expand Down
3 changes: 2 additions & 1 deletion example/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
## Examples

- [Bare Minimum](https://github.com/google/cronet.dart#example)
- [Simple (Dart CLI)](https://github.com/google/cronet.dart/tree/main/example/)
- [Simple (Dart CLI)](https://github.com/google/cronet.dart/tree/main/example/cli)
- [Simple (Flutter)](https://github.com/google/cronet.dart/tree/main/example/flutter)
14 changes: 14 additions & 0 deletions example/cli/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.

include: package:lints/recommended.yaml

analyzer:
strong-mode:
implicit-casts: false
implicit-dynamic: false
linter:
rules:
- directives_ordering
- lines_longer_than_80_chars