Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature/scalable-integration - Add dynamic and scalable segment integration #18

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,13 @@ Setup your Android, iOS and/or web sources as described at Segment.com and gener
Set your Segment write key and change the automatic event tracking (only for Android and iOS) on if you wish the library to take care of it for you.
Remember that the application lifecycle events won't have any special context set for you by the time it is initialized.

### Integration Item List
| Item | Supported | Enum Name |
|------------------|---|---|
| `Amplitude` | YES | `SegmentIntegrationItemType.amplitude` |

You can tell the plugin tu use any integration item by insert them in `integrationItems` in `SegmentConfig`.

### Via Dart Code
```dart
void main() {
Expand All @@ -106,14 +113,17 @@ void main() {
options: SegmentConfig(
writeKey: 'YOUR_WRITE_KEY_GOES_HERE',
trackApplicationLifecycleEvents: false,
amplitudeIntegrationEnabled: false,
//Insert any plugins you want to use here,
//See `SegmentIntegrationItemType` enumeration
integrationItems: const [SegmentIntegrationItemType.amplitude],
debug: false,
),
);
}
```

### Android _(Deprecated*)_

### Android _(Deprecated* & Removed)_
```xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.flutter_segment_example">
<application>
Expand All @@ -128,7 +138,7 @@ void main() {
</manifest>
```

### iOS _(Deprecated*)_
### iOS _(Deprecated* & Removed)_
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,25 @@
import android.os.Bundle;

import java.util.HashMap;
import java.util.ArrayList; // import the ArrayList class


public class FlutterSegmentOptions {
private final String writeKey;
private final Boolean trackApplicationLifecycleEvents;
private final Boolean amplitudeIntegrationEnabled;
private final Boolean debug;
private final ArrayList<String> integrationItems;

//nullable arguments
public FlutterSegmentOptions(String writeKey, Boolean trackApplicationLifecycleEvents,Boolean debug) {
this(writeKey,trackApplicationLifecycleEvents,debug,new ArrayList<String>());
}

public FlutterSegmentOptions(String writeKey, Boolean trackApplicationLifecycleEvents, Boolean amplitudeIntegrationEnabled,Boolean debug) {
public FlutterSegmentOptions(String writeKey, Boolean trackApplicationLifecycleEvents, Boolean debug, ArrayList<String> integrationItems) {
this.writeKey = writeKey;
this.trackApplicationLifecycleEvents = trackApplicationLifecycleEvents;
this.amplitudeIntegrationEnabled = amplitudeIntegrationEnabled;
this.debug = debug;
this.integrationItems = integrationItems;
}

public String getWriteKey() {
Expand All @@ -25,28 +32,20 @@ public Boolean getTrackApplicationLifecycleEvents() {
return trackApplicationLifecycleEvents;
}

public Boolean isAmplitudeIntegrationEnabled() {
return amplitudeIntegrationEnabled;
public ArrayList<String> getIntegrationItems() {
return integrationItems;
}

public Boolean getDebug() {
return debug;
}

static FlutterSegmentOptions create(Bundle bundle) {
String writeKey = bundle.getString("com.claimsforce.segment.WRITE_KEY");
Boolean trackApplicationLifecycleEvents = bundle.getBoolean("com.claimsforce.segment.TRACK_APPLICATION_LIFECYCLE_EVENTS");
Boolean isAmplitudeIntegrationEnabled = bundle.getBoolean("com.claimsforce.segment.ENABLE_AMPLITUDE_INTEGRATION", false);
Boolean debug = bundle.getBoolean("com.claimsforce.segment.DEBUG", false);
return new FlutterSegmentOptions(writeKey, trackApplicationLifecycleEvents, isAmplitudeIntegrationEnabled, debug);
}

static FlutterSegmentOptions create(HashMap<String, Object> options) {
String writeKey = (String) options.get("writeKey");
Boolean trackApplicationLifecycleEvents = (Boolean) options.get("trackApplicationLifecycleEvents");
Boolean isAmplitudeIntegrationEnabled = orFalse((Boolean) options.get("amplitudeIntegrationEnabled"));
Boolean debug = orFalse((Boolean) options.get("debug"));
return new FlutterSegmentOptions(writeKey, trackApplicationLifecycleEvents, isAmplitudeIntegrationEnabled, debug);
ArrayList<String> integrationItems = (ArrayList<String>) options.get("integrationItems");
return new FlutterSegmentOptions(writeKey, trackApplicationLifecycleEvents, debug,integrationItems);
}

private static Boolean orFalse(Boolean value) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.LinkedHashMap;
import java.util.HashMap;
import java.util.Map;
import java.util.ArrayList;

import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
Expand Down Expand Up @@ -54,18 +55,6 @@ private void setupChannels(Context applicationContext, BinaryMessenger messenger
methodChannel = new MethodChannel(messenger, "flutter_segment");
// register the channel to receive calls
methodChannel.setMethodCallHandler(this);

try {
ApplicationInfo ai = applicationContext.getPackageManager()
.getApplicationInfo(applicationContext.getPackageName(), PackageManager.GET_META_DATA);

Bundle bundle = ai.metaData;

FlutterSegmentOptions options = FlutterSegmentOptions.create(bundle);
setupChannels(options);
} catch (Exception e) {
Log.e("FlutterSegment", e.getMessage());
}
Comment on lines -57 to -68
Copy link
Contributor

Choose a reason for hiding this comment

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

Whats the idea behind this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We don't need this code anymore since these are deprecated:
image

and also in iOS side.

Copy link
Contributor

Choose a reason for hiding this comment

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

Got it, then it does not relate to this PR right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@danielgomezrico I think it's related because it is a breaking change since we can't use an array in the android manifest or .plist. So, We need to remove it then.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry, I dont understand why this is related to this, can you try to explain it again please?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

  1. The old implementation (Integration using AndroidManifest.xml and ios info.plist) is deprecated.
  2. what I propose here is a new method that will not be compatible with the old implementation. Breaking change.

@danielgomezrico ,

Copy link

Choose a reason for hiding this comment

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

  1. The old implementation (Integration using AndroidManifest.xml and ios info.plist) is deprecated.

    1. what I propose here is a new method that will not be compatible with the old implementation. Breaking change.

@danielgomezrico ,

@ariefwijaya there is another issue open where initializing the sdk using the dart initialization results in App Installed events not being tracked on iOS:
#26

So while the old implementation is marked as deprecated, we had to revert back to it and rely on it for our iOS integrations

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh Thanks for the info, but in my case, I don't get that problem and not related to my implementation.
Because, I just improve our existing dart only installation..
You can continue the discussion about Installed Events not being tracked in this issue #26

}

private void setupChannels(FlutterSegmentOptions options) {
Expand All @@ -83,8 +72,14 @@ private void setupChannels(FlutterSegmentOptions options) {
analyticsBuilder.logLevel(LogLevel.DEBUG);
}

if (options.isAmplitudeIntegrationEnabled()) {
analyticsBuilder.use(AmplitudeIntegration.FACTORY);
for (String item : options.getIntegrationItems()) {
switch(item){
case "amplitude":
analyticsBuilder.use(AmplitudeIntegration.FACTORY);
break;
default:
// do nothing
}
}

// Here we build a middleware that just appends data to the current context
Expand Down
15 changes: 0 additions & 15 deletions example/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,5 @@
</activity>

<meta-data android:name="flutterEmbedding" android:value="2" />

<!-- Set your Segment write key and change the automatic event tracking
on if you wish the library to take care of it for you.
Remember that the application lifecycle events won't have any
special context set for you by the time it is initialized. -->
<meta-data android:name="com.claimsforce.segment.WRITE_KEY" android:value="YOUR_WRITE_KEY_GOES_HERE" />
<meta-data android:name="com.claimsforce.segment.TRACK_APPLICATION_LIFECYCLE_EVENTS" android:value="false" />
<!--
If you want to debug the plugin events. Default is false.
<meta-data android:name="com.claimsforce.segment.DEBUG" android:value="true" />

Expected shell output (flutter run) when this flag is enabled:
D/Analytics(32684): Ran TrackPayload{event="ButtonClicked"} on integration Segment.io in 480110 ns.
D/Analytics(32684): Ran TrackPayload{event="ButtonClicked"} on integration Segment.io in 104410 ns.
-->
</application>
</manifest>
4 changes: 0 additions & 4 deletions example/ios/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,6 @@
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>com.claimsforce.segment.WRITE_KEY</key>
<string>YOUR_WRITE_KEY_GOES_HERE</string>
<key>com.claimsforce.segment.TRACK_APPLICATION_LIFECYCLE_EVENTS</key>
<false/>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
Expand Down
3 changes: 2 additions & 1 deletion example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ void main() {
options: SegmentConfig(
writeKey: 'YOUR_WRITE_KEY_GOES_HERE',
trackApplicationLifecycleEvents: false,
integrationItems: const [SegmentIntegrationItemType.amplitude],
),
);

Expand Down Expand Up @@ -60,7 +61,7 @@ class MyApp extends StatelessWidget {
child: const Text('TRACK ACTION WITH SEGMENT'),
onPressed: () {
Segment.track(
eventName: 'ButtonClicked',
eventName: 'DevTest ButtonClicked',
properties: {
'foo': 'bar',
'number': 1337,
Expand Down
38 changes: 10 additions & 28 deletions ios/Classes/FlutterSegmentPlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,6 @@ + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
binaryMessenger:[registrar messenger]];
FlutterSegmentPlugin* instance = [[FlutterSegmentPlugin alloc] init];

SEGAnalyticsConfiguration *configuration = [FlutterSegmentPlugin createConfigFromFile];
if(configuration) {
[instance setup:configuration];
wasSetupFromFile = YES;
}

[registrar addMethodCallDelegate:instance channel:channel];
}

Expand Down Expand Up @@ -341,34 +335,22 @@ - (void)debug:(FlutterMethodCall*)call result:(FlutterResult)result {
}
}

+ (SEGAnalyticsConfiguration*)createConfigFromFile {
NSString *path = [[NSBundle mainBundle] pathForResource: @"Info" ofType: @"plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile: path];
NSString *writeKey = [dict objectForKey: @"com.claimsforce.segment.WRITE_KEY"];
BOOL trackApplicationLifecycleEvents = [[dict objectForKey: @"com.claimsforce.segment.TRACK_APPLICATION_LIFECYCLE_EVENTS"] boolValue];
BOOL isAmplitudeIntegrationEnabled = [[dict objectForKey: @"com.claimsforce.segment.ENABLE_AMPLITUDE_INTEGRATION"] boolValue];
if(!writeKey) {
return nil;
}
SEGAnalyticsConfiguration *configuration = [SEGAnalyticsConfiguration configurationWithWriteKey:writeKey];
configuration.trackApplicationLifecycleEvents = trackApplicationLifecycleEvents;

if (isAmplitudeIntegrationEnabled) {
[configuration use:[SEGAmplitudeIntegrationFactory instance]];
}

return configuration;
}

+ (SEGAnalyticsConfiguration*)createConfigFromDict:(NSDictionary*) dict {
NSString *writeKey = [dict objectForKey: @"writeKey"];
BOOL trackApplicationLifecycleEvents = [[dict objectForKey: @"trackApplicationLifecycleEvents"] boolValue];
BOOL isAmplitudeIntegrationEnabled = [[dict objectForKey: @"amplitudeIntegrationEnabled"] boolValue];
NSArray *integrationItems = [dict objectForKey: @"integrationItems"];
SEGAnalyticsConfiguration *configuration = [SEGAnalyticsConfiguration configurationWithWriteKey:writeKey];
configuration.trackApplicationLifecycleEvents = trackApplicationLifecycleEvents;

if (isAmplitudeIntegrationEnabled) {
[configuration use:[SEGAmplitudeIntegrationFactory instance]];
for (NSString* o in integrationItems)
{
((void (^)())@{
@"amplitude" : ^{
[configuration use:[SEGAmplitudeIntegrationFactory instance]];
},
}[o] ?: ^{
//Do Nothing
})();
}

return configuration;
Expand Down
9 changes: 6 additions & 3 deletions lib/src/segment_config.dart
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
enum SegmentIntegrationItemType { amplitude, unknown }

class SegmentConfig {
SegmentConfig({
required this.writeKey,
this.trackApplicationLifecycleEvents = false,
this.amplitudeIntegrationEnabled = false,
this.debug = false,
this.integrationItems,
});

final String writeKey;
final bool trackApplicationLifecycleEvents;
final bool amplitudeIntegrationEnabled;
final List<SegmentIntegrationItemType>? integrationItems;
final bool debug;

Map<String, dynamic> toMap() {
return {
'writeKey': writeKey,
'trackApplicationLifecycleEvents': trackApplicationLifecycleEvents,
'amplitudeIntegrationEnabled': amplitudeIntegrationEnabled,
'debug': debug,
'integrationItems':
integrationItems?.map((e) => e.toString().split(".").last).toList(),
};
}
}