mapbox_ad_flutter 0.3.0 copy "mapbox_ad_flutter: ^0.3.0" to clipboard
mapbox_ad_flutter: ^0.3.0 copied to clipboard

discontinued
PlatformAndroidiOS

Mapbox Ad SDK Flutter Plugin

mapbox-ad-flutter #

Installation #

  • Run this command:
    flutter pub add mapbox_maps_flutter
    flutter pub add mapbox_ad_flutter

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

  dependencies:
    mapbox_maps_flutter: ^0.4.1
    mapbox_ad_flutter: ^0.0.8

How to configure #

  • import 'package:mapbox_maps_flutter/mapbox_maps_flutter.dart';
  • import 'package:mapbox_ad_flutter/mapbox_ad_flutter.dart';

How to use #

1. Initialize MapboxAdManager and load ads #

In your map widget, initialize the MapboxAdManager and call loadAds after map style is loaded.

class _MapboxAdAppState extends State<MapboxAdApp> {
  final _adManager = MapboxAdManager();
  MapWidget? _mapView;
  BuildContext? _context;

  _onStyleLoadedListener(mbx.StyleLoadedEventData? data) {
    if (_context == null) return;
    _adManager.onStyleLoadedCallback();
    _adManager.loadAds(
        _mapView, null, MediaQuery.of(_context!), configuration: MapboxAdConfiguration.staging);
    _adManager.callback = this;
  }

  @override
  Widget build(BuildContext context) {
    _context = context;
    final MapWidget mapWidget = MapWidget(
      key: const ValueKey("mapWidget"),
      resourceOptions: ResourceOptions(accessToken: "MAPBOX_ACCESS_TOKEN"),
      onStyleLoadedListener: _onStyleLoadedListener,
    );
    _mapView = mapWidget;
  }
}

2. Must implement WidgetsBindingObserver mixin to provide app state to MapboxAdManager when app is resumed and paused #

class _MapboxAdAppState extends State<MapboxAdApp>
    with WidgetsBindingObserver {

  @override
  void initState() {
    WidgetsBinding.instance.addObserver(this);
    super.initState();
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    switch (state) {
      case AppLifecycleState.resumed:
        _adManager.onResume();
        break;
      case AppLifecycleState.paused:
        _adManager.onPause();
        break;
      case AppLifecycleState.inactive:
        break;
      case AppLifecycleState.detached:
        break;
    }
  }
}

About MapboxAdMBPCardView, MapboxAdAttributionView #

MapboxAdMBPCardView is a card view which contains ad contents when ad pin is tapped. MapboxAdAttributionView is a card view which contains advertisement information when advertisement button is tapped.

MapboxAdMBPCardView Method #


/// Attach view to the parent with animation.
/// @param context of the parent view to be attached.
/// @param completion The block to execute after the animation finishes.
attach(BuildContext context, {bool animated = true, Function()? completion});

/// Detach view from the parent with animation.
/// @param context of the parent view to be detached.
/// @param completion The block to execute after the animation finishes.
detach(BuildContext context, {bool animated = true, Function()? completion});

How to use #

Please show the MapboxAdMBPCardView in the MapboxAdCallback -> onAdDidSelect and hide the card in the MapboxAdCallback -> onAdDidDeselect callback like the below sample code.

@override
onAdDidSelect(MapboxAdMBPCardView view, MapboxAd mapboxAd) {
  if (_context != null) view.attach(_context!);
}

@override
onAdDidDeselect(MapboxAdMBPCardView view) {
  if (_context != null) view.detach(_context!);
}  

Card tap action type #

Type Description
route Called when "Route" button is tapped. Please show route search widget.
navigation Called when "Navigation" action is triggered. Please show navigation widget. "Navigation" button is currently hidden.
businessHours Called when business hours field is tapped.
address Called when address field is tapped.
externalLinkBanner Called when banner is tapped. Transition to its URL by external/internal browser like below.
externalLinkDetailSite Called when detail site button is tapped. Transition to its URL by external/internal browser like below.
externalLinkCall Called when cs is tapped. Transition to its URL by external/internal browser like below.
externalLinkCallAttributionLink Called when attribution add button is tapped. Transition to its URL by external/internal browser like below.
@override
onAdDidTapCardAction(MapboxAdMBPCardTapAction action, MapboxAd mapboxAd,
    {String url = ''}) async {
  switch (action) {
    case MapboxAdMBPCardTapAction.navigation:
    //tapped navigation button
      break;
    case MapboxAdMBPCardTapAction.route:
    //tapped route button
      break;
    case MapboxAdMBPCardTapAction.businessHours:
    // tapped business hours area
      break;
    case MapboxAdMBPCardTapAction.address:
    // tapped address area
      break;
    case MapboxAdMBPCardTapAction.externalLinkBanner:
    // tapped banner
    // launch url in browser
      launchUrl(mapboxAd.url.toString());
      break;
    case MapboxAdMBPCardTapAction.externalLinkDetailSite:
    // tapped detail site
    // launch url in browser
      await launchUrl(url);
      break;
    case MapboxAdMBPCardTapAction.externalLinkCall:
    // tapped call
    // launch url in browser
      await launchUrl(url);
      break;
    case MapboxAdMBPCardTapAction.externalLinkAttributionLink:
    // tapped attribution
    // launch url in browser
      await launchUrl(url);
      break;
  }
}

Card transition state #

Card transition state is notified from the following delegate.

@override
onAdDidTransitionCard(MapboxAdMBPCardTransition state) {
  switch (state) {
    case MapboxAdMBPCardTransition.collapsed:
    // called the card is at the bottom of screen
      break;
    case MapboxAdMBPCardTransition.expanded:
    // called the card is showing as full screen
      break;
    case MapboxAdMBPCardTransition.closed:
    // called the card is closed
      break;
  }
}
  • Example code
import 'package:flutter/material.dart';

import 'dart:math' as math;

import 'package:logger/logger.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:mapbox_maps_flutter/mapbox_maps_flutter.dart' as mbx;
import 'package:mapbox_ad_flutter/mapbox_ad_flutter.dart' as ad;

class MapboxAdApp extends StatefulWidget {
  const MapboxAdApp({super.key});

  @override
  State<MapboxAdApp> createState() => _MapboxAdAppState();
}

///Widget state MUST implement `WidgetsBindingObserver` and `MapboxAdCallback`
class _MapboxAdAppState extends State<MapboxAdApp>
    with WidgetsBindingObserver
    implements ad.MapboxAdCallback {

  /// TOKEN and Server Environment
  static const environment = ad.AdsEnvironment.develop;
  static const String accessToken = "ADD_ACCESS_TOKEN_HERE";

  /// Demo Map Settings
  static final center =
  mbx.Point(coordinates: mbx.Position(139.776606, 35.682400)).toJson();
  static const zoom = 14.281;
  static const styleUrl =
      "mapbox://styles/mapbox-ads/ckt3mhrk4088z18ponqip6fi6";

  /// Add a `adManager` variable to the widget.
  final _adManager = ad.MapboxAdManager();
  mbx.MapWidget? _mapView;
  ad.MapboxAdConfiguration? _config;
  BuildContext? _context;
  final _logger = Logger();

  /// Add map to manager in `_onMapCreated` callback
  _onMapCreated(mbx.MapboxMap mapboxMap) {
    _adManager.onMapCreated(mapboxMap);
  }

  /// Load ads in `_onStyleLoadedListener` callback
  _onStyleLoadedListener(mbx.StyleLoadedEventData? data) {
    _adManager.onStyleLoadedCallback();

    _loadAds();
  }

  /// Call `onMapIdle()`
  _onMapIdle(mbx.CameraChangedEventData? data) {
    _adManager.onMapIdle();
  }

  /// Call `onCameraIdle()`
  _onCameraIdle(mbx.MapIdleEventData? data) {
    _adManager.onCameraIdle();
  }

  /// Call `onMapClick()` and pass coordinates
  _onMapClick(mbx.ScreenCoordinate coordinate) {
    _adManager.onMapClick(math.Point(coordinate.x, coordinate.y));
  }

  /// Load ads private method
  _loadAds() {
    if (_context == null || _config == null) return;
    final mediaQueryData = MediaQuery.of(_context!);
    _adManager.loadAds(_mapView, null, mediaQueryData, configuration: _config);
    _adManager.callback = this;
  }

  /// Get config private method
  _getConfiguration(String accessToken) {
    final rootConfig = ad.MapboxAdRootConfiguration();
    rootConfig.sdk.adServer = ad.MapboxAdServerConfiguration.init(environment);
    rootConfig.sdk.eventTrack =
        ad.MapboxEventTrackConfiguration.init(environment);
    rootConfig.sdk.token = accessToken;
    final config = ad.MapboxAdConfiguration(rootConfig);
    config.mediaID = "ADD_MEDIA_ID_HERE";
    return config;
  }

  /// Build `MapboxMap` private method
  _buildMapboxMap(String token) {
    if (_context == null) return;
    _config = _getConfiguration(accessToken);
    final mbx.MapWidget mapWidget = mbx.MapWidget(
        key: const ValueKey("mapWidget"),
        resourceOptions: mbx.ResourceOptions(accessToken: accessToken),
        cameraOptions: mbx.CameraOptions(center: center, zoom: zoom),
        styleUri: styleUrl,
        onMapCreated: _onMapCreated,
        onStyleLoadedListener: _onStyleLoadedListener,
        onCameraChangeListener: _onMapIdle,
        onMapIdleListener: _onCameraIdle,
        onTapListener: _onMapClick);
    _mapView = mapWidget;
  }

  /// Attach card view on `onAdDidSelect` callback
  @override
  onAdDidSelect(ad.MapboxAdMBPCardView view, ad.MapboxAd mapboxAd) {
    if (_context != null) view.attach(_context!);
    _logger.d("onAdDidSelect");
  }

  /// Detach card view on `onAdDidDeselect` callback
  @override
  onAdDidDeselect(ad.MapboxAdMBPCardView view) {
    if (_context != null) view.detach(_context!);
    _logger.d("onAdDidDeselect");
  }

  /// Attach attribution view on `onAdShowAttribution` callback
  @override
  onAdShowAttribution(ad.MapboxAdAttributionView view) {
    if (_context != null) view.attach(_context!);
    _logger.d("onAdShowAttribution");
  }

  @override
  onAdCloseAttribution(ad.MapboxAdAttributionView view) {
    _logger.d("onAdCloseAttribution");
  }

  /// Alert private method
  _showAlert(String title, String message) {
    return showDialog<void>(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text(title),
          content: Text(message),
          actions: <Widget>[
            TextButton(
              style: TextButton.styleFrom(
                textStyle: Theme
                    .of(context)
                    .textTheme
                    .labelLarge,
              ),
              child: const Text('OK'),
              onPressed: () {
                Navigator.of(context).pop();
              },
            ),
          ],
        );
      },
    );
  }

  /// Launch url private method
  Future<void> _launchUrl(String url) async {
    try {
      final uri = Uri.parse(url);
      await launchUrl(uri);
    } catch (e) {
      _logger.e(e);
    }
  }

  /// Card Tap Actions
  @override
  onAdDidTapCardAction(ad.MapboxAdMBPCardTapAction action, ad.MapboxAd mapboxAd,
      {String url = ''}) async {
    switch (action) {
      case ad.MapboxAdMBPCardTapAction.navigation:
        _showAlert("Open navigation", "name:${mapboxAd.name}");
        break;
      case ad.MapboxAdMBPCardTapAction.route:
        _showAlert("Open route", "name:${mapboxAd.name}");
        break;
      case ad.MapboxAdMBPCardTapAction.businessHours:
        _logger.d("Taped business hours: ${mapboxAd.name}");
        break;
      case ad.MapboxAdMBPCardTapAction.address:
        _showAlert("Open address", "name:${mapboxAd.address}");
        break;
      case ad.MapboxAdMBPCardTapAction.externalLinkBanner:
        await _launchUrl(mapboxAd.url.toString());
        break;
      case ad.MapboxAdMBPCardTapAction.externalLinkDetailSite:
        await _launchUrl(url);
        break;
      case ad.MapboxAdMBPCardTapAction.externalLinkCall:
        await _launchUrl(url);
        break;
      case ad.MapboxAdMBPCardTapAction.externalLinkCallAttributionLink:
        await _launchUrl(url);
        break;
    }
  }

  /// Card Transitions
  @override
  onAdDidTransitionCard(ad.MapboxAdMBPCardTransition state) {
    switch (state) {
      case ad.MapboxAdMBPCardTransition.collapsed:
        _logger.d("collapsed");
        break;
      case ad.MapboxAdMBPCardTransition.expanded:
        _logger.d("expanded");
        break;
      case ad.MapboxAdMBPCardTransition.closed:
        _logger.d("closed");
        break;
    }
  }

  /// App Lifecycle
  @override
  void initState() {
    WidgetsBinding.instance.addObserver(this);
    super.initState();
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    switch (state) {
    /// Call `onResume()`
      case AppLifecycleState.resumed:
        _adManager.onResume();
        break;

    /// Call `onPause()`
      case AppLifecycleState.paused:
        _adManager.onPause();
        break;

      case AppLifecycleState.inactive:
        break;
      case AppLifecycleState.detached:
        break;
    }
  }

  /// Build widget
  @override
  Widget build(BuildContext context) {
    _context = context;
    _buildMapboxMap(accessToken);
    return Scaffold(body: _mapView);
  }
}

/// Run app
void main() {
  runApp(const MaterialApp(home: MapboxAdApp()));
}