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

flutter driver and android permissions #12561

Open
JFixby opened this issue Oct 16, 2017 · 31 comments
Open

flutter driver and android permissions #12561

JFixby opened this issue Oct 16, 2017 · 31 comments

Comments

@JFixby
Copy link

@JFixby JFixby commented Oct 16, 2017

Preliminaries:

Recently it turned out that when you are developing for Android 7+ or using the latest builds tools (26+) your android application has no permissions, even of they were requested in the Android manifest.

Looks like Android team is forcing developers to align their code with the concept of dynamic/runtime permissions. So even if you are building for device with Android API 16, the app would still crash because of missing permissions.

To handle this developer have to create a permission requesting dialog. Basically on application start developer has to collect list of missing permissions and using Android app compat send a request from OS to user asking him to accept new permissions. Looks like this:

image

So user has to accept the permissions and restart the app.

the problem with testing

When app starts all tests fail because of the permissions request dialog above.

workaround

Developer have to grant all permits to APK using the following example commands:
(permission granting script)

adb shell pm grant com.my.app  android.permission.ACCESS_FINE_LOCATION
adb shell pm grant com.my.app  android.permission.ACCESS_COARSE_LOCATION
adb shell pm grant com.my.app  android.permission.CAMERA
adb shell pm grant com.my.app  android.permission.WRITE_EXTERNAL_STORAGE
...

This will unlock permissions for apk and prevent the runtime permit popup.

Flutter Driver:

To run flutter driver you need to execute the following command:
flutter drive --target=./test_driver/sometest.dart

This calls the following code (https://github.com/flutter/flutter/blob/master/packages/flutter_tools/lib/src/commands/drive.dart#L248):

final ApplicationPackage package = await command.applicationPackages
      .getPackageForPlatform(await command.device.targetPlatform);
  if (await command.device.isAppInstalled(package))
    await command.device.uninstallApp(package);
  await command.device.installApp(package);// Step A
...
...// run app and tests, Step B

the problem

During the installApp Android deletes app permissions and all test fail again.

feature request

To add possibility to run external .bat or .sh script between steps A and B, so developer can put there some commands executed between APK installation and launch (i.e. the permission granting script).

@eseidelGoogle

This comment has been minimized.

Copy link
Contributor

@eseidelGoogle eseidelGoogle commented Oct 16, 2017

FYI @yjbanov

@JFixby

This comment has been minimized.

Copy link
Author

@JFixby JFixby commented Oct 17, 2017

practically it is a couple lines of code: add new flag like -pre-start-script=prestart.sh to the flutter driver tool
and run it right after the await command.device.installApp(package)

@Hixie Hixie added this to the 4: Next milestone milestone Oct 17, 2017
@antoninobajeli

This comment has been minimized.

Copy link

@antoninobajeli antoninobajeli commented Sep 28, 2018

Is there any news about this possible implementation?

@JFixby

This comment has been minimized.

Copy link
Author

@JFixby JFixby commented Sep 28, 2018

Wow, looks like this issue is going to celebrate an anniversary this October.

@yjbanov

This comment has been minimized.

Copy link
Contributor

@yjbanov yjbanov commented Sep 28, 2018

Sorry, somehow I missed it. I currently do not have the cycles to fix this. However, flutter drive has a --use-existing-app option, which lets you install and launch the app yourself. The driver will then connect to that app and execute the script. The automatic installation is only there for convenience.

To learn more run flutter drive --help.

@antoninobajeli

This comment has been minimized.

Copy link

@antoninobajeli antoninobajeli commented Oct 2, 2018

This is a good solution for the moment.
Thanks

@blackmenthor

This comment has been minimized.

Copy link

@blackmenthor blackmenthor commented Oct 12, 2018

If i run flutter drive with argument --use-existing-app, i can't define my own dart target file, is this a bug or this is the actual behavior?

@JFixby

This comment has been minimized.

Copy link
Author

@JFixby JFixby commented Oct 12, 2018

@blackmenthor this flag has nothing to do with dart files.

@yjbanov

This comment has been minimized.

Copy link
Contributor

@yjbanov yjbanov commented Oct 17, 2018

@blackmenthor this is by design. When you use this flag you already started the app, which means you already picked a target and launched it. All flutter drive needs to do at this point is connect to an already running app and execute the test script, which you can choose using the --driver option.

@klaidoja

This comment has been minimized.

Copy link

@klaidoja klaidoja commented Oct 19, 2018

I tried the approach with --use-existing-app, but ended up with driver not being able to connect.

... 
[info ] FlutterDriver: Waiting for application to start
[critical] FlutterDriver: Application has not started in 30 seconds. Giving up.

To be more precise, what I did was:

  1. run the app in development mode like I normally run it
  2. run flutter drive --use-existing-app=http://127.0.0.1:38892/ --driver=test_driver/app_test.dart

Can anybody help me out? Thanks

@yjbanov

This comment has been minimized.

Copy link
Contributor

@yjbanov yjbanov commented Oct 20, 2018

@klaidoja Ah, I forgot to mention that first thing in your main method you need to call enableFlutterDriverExtension so that the framework accept commands from FlutterDriver. This is disabled by default to keep the code small and your app fast. Consider having multiple entrypoints to your app, each with its own main function. One is for production deployment. Others are for testing.

More info: https://flutter.io/cookbook/testing/integration-test-introduction/

@yjbanov

This comment has been minimized.

Copy link
Contributor

@yjbanov yjbanov commented Oct 20, 2018

Actually, when FlutterDriver is giving up it could suggest it as an option. Could you please file a feature request?

@tGeorgeDN

This comment has been minimized.

Copy link

@tGeorgeDN tGeorgeDN commented Dec 20, 2018

We basically use this workaround in our [...]_test.dart files:

import 'dart:io';
...
setUpAll(() async {
  final Map<String, String> envVars = Platform.environment;
  final String adbPath = envVars['ANDROID_SDK_ROOT'] + '/platform-tools/adb.exe';
  await Process.run(adbPath , ['shell' ,'pm', 'grant', 'com.example.apppackage', 'android.permission.READ_EXTERNAL_STORAGE']);
  await Process.run(adbPath , ['shell' ,'pm', 'grant', 'com.example.apppackage', 'android.permission.READ_PHONE_STATE']);
  driver = await FlutterDriver.connect();
});
@jsalhi

This comment has been minimized.

Copy link

@jsalhi jsalhi commented Jan 9, 2019

tGeorgeDN's solution is a workaround for Android -- does anybody know of a similar workaround for iOS?

@hjJunior

This comment has been minimized.

Copy link

@hjJunior hjJunior commented Apr 2, 2019

I using Google Sign in, and on emulator when I call the method to sign in its showed a Dialog to confirm to use Google to login, how can I interact with it on Driver tests? 

Simulator Screen Shot - iPhone XR - 2019-04-02 at 14 35 01

@yjbanov

This comment has been minimized.

Copy link
Contributor

@yjbanov yjbanov commented Apr 2, 2019

@hjJunior It's not possible to do this using the FlutterDriver object. However, you can call adb from your test script. Perhaps it is possible to do this using adb?

/cc @collinjackson

@hjJunior

This comment has been minimized.

Copy link

@hjJunior hjJunior commented Apr 3, 2019

Sorry, but I'm not sure, because this screen is on iOS and not on Android, so I think adb doesn't work on iOS, is there an command available to interact with touch on iOS simulator

@nerder

This comment has been minimized.

Copy link

@nerder nerder commented Jun 13, 2019

I'm having a similar issue with firebase_auth using googleSignIn.

Reading a bit the code of the driver i was wondering if it might be solved exposing tapAt as well as tap so giving the exact location for where to tap should happen might fix this kind of issues of interacting with native elements, but I really don't understand at which "level" the driver operates and if it possible to overcome the issue following this approach.

I'll try to spike this one out and proposing a PR eventually :)

@hjJunior

This comment has been minimized.

Copy link

@hjJunior hjJunior commented Jun 13, 2019

Good idea @nerder, a workaround that I'd like to suggest is (if possible) try to mock your firebase_auth

@yjbanov

This comment has been minimized.

Copy link
Contributor

@yjbanov yjbanov commented Jun 14, 2019

Driver performs Flutter framework-level interactions. Unfortunately, a tapAt implemented on top of WidgetController (like tap is) won't tap on native controls. This is why I'm suggesting looking into adb, although I'm not sure if it's possible via adb either 🤷‍♂

@nerder

This comment has been minimized.

Copy link

@nerder nerder commented Jun 17, 2019

Thank you @yjbanov that is what i was suspecting, to bad won't be that easy 😞

I'll try to have a look at it and see if i can spike something out, a separate discussion about this same feature request is here #34345 , we should merge them closing one in favor of the other?

@yjbanov

This comment has been minimized.

Copy link
Contributor

@yjbanov yjbanov commented Jun 17, 2019

I'll let @collinjackson figure out what's the optimal set of issues here. It might be that the general issue of not being able to interact with native controls should be treated separately from permissions. I'm not sure.

@joseignacioojeda

This comment has been minimized.

Copy link

@joseignacioojeda joseignacioojeda commented Jul 1, 2019

I'm trying to click on the native confirm message box to allow the sensors permissions in iPhone but I can find the way using "flutter driver". Does it exist in any way to interact with these kinds of the native component? Do you think to implement this feature?

@nerder

This comment has been minimized.

Copy link

@nerder nerder commented Jul 1, 2019

@joseignacioojeda at the moment there is no way to do that as far as I know. Seems like @collinjackson is working on it, you can have more details here: #34345

@joseignacioojeda

This comment has been minimized.

Copy link

@joseignacioojeda joseignacioojeda commented Jul 1, 2019

Thank you @nerder, I will be pending of the evolution

@stevenspiel

This comment has been minimized.

Copy link

@stevenspiel stevenspiel commented Jul 2, 2019

Some iOS permissions are covered with applesimutils

available options are:

calendar=YES|NO|unset
camera=YES|NO|unset
contacts=YES|NO|unset
health=YES|NO|unset (iOS 12.0 and above)
homekit=YES|NO|unset
location=always|inuse|never|unset
medialibrary=YES|NO|unset
microphone=YES|NO|unset
motion=YES|NO|unset
notifications=YES|NO|unset
photos=YES|NO|unset
reminders=YES|NO|unset
siri=YES|NO|unset
speech=YES|NO|unset

It's not very elegant, but as a stopgap, I use it in my driver tests in the setUpAll hook:

Process.run('applesimutils', ["--byId", deviceId, "--bundle", appBundleIdentifier, "--setPermissions", "location=always"]);

deviceId can be found with $ xcrun simctl list
appBundleIdentifier is in ios/Runner/Info.plist under CFBundleIdentifier

@mozes-pb

This comment has been minimized.

Copy link

@mozes-pb mozes-pb commented Jul 8, 2019

Hi @stevenspiel, can you share on how you do it on ios simulator? because whenever i set permission using applesimutils, the springboard is restarted, and then the app is not launched anymore.

I tried to add this in setUpAll :
Process.run('xcrun', ["simctl", "launch", "booted", iosBundleIdentifier]);

this does launch back the app, but the driver cannot connect to the VM.

@stevenspiel

This comment has been minimized.

Copy link

@stevenspiel stevenspiel commented Jul 10, 2019

@mozes-pb I haven't run into that. How are you running the tests?

$ flutter drive --target=test_driver/app.dart

or do you run the app with an observatory port and VM_SERVICE_URL?

$ flutter run test_driver/app.dart --observatory-port 8888

# open new session/tab
$ export VM_SERVICE_URL=${vm_service_url}
$ dart -d test_driver/app_test.dart

What happens if you run:

$ flutter run test_driver/app.dart

# open new session/tab
$ applesimutils --byId ${device_id} --bundle ${bundleId} --setPermissions location=always

Does the app stop running? What do you mean by "the app is not launched anymore"? Any logging would be helpful.

@NerditLtd

This comment has been minimized.

Copy link

@NerditLtd NerditLtd commented Oct 12, 2019

How we should test share dialog(share plugin) using FlutterDriver . How we should get notified the dialog opened

@genert

This comment has been minimized.

Copy link

@genert genert commented Nov 27, 2019

This issue blocks us from writing e2e tests. Any updates on when this will resolved?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Flutter Driver
Awaiting triage
You can’t perform that action at this time.