পরীক্ষামূলক YouTube Playables Flutter Web SDK

এই নির্দেশিকাটি ব্যাখ্যা করে যে কীভাবে একটি ফ্লাটার ওয়েব অ্যাপের মাধ্যমে YouTube Playables SDK ব্যবহার করতে হয়।

ফ্লটার কনফিগারেশন

ডিফল্ট ফ্লাটার ওয়েব অ্যাপে প্লেযোগ্য হিসেবে কাজ করার জন্য কিছু পরিবর্তন প্রয়োজন। Flutter সংস্করণ 3.24.5 হিসাবে নিম্নলিখিত পরিবর্তনগুলি প্রয়োজন৷

ডিফল্টরূপে, রুট ডিরেক্টরি থেকে সংস্থানগুলি লোড করার জন্য Flutter কনফিগার করা হয়, যেখানে Playables এর প্রয়োজন হয় যে সংস্থানগুলি এন্ট্রি পয়েন্টের সাথে লোড করা হয়। এটি একটি 404 ত্রুটি হিসাবে দেখাবে, অথবা সম্ভবত একটি ত্রুটি হিসাবে প্রদর্শিত হবে যা জাভাস্ক্রিপ্ট কনসোলে প্রদর্শিত হবে যা পড়ে: Refused to execute script from... because its MIME type ('text/html') is not executable. এটি পুনরায় কনফিগার করার একটি উপায় হল index.html ফাইল থেকে নিম্নলিখিত ট্যাগটি সরানো:

<base href="$FLUTTER_BASE_HREF">

ডিফল্টরূপে, Flutter কিছু লাইব্রেরি অ্যাপে এম্বেড করার পরিবর্তে গতিশীলভাবে লোড করে। ক্যানভাসকিট এর একটি উদাহরণ। এটি জাভাস্ক্রিপ্ট কনসোলে একটি ত্রুটি হিসাবে দেখাবে যা পড়ে: Refused to connect to '...' because it violates the following Content Security Policy directive: "connect-src 'self' blob: data:". লোডিং ব্যর্থ হলে ফ্লটার অতিরিক্ত লগ আউটপুট করতে পারে, যেমন Failed to download any of the following CanvasKit URLs । এটি ঠিক করতে, আপনি নিম্নলিখিত অতিরিক্ত পতাকা দিয়ে আপনার ওয়েব অ্যাপ তৈরি করতে পারেন:

$ flutter build web --no-web-resources-cdn

ডিফল্টরূপে, ফ্লাটার ওয়েব অ্যাপগুলি ফন্টগুলিকে অ্যাপে এম্বেড করার পরিবর্তে গতিশীলভাবে লোড করে। ডিফল্ট ফ্লাটার অ্যাপটি রোবোটো ফন্ট ব্যবহার করে, এবং এটি জাভাস্ক্রিপ্ট কনসোলে একটি ত্রুটি হিসাবে দেখাবে যেটিতে লেখা আছে: Refused to connect to '...' because it violates the following Content Security Policy directive: "connect-src 'self' blob: data". এটি ঠিক করতে আপনি নিম্নলিখিত পদক্ষেপগুলি নিতে পারেন:

  • আপনার ফ্লাটার ওয়েব অ্যাপের রুটে "ফন্টস" নামে একটি ফোল্ডার তৈরি করুন
  • fonts.google.com থেকে রোবোটো ফন্ট ফ্যামিলি ডাউনলোড করুন।
  • ফন্টগুলি বের করুন এবং Roboto-Regular.ttf ফন্ট ফোল্ডারে অনুলিপি করুন
  • আপনার ফ্লাটার ওয়েব অ্যাপের pubspec.yaml-এ নিম্নলিখিত লাইন যোগ করুন:
  fonts:
    - family: Roboto
      fonts:
       - asset: fonts/Roboto-Regular.ttf

ফন্ট কনফিগারেশন সম্পর্কে আরও তথ্য ফ্লটার ডকুমেন্টেশনে পাওয়া যাবে।

SDK ইন্টিগ্রেশন

YouTube Playables SDK একটি Flutter ওয়েব গেম থেকে এটির মতো একটি JS-interop wrapper এর মাধ্যমে ব্যবহার করা যেতে পারে:

ytgame.dart

// Copyright 2023 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

@JS()
library ytgame_api;

import 'package:js/js.dart';
import 'package:js/js_util.dart' as js_util;

enum PlayablesErrorType {
  unknown('UNKNOWN'),
  apiUnavailable('API_UNAVAILABLE'),
  invalidParams('INVALID_PARAMS'),
  sizeLimitExceeded('SIZE_LIMIT_EXCEEDED');

  const PlayablesErrorType(String type) : _type = type;
  final String _type;

  @override
  String toString() => _type;

  static PlayablesErrorType fromString(String errorType) {
    return values.firstWhere(
      (element) => element._type == errorType,
    );
  }
}

@JS()
@staticInterop
class PlayablesError {}

extension PlayablesErrorExtension on PlayablesError {
  @JS('errorType')
  external String get _errorType;
  PlayablesErrorType get errorType {
    return PlayablesErrorType.fromString(_errorType);
  }
}

@JS()
@anonymous
@staticInterop
class PlayablesScore {
  external factory PlayablesScore({
    required num value,
  });
}

extension PlayablesScoreExtension on PlayablesScore {
  external num get value;
}

// engagement
@JS()
@staticInterop
class PlayablesEngagement {}

extension PlayablesEngagementExtension on PlayablesEngagement {
  @JS('sendScore')
  external Object _sendScore(PlayablesScore score);
  Future<void> sendScore(PlayablesScore score) {
    return js_util.promiseToFuture(_sendScore(score));
  }
}

// game
@JS()
@staticInterop
class PlayablesGame {}

extension PlayablesGameExtension on PlayablesGame {
  external void firstFrameReady();
  external void gameReady();

  @JS('loadData')
  external Object _loadData();
  Future<String?> loadData() {
    return js_util.promiseToFuture<String?>(_loadData());
  }

  @JS('saveData')
  external Object _saveData(String? data);
  Future<void> saveData(String? data) {
    return js_util.promiseToFuture<void>(_saveData(data));
  }
}

// health
@JS()
@staticInterop
class PlayablesHealth {}

extension PlayablesHealthExtension on PlayablesHealth {
  external void logError();
  external void logWarning();
}

// system
typedef PlayablesUnsetCallback = void Function();
typedef PlayablesOnAudioEnabledChange = void Function(bool isAudioEnabled);
typedef PlayablesOnPause = void Function();
typedef PlayablesOnResume = void Function();

@JS()
@staticInterop
class PlayablesSystem {}

extension PlayablesSystemExtension on PlayablesSystem {
  external bool isAudioEnabled();

  @JS('onAudioEnabledChange')
  external PlayablesUnsetCallback _onAudioEnabledChange(
      PlayablesOnAudioEnabledChange callback);
  PlayablesUnsetCallback onAudioEnabledChange(
      PlayablesOnAudioEnabledChange callback) {
    return _onAudioEnabledChange(allowInterop(callback));
  }

  @JS('onPause')
  external PlayablesUnsetCallback _onPause(PlayablesOnPause callback);
  PlayablesUnsetCallback onPause(PlayablesOnPause callback) {
    return _onPause(allowInterop(callback));
  }

  @JS('onResume')
  external PlayablesUnsetCallback _onResume(PlayablesOnResume callback);
  PlayablesUnsetCallback onResume(PlayablesOnResume callback) {
    return _onResume(allowInterop(callback));
  }
}

@JS()
@staticInterop
class Playables {}

extension PlayablesExtension on Playables {
  @JS('SDK_VERSION')
  external String get sdkVersion;
  external PlayablesEngagement get engagement;
  external PlayablesGame get game;
  external PlayablesHealth get health;
  external PlayablesSystem get system;
}

@JS('ytgame')
external Playables get ytgame;

ব্যবহার

  1. ওয়েব SDK সেটআপ এবং আরম্ভ করার জন্য নির্দেশাবলী অনুসরণ করুন।
    • প্রয়োজনীয় স্ক্রিপ্ট ট্যাগগুলি অন্তর্ভুক্ত করতে আপনার ফ্লটার ওয়েব অ্যাপের web/index.html পরিবর্তন করুন৷
  2. আপনার Flutter ওয়েব অ্যাপের srcytgame.dart এর একটি অনুলিপি যোগ করুন।
  3. নিশ্চিত করুন যে js প্যাকেজটি Flutter-এ যোগ করা হয়েছে, যেমন flutter pub add js কমান্ড চালানোর মাধ্যমে।
  4. import 'src/location/of/ytgame.dart'; যেখানে প্রয়োজন।
  5. SDK অ্যাক্সেস করতে ytgame অবজেক্ট ব্যবহার করুন।

উদাহরণ

কর্মে ডার্ট API এর কয়েকটি উদাহরণ নীচে খুঁজুন।

firstFrameReady এবং gameReady

আপনার গেমটি সঠিকভাবে শুরু করার জন্য, প্রথম ফ্রেমটি প্রদর্শনের জন্য প্রস্তুত হলে আপনাকে firstFrameReady কল করতে হবে এবং গেমটি ইন্টারঅ্যাক্ট করার জন্য প্রস্তুত হলে gameReady হবে। ডিফল্ট ফ্লাটার অ্যাপে এটি করার একটি উপায় হল main.dart ফাইলে কল যোগ করা:

...
import 'src/ytgame.dart';
...

void main() {
  ytgame.game.firstFrameReady();
  ytgame.game.gameReady();
  runApp(const MyApp());
}

মনে রাখবেন যে আপনার গেমটি চালানোর জন্য এটি শুধুমাত্র একটি উদাহরণ - সঠিক বাস্তবায়ন প্রদান করার জন্য আপনাকে এই কলগুলির অবস্থান সঠিকভাবে স্থাপন করতে হবে।

sendScore

এই উদাহরণটি ডার্টে sendScore(int points) এর বাস্তবায়ন দেখায়:

...
import 'src/ytgame.dart';
...

/// Sends [points] as score to YT Playables
Future<void> sendScore(int points) async {
  // Create a score object...
  final PlayablesScore score = PlayablesScore(
    value: points,
  );
  // Submit the score to ytgame
  await ytgame.engagement.sendScore(score);
}

onPause

এটি একটি উদাহরণ যে কীভাবে একটি গেম YT Playables থেকে আসা Pause ইভেন্টগুলি শুনতে পারে, প্রয়োজনের সময় তার ইঞ্জিনকে বিরতি দিতে পারে:

...
import 'src/ytgame.dart';
...

/// The instance of your game.
late Game myGame;

/// Callback to stop listening for Pause events (cleanup).
PlayablesUnsetCallback? _unsetOnPause;
...

/// Sets a [callback] to respond to Pause events.
void registerOnPauseListener(PlayablesOnPause callback) {
  _unsetOnPause = ytgame.system.onPause(callback);
}

/// Stops listening to Pause events, and clears [_unsetOnPause].
void unsetOnPauseListener() {
  if (_unsetOnPause != null) {
    _unsetOnPause!();
    _unsetOnPause = null;
  }
}

...

/// Initialization for your game
void initGame() {
  ...
  myGame = ...
  registerOnPauseListener(_onPause);
}

void _onPause() {
  // This is called when a Pause event is received from YT Playables.
  myGame.pauseEngine();
}

/// Teardown for your game
void disposeGame() {
  ...
  unsetOnPauseListener();
}

সম্পূর্ণ YT Playables API রেফারেন্স দেখুন।