diff --git a/.github/workflows/cronet.yml b/.github/workflows/cronet.yml
index 7bc1a4f089..0976a756ff 100644
--- a/.github/workflows/cronet.yml
+++ b/.github/workflows/cronet.yml
@@ -6,10 +6,12 @@ on:
- main
- master
paths:
+ - '.github/workflows/cronet.yaml'
- 'pkgs/cronet_http/**'
- 'pkgs/http_client_conformance_tests/**'
pull_request:
paths:
+ - '.github/workflows/cronet.yaml'
- 'pkgs/cronet_http/**'
- 'pkgs/http_client_conformance_tests/**'
schedule:
@@ -19,48 +21,48 @@ env:
PUB_ENVIRONMENT: bot.github
jobs:
- analyze:
- name: Lint and static analysis
- runs-on: ubuntu-latest
- defaults:
- run:
- working-directory: pkgs/cronet_http
+ verify:
+ name: Format & Analyze & Test
+ runs-on: macos-latest
+ strategy:
+ matrix:
+ package: ['cronet_http', 'cronet_http_embedded']
steps:
- uses: actions/checkout@v4
+ - uses: actions/setup-java@v4
+ with:
+ distribution: 'zulu'
+ java-version: '17'
- uses: subosito/flutter-action@v2
with:
- # TODO: Change to 'stable' when a release version of flutter
- # pins version 1.21.1 or later of 'package:test'
- channel: 'master'
+ channel: 'stable'
+ - name: Make cronet_http_embedded copy
+ if: ${{ matrix.package == 'cronet_http_embedded' }}
+ run: |
+ cp -r pkgs/cronet_http pkgs/cronet_http_embedded
+ cd pkgs/cronet_http_embedded
+ flutter pub get && dart tool/prepare_for_embedded.dart
- id: install
name: Install dependencies
+ working-directory: 'pkgs/${{ matrix.package }}'
run: flutter pub get
- name: Check formatting
+ working-directory: 'pkgs/${{ matrix.package }}'
run: dart format --output=none --set-exit-if-changed .
if: always() && steps.install.outcome == 'success'
- name: Analyze code
+ working-directory: 'pkgs/${{ matrix.package }}'
run: flutter analyze --fatal-infos
if: always() && steps.install.outcome == 'success'
-
- test:
- # Test package:cupertino_http use flutter integration tests.
- needs: analyze
- name: "Build and test"
- runs-on: macos-latest
- steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-java@v4
- with:
- distribution: 'zulu'
- java-version: '17'
- - uses: subosito/flutter-action@v2
- with:
- channel: 'stable'
- name: Run tests
uses: reactivecircus/android-emulator-runner@v2
+ if: always() && steps.install.outcome == 'success'
with:
+ # api-level/minSdkVersion should be help in sync in:
+ # - .github/workflows/cronet.yml
+ # - pkgs/cronet_http/android/build.gradle
+ # - pkgs/cronet_http/example/android/app/build.gradle
api-level: 28
- target: playstore
- arch: x86_64
+ target: ${{ matrix.package == 'cronet_http_embedded' && 'google_apis' || 'playstore' }}
profile: pixel
- script: cd ./pkgs/cronet_http/example && flutter test --timeout=1200s integration_test/
+ script: cd 'pkgs/${{ matrix.package }}/example' && flutter test --timeout=1200s integration_test/
diff --git a/pkgs/cronet_http/CHANGELOG.md b/pkgs/cronet_http/CHANGELOG.md
index 59ef74fe62..cf1fcbc208 100644
--- a/pkgs/cronet_http/CHANGELOG.md
+++ b/pkgs/cronet_http/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.0.0
+
+* No functional changes.
+
## 0.4.2
* Require `package:jni >= 0.7.2` to remove a potential buffer overflow.
diff --git a/pkgs/cronet_http/README.md b/pkgs/cronet_http/README.md
index 0238eb6d63..49acf3390d 100644
--- a/pkgs/cronet_http/README.md
+++ b/pkgs/cronet_http/README.md
@@ -1,31 +1,61 @@
+[![pub package](https://img.shields.io/pub/v/cronet_http.svg)](https://pub.dev/packages/cronet_http)
+[![package publisher](https://img.shields.io/pub/publisher/cronet_http.svg)](https://pub.dev/packages/cronet_http/publisher)
+
An Android Flutter plugin that provides access to the
-[Cronet](https://developer.android.com/guide/topics/connectivity/cronet/reference/org/chromium/net/package-summary)
+[Cronet][]
HTTP client.
Cronet is available as part of
-[Google Play Services](https://developers.google.com/android/guides/overview).
+[Google Play Services][].
-This package depends on
-[Google Play Services](https://developers.google.com/android/guides/overview)
-for its Cronet implementation.
+This package depends on [Google Play Services][] for its [Cronet][]
+implementation.
[`package:cronet_http_embedded`](https://pub.dev/packages/cronet_http_embedded)
-is functionally identical to this package but embeds Cronet directly instead
-of relying on
-[Google Play Services](https://developers.google.com/android/guides/overview).
-
-## Status: Experimental
-
-**NOTE**: This package is currently experimental and published under the
-[labs.dart.dev](https://dart.dev/dart-team-packages) pub publisher in order to
-solicit feedback.
-
-For packages in the labs.dart.dev publisher we generally plan to either graduate
-the package into a supported publisher (dart.dev, tools.dart.dev) after a period
-of feedback and iteration, or discontinue the package. These packages have a
-much higher expected rate of API and breaking changes.
-
-Your feedback is valuable and will help us evolve this package.
-For general feedback and suggestions please comment in the
-[feedback issue](https://github.com/dart-lang/http/issues/764).
-For bugs, please file an issue in the
-[bug tracker](https://github.com/dart-lang/http/issues).
+is functionally identical to this package but embeds [Cronet][] directly
+instead of relying on [Google Play Services][].
+
+## Motivation
+
+Using [Cronet][], rather than the socket-based [dart:io HttpClient][]
+implemententation, has several advantages:
+
+1. It automatically supports Android platform features such as HTTP proxies.
+2. It supports configurable caching.
+3. It supports more HTTP features such as HTTP/3.
+
+## Using
+
+The easiest way to use this library is via the the high-level interface
+defined by [package:http Client][].
+
+This approach allows the same HTTP code to be used on all platforms, while
+still allowing platform-specific setup.
+
+```dart
+import 'package:cronet_http/cronet_http.dart';
+import 'package:http/http.dart';
+import 'package:http/io_client.dart';
+
+void main() async {
+ late Client httpClient;
+ if (Platform.isAndroid) {
+ final engine = CronetEngine.build(
+ cacheMode: CacheMode.memory,
+ cacheMaxSize: 2 * 1024 * 1024,
+ userAgent: 'Book Agent');
+ httpClient = CronetClient.fromCronetEngine(engine);
+ } else {
+ httpClient = IOClient(HttpClient()..userAgent = 'Book Agent');
+ }
+
+ final response = await client.get(Uri.https(
+ 'www.googleapis.com',
+ '/books/v1/volumes',
+ {'q': 'HTTP', 'maxResults': '40', 'printType': 'books'}));
+}
+```
+
+[Cronet]: https://developer.android.com/guide/topics/connectivity/cronet/reference/org/chromium/net/package-summary
+[dart:io HttpClient]: https://api.dart.dev/stable/dart-io/HttpClient-class.html
+[Google Play Services]: https://developers.google.com/android/guides/overview
+[package:http Client]: https://pub.dev/documentation/http/latest/http/Client-class.html
diff --git a/pkgs/cronet_http/android/build.gradle b/pkgs/cronet_http/android/build.gradle
index 3a91d8a295..96bb197c73 100644
--- a/pkgs/cronet_http/android/build.gradle
+++ b/pkgs/cronet_http/android/build.gradle
@@ -2,14 +2,14 @@ group 'io.flutter.plugins.cronet_http'
version '1.0-SNAPSHOT'
buildscript {
- ext.kotlin_version = '1.6.10'
+ ext.kotlin_version = '1.7.21'
repositories {
google()
mavenCentral()
}
dependencies {
- classpath 'com.android.tools.build:gradle:7.1.2'
+ classpath 'com.android.tools.build:gradle:7.4.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
@@ -25,6 +25,11 @@ apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
android {
+ // Conditional for compatibility with AGP <4.2.
+ if (project.android.hasProperty("namespace")) {
+ namespace 'io.flutter.plugins.cronet_http'
+ }
+
compileSdkVersion 31
compileOptions {
@@ -41,7 +46,11 @@ android {
}
defaultConfig {
- minSdkVersion 16
+ // api-level/minSdkVersion should be help in sync in:
+ // - .github/workflows/cronet.yml
+ // - pkgs/cronet_http/android/build.gradle
+ // - pkgs/cronet_http/example/android/app/build.gradle
+ minSdkVersion 28
}
defaultConfig {
diff --git a/pkgs/cronet_http/example/android/app/build.gradle b/pkgs/cronet_http/example/android/app/build.gradle
index 88b33564c3..1f7cd94749 100644
--- a/pkgs/cronet_http/example/android/app/build.gradle
+++ b/pkgs/cronet_http/example/android/app/build.gradle
@@ -46,7 +46,11 @@ android {
applicationId "io.flutter.cronet_http_example"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
- minSdkVersion flutter.minSdkVersion
+ // api-level/minSdkVersion should be help in sync in:
+ // - .github/workflows/cronet.yml
+ // - pkgs/cronet_http/android/build.gradle
+ // - pkgs/cronet_http/example/android/app/build.gradle
+ minSdkVersion 28
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
diff --git a/pkgs/cronet_http/example/android/app/src/debug/AndroidManifest.xml b/pkgs/cronet_http/example/android/app/src/debug/AndroidManifest.xml
index b17be9f3cb..6170951031 100644
--- a/pkgs/cronet_http/example/android/app/src/debug/AndroidManifest.xml
+++ b/pkgs/cronet_http/example/android/app/src/debug/AndroidManifest.xml
@@ -1,4 +1,4 @@
+ package="io.flutter.cronet_http_example">
diff --git a/pkgs/cronet_http/example/android/app/src/main/AndroidManifest.xml b/pkgs/cronet_http/example/android/app/src/main/AndroidManifest.xml
index e8d5f3f208..254760d3ed 100644
--- a/pkgs/cronet_http/example/android/app/src/main/AndroidManifest.xml
+++ b/pkgs/cronet_http/example/android/app/src/main/AndroidManifest.xml
@@ -1,5 +1,5 @@
+ package="io.flutter.cronet_http_example">
+ package="io.flutter.cronet_http_example">
diff --git a/pkgs/cronet_http/example/android/build.gradle b/pkgs/cronet_http/example/android/build.gradle
index 83ae220041..954fa1cd5c 100644
--- a/pkgs/cronet_http/example/android/build.gradle
+++ b/pkgs/cronet_http/example/android/build.gradle
@@ -1,12 +1,12 @@
buildscript {
- ext.kotlin_version = '1.6.10'
+ ext.kotlin_version = '1.7.21'
repositories {
google()
mavenCentral()
}
dependencies {
- classpath 'com.android.tools.build:gradle:7.1.2'
+ classpath 'com.android.tools.build:gradle:7.4.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
@@ -26,6 +26,6 @@ subprojects {
project.evaluationDependsOn(':app')
}
-task clean(type: Delete) {
+tasks.register("clean", Delete) {
delete rootProject.buildDir
}
diff --git a/pkgs/cronet_http/example/android/gradle/wrapper/gradle-wrapper.properties b/pkgs/cronet_http/example/android/gradle/wrapper/gradle-wrapper.properties
index cc5527d781..cfe88f6904 100644
--- a/pkgs/cronet_http/example/android/gradle/wrapper/gradle-wrapper.properties
+++ b/pkgs/cronet_http/example/android/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-all.zip
diff --git a/pkgs/cronet_http/pubspec.yaml b/pkgs/cronet_http/pubspec.yaml
index 602a1bbfd5..5f4229ebf8 100644
--- a/pkgs/cronet_http/pubspec.yaml
+++ b/pkgs/cronet_http/pubspec.yaml
@@ -1,5 +1,5 @@
name: cronet_http
-version: 0.4.2
+version: 1.0.0
description: >-
An Android Flutter plugin that provides access to the Cronet HTTP client.
repository: https://github.com/dart-lang/http/tree/master/pkgs/cronet_http
diff --git a/pkgs/cronet_http/tool/prepare_for_embedded.dart b/pkgs/cronet_http/tool/prepare_for_embedded.dart
index e0f99d7a23..3442bc6843 100644
--- a/pkgs/cronet_http/tool/prepare_for_embedded.dart
+++ b/pkgs/cronet_http/tool/prepare_for_embedded.dart
@@ -13,6 +13,9 @@
/// 1. Modifying the Gradle build file to reference the embedded Cronet.
/// 2. Modifying the *name* and *description* in `pubspec.yaml`.
/// 3. Replacing `README.md` with `README_EMBEDDED.md`.
+/// 4. Change the name of `cronet_http.dart` to `cronet_http_embedded.dart`.
+/// 5. Update all the imports from `package:cronet_http/cronet_http.dart` to
+/// `package:cronet_http_embedded/cronet_http_embedded.dart`
///
/// After running this script, `flutter pub publish`
/// can be run to update package:cronet_http_embedded.
@@ -40,7 +43,7 @@ final _cronetVersionUri = Uri.https(
'android/maven2/org/chromium/net/group-index.xml',
);
-void main() async {
+void main(List args) async {
if (Directory.current.path.endsWith('tool')) {
_packageDirectory = Directory.current.parent;
} else {
@@ -51,6 +54,8 @@ void main() async {
updateCronetDependency(latestVersion);
updatePubSpec();
updateReadme();
+ updateLibraryName();
+ updateImports();
}
Future _getLatestCronetVersion() async {
@@ -69,7 +74,7 @@ Future _getLatestCronetVersion() async {
return versions.last;
}
-/// Update android/build.gradle
+/// Update android/build.gradle.
void updateCronetDependency(String latestVersion) {
final fBuildGradle = File('${_packageDirectory.path}/android/build.gradle');
final gradleContent = fBuildGradle.readAsStringSync();
@@ -88,18 +93,48 @@ void updateCronetDependency(String latestVersion) {
fBuildGradle.writeAsStringSync(newGradleContent);
}
-/// Update pubspec.yaml
+/// Update pubspec.yaml and example/pubspec.yaml.
void updatePubSpec() {
+ print('Updating pubspec.yaml');
final fPubspec = File('${_packageDirectory.path}/pubspec.yaml');
final yamlEditor = YamlEditor(fPubspec.readAsStringSync())
..update(['name'], _packageName)
..update(['description'], _packageDescription);
fPubspec.writeAsStringSync(yamlEditor.toString());
+ print('Updating example/pubspec.yaml');
+ final examplePubspec = File('${_packageDirectory.path}/example/pubspec.yaml');
+ final replaced = examplePubspec
+ .readAsStringSync()
+ .replaceAll('cronet_http:', 'cronet_http_embedded:');
+ examplePubspec.writeAsStringSync(replaced);
}
-/// Move README_EMBEDDED.md to replace README.md
+/// Move README_EMBEDDED.md to replace README.md.
void updateReadme() {
+ print('Updating README.md from README_EMBEDDED.md');
File('${_packageDirectory.path}/README.md').deleteSync();
File('${_packageDirectory.path}/README_EMBEDDED.md')
.renameSync('${_packageDirectory.path}/README.md');
}
+
+void updateImports() {
+ print('Updating imports in Dart files');
+ for (final file in _packageDirectory.listSync(recursive: true)) {
+ if (file is File && file.path.endsWith('.dart')) {
+ final updatedSource = file.readAsStringSync().replaceAll(
+ 'package:cronet_http/cronet_http.dart',
+ 'package:cronet_http_embedded/cronet_http_embedded.dart',
+ );
+ file.writeAsStringSync(updatedSource);
+ }
+ }
+}
+
+void updateLibraryName() {
+ print('Renaming cronet_http.dart to cronet_http_embedded.dart');
+ File(
+ '${_packageDirectory.path}/lib/cronet_http.dart',
+ ).renameSync(
+ '${_packageDirectory.path}/lib/cronet_http_embedded.dart',
+ );
+}
diff --git a/pkgs/cupertino_http/CHANGELOG.md b/pkgs/cupertino_http/CHANGELOG.md
index 47e25cb590..d768f7a5c7 100644
--- a/pkgs/cupertino_http/CHANGELOG.md
+++ b/pkgs/cupertino_http/CHANGELOG.md
@@ -1,4 +1,4 @@
-## 1.2.0-wip
+## 1.2.0
* Add support for setting additional http headers in
`URLSessionConfiguration`.
diff --git a/pkgs/cupertino_http/pubspec.yaml b/pkgs/cupertino_http/pubspec.yaml
index 81905aa87e..0a97bdd25d 100644
--- a/pkgs/cupertino_http/pubspec.yaml
+++ b/pkgs/cupertino_http/pubspec.yaml
@@ -1,5 +1,5 @@
name: cupertino_http
-version: 1.2.0-wip
+version: 1.2.0
description: >-
A macOS/iOS Flutter plugin that provides access to the Foundation URL
Loading System.
diff --git a/pkgs/http/CHANGELOG.md b/pkgs/http/CHANGELOG.md
index 9bbbb05a2d..7b8dec4fdd 100644
--- a/pkgs/http/CHANGELOG.md
+++ b/pkgs/http/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.1.3-wip
+
+* Add `MockClient.pngResponse`, which makes it easier to fake image responses.
+
## 1.1.2
* Allow `web: '>=0.3.0 <0.5.0'`.
diff --git a/pkgs/http/lib/src/mock_client.dart b/pkgs/http/lib/src/mock_client.dart
index bf2df40ee7..52f108a577 100644
--- a/pkgs/http/lib/src/mock_client.dart
+++ b/pkgs/http/lib/src/mock_client.dart
@@ -2,6 +2,8 @@
// 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.
+import 'dart:convert';
+
import 'base_client.dart';
import 'base_request.dart';
import 'byte_stream.dart';
@@ -10,6 +12,11 @@ import 'response.dart';
import 'streamed_request.dart';
import 'streamed_response.dart';
+final _pngImageData = base64Decode(
+ 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDw'
+ 'AEhQGAhKmMIQAAAABJRU5ErkJggg==',
+);
+
// TODO(nweiz): once Dart has some sort of Rack- or WSGI-like standard for
// server APIs, MockClient should conform to it.
@@ -69,6 +76,17 @@ class MockClient extends BaseClient {
var bodyStream = request.finalize();
return await _handler(request, bodyStream);
}
+
+ /// Return a response containing a PNG image.
+ static Response pngResponse({BaseRequest? request}) {
+ final headers = {
+ 'content-type': 'image/png',
+ 'content-length': '${_pngImageData.length}'
+ };
+
+ return Response.bytes(_pngImageData, 200,
+ request: request, headers: headers, reasonPhrase: 'OK');
+ }
}
/// A handler function that receives [StreamedRequest]s and sends
diff --git a/pkgs/http/pubspec.yaml b/pkgs/http/pubspec.yaml
index 118292fa13..1645f96048 100644
--- a/pkgs/http/pubspec.yaml
+++ b/pkgs/http/pubspec.yaml
@@ -1,5 +1,5 @@
name: http
-version: 1.1.2
+version: 1.1.3-wip
description: A composable, multi-platform, Future-based API for HTTP requests.
repository: https://github.com/dart-lang/http/tree/master/pkgs/http
diff --git a/pkgs/http/test/mock_client_test.dart b/pkgs/http/test/mock_client_test.dart
index db561c51d6..625285cb33 100644
--- a/pkgs/http/test/mock_client_test.dart
+++ b/pkgs/http/test/mock_client_test.dart
@@ -5,6 +5,7 @@
import 'dart:convert';
import 'package:http/http.dart' as http;
+import 'package:http/src/request.dart';
import 'package:http/testing.dart';
import 'package:test/test.dart';
@@ -43,4 +44,25 @@ void main() {
expect(await client.read(Uri.http('example.com', '/foo')),
equals('you did it'));
});
+
+ test('pngResponse with default options', () {
+ final response = MockClient.pngResponse();
+ expect(response.statusCode, 200);
+ expect(response.bodyBytes.take(8),
+ [137, 80, 78, 71, 13, 10, 26, 10] // PNG header
+ );
+ expect(response.request, null);
+ expect(response.headers, containsPair('content-type', 'image/png'));
+ });
+
+ test('pngResponse with request', () {
+ final request = Request('GET', Uri.https('example.com'));
+ final response = MockClient.pngResponse(request: request);
+ expect(response.statusCode, 200);
+ expect(response.bodyBytes.take(8),
+ [137, 80, 78, 71, 13, 10, 26, 10] // PNG header
+ );
+ expect(response.request, request);
+ expect(response.headers, containsPair('content-type', 'image/png'));
+ });
}