Skip to content

Commit 76b43e1

Browse files
mjtalbottarek360mjtalbot
committed
Add setting custom headers
adding pr from the community #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>
1 parent 58c9989 commit 76b43e1

File tree

6 files changed

+96
-5
lines changed

6 files changed

+96
-5
lines changed

.rive_head

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
cae6fa5ccfb6029614e6306d443a2039d1f0657c
1+
c163c1a7fe5a8d26506c439e686716b4131f6ffe

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.11.2
2+
3+
- Add parameter to specifcy headers on RiveAnimation.network widget
4+
15
## 0.11.1
26

37
- Joysticks with custom handle sources.

lib/src/rive_file.dart

+2-2
Original file line numberDiff line numberDiff line change
@@ -277,8 +277,8 @@ class RiveFile {
277277
/// your file contains images that needed to be loaded with separate network
278278
/// requests.
279279
static Future<RiveFile> network(String url,
280-
{FileAssetResolver? assetResolver}) async {
281-
final res = await http.get(Uri.parse(url));
280+
{FileAssetResolver? assetResolver, Map<String, String>? headers}) async {
281+
final res = await http.get(Uri.parse(url), headers: headers);
282282
final bytes = ByteData.view(res.bodyBytes.buffer);
283283
return RiveFile.import(bytes, assetResolver: assetResolver);
284284
}

lib/src/widgets/rive_animation.dart

+8-1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ class RiveAnimation extends StatefulWidget {
5555
/// Callback fired when [RiveAnimation] has initialized
5656
final OnInitCallback? onInit;
5757

58+
/// Headers for network requests
59+
final Map<String, String>? headers;
60+
5861
/// Creates a new [RiveAnimation] from an asset bundle.
5962
///
6063
/// *Example:*
@@ -75,6 +78,7 @@ class RiveAnimation extends StatefulWidget {
7578
Key? key,
7679
}) : name = asset,
7780
file = null,
81+
headers = null,
7882
src = _Source.asset,
7983
super(key: key);
8084

@@ -95,6 +99,7 @@ class RiveAnimation extends StatefulWidget {
9599
this.antialiasing = true,
96100
this.controllers = const [],
97101
this.onInit,
102+
this.headers,
98103
Key? key,
99104
}) : name = url,
100105
file = null,
@@ -121,6 +126,7 @@ class RiveAnimation extends StatefulWidget {
121126
Key? key,
122127
}) : name = path,
123128
file = null,
129+
headers = null,
124130
src = _Source.file,
125131
super(key: key);
126132

@@ -145,6 +151,7 @@ class RiveAnimation extends StatefulWidget {
145151
this.onInit,
146152
Key? key,
147153
}) : name = null,
154+
headers = null,
148155
src = _Source.direct,
149156
super(key: key);
150157

@@ -182,7 +189,7 @@ class RiveAnimationState extends State<RiveAnimation> {
182189
case _Source.asset:
183190
return RiveFile.asset(widget.name!);
184191
case _Source.network:
185-
return RiveFile.network(widget.name!);
192+
return RiveFile.network(widget.name!, headers: widget.headers);
186193
case _Source.file:
187194
return RiveFile.file(widget.name!);
188195
case _Source.direct:

pubspec.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: rive
2-
version: 0.11.1
2+
version: 0.11.2
33
homepage: https://rive.app
44
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.
55
repository: https://github.com/rive-app/rive-flutter

test/rive_network_test.dart

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import 'dart:io';
2+
3+
import 'package:flutter/material.dart';
4+
import 'package:flutter_test/flutter_test.dart';
5+
import 'package:mocktail/mocktail.dart';
6+
import 'package:rive/rive.dart';
7+
8+
import 'mocks/mocks.dart';
9+
import 'src/utils.dart';
10+
11+
class MockHttpClient extends Mock implements HttpClient {}
12+
13+
class MockHttpClientRequest extends Mock implements HttpClientRequest {}
14+
15+
class MockHttpClientResponse extends Mock implements HttpClientResponse {}
16+
17+
class MockHttpHeaders extends Mock implements HttpHeaders {}
18+
19+
void main() {
20+
late MockHttpClient mockHttpClient;
21+
late MockHttpClientRequest request;
22+
setUpAll(() {
23+
registerFallbackValue(ArtboardFake());
24+
registerFallbackValue(Uri());
25+
registerFallbackValue(Stream.value(<int>[]));
26+
// Build our app and trigger a frame.
27+
final riveBytes = loadFile('assets/rive-flutter-test-asset.riv');
28+
final body = riveBytes.buffer.asUint8List();
29+
mockHttpClient = MockHttpClient();
30+
request = MockHttpClientRequest();
31+
32+
when(() => request.headers).thenReturn(MockHttpHeaders());
33+
34+
when(() => mockHttpClient.openUrl(any(), any())).thenAnswer((invocation) {
35+
final response = MockHttpClientResponse();
36+
when(request.close).thenAnswer((_) => Future.value(response));
37+
when(() => request.addStream(any())).thenAnswer((_) async => null);
38+
when(() => response.headers).thenReturn(MockHttpHeaders());
39+
when(() => response.handleError(any(), test: any(named: 'test')))
40+
.thenAnswer((_) => Stream.value(body));
41+
when(() => response.statusCode).thenReturn(200);
42+
when(() => response.reasonPhrase).thenReturn('OK');
43+
when(() => response.contentLength).thenReturn(body.length);
44+
when(() => response.isRedirect).thenReturn(false);
45+
when(() => response.persistentConnection).thenReturn(false);
46+
return Future.value(request);
47+
});
48+
});
49+
50+
testWidgets('Using the network, calls the http client without headers',
51+
(WidgetTester tester) async {
52+
await HttpOverrides.runZoned(() async {
53+
await tester.pumpWidget(
54+
const MaterialApp(
55+
home: RiveAnimation.network('https://some.fake.url'),
56+
),
57+
);
58+
}, createHttpClient: (_) => mockHttpClient);
59+
60+
verify(() => mockHttpClient.openUrl(any(), any())).called(1);
61+
verifyNever(() => request.headers.set(any(), any()));
62+
});
63+
64+
testWidgets('Using the network, calls the http client with headers',
65+
(WidgetTester tester) async {
66+
await HttpOverrides.runZoned(() async {
67+
await tester.pumpWidget(
68+
const MaterialApp(
69+
home: RiveAnimation.network('https://some.fake.url', headers: {
70+
'first': 'header',
71+
'second': 'header',
72+
}),
73+
),
74+
);
75+
}, createHttpClient: (_) => mockHttpClient);
76+
77+
verify(() => mockHttpClient.openUrl(any(), any())).called(1);
78+
verify(() => request.headers.set(any(), any())).called(2);
79+
});
80+
}

0 commit comments

Comments
 (0)