回答編集履歴

6

修正

2022/04/09 07:40

投稿

jimbe
jimbe

スコア12634

test CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  ---
10
10
  以下の環境を構築してプラグインを作って見ました。
11
- main.dart を実行すると(?) StrageAccessFramework のアクティビティで Downloads フォルダが表示されます。SAVE ボタンを押すと test.csv ファイルが作られ、 Flutter の画面が出て(戻って) 該当ファイルのコンテンツプロバイダでの URI が表示されます。
11
+ main.dart を実行すると(?) StrageAccessFramework のアクティビティで Downloads フォルダが表示されます。フォルダやファイル名を変更しSAVE ボタンを押すとファイルが作られ、 Flutter の画面が出て(戻って) 該当ファイルのコンテンツプロバイダでの URI が表示されます。
12
12
  …で、これはどうすれば(pub なんとかに公開する以外で)プラグインとして GitHub とかで公開できるんでしょうか(X_X;;;
13
13
 
14
14
  Flutter

5

追加

2022/04/09 07:35

投稿

jimbe
jimbe

スコア12634

test CHANGED
@@ -5,3 +5,225 @@
5
5
  (Android10 以前では ) メディアファイル以外のファイルは [ストレージ アクセス フレームワーク](https://developer.android.com/training/data-storage/shared/documents-files?hl=ja) を用いるのが良いかもしれません。
6
6
  Flutter プラグインを探しましたら以下がありました。※ホンモノかどうか私には分かりませんので、一応ご注意ください。
7
7
  [saf: ^1.0.3+3](https://pub.dev/packages/saf)
8
+
9
+ ---
10
+ 以下の環境を構築してプラグインを作って見ました。
11
+ main.dart を実行すると(?) StrageAccessFramework のアクティビティで Downloads フォルダが表示されます。SAVE ボタンを押すと test.csv ファイルが作られ、 Flutter の画面が出て(戻って) 該当ファイルのコンテンツプロバイダでの URI が表示されます。
12
+ …で、これはどうすれば(pub なんとかに公開する以外で)プラグインとして GitHub とかで公開できるんでしょうか(X_X;;;
13
+
14
+ Flutter
15
+ ```plain
16
+ >flutter --version
17
+ Flutter 2.10.4 • channel stable • https://github.com/flutter/flutter.git
18
+ Framework • revision c860cba910 (2 weeks ago) • 2022-03-25 00:23:12 -0500
19
+ Engine • revision 57d3bac3dd
20
+ Tools • Dart 2.16.2 • DevTools 2.9.2
21
+ ```
22
+ AndroidStudio
23
+ ```plain
24
+ Android Studio Bumblebee | 2021.1.1 Patch 2
25
+ Build #AI-211.7628.21.2111.8193401, built on February 17, 2022
26
+ Runtime version: 11.0.11+9-b60-7590822 amd64
27
+ VM: OpenJDK 64-Bit Server VM by Oracle Corporation
28
+ Windows 10 10.0
29
+ GC: G1 Young Generation, G1 Old Generation
30
+ Memory: 1280M
31
+ Cores: 6
32
+ Registry: external.system.auto.import.disabled=true
33
+ Non-Bundled Plugins: Dart (211.7811), org.jetbrains.kotlin (211-1.6.20-release-275-AS7442.40), io.flutter (66.0.1)
34
+ ```
35
+ AndroidStudio Plugin
36
+ - Flutter flutter.dev 66.0.1
37
+ - Dart JetBrains 211.7811
38
+
39
+ plugin サンプル生成コマンド(うろ覚え...)
40
+ ```plain
41
+ > flutter create --org com.teratail.q_jmx3uadrrp6bi3 -t plugin --platforms android -a java saf_plugin_sample
42
+ ```
43
+
44
+ **サンプルから修正したコード**
45
+
46
+ saf_plugin_sample/example/lib/main.dart
47
+ ```dart
48
+ import 'package:flutter/material.dart';
49
+ import 'dart:async';
50
+
51
+ import 'package:flutter/services.dart';
52
+ import 'package:saf_plugin_sample/saf_plugin_sample.dart';
53
+
54
+ void main() {
55
+ runApp(const MyApp());
56
+ }
57
+
58
+ class MyApp extends StatefulWidget {
59
+ const MyApp({Key? key}) : super(key: key);
60
+
61
+ @override
62
+ State<MyApp> createState() => _MyAppState();
63
+ }
64
+
65
+ class _MyAppState extends State<MyApp> {
66
+ String _uri = 'Unknown';
67
+
68
+ @override
69
+ void initState() {
70
+ super.initState();
71
+ initPlatformState();
72
+ }
73
+
74
+ // Platform messages are asynchronous, so we initialize in an async method.
75
+ Future<void> initPlatformState() async {
76
+ String uri;
77
+ try {
78
+ uri = await SafPluginSample.createDocument("text/csv", "test.csv", "AAA,BBB,CCC\n111,222,333") ?? 'Canceled';
79
+ } on PlatformException {
80
+ uri = 'Exception';
81
+ }
82
+
83
+ if (!mounted) return;
84
+
85
+ setState(() {
86
+ _uri = uri;
87
+ });
88
+ }
89
+
90
+ @override
91
+ Widget build(BuildContext context) {
92
+ return MaterialApp(
93
+ home: Scaffold(
94
+ appBar: AppBar(
95
+ title: const Text('Plugin example app'),
96
+ ),
97
+ body: Center(
98
+ child: Text('Running on: $_uri\n'),
99
+ ),
100
+ ),
101
+ );
102
+ }
103
+ }
104
+ ```
105
+ saf_plugin_sample/lib/saf_plugin_sample.dart
106
+ ```dart
107
+ import 'dart:async';
108
+
109
+ import 'package:flutter/services.dart';
110
+
111
+ class SafPluginSample {
112
+ static const MethodChannel _channel = MethodChannel('com.teratail.q_jmx3uadrrp6bi3/saf_plugin_sample');
113
+
114
+ static Future<String?> createDocument(String type, String title, String contents) async {
115
+ final String? uri = await _channel.invokeMethod(
116
+ 'createDocument',
117
+ <String, dynamic>{
118
+ 'type': type,
119
+ 'title': title,
120
+ 'contents': contents
121
+ });
122
+ return uri;
123
+ }
124
+ }
125
+ ```
126
+ saf_plugin_sample/android/src/main/java/com/teratail/q_jmx3uadrrp6bi3/saf_plugin_sample/SafPluginSamplePlugin.java
127
+ ```java
128
+ package com.teratail.q_jmx3uadrrp6bi3.saf_plugin_sample;
129
+
130
+ import android.app.Activity;
131
+ import android.content.Intent;
132
+ import android.net.Uri;
133
+
134
+ import androidx.annotation.NonNull;
135
+
136
+ import java.io.*;
137
+
138
+ import io.flutter.embedding.engine.plugins.FlutterPlugin;
139
+ import io.flutter.embedding.engine.plugins.activity.*;
140
+ import io.flutter.plugin.common.*;
141
+ import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
142
+ import io.flutter.plugin.common.MethodChannel.Result;
143
+
144
+ /** SafPluginSamplePlugin */
145
+ public class SafPluginSamplePlugin implements FlutterPlugin, MethodCallHandler, ActivityAware, PluginRegistry.ActivityResultListener {
146
+ private static final int REQUEST_CODE = 1;
147
+
148
+ private MethodChannel channel;
149
+ private ActivityPluginBinding binding;
150
+ private Result result;
151
+ private String contents;
152
+
153
+ @Override
154
+ public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
155
+ channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "com.teratail.q_jmx3uadrrp6bi3/saf_plugin_sample");
156
+ channel.setMethodCallHandler(this);
157
+ }
158
+
159
+ @Override
160
+ public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
161
+ channel.setMethodCallHandler(null);
162
+ }
163
+
164
+ @Override
165
+ public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
166
+ if(call.method.equals("createDocument")) {
167
+ if(binding != null) {
168
+ this.result = result;
169
+
170
+ String type = call.argument("type");
171
+ String title = call.argument("title");
172
+ contents = call.argument("contents");
173
+
174
+ Intent intent = new Intent();
175
+ intent.setAction(Intent.ACTION_CREATE_DOCUMENT);
176
+ intent.setType(type);
177
+ intent.putExtra(Intent.EXTRA_TITLE, title);
178
+ //intent.putExtra(EXTRA_CONTENTS, contents);
179
+ binding.getActivity().startActivityForResult(intent, REQUEST_CODE);
180
+ }
181
+ } else {
182
+ result.notImplemented();
183
+ }
184
+ }
185
+
186
+ @Override
187
+ public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
188
+ switch(requestCode) {
189
+ case REQUEST_CODE:
190
+ if(resultCode != Activity.RESULT_OK) {
191
+ result.success(null); //CANCEL?
192
+ return true;
193
+ }
194
+ Uri uri = data.getData();
195
+ try(OutputStream os = binding.getActivity().getContentResolver().openOutputStream(uri);
196
+ PrintStream ps = new PrintStream(os);) {
197
+ ps.print(contents);
198
+ result.success(uri.toString());
199
+ } catch(IOException e) {
200
+ result.error("IOException", e.getLocalizedMessage(), e);
201
+ }
202
+ return true;
203
+ }
204
+ return false;
205
+ }
206
+
207
+ @Override
208
+ public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
209
+ this.binding = binding;
210
+ binding.addActivityResultListener(this);
211
+ }
212
+
213
+ @Override
214
+ public void onDetachedFromActivity() {
215
+ binding.removeActivityResultListener(this);
216
+ binding = null;
217
+ }
218
+
219
+ @Override
220
+ public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) {
221
+ onAttachedToActivity(binding);
222
+ }
223
+
224
+ @Override
225
+ public void onDetachedFromActivityForConfigChanges() {
226
+ onDetachedFromActivity();
227
+ }
228
+ }
229
+ ```

4

修正

2022/04/03 19:11

投稿

jimbe
jimbe

スコア12634

test CHANGED
@@ -1,6 +1,6 @@
1
1
  Flutter は全く分からないのですが、 Android で「アプリの固有フォルダ」と言えば、そのアプリ以外からはアクセス出来ないと思います。
2
2
 
3
- 仰られるように、 Android はバージョン毎に「公開したいファイルをどこに作ればいいのか」が[コロコロ変わっている印象](https://developer.android.com/training/data-storage/use-cases?hl=ja#export-files-to-device)ですので、お使いの Android のバージョンと Flutter でのフォルダ/ディレクトリの得方をしっかりマッチングさせて調べる必要があるように思います。
3
+ 仰られるように、 Android はバージョン毎に「公開したいファイルをどこに作ればいいのか」が[コロコロ変わっている印象](https://developer.android.com/training/data-storage/use-cases?hl=ja)ですので、お使いの Android のバージョンと Flutter でのフォルダ/ディレクトリの得方をしっかりマッチングさせて調べる必要があるように思います。
4
4
 
5
5
  (Android10 以前では ) メディアファイル以外のファイルは [ストレージ アクセス フレームワーク](https://developer.android.com/training/data-storage/shared/documents-files?hl=ja) を用いるのが良いかもしれません。
6
6
  Flutter プラグインを探しましたら以下がありました。※ホンモノかどうか私には分かりませんので、一応ご注意ください。

3

修正

2022/04/03 19:08

投稿

jimbe
jimbe

スコア12634

test CHANGED
@@ -1,6 +1,6 @@
1
1
  Flutter は全く分からないのですが、 Android で「アプリの固有フォルダ」と言えば、そのアプリ以外からはアクセス出来ないと思います。
2
2
 
3
- 仰られるように、 Android はバージョン毎に「公開したいファイルをどこに作ればいいのか」がコロコロ変わっている印象ですので、お使いの Android のバージョンと Flutter でのフォルダ/ディレクトリの得方をしっかりマッチングさせて調べる必要があるように思います。
3
+ 仰られるように、 Android はバージョン毎に「公開したいファイルをどこに作ればいいのか」が[コロコロ変わっている印象](https://developer.android.com/training/data-storage/use-cases?hl=ja#export-files-to-device)ですので、お使いの Android のバージョンと Flutter でのフォルダ/ディレクトリの得方をしっかりマッチングさせて調べる必要があるように思います。
4
4
 
5
5
  (Android10 以前では ) メディアファイル以外のファイルは [ストレージ アクセス フレームワーク](https://developer.android.com/training/data-storage/shared/documents-files?hl=ja) を用いるのが良いかもしれません。
6
6
  Flutter プラグインを探しましたら以下がありました。※ホンモノかどうか私には分かりませんので、一応ご注意ください。

2

追加

2022/04/03 19:02

投稿

jimbe
jimbe

スコア12634

test CHANGED
@@ -1,3 +1,7 @@
1
1
  Flutter は全く分からないのですが、 Android で「アプリの固有フォルダ」と言えば、そのアプリ以外からはアクセス出来ないと思います。
2
2
 
3
3
  仰られるように、 Android はバージョン毎に「公開したいファイルをどこに作ればいいのか」がコロコロ変わっている印象ですので、お使いの Android のバージョンと Flutter でのフォルダ/ディレクトリの得方をしっかりマッチングさせて調べる必要があるように思います。
4
+
5
+ (Android10 以前では ) メディアファイル以外のファイルは [ストレージ アクセス フレームワーク](https://developer.android.com/training/data-storage/shared/documents-files?hl=ja) を用いるのが良いかもしれません。
6
+ Flutter プラグインを探しましたら以下がありました。※ホンモノかどうか私には分かりませんので、一応ご注意ください。
7
+ [saf: ^1.0.3+3](https://pub.dev/packages/saf)

1

修正

2022/04/03 18:05

投稿

jimbe
jimbe

スコア12634

test CHANGED
@@ -1,3 +1,3 @@
1
1
  Flutter は全く分からないのですが、 Android で「アプリの固有フォルダ」と言えば、そのアプリ以外からはアクセス出来ないと思います。
2
2
 
3
- 仰られるように、 Android はバージョン毎に公開したいファイルをどこに作ればいいのかがコロコロ変わっている印象ですので、お使いの Android のバージョンと Flutter でのフォルダ/ディレクトリの得方をしっかりマッチングさせて調べる必要があるように思います。
3
+ 仰られるように、 Android はバージョン毎に公開したいファイルをどこに作ればいいのかがコロコロ変わっている印象ですので、お使いの Android のバージョンと Flutter でのフォルダ/ディレクトリの得方をしっかりマッチングさせて調べる必要があるように思います。