플러터로 하이브리드 앱을 만들려고 하는데,
아래와 같은 페이지에서 파일 선택이 되지 않는 문제가 발생했다.
크롬 앱에서 접속했을 땐 가능했으니 어떻게든 방법이 있을거라 믿고 오랜 시간 검색하여 방법을 알아냈다.
일단 사전 설정이 조금 필요한데, 대부분의 것들은 아래 공식문서에 잘 나와있다:
https://pub.dev/packages/permission_handler
위 페이지에서 제공하는 정보에 따르면, 여러분이 해야할 것은 권한 설정이고,
권한 설정을 위해
`android/app/src/main` 밑의 AndroidManifest.xml 파일을 다음과 같이 수정해야 한다.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.permissionhandlerexample">
<!-- 여기 아래의 uses-permission 부분들을 추가하면 된다. -->
<!-- 얻고자 하는 권한만 적어줘도 된다. -->
<!--
Internet permissions do not affect the `permission_handler` plugin, but are required if your app needs access to
the internet.
-->
<uses-permission android:name="android.permission.INTERNET"/>
<!-- Permissions options for the `contacts` group -->
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<!-- Permissions options for the `storage` group -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- Permissions options for the `camera` group -->
<uses-permission android:name="android.permission.CAMERA"/>
<!-- Permissions options for the `sms` group -->
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.RECEIVE_WAP_PUSH"/>
<uses-permission android:name="android.permission.RECEIVE_MMS"/>
<!-- Permissions options for the `phone` group -->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.ADD_VOICEMAIL"/>
<uses-permission android:name="android.permission.USE_SIP"/>
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
<uses-permission android:name="android.permission.WRITE_CALL_LOG"/>
<uses-permission android:name="android.permission.BIND_CALL_REDIRECTION_SERVICE"/>
<!-- Permissions options for the `calendar` group -->
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
<!-- Permissions options for the `location` group -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<!-- Permissions options for the `microphone` or `speech` group -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- Permissions options for the `sensors` group -->
<uses-permission android:name="android.permission.BODY_SENSORS" />
<!-- Permissions options for the `accessMediaLocation` group -->
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
<!-- Permissions options for the `activityRecognition` group -->
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
<!-- Permissions options for the `ignoreBatteryOptimizations` group -->
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<!-- Permissions options for the `bluetooth` group -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<application
...
했다면 아래 그림처럼 두 파일이 해당 내용들을 포함하는지 확인한다.
(아마 돼 있을 것이다 이미)
그리고 permission_handler 를 pub get 하도록 한다.
글을 쓰는 현재 시점의 버젼은
permission_handler: ^8.1.4+2
이다.
flutter pub get 해주어 설치해준다.
여기까지 따라했다면 준비물은 끝이다.
이제 코드를 쳐보자.
MyHomePage class를 띄운다고 생각해보자.
이 경우 필자는 코드를 다음과 같이 짬으로서 floating button을 누르면 권한을 확인하도록 만들었다.
(WebViewPlugin은 맨 아래에서 설명)
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var permissionState = false;
Future<bool> requestCameraPermission(BuildContext context) async {
// PermissionStatus status = await Permission.storage.request();
Map<Permission, PermissionStatus> statuses =
await [Permission.camera, Permission.storage].request();
// var status = await requestCameraPermission(context);
if (statuses[Permission.camera]!.isGranted == false ||
statuses[Permission.storage]!.isGranted == false) {
// 허용이 안된 경우
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
content: Text("권한 설정을 확인해주세요."),
actions: [
ElevatedButton(
onPressed: () {
openAppSettings(); // 앱 설정으로 이동
},
child: Text('설정하기')),
],
);
});
print("permission denied by user");
return false;
}
print("permission ok");
return true;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
toolbarHeight: 0,
backgroundColor: Colors.transparent,
),
body:
permissionState == true ? WebViewPlugin() : Text('버튼을 눌러 권한을 획득하십시오'),
floatingActionButton: FloatingActionButton(
onPressed: () async {
var status = await requestCameraPermission(context);
setState(() {
this.permissionState = status;
});
},
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
위 코드에서 권한을 얻는 부분은 다음과 같다.
아래에서 openAppSettings는 만약 사용자가 권한을 거절했을 경우
시스템 설정에서 바꿀 수 있도록 친전히 거기로 보내주는 것이다.
Future<bool> requestCameraPermission(BuildContext context) async {
// PermissionStatus status = await Permission.storage.request();
Map<Permission, PermissionStatus> statuses =
await [Permission.camera, Permission.storage].request();
// var status = await requestCameraPermission(context);
if (statuses[Permission.camera]!.isGranted == false ||
statuses[Permission.storage]!.isGranted == false) {
// 허용이 안된 경우
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
content: Text("권한 설정을 확인해주세요."),
actions: [
ElevatedButton(
onPressed: () {
openAppSettings(); // 앱 설정으로 이동
},
child: Text('설정하기')),
],
);
});
print("permission denied by user");
return false;
}
print("permission ok");
return true;
}
Flutter에서 webview를 띄우고 싶을 때 가장 자주 쓰는 pacakge는 webview_flutter이다.
그러나 우리의 상황같이 웹뷰에서 파일선택을 눌렀을 때 파일을 업로드하려면
flutter_webview_plugin을 pub get 해야 한다.
따라서 pubspec.yaml에 다음을 추가해주자.
flutter_webview_plugin: ^0.4.0 # 글을 쓰는 시점의 버젼
그리고
아래와 같이 WebViewPlugin를 작성해주자.
WebViewPlugin의 url은 아래 사진처럼 파일을 업로드할 수 있도록 버튼이 마련되어 있는 사이트를 지정하자.
WebviewPlugin.class
import 'package:flutter/material.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
class WebViewPlugin extends StatefulWidget {
const WebViewPlugin({Key? key}) : super(key: key);
@override
_WebViewPluginState createState() => _WebViewPluginState();
}
class _WebViewPluginState extends State<WebViewPlugin> {
@override
Widget build(BuildContext context) {
return WebviewScaffold(
url: "http://10.0.2.2:8080/kchoiCustomUploadTest",
withLocalStorage: true,
);
}
}
'flutter > flutter_issue&bugs' 카테고리의 다른 글
[플러터 2.0] Flutter and google_sign_in plugin: PlatformException 에러 (0) | 2021.10.01 |
---|---|
Firebase Flutter Web 프로젝트 deploy 하는 법. (0) | 2021.09.06 |
FirebaseFirestore CORS 에러 처리[Flutter] (0) | 2021.09.06 |
flutter web http CORS 에러 발생 시 (0) | 2021.08.30 |
최근댓글