how to show a pdf fetched from an API response in flutter? - flutter

I am working in a project where I have to show certificate that the user finished a course, there is an URL of the API that uses the get method within a token to have acces to a pdf file, the problem is that I do not know how to show or transform that response into a pdf, using flutter,
I tried to use the url_launcher dependency because in the browser shows the pdf normally, but the problem is that it I need to pass a token to that url.
the second thing that i tried was to fetched the response of the api and save it in a temporal file and use flutter_pdfview dependency but it shows errors.
this is how the response of the api looks like:
%PDF-1.4
1 0 obj
<<
/Title (þÿ)
/Creator (þÿ)
/Producer (þÿQt 5.5.1)
/CreationDate (D:20211120205047)
>>
endobj
2 0 obj
<<
/Type /Catalog
/Pages 3 0 R
>>
endobj
4 0 obj
<<
/Type /ExtGState
/SA true
/SM 0.02
/ca 1.0
/CA 1.0
/AIS false
this is what I tried:
Future LoadPDF(APIurl)async {
Map<String,String> Headers={
'Content-type': 'application/json; charset=UTF-8',
'Accept': 'application/json',
'Authorization': 'Bearer $userToken'
};
final response = await http.get(Uri.parse(APIurl),headers: Headers);
final bytes = response.bodyBytes;
// print(response.bodyBytes);
var dir = await getTemporaryDirectory();
File file = File(dir.path + "/data.pdf");
await file.writeAsBytes(bytes, flush: true);
setState(() {
loadDocument(file);
});
// return file;
}

Here is how I solved it:
Future<http.Response> apiCall(String fileId, String clientId) async {
String token = (await _storage.read(key: 'token')).toString();
final url = Uri.parse('$BASE_URL/oauth/notes/upload/view/$fileId/$clientId');
final headers = {"Authorization" : "Bearer $token", "Accept" : "*/*", "Accept-Encoding" : "gzip, deflate, br", "Connection": "keep-alive"};
final response = await http.get(url, headers: headers);
return response;
}
Future<File?> getContent(String fileId, String clientId, String extension) async {
//this is the api mentioned in next part
http.Response res = await api.apiCall(fileId, clientId);
dynamic response = res.bodyBytes;
if (response != null) {
final Directory? appDir = Platform.isAndroid
? await getExternalStorageDirectory()
: await getApplicationDocumentsDirectory();
String tempPath = appDir!.path;
final String fileName =
DateTime.now().microsecondsSinceEpoch.toString() + extension;
File file = File('$tempPath/$fileName');
if (!await file.exists()) {
await file.create();
}
await file.writeAsBytes(response);
return file;
}
}
File? file = await contentService.getContent(
fileid,
id,
'.pdf');
if (file != null) {
final String? result = await openFile(file.path.toString());
if (result != null) {
print('result');
print(result);
// Warning
}
}
static Future<String?> openFile(String url) async {
final OpenResult result = await OpenFile.open(url);
}

Hi I got the same response as you. Here I used Dio api structure. Take this as reference. Below code work fine for me.
Future<File?> downloadPDF(String applicantId, String templateId) async {
try {
final response = await dioClient.post('xxxxxx/pdfService/pdfOperation/downloadPDF', data:DownloadRequestDTO(applicantId, templateId), headers: <String, dynamic>{
'Content-Type': 'application/json'}, options: Options(responseType: ResponseType.bytes));
if (response != null) {
final Directory? appDir = Platform.isAndroid
? await getExternalStorageDirectory()
: await getApplicationDocumentsDirectory();
String tempPath = appDir!.path;
final String fileName =
DateTime.now().microsecondsSinceEpoch.toString() + '-' + 'akt.pdf';
File file = new File('$tempPath/$fileName');
if (!await file.exists()) {
await file.create();
}
await file.writeAsBytes(response);
return file;
}
throw DownloadException('The download failed.', response);
} catch (value) {
if (value is DioError) {
print(value.response);
}
print(value.toString());
}
}
Then use open_file package to open downloaded file
static Future<String?> openFile(String url) async {
final OpenResult result = await OpenFile.open(url);
switch (result.type) {
case ResultType.error:
return result.message;
case ResultType.fileNotFound:
return LocaleKeys.fileNotFound.tr();
case ResultType.noAppToOpen:
return LocaleKeys.noAppToOpen.tr();
case ResultType.permissionDenied:
return LocaleKeys.permissionDenied.tr();
default:
return null;
}}
And call this functions as below
Future<void> downloadAndOpenFile(BuildContext context) async {
try {
File? file = await downloadPDF('1234', 'xxxxxx');
if (file != null) {
final String? result = await openFile(file.path.toString());
if (result != null) {
// Warning
}
}
} catch (e) {
print(e);
}}

you can use flutter_pdfview package to show pdf:
loadDocument(file) {
PDFView(
filePath: file.path,
enableSwipe: true,
swipeHorizontal: true,
autoSpacing: false,
pageFling: false,
onRender: (_pages) {
setState(() {
pages = _pages;
isReady = true;
});
},
onError: (error) {
print(error.toString());
},
onPageError: (page, error) {
print('$page: ${error.toString()}');
},
onViewCreated: (PDFViewController pdfViewController) {
_controller.complete(pdfViewController);
},
onPageChanged: (int page, int total) {
print('page change: $page/$total');
},
),
}

Related

Http listening to upload progress Flutter Web

I was trying to listen to the upload progress using StreamedRequest and wanted to show the upload progress in UI by listening to bytes sent, but for some reason, it doesn't seem to work. The file is being picked with the file picker package and the selected file is in binary format (Unit8List). Here's the code:
final sha1OfFileData = sha1.convert(fileData);
try {
final request = http.StreamedRequest('POST', Uri.parse(data['uploadUrl']));
request.headers.addAll({
'Authorization': data['authorizationToken'],
'Content-Type': "application/octet-stream",
'X-Bz-File-Name': fileName,
'X-Bz-Content-Sha1': sha1OfFileData.toString(),
'X-Bz-Server-Side-Encryption': 'AES256',
});
request.sink.add(fileData);
final streamedResponse = await request.send();
var received = 0;
var total = streamedResponse.contentLength ?? -1;
streamedResponse.stream.listen(
(List<int> chunk) {
received += chunk.length;
if (total == -1) {
print('Received $received bytes');
} else {
final progress = received / total;
print('Upload progress: ${(progress * 100).toStringAsFixed(2)}%');
}
},
onDone: () async {
final responseBytes = await streamedResponse.stream.toBytes();
final responseString = utf8.decode(responseBytes);
response = jsonDecode(responseString);
print(response);
},
onError: (error) {
print('Error uploading file: $error');
},
cancelOnError: true,
);
} catch (e) {
print(e);
}
However if I upload it with the normal request, it works, here's that code:
final sha1OfFileData = sha1.convert(fileData);
var response;
try {
final request = http.Request('POST', Uri.parse(data['uploadUrl']));
request.headers.addAll({
'Authorization': data['authorizationToken'],
'Content-Type': "application/octet-stream",
'X-Bz-File-Name': fileName,
'X-Bz-Content-Sha1': sha1OfFileData.toString(),
'X-Bz-Server-Side-Encryption': 'AES256',
});
request.bodyBytes = fileData;
final streamedResponse = await request.send();
final responseBytes = await streamedResponse.stream.toBytes();
final responseString = utf8.decode(responseBytes);
response = jsonDecode(responseString);
print(response);
} catch (e) {
print(e);
}

Retrieving data from http web call in flutter into a list object always empty

List is always empty even though body has contents. I am new to flutter so bare with me if this is basic. I am wanting to get back a list of station data I am coming from a c# background so forgive me if am missing something simple the test string body has the items and can see the items when i debug
class HttpService {
final String url = "url hidden";
final String host = 'url hidden';
final String apiSegment = "api/";
// ignore: non_constant_identifier_names
void login(email, password) async {
try {
Map<String, String> body = {
'username': email,
'password': password,
};
Map<String, String> headers = {'Content-Type': 'application/json'};
final msg = jsonEncode(body);
Response response =
await post(Uri.parse("$url/Login"), headers: headers, body: msg);
if (response.statusCode == 200) {
var data = jsonDecode(response.body.toString());
print(data['jwtToken']);
print('Login successfully');
final prefs = await SharedPreferences.getInstance();
await prefs.setString('jwtToken', data['jwtToken']);
List<Stations> stationData = await getStationData('11');
var test = stationData;
} else {
print('failed');
}
} catch (e) {
print(e.toString());
}
}
Future<List<Stations>> getStationData(String stationId) async {
final prefs = await SharedPreferences.getInstance();
final String? token = prefs.getString('jwtToken');
const String path = 'Station/GetAllStationData';
final uri = Uri.parse('$url/api/$path')
.replace(queryParameters: {'stationId': stationId});
List<Stations> stationData = <Stations>[];
try {
Response res = await get(uri, headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
// 'Authorization': 'Bearer $token',
});
if (res.statusCode == 200) {
var body = jsonDecode(res.body);
var body2 = body.toString();
stationData = body
.map(
(dynamic item) => Stations.fromJson(item),
)
.toList();
} else {
throw "Unable to retrieve posts.";
}
} catch (e) {
print(e.toString());
}
return stationData;
}
}
I am calling my function from the same class
List<Stations> stationData = await getStationData('11');
Data from body
Actually the problem is you are returning the data after the end of try catch.
Try this
Future<List<Stations>> getStationData(String stationId) async {
final prefs = await SharedPreferences.getInstance();
final String? token = prefs.getString('jwtToken');
const String path = 'Station/GetAllStationData';
final uri = Uri.parse('$url/api/$path')
.replace(queryParameters: {'stationId': stationId});
try {
Response res = await get(uri, headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
// 'Authorization': 'Bearer $token',
});
if (res.statusCode == 200) {
var body = jsonDecode(res.body);
final stationData = List<Stations>.from(body.map((item) => Stations.fromJson(item))); // made some changes
return stationData;
} else {
throw "Unable to retrieve posts.";
}
} catch (e) {
rethrow;
}
}
I hope this will help you

Image upload using post method in Flutter

I have to upload image from gallery to server using provider in Flutter.
Here is the file picker
_loadPicker(ImageSource source) async {
File picked = await ImagePicker.pickImage(source: ImageSource.gallery);
print(picked);
if (picked != null) {
final response = await Provider.of<ProfilePictureUpdate>(context, listen:
false).profilePicUpdate(picked);
if (response["status"] ) {
Fluttertoast.showToast(msg: response["title"]);
}
else {
Fluttertoast.showToast(msg: response["title"]);
}
}
}
And here is the post method
Future<Map<String, dynamic>> profilePicUpdate(picked) async {
try {
final response = await ApiRequest.send(route: "profile/update/picture", method: "POST",
body: {
" photo_url" : picked,
});
if (response.statusCode == 200 ) {
return {
"status": true,
"title" : response["title"]
};
}
}
If you want sent image to you have to use formData( multi part) in 'Dio' similar
web (enctype). In http, you can also use multipart.
Must remember u use image is always not same, here use this field when server side params name same.
class ImageRepository {
Future<dynamic> uploadImage(filepath) async {
FormData formData = FormData.fromMap({
"image": await MultipartFile.fromFile(filepath,
filename: filepath.split('/').last)
});
var response = await Dio().post(
url,
data: formData),
);
print(response.data);
if (response.statusCode == 200) {
return 'Image Upload';
} else {
throw Exception 'Problem occour';
}
}

http MultipartRequest file not receiving in server

I'm trying to upload image to my server but it's not receiving in my server when I upload file from app. But if I upload via postman it works but not from simulator
My Code
final request = http.MultipartRequest(
'POST', Uri.parse(''));
request.fields['title'] = title.text;
request.fields['sub_title'] = subTitle.text;
request.files
.add(await http.MultipartFile.fromPath('profile_photo', photo.path));
request.files
.add(await http.MultipartFile.fromPath('profile_video', video.path));
var response = await request.send();
var responseString = await response.stream.bytesToString();
print(responseString);
`
Output
{'title': 'zia', 'sub_title' : 'sultan', 'profile_photo' : {}, 'profile_video' : {}}
I too faced a similar issue and here is the solution to how I fixed it:
var fileExtension = AppUtils.getFileExtension(filePath);
if (fileExtension.isEmpty) {
AppUtils.showToast('File extension was not found');
return false;
}
final file = await http.MultipartFile.fromPath('vid', filePath,
contentType: MediaType('application', fileExtension));
request.files.add(file);
var res = await request.send();
if (res.statusCode == 200) {
final respString = await res.stream.bytesToString();
debugPrint('respString: $respString');
}
AppUtils:
class AppUtils {
static String getFileExtension(String filePath) {
try {
int index = filePath.lastIndexOf('.');
return filePath.substring(index + 1);
} catch (e) {
return '';
}
}
}

Image Upload in Flutter Using Http post method

I'm new in this Framework and I want to Upload the Image along with the User name id and wmail and phone,
but Unable to to that I'm getting error
this is the Image get image function
File _image;
final picker = ImagePicker();
Future getImage() async {
pickedFile = await picker.getImage(source: ImageSource.gallery);
setState(() {
if (pickedFile != null) {
_image = File(pickedFile.path);
} else {
print('No image selected.');
}
});
}
Here i have written the Code for Upkoadung How to do Please help me with that
Future updateUserApiCall(
String name, String email, String mobile, File profile) async {
String token;
var userId;
SharedPreferences storage = await SharedPreferences.getInstance();
token = storage.getString("apiToken");
userId = storage.getInt("id");
String url = "https://www.example.com/api/updateprofile";
final response = await http.post(
url + "?page=" + "",
body: json.encode({
'user_id': userId,
'email': email,
'name': name,
'phone': mobile,
'image': profile,
}),
headers: {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer " + token,
},
);
if (response.statusCode == 200) {
print(response.body);
return UpdateProfileResponseModel.fromJson(
json.decode(response.body),
);
} else if (response.statusCode == 400) {
print(response.body);
return ErrorResponseModel.fromJson(
json.decode(response.body),
);
} else if (response.statusCode == 422) {
print(response.body);
return ValidationErrorResponseModel.fromJson(
json.decode(response.body),
);
} else {
print(response);
throw Exception('Failed to load data!');
}
}
}
As far as I know you can not pass image data using just http.post method. You have to use Multipart Request. I have also faced similar problem and asked a similar question in StackOverFlow. Please check the link below:
uploading image using file_picker flutter to a nodejs server
My use case was updating image of an user, I have used the following code to send image to a node server.
Future<bool> updateImage(File imageFile, AuthModel authModel) async{
final String _accessToken = 'abc';
final String url =
'https://justyourserverURL.com/update';
print("auth : " + _accessToken);
var request = http.MultipartRequest('POST', Uri.parse(url));
request.headers['Authorization'] = _accessToken;
// request.fields['id'] = '104';
// request.fields['firstName'] = authModel.data.firstName;
// request.fields['lastName'] = authModel.data.lastName;
// request.fields['surname'] = authModel.data.surname;
request.files.add(await http.MultipartFile.fromPath('file', imageFile.path));
var res = await request.send();
final respStr = await res.stream.bytesToString();
print('responseBody: ' + respStr);
if(res.statusCode==200){
setCurrentUser(respStr);
currentUser = authModelFromJson(respStr);
return true;
} else {
print(respStr);
print('Failed');
return false;
}
}
To pass username or id just pass data using request.fields['user_id'] = userId.