11

I have a basic flutter project running on android where when the application starts, I write an executable bundled in my assets.

  static String appInternalPath = '/data/data/com.maksimdan.face_merger';

  void writeExecutable() async {
    var executablePath = join(appInternalPath, 'main');

    if (await File(executablePath).exists()) {
      File(executablePath).delete();
      print('deleted old executable');
    } else {
      print('not executable exists');
    }

    ByteData data = await rootBundle.load('lib/py/dist/main');
    List<int> bytes =
        data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
    await File(executablePath).writeAsBytes(bytes);
    print('wrote new executable');
  }

Sometime later in my code I try to run it.

  void invokeExecutable() async {
    String executablePath = join(appInternalPath, 'main');
    Process.run('chmod', ['u+x', executablePath]).then((ProcessResult results) {
      Process.run(executablePath, []).then((ProcessResult results) {
        print(results.stdout);
      });
    });
  }

But obtain a permission denied error.

E/flutter (31825): [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: ProcessException: Permission denied
E/flutter (31825):   Command: /data/data/com.maksimdan.flutter_general/main 
E/flutter (31825): #0      _ProcessImpl._start (dart:io-patch/process_patch.dart:390:33)
E/flutter (31825): #1      Process.start (dart:io-patch/process_patch.dart:36:20)
E/flutter (31825): #2      _runNonInteractiveProcess (dart:io-patch/process_patch.dart:565:18)
E/flutter (31825): #3      Process.run (dart:io-patch/process_patch.dart:47:12)
E/flutter (31825): #4      _MyHomePageState.invokeExecutable.<anonymous closure> (package:flutter_general/main.dart:51:15)
E/flutter (31825): #5      _rootRunUnary (dart:async/zone.dart:1362:47)
E/flutter (31825): #6      _CustomZone.runUnary (dart:async/zone.dart:1265:19)
E/flutter (31825): <asynchronous suspension>

I've also tried:

      Process.run('/system/bin/chmod', ['744', path]).then((ProcessResult results) {
        print('shell1 complete');
        Process.run(path, []).then((ProcessResult results) {
          print('shell2 complete');
          print(results.stdout);
        });
      });

My executable:

// 'Hello World!' program 
 
#include <iostream>
 
int main()
{
  std::cout << "Hello World!" << std::endl;
  return 0;
}
>> g++ main.cc -o main

Is there a way to run your own executables in flutter with the proper permissions? On native android, there is an option to file.setExecutable(true); using this strategy. (Hosting an executable within Android application)

Or will I have to experiment with method channels?


pubspec.yml

name: face_merger
description: A new Flutter project.

version: 1.0.0+1

environment:
  sdk: ">=2.1.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter

  sqflite: ^1.3.0+2
  process_run: ^0.10.10+1
  cupertino_icons: ^0.1.3

dev_dependencies:
  flutter_test:
    sdk: flutter


flutter:
  uses-material-design: true
  assets:
    - lib/py/dist/main

I also verified that the file was written to the internal memory of on the device that I expected it to be written to using android studio's device explore.

screenshot of executable within the android simulator

onesiumus
  • 279
  • 6
  • 26

2 Answers2

1

Besides the writable permission you need to have readable permission in your app.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.xxx.yyy">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

...

  • I tried this as well for completness. The executable is being written in the phones internal memory, not external. – onesiumus Jun 04 '20 at 04:23
0

You need to put the .db file extension at the end of the database name (Assuming DB_DIR is for a database). var path = join(DB_DIR, 'main.db');

Then I think you may want to use path_provider package and use

Directory documentsDirectory = await getApplicationDocumentsDirectory();

for the directory where you are accessing the database.

returnVoid
  • 604
  • 1
  • 9
  • 17
  • I initially used db_dir as placeholder name; sorry for the confusion; I've edited the question. But I am not interested in copying over a database. Its is an executable that can be run over the terminal. I've shown that copying over the executable is not the issue, but its attempt of executing it within the application that fails. – onesiumus Jun 06 '20 at 08:29