Home > Back-end >  Unable to open .pem file in flutter
Unable to open .pem file in flutter

Time:01-03

I am beginner in programming, for a school project i was building an android application to turn on/off LED using esp 32 and AWS IOT. I am using mqtt_client 9.6.4, when i run the aws_iot.dart example i am able to connect to AWS IOT and perform the action using the same script. when i use the same code in a flutter i get the following error message in my debug console, E/flutter (15280): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: FileSystemException: Cannot open file, path = 'AmazonRootCA1.pem' (OS Error: No such file or directory, errno = 2)

How can this be resolved?

import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/services.dart';

import 'lib/mqtt_server_client.dart';
import 'lib/mqtt_client.dart';
import 'package:pem/pem.dart';

var switch1 = 0;

Future<int> main() async {
  const url = 'xxxxxxxxxxxxxxxx.amazonaws.com';

  const port = 8883;

  const clientId = 'Flutter';

 
  final client = MqttServerClient.withPort(url, clientId, port);

 
  client.secure = true;

  client.keepAlivePeriod = 20;
  
  client.setProtocolV311();

  client.logging(on: true);

  final context = SecurityContext.defaultContext;

  context.setClientAuthorities('AmazonRootCA1.pem');

  context.useCertificateChain('certificate.pem.crt');

  context.usePrivateKey('private.pem.key');


  client.securityContext = context;

  final connMess =
      MqttConnectMessage().withClientIdentifier(clientId).startClean();
  client.connectionMessage = connMess;

  
  try {
    print('MQTT client connecting to AWS IoT....');
    await client.connect();
  } on Exception catch (e) {
    print('MQTT client exception - $e');
    client.disconnect();
  }

  if (client.connectionStatus!.state == MqttConnectionState.connected) {
    print('MQTT client connected to AWS IoT');

    
    const topic = 'esp32/relay1';
    const topic2 = 'esp32/relay2';
    final builder = MqttClientPayloadBuilder();
    builder.addString('{\"status\":\"0\"}');
    
    client.publishMessage(topic, MqttQos.atLeastOnce, builder.payload!);

    
    client.subscribe(topic2, MqttQos.atLeastOnce);
    
    client.updates!.listen((List<MqttReceivedMessage<MqttMessage>> c) {
      final recMess = c[0].payload as MqttPublishMessage;
      final pt =
          MqttPublishPayload.bytesToStringAsString(recMess.payload.message);
      print(
          'EXAMPLE::Change notification:: topic is <${c[0].topic}>, payload is <-- $pt -->');
      print('');
    });
  } else {
    print(
        'ERROR MQTT client connection failed - disconnecting, state is ${client.connectionStatus!.state}');
    client.disconnect();
  }

  print('Sleeping....');
  await MqttUtilities.asyncSleep(60);

  print('Disconnecting');
  client.disconnect();

  return 0;
}

CodePudding user response:

I would try using the Bytes variants of the SecurityContext methods.

First, you will need to make sure that the files you are referencing are defined in your pubspec.yaml file:

flutter:
  assets:
    - assets/AmazonRootCA1.pem # assuming you placed these files in a folder called assets
    - assets/certificate.pem.crt
    - assets/private.pem.key

This will ensure that the files are packaged with the app such that you can load them using rootBundle.

Then in your code load the files using rootBundle and pass the data to the SecurityContext as bytes.

  final context = SecurityContext.defaultContext;

  final clientAuthorities = await rootBundle.load('assets/AmazonRootCA1.pem');
  context.setClientAuthoritiesBytes(clientAuthorities.buffer.asUint8List());

  final certificateChain = await rootBundle.load('assets/certificate.pem.crt');
  context.useCertificateChainBytes(certificateChain.buffer.asUint8List());

  final privateKey = await rootBundle.load('assets/private.pem.key');
  context.usePrivateKeyBytes(privateKey.buffer.asUint8List());

As an aside, I'm a little confused by why your main method in a flutter project doesn't call runApp, and instead returns an int. But if you do use the code above in the main method of a flutter app, you may need to call WidgetsFlutterBinding.ensureInitialized(); in main prior to using rootBundle.load.

  • Related