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 @@ -5,160 +5,53 @@
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;
public class FirebasePerformancePlugin implements MethodChannel.MethodCallHandler {
private static final String CHANNEL_NAME = "plugins.flutter.io/firebase_performance";

private final SparseArray<Trace> traces = new SparseArray<>();
private final SparseArray<HttpMetric> httpMetrics = new SparseArray<>();
private static final SparseArray<MethodChannel.MethodCallHandler> handlers = new SparseArray<>();

public static void registerWith(Registrar registrar) {
final MethodChannel channel =
new MethodChannel(registrar.messenger(), "plugins.flutter.io/firebase_performance");
final MethodChannel channel = new MethodChannel(registrar.messenger(), CHANNEL_NAME);
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:
public void onMethodCall(MethodCall call, MethodChannel.Result result) {
if (call.method.equals("FirebasePerformance#instance")) {
FlutterFirebasePerformance.getInstance(call, result);
} else {
final MethodChannel.MethodCallHandler handler = getHandler(call);

if (handler != null) {
handler.onMethodCall(call, result);
} else {
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());
static void addHandler(final int handle, final MethodChannel.MethodCallHandler handler) {
if (handlers.get(handle) != null) {
final String message = String.format("Object for handle already exists: %s", handle);
throw new IllegalArgumentException(message);
}

trace.stop();
traces.remove(handle);
result.success(null);
handlers.put(handle, handler);
}

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);
static void removeHandler(final int handle) {
handlers.remove(handle);
}

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());
}
private static MethodChannel.MethodCallHandler getHandler(final MethodCall call) {
final Integer handle = call.argument("handle");

metric.stop();
httpMetrics.remove(handle);
result.success(null);
if (handle == null) return null;
return handlers.get(handle);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// 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 com.google.firebase.perf.metrics.Trace;
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 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 FirebasePerformance performance;

@SuppressWarnings("ConstantConditions")
static void getInstance(MethodCall call, MethodChannel.Result result) {
final Integer handle = call.argument("handle");
FirebasePerformancePlugin.addHandler(handle, new FlutterFirebasePerformance());
result.success(null);
}

private FlutterFirebasePerformance() {
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());
}

@SuppressWarnings("ConstantConditions")
private void setPerformanceCollectionEnabled(MethodCall call, MethodChannel.Result result) {
final Boolean enable = call.argument("enable");
performance.setPerformanceCollectionEnabled(enable);

result.success(null);
}

@SuppressWarnings("ConstantConditions")
private void newTrace(MethodCall call, MethodChannel.Result result) {
final String name = call.argument("name");
final Trace trace = performance.newTrace(name);

final Integer handle = call.argument("traceHandle");
FirebasePerformancePlugin.addHandler(handle, new FlutterTrace(trace));

result.success(null);
}

@SuppressWarnings("ConstantConditions")
private void newHttpMetric(MethodCall call, MethodChannel.Result result) {
final String url = call.argument("url");
final String httpMethod = call.argument("httpMethod");

final HttpMetric metric = performance.newHttpMetric(url, parseHttpMethod(httpMethod));

final Integer handle = call.argument("httpMetricHandle");
FirebasePerformancePlugin.addHandler(handle, new FlutterHttpMetric(metric));

result.success(null);
}
}
Loading