flutter_sdk icon indicating copy to clipboard operation
flutter_sdk copied to clipboard

Integrate Adjust SDK for Flutter Web

Open sarthakappinventiv1 opened this issue 1 year ago • 10 comments

Hello Adjust Team,

I'm building a web application using flutter. Could you please guide and help me to integrate the Adjust sdk in Flutter Web application

Looking forward for your support here

Thanks,

sarthakappinventiv1 avatar Oct 25 '24 10:10 sarthakappinventiv1

@uerceg Hey hey, sorry to ping directly, but there's no response on this issue for over a month. Could you please at least provide any insights on Adjust's plans for Flutter Web Support, possible timeline, etc? Any info would be helpful so we can determine our next steps if we go with Adjust or a different solution.

brian-superlist avatar Nov 20 '24 11:11 brian-superlist

Hey guys,

@brian-superlist no worries about the ping, thanks for it and sorry for the delay in replying on this one.

Unfortunately, we don't have this in our roadmap for the time being. We do have Web SDK which can be used in web apps, but so far we were not considering to add support for web in Flutter.

How does your use case look like? I am familiar with using Flutter to build iOS and Android apps (this is obviously what we have built our plugin to support), but how does the web platform fit in there? Is code base between the three platforms being shared and Flutter generates apps for all of those targets for you? How does that even work in terms of UI when it comes to web vs. mobile?

Thanks in advance for any kind of answer and clarification on the topic.

uerceg avatar Nov 20 '24 11:11 uerceg

How does your use case look like? I am familiar with using Flutter to build iOS and Android apps (this is obviously what we have built our plugin to support), but how does the web platform fit in there? Is code base between the three platforms being shared and Flutter generates apps for all of those targets for you?

Yep, exactly. For example, our app Superlist, is a Flutter app deployed to Web, iOS, Android, and MacOS all from one single codebase.

How does that even work in terms of UI when it comes to web vs. mobile?

We use a combination of screen size + platform to change the UI. Kind of like responsive design on the web, but in some cases we also take platform into account so we can show more native-looking components or animations in some situations, such as screen to screen transitions. Overall though, we mostly rely on our own design system that works well across all platforms for various screen sizes and form factors.


Basically, for this plugin: My hope was that the Flutter Adjust SDK also wrapped the Adjust Web SDK and exposed that functionality to the Dart side, just as it does the iOS/Android SDKs. That way, we could just call the Adjust SDK directly from our web app to attribute inbound ad campaigns, affiliate links, etc directly to the source and send the relevant events to do so.

Hope that helps and thanks for the response!

brian-superlist avatar Nov 20 '24 11:11 brian-superlist

As an example of how this is generally structured, the Firebase Analytics package provides SDKs for MacOS, iOS, Android and Web.

brian-superlist avatar Nov 20 '24 11:11 brian-superlist

Thank you very much, this clarifies things a lot. (without researching a lot) I was somewhat puzzled why people would be interested in having their web apps built with Flutter, but now after your explanation and realization how Flutter is abstracting all this automagically for various platforms, things are starting to make sense. Also, thank you for the Firebase reference.

We'll try to check this out on our end to see how big of an effort this would be, but like said, unfortunately this is not officially on our roadmap for the time being and except using our Web SDK for attribution in web, nothing other than that is possible for the time being.

uerceg avatar Nov 20 '24 12:11 uerceg

Thanks again. If you have even a rough timeline, that would be helpful. It might be easier or us to simply make a contribution to the repository to add the Web SDK Functionality than come up with some kind of Frankenstein solution where our web apps does one thing and our iOS/Android apps do another.

brian-superlist avatar Nov 20 '24 13:11 brian-superlist

In case you guys have the willingness to do that, that would be absolutely great. We would be more than willing to help you on that road in case you have any questions for us.

uerceg avatar Nov 20 '24 13:11 uerceg

Hey @brian-superlist, Did you end up making a start to this web integration ?

ToddZeil avatar Mar 17 '25 22:03 ToddZeil

I've just put together a very simple wrapper that covers the two methods we needed: trackEvent and getAttribution using the js_interop library and have a conditional export for web vs io. This isn't a full plugin, but it was enough for us to try Adjust for web.

You can see the code below.

import 'dart:js_interop';

import 'package:flutter/foundation.dart';

enum AdjustMarketingEnvironment {
  production,
  sandbox,
}

class AdjustMarketingAttribution {
  const AdjustMarketingAttribution({
    required this.adjustId,
    this.network,
    this.campaign,
    this.adgroup,
    this.creative,
    this.webUuid,
  });

  final String adjustId;
  final String? network;
  final String? campaign;
  final String? adgroup;
  final String? creative;
  final String? webUuid;

  @override
  String toString() {
    return 'AdjustMarketingAttribution{adjustId: $adjustId, network: $network, campaign: $campaign, adgroup: $adgroup, creative: $creative, webUuid: $webUuid}';
  }

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is AdjustMarketingAttribution &&
          runtimeType == other.runtimeType &&
          adjustId == other.adjustId &&
          network == other.network &&
          campaign == other.campaign &&
          adgroup == other.adgroup &&
          creative == other.creative &&
          webUuid == other.webUuid;

  @override
  int get hashCode =>
      adjustId.hashCode ^
      network.hashCode ^
      campaign.hashCode ^
      adgroup.hashCode ^
      creative.hashCode ^
      webUuid.hashCode;
}


Future<void> initialize({
  required String appToken,
  required AdjustMarketingEnvironment environment,
}) async {
  _AdjustSdk.initSdk(
    _InitSdkOptions(
      appToken: appToken,
      environment: environment.name,
      logLevel: kDebugMode ? 'verbose' : 'none',
    ),
  );
}

Future<void> trackEvent(String token) async {
  _AdjustSdk.trackEvent(_TrackEventOptions(eventToken: token));
}

Future<AdjustMarketingAttribution> getAttribution() async {
  final attribution = await _AdjustSdk.waitForAttribution().toDart;
  final webUuid = await _AdjustSdk.waitForWebUUID().toDart;

  return AdjustMarketingAttribution(
    adjustId: attribution.adid,
    network: attribution.network,
    campaign: attribution.campaign,
    adgroup: attribution.adgroup,
    creative: attribution.creative,
    webUuid: webUuid.toDart,
  );
}

@JS('Adjust')
extension type _AdjustSdk._(JSObject _) implements JSObject {
  external static void initSdk(_InitSdkOptions options);
  external static void trackEvent(_TrackEventOptions options);
  external static JSPromise<_JsMarketingAttribution> waitForAttribution();
  external static JSPromise<JSString> waitForWebUUID();
}

extension type _InitSdkOptions._(JSObject o) implements JSObject {
  external _InitSdkOptions({
    required String appToken,
    required String environment,
    required String logLevel,
  });

  external String get appToken;
  external String get environment;
  external String get logLevel;
}

extension type _TrackEventOptions._(JSObject o) implements JSObject {
  external _TrackEventOptions({required String eventToken});

  external String get eventToken;
}

extension type _JsMarketingAttribution._(JSObject o) implements JSObject {
  external String get eventToken;

  external String adid;
  @JS('tracker_token')
  external String trackerToken;
  @JS('tracker_name')
  external String trackerName;
  external String? network;
  external String? campaign;
  external String? adgroup;
  external String? creative;
  @JS('click_label')
  external String? clickLabel;
  external String state;
}

Future<void> requestTrackingPermission() async {}

brian-superlist avatar Mar 18 '25 09:03 brian-superlist

Thank you @brian-superlist!! That's all we needed also

ToddZeil avatar Mar 19 '25 03:03 ToddZeil