New File() on Android sets name different then Web and PWA

This is crazy and im not understanding this. When we run this angular 12 application in Web or PWA the captured image is created to a file correctly. The name is correct. However when run on an Android device its completely wrong

 async addPhoto() {
    const image = await Camera.getPhoto({
      quality: 100,
      // allowEditing: true,
      resultType: CameraResultType.Base64,
      // source: CameraSource.Photos, // Shows a prompt to Take Photo or Select from File
      webUseInput: !(this.platform.is('android') || this.platform.is('ios')), // Always use File window instead of camera
      // saveToGallery: true
    });

    // Create File from photo
    const fileName = new Date().getTime() + '.jpeg';
    const file = await this.base64ToFile(`data:image/jpeg;base64,${image.base64String}`, fileName);
    this.files.push(file);

    // Add images to list for displaying on screen
    this.images.unshift({
      fileName,
      imgSrc: `data:image/jpeg;base64,${image.base64String}`,
      base64: image.base64String
    });
  }

  private async base64ToFile(base64: string, newImageName: string): Promise<File> {
    const res: Response = await fetch(base64);
    const blob: Blob = await res.blob();
    return new File([blob], newImageName, { type: 'image/png' });
  }

Web/PWA

Android

Here is my package.json

{
  "name": "race-chat",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "^12.2.4",
    "@angular/cdk": "^12.2.4",
    "@angular/common": "^12.2.4",
    "@angular/compiler": "^12.2.4",
    "@angular/core": "^12.2.4",
    "@angular/forms": "^12.2.4",
    "@angular/google-maps": "^12.2.10",
    "@angular/material": "^12.2.4",
    "@angular/platform-browser": "^12.2.4",
    "@angular/platform-browser-dynamic": "^12.2.4",
    "@angular/router": "^12.2.4",
    "@angular/service-worker": "^12.2.4",
    "@asymmetrik/ngx-leaflet": "^8.1.0",
    "@capacitor/android": "3.2.3",
    "@capacitor/angular": "^1.0.3",
    "@capacitor/camera": "^1.1.2",
    "@capacitor/core": "^3.2.3",
    "@capacitor/device": "^1.0.4",
    "@capacitor/geolocation": "^1.1.2",
    "@capacitor/ios": "3.2.3",
    "@capacitor/push-notifications": "^1.0.4",
    "@ionic-native/core": "^5.36.0",
    "@ionic-native/file": "^5.36.0",
    "@ionic-native/file-opener": "^5.36.0",
    "@ionic/angular": "^5.8.1",
    "@ionic/angular-toolkit": "^4.0.0",
    "@ionic/pwa-elements": "^3.0.2",
    "@ngrx/effects": "^12.4.0",
    "@ngrx/store": "^12.4.0",
    "@ngrx/store-devtools": "^12.4.0",
    "@stencil/core": "^2.9.0",
    "@types/signalr": "^2.2.36",
    "bootstrap": "^4.4.1",
    "canvas": "^2.5.0",
    "cordova-plugin-file": "^6.0.2",
    "cordova-plugin-file-opener2": "^3.0.5",
    "core-js": "^2.6.11",
    "devextreme": "^19.2.7",
    "devextreme-angular": "^19.2.7",
    "guid-typescript": "^1.0.9",
    "jetifier": "^2.0.0",
    "jquery": "^3.4.1",
    "leaflet": "^1.7.1",
    "material-design-icons": "^3.0.1",
    "material-icons": "^0.3.1",
    "ngx-bootstrap": "^3.2.0",
    "ngx-color": "^5.0.2",
    "popper": "^1.0.1",
    "rxjs": "~6.5.4",
    "signalr": "^2.4.1",
    "swiper": "^7.0.9",
    "tslib": "^2.0.0",
    "zone.js": "~0.11.4"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "^12.2.3",
    "@angular/cli": "^12.2.3",
    "@angular/compiler-cli": "^12.2.4",
    "@angular/language-service": "^12.2.4",
    "@capacitor/cli": "^3.2.3",
    "@ionic/angular-toolkit": "latest",
    "@types/adal": "^1.0.29",
    "@types/jasmine": "~3.6.0",
    "@types/jasminewd2": "~2.0.3",
    "@types/jquery": "^2.0.53",
    "@types/leaflet": "^1.7.6",
    "@types/node": "^12.12.34",
    "codelyzer": "^6.0.0",
    "devextreme-cli": "latest",
    "devextreme-themebuilder": "^19.2.7",
    "jasmine-core": "~3.6.0",
    "jasmine-spec-reporter": "~5.0.0",
    "karma": "~6.3.4",
    "karma-chrome-launcher": "~3.1.0",
    "karma-coverage-istanbul-reporter": "~3.0.2",
    "karma-jasmine": "~4.0.0",
    "karma-jasmine-html-reporter": "^1.5.0",
    "protractor": "~7.0.0",
    "ts-node": "~7.0.0",
    "tslint": "~6.1.0",
    "typescript": "~4.3.5"
  }
}

Looks like a new webview/chrome update has messed things up.

What’s your android version and webview version.
And which webview implementation is being used Chrome or Android System Webview?

@parviz0121 chrome and the PWA are working the way it should be. The file name is correct. The issue is when its run on an Android device.

Android version 11 and its running on Android Webview on the android device

what looks like is happening is the ionic-native/file is replacing the typescript lib File object. When the File is created on web, pwa or mobile web browser there are no issues, its using the Typscript File object and creating the file correctly with the name correctly. When on Android natively it looks like that File object is now the ionic-native/file object and its constructor is different. So its not naming the file correctly, it looks like its assigning the blob of the file to the name instead of the actual file name.

:wave: Hello, are you using the cordova plugin or just regular Capacitor APIs?

“when its run on an Android device” The webview is giving a different File object.

In past, webview has had problems like no file chooser would come on tapping choose file.

You have already confirmed that your default webview app is Android System Webview so ignore this paragraph: Goto developer tools on your device and tap Webview implementation. There are 2 webview providers (Android System Webview and Chrome webview). Find out which one is default on your device.

Try to downgrade the webview app to an older version by installing old webview from ApkMirror.

If this fixes your issue, webview is to be blamed and you need to update your code to work around this issue. From time to time webview messes up z-index bugs, add screen flickering and other device specific issues like extension goes missing from chosen filename (i had to workaround this on my app).

@mhartington as for this component, this is my imports section

import { NullTemplateVisitor } from '@angular/compiler';
import { Image, PointOfInterestData, PointOfInterestType, PointOfInterestSeverity } from './../../../models/map-model';
import { Component, OnInit, OnDestroy } from '@angular/core';
import { ModalController, NavParams, Platform, PopoverController, ToastController } from '@ionic/angular';
import { Geolocation } from '@capacitor/geolocation';
import { AddPointOfInterestMapComponent } from '../add-point-of-interest-map/add-point-of-interest-map.component';
import { Camera, CameraResultType, CameraSource, Photo } from '@capacitor/camera';

The File referenced in the code is the standard Typescript File from node_modules/typescript/lib/lib.dom.d.ts

Hi all,

Have you solved this issue? I’m encountering the same issue

We resolved this issue by creating the file as a blob instead.

Example:

  private async base64ToFile(base64: string, newImageName: string): Promise<File> {
    const res: Response = await fetch(base64);
    const blob: Blob = await res.blob();
    return new Blob([blob], { type: 'image/jpeg' });
  }

For whomever encounters this problem the solution is simple: remove any Cordova/Capacitor native File plugin and the issue will be resolved instantly. As mentioned in the comments above, the native File structure is different than the web view’s.

This way worked for me in Both Web and Android.

You have to go to cordova-plugin-file from the Plugins folder:

  • after that open the Pluging.xml
    there change this
<js-module src="www/File.js" name="File">
    <clobbers target="window.File" />
</js-module>

to this

<js-module src="www/File.js" name="File">
    <clobbers target="window.FileC" />
</js-module>

after that

cordova platform remove android
cordova platform remove browser

and then add them back

cordova platform add android
cordova platform add browser