mirror of
https://github.com/rive-app/rive-flutter.git
synced 2025-06-22 23:07:49 +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
|
## 0.11.1
|
||||||
|
|
||||||
- Joysticks with custom handle sources.
|
- Joysticks with custom handle sources.
|
||||||
|
@ -277,8 +277,8 @@ class RiveFile {
|
|||||||
/// your file contains images that needed to be loaded with separate network
|
/// your file contains images that needed to be loaded with separate network
|
||||||
/// requests.
|
/// requests.
|
||||||
static Future<RiveFile> network(String url,
|
static Future<RiveFile> network(String url,
|
||||||
{FileAssetResolver? assetResolver}) async {
|
{FileAssetResolver? assetResolver, Map<String, String>? headers}) async {
|
||||||
final res = await http.get(Uri.parse(url));
|
final res = await http.get(Uri.parse(url), headers: headers);
|
||||||
final bytes = ByteData.view(res.bodyBytes.buffer);
|
final bytes = ByteData.view(res.bodyBytes.buffer);
|
||||||
return RiveFile.import(bytes, assetResolver: assetResolver);
|
return RiveFile.import(bytes, assetResolver: assetResolver);
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,9 @@ class RiveAnimation extends StatefulWidget {
|
|||||||
/// Callback fired when [RiveAnimation] has initialized
|
/// Callback fired when [RiveAnimation] has initialized
|
||||||
final OnInitCallback? onInit;
|
final OnInitCallback? onInit;
|
||||||
|
|
||||||
|
/// Headers for network requests
|
||||||
|
final Map<String, String>? headers;
|
||||||
|
|
||||||
/// Creates a new [RiveAnimation] from an asset bundle.
|
/// Creates a new [RiveAnimation] from an asset bundle.
|
||||||
///
|
///
|
||||||
/// *Example:*
|
/// *Example:*
|
||||||
@ -75,6 +78,7 @@ class RiveAnimation extends StatefulWidget {
|
|||||||
Key? key,
|
Key? key,
|
||||||
}) : name = asset,
|
}) : name = asset,
|
||||||
file = null,
|
file = null,
|
||||||
|
headers = null,
|
||||||
src = _Source.asset,
|
src = _Source.asset,
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
@ -95,6 +99,7 @@ class RiveAnimation extends StatefulWidget {
|
|||||||
this.antialiasing = true,
|
this.antialiasing = true,
|
||||||
this.controllers = const [],
|
this.controllers = const [],
|
||||||
this.onInit,
|
this.onInit,
|
||||||
|
this.headers,
|
||||||
Key? key,
|
Key? key,
|
||||||
}) : name = url,
|
}) : name = url,
|
||||||
file = null,
|
file = null,
|
||||||
@ -121,6 +126,7 @@ class RiveAnimation extends StatefulWidget {
|
|||||||
Key? key,
|
Key? key,
|
||||||
}) : name = path,
|
}) : name = path,
|
||||||
file = null,
|
file = null,
|
||||||
|
headers = null,
|
||||||
src = _Source.file,
|
src = _Source.file,
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
@ -145,6 +151,7 @@ class RiveAnimation extends StatefulWidget {
|
|||||||
this.onInit,
|
this.onInit,
|
||||||
Key? key,
|
Key? key,
|
||||||
}) : name = null,
|
}) : name = null,
|
||||||
|
headers = null,
|
||||||
src = _Source.direct,
|
src = _Source.direct,
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
@ -182,7 +189,7 @@ class RiveAnimationState extends State<RiveAnimation> {
|
|||||||
case _Source.asset:
|
case _Source.asset:
|
||||||
return RiveFile.asset(widget.name!);
|
return RiveFile.asset(widget.name!);
|
||||||
case _Source.network:
|
case _Source.network:
|
||||||
return RiveFile.network(widget.name!);
|
return RiveFile.network(widget.name!, headers: widget.headers);
|
||||||
case _Source.file:
|
case _Source.file:
|
||||||
return RiveFile.file(widget.name!);
|
return RiveFile.file(widget.name!);
|
||||||
case _Source.direct:
|
case _Source.direct:
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
name: rive
|
name: rive
|
||||||
version: 0.11.1
|
version: 0.11.2
|
||||||
homepage: https://rive.app
|
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.
|
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
|
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