Arquitectura de Aplicaciones

1

¡Renovaremos este curso! Te quedan unos días para concluirlo.

2

Pasos para aprender Flutter Avanzado

3

¿Qué es una Arquitectura de software?

4

Tipos de Arquitecturas para Flutter

5

Arquitectura BLoC en Flutter

6

BLoC + Clean Architecture en Flutter

7

Estructurando nuestro proyecto utilizando la Arquitectura BLoC

8

Haciendo BLoC Singleton en Flutter

9

Aplicando Providers al Proyecto

Firebase y Flutter

10

¡Renovaremos este curso! Te quedan unos días para concluirlo.

11

Integrando Firebase Authentication, Cloud Firestore y Firebase Storage al proyecto

12

Integrando Firebase a Flutter para iOS

13

Integrando Firebase a Flutter para Android

14

Creación de Pantalla de Login con Flutter

15

Creando botones reutilizables en Flutter

16

Autenticación de Firebase con Google

17

¡Renovaremos este curso! Te quedan unos días para concluirlo.

18

Implementando Firebase Authentication en BLoC Pattern

19

Streams en Flutter

20

Manejando una sesión con Firebase Authentication y Flutter

21

Implementando Google SignOut en BLoC

22

Implementando Google SignOut en View

23

Monitoreando y validando la conexión al Sign con Google

24

Mostrando los datos de usuario de Google en la interfaz en Flutter

Cloud Firestore de Firebase en Flutter

25

¡Renovaremos este curso! Te quedan unos días para concluirlo.

26

¿Qué es Cloud Firestore de Firebase?

27

Analizando un modelo de datos no relacional

28

Creando un Modelo de datos en Cloud Firestore

29

Enviando datos a Cloud Firestore

30

Creando un Widget gradiente personalizado

31

Manejo de Desbordamiendo de Texto de Widget Text

32

Botón de Back en un Appbar en Flutter

33

Navegación entre pantallas en Flutter

34

Widget Text Appbar personalizado en Flutter

35

¡Renovaremos este curso! Te quedan unos días para concluirlo.

36

Widget TextField personalizado en Flutter

37

Creando una Safe Area para una interfaz que tiene un AppBar

38

Widget TextField con iconos en Flutter

39

Retocando el CardView

40

Mostrando imágenes en un CardView

41

Creando un botón de Submit en Flutter

42

Envío de datos de un fórmulario en Flutter

43

Subiendo datos a Firestore de Firebase

44

Formularios en Flutter

Acceso al Hardware con Flutter

45

¡Renovaremos este curso! Te quedan unos días para concluirlo.

46

Acceso a la cámara en Flutter

47

Librerías de acceso a Hardware en Flutter

Firebase Storage en Flutter

48

¡Renovaremos este curso! Te quedan unos días para concluirlo.

49

Qué es y cómo funciona Firebase Storage en Flutter

50

Subiendo una imagen a Firebase Storage desde Flutter

Querys avanzados en Cloud Firestore de Firebase en Flutter

51

¡Renovaremos este curso! Te quedan unos días para concluirlo.

52

Manejo de imágenes en Cloud Firestore

53

Cloud Firestore insertando referencias y arrays en la base de datos

54

Descargar imágenes de Firebase Storage y mostrarlas en Flutter

55

Procesando datos con BLoC Pattern

56

Trayendo datos de Cloud Firestore

57

Persistiendo datos de un usuario logueado

58

Aplicando Filtros en Cloud Firestore

59

¡Renovaremos este curso! Te quedan unos días para concluirlo.

60

Construyendo los Places en la pantalla de Home

61

Mostrando los Places en la pantalla de Home

62

Actualizando datos en tiempo real

63

Manejando la lógica de likes, como botón toggle.

64

Insertando y obteniendo referencias en datos de Firestore.

65

Usando el caché para cargar imágenes más rápido

66

StreamController, sink, add y StreamBuilder

Conclusiones

67

¡Renovaremos este curso! Te quedan unos días para concluirlo.

68

Conclusiones

No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Curso Avanzado de Flutter

Curso Avanzado de Flutter

Anahí Salgado Díaz de la Vega

Anahí Salgado Díaz de la Vega

Acceso a la cámara en Flutter

46/68
Recursos

Ahora que estamos en esta clase debemos entender cómo es que Android y iOS manejan el acceso al Hardware, cada uno tiene un sistema de permisos que debemos darle de alta. Desde el código debemos manejar este sistema de permisos en dado caso que el hardware sea obligatorio, en este caso el único permiso que configuraremos es el uso a la cámara.

Debemos agregar el paquete image_picker a nuestro proyecto, puedes consultar en la sección de enlaces para encontrar la versión más actualizada.

Aquí está el repositorio de esta clase.

Aportes 43

Preguntas 4

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

o inicia sesión.

Para seguir el curso con image_picker: ^0.6.7+9 actualmente
en archivo button_bar.dart en Widget build
agregar

final picker = ImagePicker();

y luego donde trabaja el ImagePicker.pickImage esta deprecado, utilizar

picker.getImage(source: ImageSource.camera).then((PickedFile image) {
                  Navigator.push(
                    context, 
                    MaterialPageRoute(builder: (BuildContext context) => AddPlaceScreen(image: File(image.path))));
              }).catchError((onError) => print(onError));

y luego en el archivo card_image, clase CardImageWithFabIcon agregar donde trabaja con el AssetImage

image: pathImage.contains('assets') ? AssetImage(pathImage) : FileImage(new File(pathImage)),

te pedirá importar dart:io

Buena explicación aun que por alguna razón ahora el método AssetImage que se ocupa en la clase CardImageWithFabIcon ya no funciona como en el video, es decir, si lo que quieres cargar esta fuera de la carpeta donde se encuentran los “assets” te manda un error de “unable to load asset storage/emulated/0…” . Para esto solo realice una validación en la clase que mencione anteriormente al cargar la imagen. En caso que la ruta tuviera “assets” el programa usa el metodo AssetImage y en caso contrario FileImage.

Puede que haya otras soluciones mas practicas pero por ahora fue lo unico que se me ocurrio para seguir el curso.

card_image.dart (Clase CardImageWithFabIcon)

 decoration: BoxDecoration(
          image: DecorationImage(
              fit: BoxFit.cover,
              //image: AssetImage(pathImage)
              image: pathImage.contains('assets')? AssetImage(pathImage):new FileImage(new File(pathImage))
          ),

Los permisos de apple:

<key>NSCameraUsageDescription</key>
	<string>Platzi Trips reuiere tomar una foto. ¿Podemos user tú cámara?</string>
	<key>NSPhotoLibraryUsageDescription</key>
	<string>Platzi Trips reuiere tomar una foto. ¿Podemos user tú cámara?</string>
	<key>NSMicrophoneUsageDescription</key>
	<string>Platzi Trips reuiere tomar una foto. ¿Podemos user tú cámara?</string>

Lo que hice al aplicar el ImagePicker fue validar que la imagen no sea null . Eso puede ocurrir si el usuario se devuelve y no toma ninguna foto. Esto nos mostraría un error porque igual se ejecutaría el Navigator.push. En este caso no 😄 .

ImagePicker.pickImage(source: ImageSource.gallery).then(

                      (File image) {

                        if (image != null){
                          Navigator.push(context,
                              MaterialPageRoute(
                                  builder: (BuildContext context) =>
                                      AddPlaceScreen(image: image)
                              ));
                        }

                      }
                  ).catchError((onError) {
                    print(onError);
                  });```

Al principio tuve problemas utilizando las librería image_picker.

Primeramente utilicé la ultima version (al momento que esto escribiendo este comentario es la versión 0.6.1+11). Al usar esta versión no dejaba compilar y me daba el siguiente error :

Android dependency ‘androidx.core:core’ has different version for the compile (1.0.0) and runtime (1.0.1) classpath. You should manually set the same version via DependencyResolution

Luego probé con una versión menor a la 0.6, incluso con la versión que se utiliza en este video, y ahí si compilaba e incluso me permitía seleccionar la imagen de la cámara, pero luego redireccionaba al home y no a la vista del formulario y me daba este otro error:

java.lang.RuntimeException: Methods marked with @UiThread must be executed on the main thread.

Y al volver a intentar da este otro mensaje:

Unhandled Exception: PlatformException(already_active, Image picker is already active, null)

Entonces lo solucioné del siguiente modo, volví a la última versión de la librería y en el archivo “android/build.gradle” agregué las siguientes líneas

subprojects {
    project.configurations.all {
        resolutionStrategy.eachDependency { details ->
                if (details.requested.group == 'androidx.core' &&
            !details.requested.name.contains('androidx')) {
            details.useVersion "1.0.1"
                }
        }
    }    
}

La solucióm que tuve para el problema unable to load asset… fué asignarle una validación si contiene ‘assets’ , quedando para el caso de que no, creamos un FileImage y un cast para recibirlo como ImageProvider<Object>

       image: DecorationImage(
            image: imagepath.contains('assets')? AssetImage(imagepath):FileImage(File(imagepath)) as ImageProvider<Object> ,
          fit: BoxFit.cover,
        ),

Compañeros les quiero compartir como lo solucione con la versión 0.6.7+2 de image_picker, para lo cual modifique varios archivos

card_image.dart

Cambiar el string de path image por ImageProvider

String pathImage -> ImageProvider image

decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: pathImage —> image
),

add_place_screen.dart

Agregar el archivo de la imagen y el image picker a la clase hija no a la principal por lo que el constructor se puede eliminar

class _AddPlaceScreen extends State{
File image;
final ImagePicker picker=ImagePicker();

Agregar el metodo getImage y modificar la imagen con lo que se obtenga con la cámara

Future getImage() async {
final pickedFile = await picker.getImage(source: ImageSource.camera);
setState(() {
image = File(pickedFile.path);
});
}

Donde se agrega la cardImage definir el tipo de imagen por asset o por archivo y agregar la funcionalidad para capturar la foto

child: CardImageWithFabButton(
image: image==null?AssetImage(“assets/img/river.jpeg”):FileImage(image),
width: 300,
height: 200,
left: 0,
onPresedFabIcon: (){
getImage();
},
iconData: Icons.add_a_photo,
),

button_bar.dart

Donde cambiamos de pantalla (push) solo pasar la pantalla sin el file quedando

CircleButton(false, Icons.add, 40.0, Color.fromRGBO(255, 255, 255, 1),(){
Navigator.push(context,
MaterialPageRoute(builder:(BuildContext context) => AddPlaceScreen()));
}),

Y por ultimo en
Card_image.dart

Cambiar el storing por el constructor del asset, toDo es un método vacio que genere por si se llega a ocupar

void toDo(){
}

CardImageWithFabButton(
image: “assets/img/sunset.jpeg”, —> AssetImage(“assets/img/sunset.jpeg”)
width: width,
height: height,
left: left,
iconData: Icons.favorite_border,
onPresedFabIcon: toDo,
),

Espero les sirva y tambien comentarles que en el emulador de ios no he podido hacer que funcione la camara, segun lo que he encontrado es imposible, que solo con un dispositivo fisico asi que si quieren probar a conseguirse un iphone o a crear una solucion para esto, bueno gracias por leerme.

La solucion para el bug de Unable to load asset: luego de tomar la foto con la camara se realiza de la siguiente manera

Primero debemos modificar el archivo card_image preferiblemente creando uno igual solo para el add place, en el cambiaremos el parametro image de la image para que sea tipo file y leeremos un archivo por defecto en caso de que venga vacio el card

 final card = Container(
      height: height,
      width: width,
      margin: EdgeInsets.only(
          top: 80.0,
          left: left

      ),

      decoration: BoxDecoration(
          image: DecorationImage(
              fit: BoxFit.cover,
              image: pathImage != null ? FileImage( pathImage ) : AssetImage('assets/no-image.jpeg')
          ),
          borderRadius: BorderRadius.all(Radius.circular(10.0)),
          shape: BoxShape.rectangle,
          boxShadow: <BoxShadow>[
            BoxShadow (
                color:  Colors.black38,
                blurRadius: 15.0,
                offset: Offset(0.0, 7.0)
            )
          ]

      ),
    );

Segundo paso consiste en declarar pathImage como File con

  final File pathImage;```

En el archivo add place enviaremos el widget.image sin el .path es decir el archivo completo 


Container(
alignment: Alignment.center,
child: CardImageWithFabIcon(
pathImage: widget.image,//“assets/img/sunset.jpeg”,
iconData: Icons.camera_alt,
width: 350.0,
height: 250.0,left: 0,
),
), //Foto```

Con esto conseguiremos enviar la foto tomada como archivo del android y no una ruta que por supuesto flutter no puede leer pues no se ha declarado dentro del yaml.

Espero les sirva probe otras soluciones como el await o rebajar la resolucion pero nada sirvio al 100%

si llegas hasta aca sabras que mucho de lo que esta en este curso esta desactualizado y se deben cambiar algunos detalles para que funcione como a la hora de tomar la foto y querer mostrarla sale el error tipo _“unable to load asset storage/emulated/0…” _ , aca les dejo el link a mi repositorio en el commit extacto de como quedo y si les da pereza, asi queda:

decoration: BoxDecoration(
        image: DecorationImage(
          fit: BoxFit.cover,
            image: pathImage.contains('assets') ? AssetImage(pathImage)
                :  FileImage( File(pathImage)) as ImageProvider,
        ),

Esta es la última versión para mayo 2022:
image_picker: ^0.8.5+3

Muy buenos días compañer@s, después de dos días, son las 2am hora Perú y recién termino mi código. ¡¡¡¡¡POR FIN FUNCIONO!!!
Ok, solo tienen que copiar esto en el archivo add_place_screen.dart
si desean pueden borrar todo su código, copian el mio y lo pegan; lo siguiente que tienen que hacer es modificar el archivo button_bar.dart, aquí les dejo el código como tiene que quedar:

//añadir una nueva foto
            CircleButton(false, Icons.add, 40.0, Color.fromRGBO(255, 255, 255, 1),
                    () {
                Navigator.push(
                    context,
                    MaterialPageRoute(builder:
                        (BuildContext context) => AddPhotoScreen()));
                    }),```

Aquí también les dejo el código del archivo Add_place_screen.dart:



import ‘dart:io’;

import ‘package:flutter/cupertino.dart’;
import ‘package:flutter/material.dart’;
import ‘package:generic_bloc_provider/generic_bloc_provider.dart’;
import ‘package:goldenboys/barbershop/model/barbershop.dart’;
import ‘package:goldenboys/user/bloc/bloc_user.dart’;
import ‘package:goldenboys/widgets/button_add_photo_screen_and_reservar.dart’;
import ‘package:goldenboys/widgets/gradient_back_generico.dart’;
import ‘package:goldenboys/widgets/text_input.dart’;
import ‘package:goldenboys/widgets/title_header.dart’;
import ‘package:image_picker/image_picker.dart’;

class AddPhotoScreen extends StatefulWidget{
@override
_AddPhotoScreen createState() => _AddPhotoScreen();
}

class _AddPhotoScreen extends State<AddPhotoScreen>{

File _image;
final picker = ImagePicker();

final _controllerTitlePhoto = TextEditingController();
final _controllerDescriptionPhoto = TextEditingController();

Future getImage() async {
final pickedFile = await picker.getImage(source: ImageSource.camera);

setState(() {
  _image = File(pickedFile.path);
});

}

@override
Widget build(BuildContext context) {
// TODO: implement build
UserBloc userBloc = BlocProvider.of<UserBloc>(context);
double screenWidth = MediaQuery.of(context).size.width;

return Scaffold(
  body: Stack(
    children: <Widget>[
      GradientBackGenerico(height: 300.0,),
      Row( //esto es el appbar
        children: <Widget>[
          Container(
            padding: EdgeInsets.only(top: 30.0, left: 5.0),
            child: SizedBox(
              height: 45.0,
              width: 45.0,
              child: IconButton(
                icon: Icon(
                  Icons.arrow_back,
                  color: Colors.white, size: 40,
                ),
                onPressed: (){
                  Navigator.pop(context);
                },
              ),
            ),
          ),

          Flexible(
            child: Container(
              width: screenWidth,
              padding: EdgeInsets.only(top: 40.0, left: 20.0, right: 10.0),
              child: TitleHeader(title: "Agreaga una foto"),
          ),
          )
        ],
      ),

      Container(
        margin: EdgeInsets.only(top: 100.0),
        child: ListView(
          children: <Widget>[ //aqui contiene la foto
            Stack(
              alignment: Alignment(0.9,1.0),
              children: <Widget>[
                Container(    //aqui contiene la foto
                  alignment: Alignment.center, //esto hace que el texto se alinie al medio
                  height: 480.0,
                  width: 360.0,
                  margin: EdgeInsets.only(
                      top: 10.0, bottom: 20.0
                  ),
                  decoration: BoxDecoration(
                    //borderRadius: BorderRadius.all(Radius.circular(10.0)),
                    color: Colors.white,
                    boxShadow: <BoxShadow>[
                      BoxShadow (
                          color:  Colors.black38,
                          blurRadius: 15.0,
                          offset: Offset(0.0, 7.0)
                      )
                    ]
                  ),
                  child: _image == null
                      ? Text('No hay imagen seleccionada.', textAlign: TextAlign.center,)
                      : Image.file(_image),
                ),
                FloatingActionButton(
                  onPressed: getImage,
                  tooltip: 'Pick Image',
                  child: Icon(Icons.add_a_photo),
                ),
              ],
            ),



            Container(
              margin: EdgeInsets.only(top: 30.0, bottom: 20.0),
              child: TextInput(
                hintText: "Titulo",
                inputType: null,
                maxLines: 1,
                controller: _controllerTitlePhoto,
              ),
            ), //esto contiene el titulo de la foto
            TextInput( //esto es para la descripcion de la foto
              hintText: "Descripción",
              inputType: TextInputType.multiline,
              maxLines: 5,
              controller: _controllerDescriptionPhoto,
            ),
            Container(
              width: 70.0,
              child: ButtonAddPhotoScreen(
                height: 45.0,
                width: 180.0,
                buttonText: "Añadir foto",
                onPressed: (){
                  //1.Firebastore
                  //url -

                  //2.cloud Firestore
                  //Photo: title, description, url, userOwner, likes
                  userBloc.updateBarbershopDate(Barbershop(
                    name: _controllerTitlePhoto.text,
                    description: _controllerDescriptionPhoto.text,
                    likes: 0,

                  )).whenComplete((){
                    print("TERMINADO");
                    Navigator.pop(context); //esto es para destruir la ventana, para regresar a la ventana anterior
                  });
                },
              ),
            )
          ],
        ),
      )

    ],
  ),
);

}

}```

Tuve inconvenientes para utilizar la librería image_picker, con excepciones como:

java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.ProviderInfo.loadXmlMetaData

Para las personas que tengan problema en algún punto para utilizar la camara en Android.

Detener la ejecución en el dispositivo o emulador
Ejecutar los siguientes comandos desde el terminal:

  1. flutter clean.
  2. flutter packages get

De esta manera flutter reconstruirá el build de la aplicación desde 0 y refrescará la implementación de las distintas librerías.

Luego ejecutar la aplicación nuevamente y listo!

Compañeros, una pregunta. Ya pude configurar las librerìas con el mensaje del compañero @Jose Gonzalez.
Ahora me lanza el siguiente error.

Unable to load asset: /storage/emulated/0/Android/data/com.anncode.platzitripsapp/files/Pictures/fe9801b4-2b3f-467d-9e12-367e07006f3f-1645602123.jpg```

Estoy depurando directamente en un dispositivo Samsung Galaxy J2.

Tuve un problema con mostrar la imagen. Lo que tengo hecho es que en el mismo screen puedas sacar foto. Después de hacer la foto, me saltaba el error “platform exception: image picker is already active”. Esto lo he podido solucionar en “Tools ->Flutter->Flutter Clean”. En caso de dar error otra vez (como a mi), id a la carpeta del proyecto y eliminad el interior de “build”. Después de volverlo a ejecutar me ha funcionado. Espero que esta información le pueda ser util a alguien.

En celulares de gama baja funciona lento el ImagePicker y según la documentación de la librería en ocasiones la app se reinicia al tomar fotos en resoluciones altas.
Por ello seguí esta guía para acceder a la cámara desde la aplicación.
Toma una imagen usando la cámara
La diferencia es notable en el rendimiento de la app.

image_picker: ^0.6.7+4

onPressed: () {
          ImagePicker.platform.pickImage(
            source: ImageSource.camera).then((image){
              if(image != null)
                Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => RegisterReceipt(image: image))
            );
          }).catchError((onError) => print(onError));
        }

En el archivo dart add_place_screen se debe cambiar File image a PickedFile image;

Desde Android M el acceso a la cámara en Android es privado, por tanto, es obligatorio solicitar el acceso a la cámara. Si se compila para esa versión de Android, con solo añadir el permiso en el archivo de manifiesto, el propio sistema genera el diálogo de permiso, pero desde Android 7 en adelante, es obligatorio solicitar el permiso, no solo añadiendo el permiso en el manifiesto, sino desde el propio código de la aplicación.

Los queries en el manifest de Android, para la versión 11 y superior es para interactuar con aplicaciones que no sean visibles para la app propia, es decir, que si se tiene alguna aplicación adicional que maneje la cámara, con solo el permiso, nuestra app usará directamente la cámara, mientras que con el query, el sistema hará uso de la app que se disponga para la cámara.

Si les marca el siguiente error:

The argument type 'Null Function(File)' can't be assigned to the parameter type 'FutureOr<dynamic> Function(XFile?)'

Pueden solucionarlo quitando el tipo ‘File’ del argumento de la función en “then”, de la siguiente manera:

picker.pickImage(source: ImageSource.camera).then((image) {
                  Navigator.push(
                    context, 
                    MaterialPageRoute(builder: (BuildContext context) => AddPlaceScreen(image: File(image!.path))));
              }).catchError((onError) =>print(onError));

A algunos les puede pasar que les salga el error

The plugin `flutter_plugin_android_lifecycle` doesn't have a main class defined in

Cuando hagan flutter pub get después de poner la dependencia en el pubspect.yaml, yo logré solucionar el error eliminando la carpeta .pub-cache, que en mi caso estaba en C:\src\flutter.pub-cache y después corriendo flutter pub get de nuevo

Hola a todos
Tengo el siguiente problema, al presionar el botón para ir a “Add new place” y tomar la foto, logro tomar la foto pero vuelve a la pantalla de profile, no da error pero no puedo ir a “new place”, hay alguna forma de debugear la libreria. Se que es muy vago la descripción que doy pero no tengo mas que eso

Gente me metí a explorar la documentación de image_picker y encontré que se pueden ajustar los tamaños de la foto al sacarla con la camara como en este codigo:

var fileFromCamera = await ImagePicker.pickImage(source: ImageSource.camera, maxHeight: 480, maxWidth: 640);

Gracias a la respuesta de Idee en
https://stackoverflow.com/questions/50453705/image-size-taken-from-flutter-image-picker-plugin-is-way-too-big

Gente a algunos podría pasarles como a mí que tenían un bug en la camara, que al arrepentirse de tomar una foto y regresar el telefono mandaba error diciendo imageFile == null o algo así. Lo logré arreglar incluyendo el siguiente fragmento de código antes de llamar a la clase AddPlaceScreen:

if (pickedFile == null) {
                  return;
                }

Y este era el codigo del boton correspondiente en el archivo button_bar.dart

CircleButton(
                false, Icons.camera_alt, 40.0, Color.fromRGBO(255, 255, 255, 1),
                () async {
              await ImagePicker()
                  .getImage(
                      source: ImageSource.camera, maxHeight: 480, maxWidth: 640)
                  .then((pickedFile) {
                if (pickedFile == null) {
                  return;
                }
                Navigator.push(
                    context,
                    MaterialPageRoute(
                        builder: (BuildContext context) =>
                            AddPlantaScreen(imagen: File(pickedFile.path))));
              }).catchError((onError) => print(onError));
            }),

Nota

Yo hice otro botón para que se pudiera sacar una imagen desde la galería, el código es casi igual excepto por el image.source en el ImagePicker.getImage(), ahi puse ImageSource.gallery y todo lo demás exactamente igual

Espero que sirva, saludos y exito con el curso, está muy bueno

Creo que hay un error bastante grave… Se propone que todo se ejecute desde la button_bar de la add_places_Screen… NO TIENE SENTIDO… Se necesita entrar en la add_places_
Screen y, en el botón de la imagen, hacer la foto…

Permisos IOS (info.plist)

<key>NSCameraUsageDescription</key>
    <string>Platzi Trips quiere tomar una foto. ¿Podemos usar tu cámara?</string>
    <key>NSPhotoLibraryUsageDescription</key>
    <string>Platzi Trips quiere tomar una foto. ¿Podemos usar tu cámara?</string>
    <key>NSMicrophoneUsageDescription</key>
    <string>Platzi Trips quiere tomar una foto. ¿Podemos usar tu cámara?</string>

Al momento de aceptar que la imagen se guarde (desde la camara) obtengo el siguiente error:

I/InputMethodManager( 8465): startInputInner - mService.startInputOrWindowGainedFocus
W/Binder ( 8465): Caught a RuntimeException from the binder stub implementation.
W/Binder ( 8465): java.lang.RuntimeException: Methods marked with @UiThread must be executed on the main thread. Current thread: Binder:8465_3
W/Binder ( 8465): at io.flutter.embedding.engine.FlutterJNI.ensureRunningOnMainThread(FlutterJNI.java:793)
W/Binder ( 8465): at io.flutter.embedding.engine.FlutterJNI.invokePlatformMessageResponseCallback(FlutterJNI.java:726)
W/Binder ( 8465): at io.flutter.embedding.engine.dart.DartMessenger$Reply.reply(DartMessenger.java:153)
W/Binder ( 8465): at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler$1.success(MethodChannel.java:234)
W/Binder ( 8465): at io.flutter.plugins.imagepicker.ImagePickerDelegate.finishWithSuccess(ImagePickerDelegate.java:540)
W/Binder ( 8465): at io.flutter.plugins.imagepicker.ImagePickerDelegate.handleImageResult(ImagePickerDelegate.java:505)
W/Binder ( 8465): at io.flutter.plugins.imagepicker.ImagePickerDelegate.access$000(ImagePickerDelegate.java:66)
W/Binder ( 8465): at io.flutter.plugins.imagepicker.ImagePickerDelegate$4.onPathReady(ImagePickerDelegate.java:470)
W/Binder ( 8465): at io.flutter.plugins.imagepicker.ImagePickerDelegate$3$1.onScanCompleted(ImagePickerDelegate.java:160)
W/Binder ( 8465): at android.media.MediaScannerConnection$ClientProxy.onScanCompleted(MediaScannerConnection.java:254)
W/Binder ( 8465): at android.media.MediaScannerConnection$1.scanCompleted(MediaScannerConnection.java:55)
W/Binder ( 8465): at android.media.IMediaScannerListener$Stub.onTransact(IMediaScannerListener.java:97)
W/Binder ( 8465): at android.os.Binder.execTransactInternal(Binder.java:1021)
W/Binder ( 8465): at android.os.Binder.execTransact(Binder.java:994)

En Android.

Si están realizando los ejercicios para web, y en vez de tomar foto quieren adjuntar una imagen se puede solucionar con el siguiente código con el picker

ImagePicker imgPicker = ImagePicker();
imgPicker.pickImage(source: ImageSource.camera).
   then((image) {
              Navigator.push(context, 
              MaterialPageRoute(builder: (BuildContext context) => 
              AddPlaceScreen(image: File(image!.path))));
            }).catchError((onError) => print(onError));

para utilizar la librería de image_picker es mejor utilizar el comando pub para instalar la última versión

 $ flutter pub add image_picker

saludos gente de platzi, en la actualidad

  1. es necesario poner la versión de de la image_picker en pubspec.yaml

  2. en el manifiesto de android debes colocar las siquientes lineas de codigo

    <queries>
    <intent>
    <action android:name=“android.media.action.IMAGE_CAPTURE” />
    </intent>
    </queries>

Para todos aquellos que les aparecen los errores :

  • java.lang.RuntimeException: Methods marked with @UiThread must be executed on the main thread.

  • Unhandled Exception: PlatformException(already_active, Image picker is already active, null)

Mi solucion para android API >= 29:
en pubspec.yaml

  #image picker (2020) ^0.6.7+17 or bigger, you can also just add image_picker: with nothing else to get the last version (no suggested for deployments)
  image_picker: ^0.6.7+17 

en button_bar.dart

CircleButton(false, Icons.add, 40.0, Color.fromRGBO(255, 255, 255, 1),
              () {
                ImagePicker().getImage(
                    source: ImageSource.camera
                )
                .then((PickedFile image) {
                  if(image != null) {
                    Navigator.push(
                        context,
                        MaterialPageRoute(builder: (BuildContext context) => AddPlaceScreen(image: image) )
                    );
                  } else { print('Not image selected, do nothing'); }

                })
                .catchError((error) => print('${error}'));

              }),

finalmente en el archivo add_place_screen.dart, cambiamos el tipo de archivo del parametro file

class AddPlaceScreen extends StatefulWidget {
  #old File image;
  PickedFile image;
#...rest of code...

Explicacion:
Segun la documentacion de la libreria los el tipo de archivo File ha sido colocado como obsoleto y en las nuesvas versiones de la libreria se reemplaza:

  • File por PickedFile

  • El metodo pickImage por getImage

  • El metodo pickVideo por getVideo

  • Tambien se debe instanciar la clase primero para poder usar estos metodos

Pueden usar este link como referencia de mi código: https://pub.dev/packages/image_picker

Solicitud de permisos para IOS con las 3 llaves:

<key>NSCameraUsageDescription</key>
    <string>Platzi Trips quiere tomar una foto. ¿Podemos usar tu cámara?</string>
    <key>NSPhotoLibraryUsageDescription</key>
    <string>Platzi Trips quiere tomar una foto. ¿Podemos usar tu cámara?</string>
    <key>NSMicrophoneUsageDescription</key>
    <string>Platzi Trips quiere tomar una foto. ¿Podemos usar tu cámara?</string>

Permisos para camara en ios

No están los permisos en la descripción.

Hola compañeros, alguno de ustedes ha hecho algún choose source para seleccionar de que fuente quiero obtener la imagen, me puede explicar como hacerlo, gracias.

Hola, alguien sabe como solucionar el error: I/flutter ( 9676): PlatformException(already_active, Image picker is already active, null) he intentado lo que aparece por las diferentes webs: reinstalar, añadir async y await, etc. pero no consigo solucionar el problema.

Aparece un error cuand cancelas la toma de foto

Tuve problemas con la versión que se utiliza en el video, descargue la última y funcionó sin problemas.
Si por algún motivo el usuario cancela tomar la foto, genera un error al intentar abrir el widget AddPlaceScreen, para que no suceda eso, solo es necesario realizar un control sobre el objeto image, que solo vaya a AddPlaceScreen en caso que la image sea diferente a nulo, y listo.

Obtuve el siguiente error:
Android dependency ‘androidx.core:core’ has different version for the compile (1.0.0) and runtime (1.0.2) classpath. You should manually set the same version via DependencyResolution
Fue solucionado agregando este fragmento de código en el archivo build.gradle del proyecto

subprojects {
project.configurations.all {
resolutionStrategy.eachDependency { details ->
if (details.requested.group == ‘com.android.support’
&& !details.requested.name.contains(‘multidex’) ) {
details.useVersion “27.1.1”
}
if (details.requested.group == ‘androidx.core’
&& !details.requested.name.contains(‘androidx’) ) {
details.useVersion “1.0.1”
}
}
}
}

Hola a todos, tengo un problema logro tomar la foto pero hacer que se vea en add new place pero cuando vuelvo a intentar tomar la foto se sale de app y la pantalla esta en blanco(en la app), alguien sabe por que pasa?!

Agregar otra punto, esto me funciono con la ultima versión de image_picker, lo agregan en dependencias:
image_picker: ^0.6.7+1

Esto tambien agregue:
flutter_plugin_android_lifecycle: ^1.0.8

Y lo ultimo para finalizar, actualice mi sdk de Dart

Esta clase me costo un poco de trabajo. Use la versión mas reciente del imagepicker(la 0.6.7 que tenia 3 días que se había lanzado, regrese a una versión anterior y ) y al parecer cambio la manera en que se implementa así que regrese a una versión previa.

Después me aparecía este error : Shader compilation error repetido muchas veces al tomar la foto. Y al parecer pasa con algunos emuladores y se soluciona corriendo la app así: flutter run --enable-software-rendering

Permisos para el uso de la camara en Iphone