Convert String path to File FLUTTER - firebase

I have List containing paths like below
/storage/emulated/0/Whatsapp/Media/Whatsapp Images/IMG-20210623-WA0016.jpg
Converting it to file always returns false.
for (var i = 0; i < tempLocations.length; i++) {
print(tempLocations.length);
File newFile = File(tempLocations[0]);
if (await newFile.exists()) {
print("true");
} else {
print("false");
}
}
How do i convert it to a file?

You can use flutter_absolute_path to get the excat path
A flutter plugin that finds the absolute path of a file in iOS or Android devices.
null safety version
flutter_absolute_path:
git:
url: https://github.com/kornperkus/flutter_absolute_path.git
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> init() async {
/// uri can be of android scheme content or file
/// for iOS PHAsset identifier is supported as well
List<Asset> assets = await selectImagesFromGallery();
List<File> files = [];
for (Asset asset in assets) {
// asset.identifier replace with your path
final filePath =
await FlutterAbsolutePath.getAbsolutePath(asset.identifier);
files.add(File(filePath));
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_files = files;
});
}

Related

How to cache images from Firebase in Flutter?

I'm trying to access images in Firebase Storage and cache them locally on the device.
My current attempt uses flutter_cache_manager. The documentation states:
Most common file service will be an [HttpFileService], however one can also make something more specialized. For example you could fetch files from other apps or from local storage.
class HttpFileService implements FileService {
http.Client _httpClient;
HttpFileService({http.Client httpClient}) {
_httpClient = httpClient ?? http.Client();
}
#override
Future<FileServiceResponse> get(String url,
{Map<String, String> headers = const {}}) async {
final req = http.Request('GET', Uri.parse(url));
req.headers.addAll(headers);
final httpResponse = await _httpClient.send(req);
return HttpGetResponse(httpResponse);
}
}
I've tried to extend this class to process the URL for Firebase
class FirebaseHttpFileService extends HttpFileService {
#override
Future<FileServiceResponse> get(String url, {Map<String, String> headers = const {}}) async {
var ref = FirebaseStorage.instance.ref().child(url);
var _url = await ref.getDownloadURL() as String;
return super.get(_url);
}
}
And extend the BaseCacheManager using a template from the GitHub repo, replacing the file service with my new one.
class FirebaseCacheManager extends BaseCacheManager {
static const key = "firebaseCache";
static FirebaseCacheManager _instance;
factory FirebaseCacheManager() {
if (_instance == null) {
_instance = new FirebaseCacheManager._();
}
return _instance;
}
FirebaseCacheManager._() : super(key,
maxAgeCacheObject: Duration(days: 7),
maxNrOfCacheObjects: 20,
fileService: FirebaseHttpFileService());
Future<String> getFilePath() async {
var directory = await getTemporaryDirectory();
return p.join(directory.path, key);
}
}
But I get the following error:
setState() called after dispose(): _ImageState#50d41(lifecycle state: defunct, not mounted, stream: ImageStream#ac6d5(MultiFrameImageStreamCompleter#0c956, [2448×3264] # 1.0x, 3 listeners), pixels: null, loadingProgress: null, frameNumber: null, wasSynchronouslyLoaded: false)
I can process the URL before attempting to retrieve the file but that needlessly wastes time. I've also tried to use other packages like Flutter Cache Image but it seems to crash the app after a short amount of time.
Thanks for any pointers in the right direction!
This problem is actually tied to the errorWidget as seen in the issue here.
The code is working if the error widget is commented out in CachedNetworkImage.

Store Firebase Data as JSON locally

I want to use JSON as a local database for my firebase data ,I don't want offline data store.I am using path_provider to store my data on the phone
So I tried storing data with
file.writeAsStringSync(json.encode(snapshot.toString()))
And it worked the stored data file looked like a JSON file
"{-key:{name:name,age:age},-key:{name:name,age:age}}"
The " " where missing and I can't decode it.
So what can be done here ?
(Edit:Does Firestore provide anything that can help me with this ?)
You can use the shared_preferences package to store JSON,
or if you want to write to a custom file use the path_provider package to get paths to directories where you app has permissions to write to.
You might also need to use the async versions of the dart:io API to access files in Flutter (not sure about that tough)
"{-key:{name:name,age:age},-key:{name:name,age:age}}" is not valid JSON
Either use
import 'dart:convert';
...
var myJson = {'-key':{'name:name','age:age'},'-key':{'name:name','age:age'}}";
var myJsonString = jsonEncode(myJson);
await file.writeAsString(myJsonString);
or
var myJsonString = '{"-key":{"name:name","age:age"},"-key":{"name:name","age:age"}}';
await file.writeAsString(myJsonString);
Create a JSON File
Future<String> get _localPath async {
final directory = await getExternalStorageDirectory();
return directory.path;
}
Future<File> get _dbFile async {
final path = await _localPath;
return new File("$path/demo.json");
}
Write data into a file
Future<File> write(DataSnapshot snapshot,String chatId) async {
final path = await _dbFile;
final String key = snapshot.key;
final String name = snapshot.value['senderUid'];
final int age= snapshot.value['receivedUid'];
String content = '{"$key":{"name":"$name","age":"$age"}}';
return file.writeAsStringSync(content);
}
Read Data
Future<Null> read() async {
try {
final file = await _dbFile;
String content = file.readAsStringSync();
Map<String, dynamic> chatMap=json.decode(content);
chatMap.keys.forEach((E){debugPrint(E);});
} catch (e) {
debugPrint('Error : '+e.toString());
}
}

Adding custom data to a firebase storage upload?

I'm uploading files to firebase storage like so:
var storageRef = firebase.storage();
var fileRef = storageRef.ref(file.name);
fileRef.put(file)
.then(function (snapshot) {
console.log('Uploaded a blob or file!');
window.URL.revokeObjectURL(file.preview);
})
After the upload I have a firebase storage trigger:
export const processUploadedFile = functions.storage.object().onChange(event => {
}
What I want to do is upload some additional information with the original upload so that the processUploadedFile knows what to do with it (for example extract the file, move it to a special directory, etc, etc).
I tried using metadata like so:
var newMetadata = {
customMetadata: {
"Test": "value"
}
}
fileRef.put(file, newMetadata)
But on the cloud storage trigger function I don't know how to get the metadata, I logged out fileMetaData like so:
file.getMetadata().then((metaData)=>console.log(metaData))
But did not see my metadata anywhere in there (or in fileMetaData[0].metadata which returned undefined)
Not sure how I can achieve this...
I think providing file meta info will do the trick. Here is the reference. Firebase Storage File metadata. You can pass custom parameters for the file with customMetadata. For instance :
customMetadata: {
'actionType': 'ACTION_CODE',
'action': 'do something info'
}
You can access this metadata with storage trigger and take the action accordingly. Here is how you can achieve that Automatically Extract Images Metadata
I believe there are some properties that cannot be changed as they are not writeable. However, if you indeed want to add a custom data to firebase storage, you can set custom metadata as an object containing String properties. For example:
var myCustomMetadata = {
customMetadata : {
'file_name': 'this is the file name'
}
}
In the case above, the file_name is the custom metadata that you want to create.
After creating a reference to the file in the firebase storage, you can then call the updateMetadata() method on the reference.
For example:
Get the reference to an image file using downloadUrl:
var getRef = firebase.storage().refFromURL(imageUrl);
Use the reference to update the metadata:
getRef.updateMetadata(myCustomMetadata).then(()=>{
//do other things
})
For me, I had to call to Firebase Storage 2x. I'm using Java on an Android device to edit the metadata. First time is to upload the image. Second time is to set the image's metadata.
Instructions to set the Metadata of a Storage file is here= https://firebase.google.com/docs/storage/android/file-metadata
"You can update file metadata at any time after the file upload completes by using the updateMetadata() method. "
Here's my functions:
private void uploadImageToFBStorageAndFS(byte[] profilePic, final StorageUrlEstablished_CL storageUrlCallback) {
String storage_directory = //You get this
StorageReference profileImageRef = FirebaseStorage.getInstance().getReference(storage_directory).child(final_filename);
//1st time, upload the image/bytes.
if (profilePic != null) {
profileImageRef.putBytes(profilePic).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
Task<Uri> result = taskSnapshot.getMetadata().getReference().getDownloadUrl();
result.addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
updateImageMetadata(profileImageRef);
String urlWhereProfilePicIsStored = uri.toString();
}
});
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
//Error handling
}
});
}
}
private void updateImageMetadata(StorageReference profileImageRef){
//Some devices, like the Asus tablet, doesn't upload good meta-data with the image.
// Create file metadata including the content type
StorageMetadata metadata = new StorageMetadata.Builder()
.setContentType("image/png")
.setCustomMetadata("myCustomProperty", "Rent App")
.build();
// Update metadata properties
profileImageRef.updateMetadata(metadata);
}

Upload a large file into Shared Folder through Microsoft Graph API app only asp.net Access Denied

I'm following the example of the aspnet-snippets-sample
and OneDriveTest.cs to upload a large file through the Microsoft Graph API into a shared folder with app only credentials
and following exception is thrown:
"Access denied. You do not have permission to perform this action or access this resource."
To initialize a large file upload session I do following:
var uploadSession = await _graph
.Drives[DRIVEID]
.Items[ITEMID]
.ItemWithPath("newFile.docx")
.CreateUploadSession()
.Request().PostAsync();
Both the driveId and itemId are valid.
I'm creating my GraphClient like following:
public MicrosoftGraphHelper()
{
_graph = new GraphServiceClient("https://graph.microsoft.com/beta",
new DelegateAuthenticationProvider((requestMessage) =>
{
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", AccessToken);
return Task.FromResult(0);
}));
}
The access token is acquired through my app credentials and secret. In Azure, my app has read/write permissions for files through Microsoft Graph.
Also, creating a new folder like
POST https://graph.microsoft.com/beta/drives/DRIVEID/items/ITEMID/children
with JSON
{
"name": "NewFolderTest",
"folder": { }
}
works as well.
here is the Upload Task
internal async Task<string> UploadLargeFile(HttpPostedFileBase file)
{
try
{
using (Stream fileStream = file.InputStream)
{
// Create the upload session. The access token is no longer required as you have session established for the upload.
// POST /v1.0/drive/root:/UploadLargeFile.bmp:/microsoft.graph.createUploadSession
var driveItems = await _graph.Drives[DRIVEID]
.Items[ITEMID]
.Children
.Request()
.GetAsync();
var uploadSession = await _graph.Drives[DRIVEID]
.Items[ITEMID].ItemWithPath("test.docx").CreateUploadSession()
.Request().PostAsync();
var maxChunkSize = 320 * 1024; // 320 KB - Change this to your chunk size. 5MB is the default.
var provider = new ChunkedUploadProvider(uploadSession, _graph, fileStream, maxChunkSize);
// Setup the chunk request necessities
var chunkRequests = provider.GetUploadChunkRequests();
var readBuffer = new byte[maxChunkSize];
var trackedExceptions = new List<Exception>();
DriveItem itemResult = null;
//upload the chunks
foreach (var request in chunkRequests)
{
// Do your updates here: update progress bar, etc.
// ...
// Send chunk request
var result = await provider.GetChunkRequestResponseAsync(request, readBuffer, trackedExceptions);
if (result.UploadSucceeded)
{
itemResult = result.ItemResponse;
}
}
// Check that upload succeeded
if (itemResult == null)
{
// Retry the upload
// ...
}
return "Success";
}
}
catch (ServiceException e)
{
// Debug.WriteLine("We could not upload the file: " + e.Error.Message);
return null;
}
}
As soon as the code hits:
var result = await provider.GetChunkRequestResponseAsync(request, readBuffer, trackedExceptions);
trying to request:
"https://myapp.sharepoint.com:443/sites/dev/_api/v2.0/drives/DRIVEID/items/ITEMID/uploadSession"
is thrown.
What and where do I have to apply required permissions? The Documentation refers to Files.ReadWrite Does Sharepoint need additional permissions to Microsoft Graph API?
Within the shared folder I can see a new created tmp file with 0 bytes.

ASP.NET Core RC-1 file upload

I am currently uploading a file via the kendo fileuploader to an api controller using ASP.NET core RC-1. I am receiving a periodic error of "object reference not set to instance of object" when attempting to read the stream following opening the stream with IFormFile.OpenReadStream().
My controller is:
[HttpPost]
[Route("api/{domain}/[controller]")]
public async Task<IActionResult> Post([FromRoute]string domain, [FromForm]IFormFile file, [FromForm]WebDocument document)
{
if (ModelState.IsValid)
{
if (file.Length > 0)
{
var userName =
Request.HttpContext.User.Claims
.FirstOrDefault(c => c.Type == ClaimTypesEx.FullName)?
.Value;
var uploadedFileName =
ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"');
document.Domain = domain;
document.MimeType = file.ContentType;
document.SizeInBytes = file.Length;
document.ChangedBy = userName;
document.FileName = (string.IsNullOrEmpty(document.FileName)) ? uploadedFileName : document.FileName;
try
{
document = await CommandStack.For<WebDocument>()
.AddOrUpdateAsync(document, file.OpenReadStream()).ConfigureAwait(false);
}
catch (Exception e)
{
return new HttpStatusCodeResult(500);
}
return Ok(document);
}
}
return new BadRequestResult();
}
And the error is being thrown when I actually try to read the stream when it is going into blob storage:
public async Task<Uri> CreateOrUpdateBlobAsync(string containerName, string fileName, string mimeType,
Stream fileStream)
{
var container = Client.GetContainerReference(containerName);
var blob = container.GetBlockBlobReference(fileName);
//Error HERE
await blob.UploadFromStreamAsync(fileStream);
blob.Properties.ContentType = mimeType;
await blob.SetPropertiesAsync();
return blob.Uri;
}
What I am having trouble with is this is sporadic and there seems to be no defined pattern of which files are accepted and which ones generate the error. At first I thought it might be a size issue but that is not the case as I have several larger files uploaded successfully and then one small file will throw the error. Images seem to work fine and it is hit or miss on other file types with no rhyme or reason that I can figure out.

Resources