Compartir Código en Flutter: Adaptación para OpenHarmony

Introducción al Concepto

Este proyecto demuestra la compartición de código entre aplicaciones Flutter y servidores Dart, habilitando una base de código unificada para múltiples plataformas. Enfocado en OpenHarmony, ilustra cómo reutilizar modelos de datos y lógica de negocio para mejorar la eficiencia y consistencia.

Características Principales

  • Reutilización de modelos de datos Dart en clientes y servidores
  • Clases de datos inmutables generadas con Freezed
  • Serialización automática de JSON mediante json_serializable
  • Ejemplo de comunicación HTTP entre cliente Flutter y servidor Dart
  • Compatibilidad con aplicaciones OpenHarmony

Mecanismo Técnico

La compartición se logra a través de un paquete independiente que contiene modelos compartidos. Se emplean anotaciones de Freezed para garantizar inmutabilidad, json_serializable para el menejo de JSON, y el paquete http para la comuniacción REST. Variables de entorno permiten configurar endpoints del servidor.

Configuración en OpenHarmony

Para integrar en un proyecto OpenHarmony, incluya las dependencias necesarias en el archivo pubspec.yaml:

dependencies:
  flutter:
    sdk: flutter
  http:
    git:
      url: "https://gitcode.com/openharmony-tpc/flutter_packages.git"
      path: "packages/http/http"
  modelos_compartidos:
    git:
      url: "https://gitcode.com/openharmony-tpc/flutter_samples.git"
      path: "code_sharing/modelos_compartidos"

Ejecute flutter pub get para obtener las dependencias. Adicionalmente, en el archivo module.json5 del módulo OpenHarmony, añada el permiso de red:

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      }
    ]
  }
}

Ejemplos de Uso

Modelos de Datos Compartidos

import 'package:modelos_compartidos/modelos_compartidos.dart';

final contador = ValorContador(42);
print('Valor actual: ${contador.cantidad}');

final incremento = Incremento(en: 5);
print('Incremento en: ${incremento.en}');

final jsonContador = contador.toJson();
print('JSON del contador: $jsonContador');

final contadorDesdeJson = ValorContador.fromJson(jsonContador);
print('Contador desde JSON: ${contadorDesdeJson.cantidad}');

Comunicación Cliente-Servidor

import 'dart:convert';
import 'dart:io' show Platform;
import 'package:http/http.dart' as cliente_http;
import 'package:modelos_compartidos/modelos_compartidos.dart';
import 'package:flutter/material.dart';

final puerto = Platform.environment['PUERTO'] ?? '8080';
final host = Platform.environment['URL_SERVIDOR'] ?? '127.0.0.1';
final esquema = Platform.environment['ESQUEMA_SERVIDOR'] ?? 'http';
final urlServidor = Uri.parse('$esquema://$host:$puerto/');

Future<int> obtenerValorActual() async {
  final respuesta = await cliente_http.get(urlServidor);
  final contador = ValorContador.fromJson(json.decode(respuesta.body));
  return contador.cantidad;
}

Future<int> ejecutarIncremento(int cantidad) async {
  final incremento = Incremento(en: cantidad);
  final respuesta = await cliente_http.post(
    urlServidor,
    body: json.encode(incremento.toJson()),
    headers: {'Content-Type': 'application/json'},
  );
  final contador = ValorContador.fromJson(json.decode(respuesta.body));
  return contador.cantidad;
}

class AplicacionContador extends StatelessWidget {
  const AplicacionContador({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Demo de Code Sharing',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const PaginaContador(),
    );
  }
}

class PaginaContador extends StatefulWidget {
  const PaginaContador({super.key});

  @override
  State<PaginaContador> createState() => _EstadoPaginaContador();
}

class _EstadoPaginaContador extends State<PaginaContador> {
  int _valorContador = 0;
  bool _cargando = false;

  @override
  void initState() {
    super.initState();
    _cargarValor();
  }

  void _cargarValor() async {
    setState(() => _cargando = true);
    try {
      final valor = await obtenerValorActual();
      setState(() => _valorContador = valor);
    } finally {
      setState(() => _cargando = false);
    }
  }

  void _incrementarValor() async {
    setState(() => _cargando = true);
    try {
      final valor = await ejecutarIncremento(1);
      setState(() => _valorContador = valor);
    } finally {
      setState(() => _cargando = false);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Demo de Code Sharing')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'Valor actual:',
              style: TextStyle(fontSize: 20),
            ),
            Text(
              '$_valorContador',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
            if (_cargando) ...[
              const SizedBox(height: 20),
              const CircularProgressIndicator(),
            ],
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _cargando ? null : _incrementarValor,
        tooltip: 'Incrementar',
        child: const Icon(Icons.add),
      ),
    );
  }
}

Implemantación del Servidor

import 'dart:convert';
import 'dart:io';

import 'package:modelos_compartidos/modelos_compartidos.dart';
import 'package:shelf/shelf.dart';
import 'package:shelf/shelf_io.dart';
import 'package:shelf_router/shelf_router.dart';

int valorGlobal = 0;

final enrutador = Router()
  ..post('/', _manejadorIncremento)
  ..get('/', _manejadorObtenerValor);

Future<Response> _manejadorIncremento(Request solicitud) async {
  final inc = Incremento.fromJson(json.decode(await solicitud.readAsString()));
  valorGlobal += inc.en;
  return Response.ok(json.encode(ValorContador(valorGlobal).toJson()));
}

Response _manejadorObtenerValor(Request solicitud) =>
    Response.ok(json.encode(ValorContador(valorGlobal).toJson()));

void main(List<String> argumentos) async {
  final direccionIp = InternetAddress.anyIPv4;
  final pipeline = Pipeline().addMiddleware(logRequests()).addHandler(enrutador);
  final puerto = int.parse(Platform.environment['PUERTO'] ?? '8080');
  final servidor = await serve(pipeline, direccionIp, puerto);
  print('Servidor escuchando en el puerto ${servidor.port}');
}

Etiquetas: Flutter Dart OpenHarmony Freezed JSON Serializable

Publicado el 6-22 16:52