Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.
Closed
Original file line number Diff line number Diff line change
Expand Up @@ -4,161 +4,15 @@

package io.flutter.plugins.firebaseperformance;

import android.util.SparseArray;
import com.google.firebase.perf.FirebasePerformance;
import com.google.firebase.perf.metrics.HttpMetric;
import com.google.firebase.perf.metrics.Trace;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry.Registrar;
import java.util.Map;

/** FirebasePerformancePlugin */
public class FirebasePerformancePlugin implements MethodCallHandler {
private FirebasePerformance firebasePerformance;

private final SparseArray<Trace> traces = new SparseArray<>();
private final SparseArray<HttpMetric> httpMetrics = new SparseArray<>();
public class FirebasePerformancePlugin {
private static final String CHANNEL_NAME = "plugins.flutter.io/firebase_performance";

public static void registerWith(Registrar registrar) {
final MethodChannel channel =
new MethodChannel(registrar.messenger(), "plugins.flutter.io/firebase_performance");
channel.setMethodCallHandler(new FirebasePerformancePlugin());
}

private FirebasePerformancePlugin() {
firebasePerformance = FirebasePerformance.getInstance();
}

@Override
public void onMethodCall(MethodCall call, Result result) {
switch (call.method) {
case "FirebasePerformance#isPerformanceCollectionEnabled":
result.success(firebasePerformance.isPerformanceCollectionEnabled());
break;
case "FirebasePerformance#setPerformanceCollectionEnabled":
final boolean enabled = (boolean) call.arguments;
firebasePerformance.setPerformanceCollectionEnabled(enabled);
result.success(null);
break;
case "Trace#start":
handleTraceStart(call, result);
break;
case "Trace#stop":
handleTraceStop(call, result);
break;
case "HttpMetric#start":
handleHttpMetricStart(call, result);
break;
case "HttpMetric#stop":
handleHttpMetricStop(call, result);
break;
default:
result.notImplemented();
}
}

private void handleTraceStart(MethodCall call, Result result) {
Integer handle = call.argument("handle");
String name = call.argument("name");

Trace trace = firebasePerformance.newTrace(name);

traces.put(handle, trace);

trace.start();
result.success(null);
}

private void handleTraceStop(MethodCall call, Result result) {
Integer handle = call.argument("handle");
Trace trace = traces.get(handle);

Map<String, Integer> metrics = call.argument("metrics");
for (Map.Entry<String, Integer> entry : metrics.entrySet()) {
trace.incrementMetric(entry.getKey(), entry.getValue());
}

Map<String, String> attributes = call.argument("attributes");
for (Map.Entry<String, String> entry : attributes.entrySet()) {
trace.putAttribute(entry.getKey(), entry.getValue());
}

trace.stop();
traces.remove(handle);
result.success(null);
}

private void handleHttpMetricStart(MethodCall call, Result result) {
Integer handle = call.argument("handle");
String url = call.argument("url");

int httpMethod = call.argument("httpMethod");
String httpMethodStr;
switch (httpMethod) {
case 0:
httpMethodStr = FirebasePerformance.HttpMethod.CONNECT;
break;
case 1:
httpMethodStr = FirebasePerformance.HttpMethod.DELETE;
break;
case 2:
httpMethodStr = FirebasePerformance.HttpMethod.GET;
break;
case 3:
httpMethodStr = FirebasePerformance.HttpMethod.HEAD;
break;
case 4:
httpMethodStr = FirebasePerformance.HttpMethod.OPTIONS;
break;
case 5:
httpMethodStr = FirebasePerformance.HttpMethod.PATCH;
break;
case 6:
httpMethodStr = FirebasePerformance.HttpMethod.POST;
break;
case 7:
httpMethodStr = FirebasePerformance.HttpMethod.PUT;
break;
case 8:
httpMethodStr = FirebasePerformance.HttpMethod.TRACE;
break;
default:
httpMethodStr = null;
break;
}

HttpMetric metric = firebasePerformance.newHttpMetric(url, httpMethodStr);

httpMetrics.put(handle, metric);

metric.start();
result.success(null);
}

private void handleHttpMetricStop(MethodCall call, Result result) {
Integer handle = call.argument("handle");
HttpMetric metric = httpMetrics.get(handle);

Integer httpResponseCode = call.argument("httpResponseCode");
Number requestPayloadSize = call.argument("requestPayloadSize");
String responseContentType = call.argument("responseContentType");
Number responsePayloadSize = call.argument("responsePayloadSize");

if (requestPayloadSize != null) metric.setRequestPayloadSize(requestPayloadSize.longValue());
if (httpResponseCode != null) metric.setHttpResponseCode(httpResponseCode);
if (responseContentType != null) metric.setResponseContentType(responseContentType);
if (responsePayloadSize != null) metric.setResponsePayloadSize(responsePayloadSize.longValue());

Map<String, String> attributes = call.argument("attributes");
for (Map.Entry<String, String> entry : attributes.entrySet()) {
metric.putAttribute(entry.getKey(), entry.getValue());
}

metric.stop();
httpMetrics.remove(handle);
result.success(null);
final MethodChannel channel = new MethodChannel(registrar.messenger(), CHANNEL_NAME);
channel.setMethodCallHandler(FlutterFirebasePerformance.getInstance(registrar.messenger()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package io.flutter.plugins.firebaseperformance;

import com.google.firebase.perf.FirebasePerformance;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;

public class FlutterFirebasePerformance implements MethodChannel.MethodCallHandler {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like you split the plugin class into two parts which is different from what we're doing with other first-party plugins. Is this a new convention that you'd like to see applied to all of Flutterfire and plugins generally? If so we could file an issue to update the flutter create -t plugin behavior. Or if not, it might be better to leave it the way it is for consistency.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I only separated this part as the FirebasePerformance plugin doesn't have any other classes that you can instantiate on there own. (e.g. to create an object you use FirebasePeformance.newTrace() or FirebasePeformance.newHttpMetric(). ML Kit works the same way, but Firebase Dynamic Links doesn't.

I created this PR to get feedback on creating separate MethodChannels for each class. Although its require more code, i think it's easier to read/maintain.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm on board with splitting things into more classes, generally. I'm ok with using it for this plugin as a one-off and we can discuss offline if we want to adopt the approach for plugins generally.

private final BinaryMessenger binaryMessenger;
private final FirebasePerformance performance;

static FlutterFirebasePerformance getInstance(BinaryMessenger messenger) {
return new FlutterFirebasePerformance(messenger);
}

private FlutterFirebasePerformance(BinaryMessenger messenger) {
this.binaryMessenger = messenger;
this.performance = FirebasePerformance.getInstance();
}

@Override
public void onMethodCall(MethodCall call, MethodChannel.Result result) {
switch (call.method) {
case "FirebasePerformance#isPerformanceCollectionEnabled":
isPerformanceCollectionEnabled(result);
break;
case "FirebasePerformance#setPerformanceCollectionEnabled":
setPerformanceCollectionEnabled(call, result);
break;
case "FirebasePerformance#newTrace":
newTrace(call, result);
break;
case "FirebasePerformance#newHttpMetric":
newHttpMetric(call, result);
break;
default:
result.notImplemented();
}
}

private void isPerformanceCollectionEnabled(MethodChannel.Result result) {
result.success(performance.isPerformanceCollectionEnabled());
}

private void setPerformanceCollectionEnabled(MethodCall call, MethodChannel.Result result) {
final boolean enabled = (Boolean) call.arguments;
performance.setPerformanceCollectionEnabled(enabled);
result.success(null);
}

private void newTrace(MethodCall call, MethodChannel.Result result) {
new FlutterTrace(performance, binaryMessenger, call, result);
}

private void newHttpMetric(MethodCall call, MethodChannel.Result result) {
new FlutterHttpMetric(performance, binaryMessenger, call, result);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package io.flutter.plugins.firebaseperformance;

import com.google.firebase.perf.FirebasePerformance;
import com.google.firebase.perf.metrics.HttpMetric;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;

@SuppressWarnings("ConstantConditions")
public class FlutterHttpMetric implements MethodChannel.MethodCallHandler {
private static String parseHttpMethod(String httpMethod) {
switch (httpMethod) {
case "HttpMethod.Connect":
return FirebasePerformance.HttpMethod.CONNECT;
case "HttpMethod.Delete":
return FirebasePerformance.HttpMethod.DELETE;
case "HttpMethod.Get":
return FirebasePerformance.HttpMethod.GET;
case "HttpMethod.Head":
return FirebasePerformance.HttpMethod.HEAD;
case "HttpMethod.Options":
return FirebasePerformance.HttpMethod.OPTIONS;
case "HttpMethod.Patch":
return FirebasePerformance.HttpMethod.PATCH;
case "HttpMethod.Post":
return FirebasePerformance.HttpMethod.POST;
case "HttpMethod.Put":
return FirebasePerformance.HttpMethod.PUT;
case "HttpMethod.Trace":
return FirebasePerformance.HttpMethod.TRACE;
default:
throw new IllegalArgumentException(String.format("No HttpMethod for: %s", httpMethod));
}
}

private final HttpMetric httpMetric;
private final MethodChannel channel;

FlutterHttpMetric(
FirebasePerformance performance,
BinaryMessenger messenger,
MethodCall call,
MethodChannel.Result result) {
final String channelName = call.argument("channelName");
final String url = call.argument("url");
final String httpMethod = call.argument("httpMethod");

this.httpMetric = performance.newHttpMetric(url, parseHttpMethod(httpMethod));

this.channel = new MethodChannel(messenger, channelName);
channel.setMethodCallHandler(this);

result.success(null);
}

@Override
public void onMethodCall(MethodCall call, MethodChannel.Result result) {
switch (call.method) {
case "HttpMetric#start":
start(result);
break;
case "HttpMetric#stop":
stop(result);
break;
case "HttpMetric#httpResponseCode":
setHttpResponseCode(call, result);
break;
case "HttpMetric#requestPayloadSize":
setRequestPayloadSize(call, result);
break;
case "HttpMetric#responseContentType":
setResponseContentType(call, result);
break;
case "HttpMetric#responsePayloadSize":
setResponsePayloadSize(call, result);
break;
case "PerformanceAttributes#putAttribute":
putAttribute(call, result);
break;
case "PerformanceAttributes#removeAttribute":
removeAttribute(call, result);
break;
case "PerformanceAttributes#getAttributes":
getAttributes(result);
break;
default:
result.notImplemented();
}
}

private void start(MethodChannel.Result result) {
httpMetric.start();
result.success(null);
}

private void stop(MethodChannel.Result result) {
httpMetric.stop();
channel.setMethodCallHandler(null);
result.success(null);
}

private void setHttpResponseCode(MethodCall call, MethodChannel.Result result) {
final Integer httpResponseCode = call.argument("httpResponseCode");
httpMetric.setHttpResponseCode(httpResponseCode);
result.success(null);
}

private void setRequestPayloadSize(MethodCall call, MethodChannel.Result result) {
final Number payloadSize = call.argument("requestPayloadSize");
httpMetric.setRequestPayloadSize(payloadSize.longValue());
result.success(null);
}

private void setResponseContentType(MethodCall call, MethodChannel.Result result) {
final String contentType = call.argument("responseContentType");
httpMetric.setResponseContentType(contentType);
result.success(null);
}

private void setResponsePayloadSize(MethodCall call, MethodChannel.Result result) {
final Number payloadSize = call.argument("responsePayloadSize");
httpMetric.setResponsePayloadSize(payloadSize.longValue());
result.success(null);
}

private void putAttribute(MethodCall call, MethodChannel.Result result) {
final String attribute = call.argument("attribute");
final String value = call.argument("value");

httpMetric.putAttribute(attribute, value);

result.success(null);
}

private void removeAttribute(MethodCall call, MethodChannel.Result result) {
final String attribute = call.argument("attribute");
httpMetric.removeAttribute(attribute);

result.success(null);
}

private void getAttributes(MethodChannel.Result result) {
result.success(httpMetric.getAttributes());
}
}
Loading