mirror of
https://github.com/rive-app/rive-flutter.git
synced 2025-06-22 06:02:11 +08:00
Add setting custom headers
adding pr from the community https://github.com/rive-app/rive-flutter/pull/314, including an update to how we make sure credits for contributions are kept when our mono scripts merge changes upstream. Some companies don't let the rive file URLs without authentication, that's why they need to send headers in the network request. Example of how to use: ``` RiveAnimation.network( 'https://cdn.rive.app/animations/vehicles.riv', headers: {'Authorization': '{token}'}, ) ``` The same idea is in the [flutter_svg package](https://pub.dev/documentation/flutter_svg/latest/svg/SvgPicture/SvgPicture.network.html) Diffs= c163c1a7f Add setting custom headers (#5327) Co-authored-by: Ahmed Wahba <a.tarek360@gmail.com> Co-authored-by: Maxwell Talbot <talbot.maxwell@gmail.com>
This commit is contained in:
@ -1 +1 @@
|
||||
cae6fa5ccfb6029614e6306d443a2039d1f0657c
|
||||
c163c1a7fe5a8d26506c439e686716b4131f6ffe
|
||||
|
@ -1,3 +1,7 @@
|
||||
## 0.11.2
|
||||
|
||||
- Add parameter to specifcy headers on RiveAnimation.network widget
|
||||
|
||||
## 0.11.1
|
||||
|
||||
- Joysticks with custom handle sources.
|
||||
|
@ -277,8 +277,8 @@ class RiveFile {
|
||||
/// your file contains images that needed to be loaded with separate network
|
||||
/// requests.
|
||||
static Future<RiveFile> network(String url,
|
||||
{FileAssetResolver? assetResolver}) async {
|
||||
final res = await http.get(Uri.parse(url));
|
||||
{FileAssetResolver? assetResolver, Map<String, String>? headers}) async {
|
||||
final res = await http.get(Uri.parse(url), headers: headers);
|
||||
final bytes = ByteData.view(res.bodyBytes.buffer);
|
||||
return RiveFile.import(bytes, assetResolver: assetResolver);
|
||||
}
|
||||
|
@ -55,6 +55,9 @@ class RiveAnimation extends StatefulWidget {
|
||||
/// Callback fired when [RiveAnimation] has initialized
|
||||
final OnInitCallback? onInit;
|
||||
|
||||
/// Headers for network requests
|
||||
final Map<String, String>? headers;
|
||||
|
||||
/// Creates a new [RiveAnimation] from an asset bundle.
|
||||
///
|
||||
/// *Example:*
|
||||
@ -75,6 +78,7 @@ class RiveAnimation extends StatefulWidget {
|
||||
Key? key,
|
||||
}) : name = asset,
|
||||
file = null,
|
||||
headers = null,
|
||||
src = _Source.asset,
|
||||
super(key: key);
|
||||
|
||||
@ -95,6 +99,7 @@ class RiveAnimation extends StatefulWidget {
|
||||
this.antialiasing = true,
|
||||
this.controllers = const [],
|
||||
this.onInit,
|
||||
this.headers,
|
||||
Key? key,
|
||||
}) : name = url,
|
||||
file = null,
|
||||
@ -121,6 +126,7 @@ class RiveAnimation extends StatefulWidget {
|
||||
Key? key,
|
||||
}) : name = path,
|
||||
file = null,
|
||||
headers = null,
|
||||
src = _Source.file,
|
||||
super(key: key);
|
||||
|
||||
@ -145,6 +151,7 @@ class RiveAnimation extends StatefulWidget {
|
||||
this.onInit,
|
||||
Key? key,
|
||||
}) : name = null,
|
||||
headers = null,
|
||||
src = _Source.direct,
|
||||
super(key: key);
|
||||
|
||||
@ -182,7 +189,7 @@ class RiveAnimationState extends State<RiveAnimation> {
|
||||
case _Source.asset:
|
||||
return RiveFile.asset(widget.name!);
|
||||
case _Source.network:
|
||||
return RiveFile.network(widget.name!);
|
||||
return RiveFile.network(widget.name!, headers: widget.headers);
|
||||
case _Source.file:
|
||||
return RiveFile.file(widget.name!);
|
||||
case _Source.direct:
|
||||
|
@ -1,5 +1,5 @@
|
||||
name: rive
|
||||
version: 0.11.1
|
||||
version: 0.11.2
|
||||
homepage: https://rive.app
|
||||
description: Rive 2 Flutter Runtime. This package provides runtime functionality for playing back and interacting with animations built with the Rive editor available at https://rive.app.
|
||||
repository: https://github.com/rive-app/rive-flutter
|
||||
|
80
test/rive_network_test.dart
Normal file
80
test/rive_network_test.dart
Normal file
@ -0,0 +1,80 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
import 'package:rive/rive.dart';
|
||||
|
||||
import 'mocks/mocks.dart';
|
||||
import 'src/utils.dart';
|
||||
|
||||
class MockHttpClient extends Mock implements HttpClient {}
|
||||
|
||||
class MockHttpClientRequest extends Mock implements HttpClientRequest {}
|
||||
|
||||
class MockHttpClientResponse extends Mock implements HttpClientResponse {}
|
||||
|
||||
class MockHttpHeaders extends Mock implements HttpHeaders {}
|
||||
|
||||
void main() {
|
||||
late MockHttpClient mockHttpClient;
|
||||
late MockHttpClientRequest request;
|
||||
setUpAll(() {
|
||||
registerFallbackValue(ArtboardFake());
|
||||
registerFallbackValue(Uri());
|
||||
registerFallbackValue(Stream.value(<int>[]));
|
||||
// Build our app and trigger a frame.
|
||||
final riveBytes = loadFile('assets/rive-flutter-test-asset.riv');
|
||||
final body = riveBytes.buffer.asUint8List();
|
||||
mockHttpClient = MockHttpClient();
|
||||
request = MockHttpClientRequest();
|
||||
|
||||
when(() => request.headers).thenReturn(MockHttpHeaders());
|
||||
|
||||
when(() => mockHttpClient.openUrl(any(), any())).thenAnswer((invocation) {
|
||||
final response = MockHttpClientResponse();
|
||||
when(request.close).thenAnswer((_) => Future.value(response));
|
||||
when(() => request.addStream(any())).thenAnswer((_) async => null);
|
||||
when(() => response.headers).thenReturn(MockHttpHeaders());
|
||||
when(() => response.handleError(any(), test: any(named: 'test')))
|
||||
.thenAnswer((_) => Stream.value(body));
|
||||
when(() => response.statusCode).thenReturn(200);
|
||||
when(() => response.reasonPhrase).thenReturn('OK');
|
||||
when(() => response.contentLength).thenReturn(body.length);
|
||||
when(() => response.isRedirect).thenReturn(false);
|
||||
when(() => response.persistentConnection).thenReturn(false);
|
||||
return Future.value(request);
|
||||
});
|
||||
});
|
||||
|
||||
testWidgets('Using the network, calls the http client without headers',
|
||||
(WidgetTester tester) async {
|
||||
await HttpOverrides.runZoned(() async {
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: RiveAnimation.network('https://some.fake.url'),
|
||||
),
|
||||
);
|
||||
}, createHttpClient: (_) => mockHttpClient);
|
||||
|
||||
verify(() => mockHttpClient.openUrl(any(), any())).called(1);
|
||||
verifyNever(() => request.headers.set(any(), any()));
|
||||
});
|
||||
|
||||
testWidgets('Using the network, calls the http client with headers',
|
||||
(WidgetTester tester) async {
|
||||
await HttpOverrides.runZoned(() async {
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: RiveAnimation.network('https://some.fake.url', headers: {
|
||||
'first': 'header',
|
||||
'second': 'header',
|
||||
}),
|
||||
),
|
||||
);
|
||||
}, createHttpClient: (_) => mockHttpClient);
|
||||
|
||||
verify(() => mockHttpClient.openUrl(any(), any())).called(1);
|
||||
verify(() => request.headers.set(any(), any())).called(2);
|
||||
});
|
||||
}
|
Reference in New Issue
Block a user