Update
Making HTTP requests to the Twitch API is fairly easy. You have to register your application on the Twitch dev console. This will grant you access to both a client id
and a client secret
. Refer to the documentation for a detailed guide.
With those two, you can make a request which generates an app access token
. Getting a video id is simply hitting a different endpoint. It requires a game id and/or user id as per the documentation
URL
GET https://api.twitch.tv/helix/videos
Required Query Parameters
Each request must specify one or more video ids, one user_id, or one
game_id.
In the example below I generated an app access token, using my own client id and secret. Got a game id from another endpoint and finally retrieved a video id from the game id.
class TwitchAPIService {
// Making a singleton pattern ensures only one instance of a class is ever created
TwitchAPIService._internal();
static final TwitchAPIService _twitchAPIService = TwitchAPIService._internal();
static TwitchAPIService get twitchAPIService => _twitchAPIService;
String twitchClientID, twitchClientSecret; // This are to be gotten from the Twitch developer console
Future<String> fetchAppAccessToken() async {
final baseUrl = 'id.twitch.tv';
Map<String, String> parameters = {
'client_id': twitchClientID,
'client_secret': twitchClientSecret,
'grant_type': 'client_credentials',
};
Map<String, String> headers = {
'Accept': 'application/json',
};
Uri uri = Uri.https(baseUrl, '/oauth2/token', parameters);
var token;
try {
token = await http.post(uri, headers: headers);
if (token.statusCode == 200) {
// Make secure requests with the token.
return token.body;
}
return json.decode(token.body)['message'];
} catch (e) {
return json.decode(token.body)['message'];
}
}
// This gets the game Id of any given game under Twitch's game library
Future<String> fetchGameId(String token) async {
final baseUrl = 'api.twitch.tv';
Map<String, String> parameters = {
'name': 'fortnite',
};
Map<String, String> headers = {
'Accept': 'application/json',
'Authorization': 'Bearer $token',
'Client-id': twitchClientID,
};
Uri uri = Uri.https(baseUrl, '/helix/games', parameters);
try {
var gameId = await http.get(uri, headers: headers);
return gameId.body;
} catch (e) {
return e.toString();
}
}
// This retrieves videoId(s) under a particular gameId
Future<dynamic> fetchVideoId(String gameId) async {
final baseUrl = 'api.twitch.tv';
Map<String, String> parameters = {
'game_id': gameId,
};
Map<String, String> headers = {
'Accept': 'application/json',
'Authorization': 'Bearer 4aq6y8pqjyw7cc9x4o8el7zha1ua8u',
'Client-id': twitchClientID,
};
Uri uri = Uri.https(baseUrl, '/helix/videos', parameters);
try {
var videoId = await http.get(uri, headers: headers);
return videoId.body;
} catch (e) {
return e.toString();
}
}
}
A Hacked Solution
The Twitch API offers various services, such as getting streams, channel details and so much more. I'll cut right to the chase and assume you have already set up your Twitch developer account here.
Note:
In regards to your question, you don't have to have an active developer account. Although if you want to use other services like the ones mentioned above, you would need a form of Authentication hence a Twitch developer account.
Prerequisite
- A WebView package preferably Flutter Inappwebview.
- A Twitch channel name or video ID. This can be hardcoded or gotten dynamically using the Twitch API. The idle way to getting it should be the latter. For the sake of this answer, I have a random video ID below.
- A deployed website bundled with a ssl certificate ( Optional ).
Please point 3 is strongly required. Usually, most developers would just directly save the html content locally in a html file or even directly write it out in dart files.
According to this thread, this will not work. The embedded Twitch player will only work over a localhost and/or a website coupled with a ssl certificate. Some hosting services automatically bundle any deployed website with a ssl certificate. I am very sure Firebase Hosting does this.
You can skip this part since, testing locally is supported.
Other things to keep in mind
Local development
Use “localhost” or any IP address in the “127.0.0.1/8” range as the
parent value to use either HTTP or HTTPS in local development. Any
port can be used, though this does not need to be specified anywhere
(80, 3000, 8100, etc) Local development over other IP ranges (e.g.
192.1.1.1) must adhere to the HTTPS requirement, though a valid certificate is not required
Now unto the codebase.
Create an index.html file which would contain the Official Iframe Player.
<!DOCTYPE html>
<html>
<head>
<style>
html,
body {
margin: 0;
padding: 0;
background-color: #000000;
overflow: hidden;
position: fixed;
height: 100%;
width: 100%;
}
</style>
<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no'>
</head>
<body>
<div id="player"></div>
<script src="https://player.twitch.tv/js/embed/v1.js"></script>
<div id="<player div ID>"></div>
<script type="text/javascript">
var options = {
width: window.innerWidth,
height: window.innerHeight,
video: "335180634",
// This should be used locally.
// If deployed, i.e not local then the parent should be the url of your website.
// For example if the full url of our deployed website is https://www.flutterproject.com then the parent would be
// parent: ["flutterproject.com"]
parent: ["localhost"]
};
var player = new Twitch.Player("<player div ID>", options);
player.setVolume(0.5);
</script>
</body>
</html>
The main thing to focus on is the script block. It contains the Interactive iframe player. It also accepts an options
object which can be customised. Much more parameters can be found here. You can simply move that code snippet into an editor an open it on a live server, to make sure it works.
Basically, we use some sort of WebView to open up our deployed website that contains the html content mention in point 1. We also have to give constraints to the WebView in order to place it along other widgets. A simple aspect Ratio of 16:9 should be sufficient.
Enabling allowsInlineMediaPlayback: true
would make sure that the video players in the correct aspect ratio. Setting it to false, will have an effect of causing the video to dive into fullscreen on IOS.
main(List<String> args) {
runApp(
MaterialApp(
home: Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
title: Text('Twtich Embed'),
),
body: AspectRatio(
aspectRatio: 16 / 9,
child: InAppWebView(
key: UniqueKey(),
initialUrl: 'flutterproject.com',
initialOptions: InAppWebViewGroupOptions(
ios: IOSInAppWebViewOptions(allowsInlineMediaPlayback: true),
crossPlatform: InAppWebViewOptions(
mediaPlaybackRequiresUserGesture: false,
transparentBackground: true,
),
),
),
),
),
),
);
}
Notes
Downsides
- This solution will push traffic to your own managed website.
- It might be relatively slow depending on how you optimise your deployed website.
Upside(s)
- It is the only way Twitch supports mobile embeds, as they do not have a native sdk.