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

Upgrade Flutter Android APIs #74

Merged
merged 8 commits into from
Jun 26, 2020

Conversation

vegaro
Copy link
Contributor

@vegaro vegaro commented Jun 25, 2020

As of the 1.12 release, new plugin APIs are available for the Android platform. The old APIs based on PluginRegistry.Registrar won’t be immediately deprecated, but we encourage you to migrate to the new APIs based on FlutterPlugin.

I followed the steps here https://flutter.dev/docs/development/packages-and-plugins/plugin-api-migration#testing-your-plugin

@vegaro vegaro linked an issue Jun 25, 2020 that may be closed by this pull request
@vegaro vegaro marked this pull request as draft June 25, 2020 22:05
public static void registerWith(Registrar registrar) {
PurchasesFlutterPlugin instance = new PurchasesFlutterPlugin();
instance.onAttachedToEngine(registrar.messenger(), registrar.context());
instance.registrar = registrar;
registrar.addViewDestroyListener(new PluginRegistry.ViewDestroyListener() {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am not sure we need this, but I don't think it would hurt to keep it since we already have it.

/**
* Plugin registration.
*/
public static void registerWith(Registrar registrar) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the old API, but we still need to support it

channel.setMethodCallHandler(new PurchasesFlutterPlugin(registrar, channel));
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
onAttachedToEngine(binding.getBinaryMessenger(), binding.getApplicationContext());
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the new API

}

public Activity getActivity() {
return registrar != null ? registrar.activity() : activity;
Copy link
Contributor Author

@vegaro vegaro Jun 26, 2020

Choose a reason for hiding this comment

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

This is how they do in https://github.com/flutter/plugins/blob/88e85c6a48063cfab9111689179e2582a99b77ff/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java

Since we still need to support the old API for apps that haven't updated yet, we need to check if the registrar is not null. registrar will be null for apps that use the new API and in that case the activity will be the one saved when onAttachedToActivity gets called.

public ActivityTestRule<EmbeddingV1Activity> rule =
new ActivityTestRule<>(EmbeddingV1Activity.class);

}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This test makes sure the old APIs are still supported. I copied this from migration docs https://flutter.dev/docs/development/packages-and-plugins/plugin-api-migration#testing-your-plugin

public class MainActivityTest {
@Rule
public ActivityTestRule<FlutterActivity> rule = new ActivityTestRule<>(FlutterActivity.class);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This test makes sure the new APIs are supported and the plugin is registered successfully. I copied this from migration docs https://flutter.dev/docs/development/packages-and-plugins/plugin-api-migration#testing-your-plugin

@@ -11,10 +11,9 @@
android:label="purchases_flutter_example"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:name="io.flutter.embedding.android.FlutterActivity"
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 a MainActivity anymore

super.onCreate(savedInstanceState);
PurchasesFlutterPlugin.registerWith(registrarFor("com.revenuecat.purchases_flutter"));
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

EmbeddingV1Activity.java uses the v1 embedding for the example project in the same folder as MainActivity to keep testing the v1 embedding’s compatibility with your plugin. Note that we have to manually register all the plugins instead of using GeneratedPluginRegistrant, as MainActivity used to do. Also copied from the upgrading docs.

@@ -30,7 +30,7 @@ class _MyAppState extends State<InitialScreen> {
Future<void> initPlatformState() async {
await Purchases.setDebugLogsEnabled(true);
await Purchases.setup("api_key");
Purchases.addAttributionData({}, PurchasesAttributionNetwork.facebook);
await Purchases.addAttributionData({}, PurchasesAttributionNetwork.facebook);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

pedantic told me this was missing

Copy link
Member

Choose a reason for hiding this comment

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

nice

@@ -20,6 +20,11 @@ dev_dependencies:
purchases_flutter:
path: ../

pedantic: ^1.8.0
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I saw most plugins use this linter tool so I added it

pedantic: ^1.8.0
e2e: ^0.2.1
flutter_driver:
sdk: flutter
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was mentioned in the upgrading docs, it's used to create end to end tests.

@@ -13,7 +13,7 @@ class Purchases {
static final Set<PurchaserInfoUpdateListener> _purchaserInfoUpdateListeners =
Set();

static final _channel = new MethodChannel('purchases_flutter')
static final _channel = MethodChannel('purchases_flutter')
Copy link
Contributor Author

Choose a reason for hiding this comment

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

pedantic told me new is not required

@@ -8,15 +8,19 @@ documentation: https://docs.revenuecat.com/

environment:
sdk: ">=2.1.0 <3.0.0"
flutter: ">=1.12.0 <2.0.0"
flutter: ">=1.12.13+hotfix.6 <2.0.0"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Also taken from the upgrading docs, this is the minimum version they offer support for.

expect(future, completes);
});

}
Copy link
Contributor Author

@vegaro vegaro Jun 26, 2020

Choose a reason for hiding this comment

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

Also copied from the upgrading docs. I ran it by doing ./gradlew app:connectedAndroidTest -Ptarget=pwd/../../test/purchases_flutter_e2e.dartinside example/android and it works. In Android Studio, it doesn't run I don't know why.

Also saw another example here https://github.com/FirebaseExtended/flutterfire/blob/master/packages/firebase_core/firebase_core/test/firebase_core_e2e.dart

This test actually runs in an emulator, so my understanding is we could test a bunch of stuff this way. It only works in Android though. I tried making a purchase and I could see the purchase dialog popping up :)

I am not even adding it to circleci for now, but I am going to leave it since it's part of the upgrading docs.

Copy link
Member

Choose a reason for hiding this comment

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

maybe we could have either a comment or something documenting how to actually run this test so we don't forget? or even a gradle task that wraps the command

await driver.requestData(null, timeout: const Duration(minutes: 1));
await driver.close();
exit(result == 'pass' ? 0 : 1);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am still not sure what this flutter driver is but I saw a lot of plugins have it (https://github.com/flutter/plugins/tree/master/packages/google_sign_in/google_sign_in/test_driver)

It's also referenced in the docs of e2e https://pub.dev/packages/e2e#using-flutter-driver-to-run-tests

Running flutter drive --driver=test_driver/purchases_flutter_e2e_test.dart ../test/purchases_flutter_e2e.dart inside the example will run the e2e test in the emulator

Copy link
Member

Choose a reason for hiding this comment

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

I guess it provides for a way to do UI tests or integration tests with a simulator

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, and I think e2e is to run flutter tests in a simulator (using flutter drive), or something like that. Alternatively, someone could write UI tests on the example app in order to test the same

@vegaro vegaro marked this pull request as ready for review June 26, 2020 02:32
@vegaro vegaro requested a review from aboedo June 26, 2020 02:32
@vegaro
Copy link
Contributor Author

vegaro commented Jun 26, 2020

I am a little bit confused with e2e y flutter_driver, but I don't think it's a blocker for this PR.

@@ -30,7 +30,7 @@ class _MyAppState extends State<InitialScreen> {
Future<void> initPlatformState() async {
await Purchases.setDebugLogsEnabled(true);
await Purchases.setup("api_key");
Purchases.addAttributionData({}, PurchasesAttributionNetwork.facebook);
await Purchases.addAttributionData({}, PurchasesAttributionNetwork.facebook);
Copy link
Member

Choose a reason for hiding this comment

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

nice

await driver.requestData(null, timeout: const Duration(minutes: 1));
await driver.close();
exit(result == 'pass' ? 0 : 1);
}
Copy link
Member

Choose a reason for hiding this comment

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

I guess it provides for a way to do UI tests or integration tests with a simulator

expect(future, completes);
});

}
Copy link
Member

Choose a reason for hiding this comment

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

maybe we could have either a comment or something documenting how to actually run this test so we don't forget? or even a gradle task that wraps the command

@vegaro vegaro merged commit da374da into develop Jun 26, 2020
@vegaro vegaro deleted the cesardelavega/ch132/upgrade-flutter-android-apis branch June 26, 2020 20:15
@vegaro vegaro mentioned this pull request Jun 26, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Upgrade to new Android plugins APIs
2 participants