(filePath: string, title: string = 'Open File...')
| 140 | * @returns {boolean} whether opening the file succeeded or not |
| 141 | */ |
| 142 | export function openFile(filePath: string, title: string = 'Open File...'): boolean { |
| 143 | const context = androidUtils.getApplicationContext(); |
| 144 | try { |
| 145 | // Ensure external storage is available |
| 146 | if (!isExternalStorageAvailable()) { |
| 147 | Trace.write( |
| 148 | ` |
| 149 | External storage is unavailable (please check app permissions). |
| 150 | Applications cannot access internal storage of other application on Android (see: https://developer.android.com/guide/topics/data/data-storage). |
| 151 | `, |
| 152 | Trace.categories.Error, |
| 153 | Trace.messageType.error, |
| 154 | ); |
| 155 | |
| 156 | return false; |
| 157 | } |
| 158 | |
| 159 | // Ensure external storage is available |
| 160 | if (isExternalStorageReadOnly()) { |
| 161 | Trace.write('External storage is read only', Trace.categories.Error, Trace.messageType.error); |
| 162 | |
| 163 | return false; |
| 164 | } |
| 165 | |
| 166 | // Determine file mimetype & start creating intent |
| 167 | const mimeType = getMimeTypeNameFromExtension(filePath); |
| 168 | const intent = new android.content.Intent(android.content.Intent.ACTION_VIEW); |
| 169 | const chooserIntent = android.content.Intent.createChooser(intent, title); |
| 170 | |
| 171 | intent.addFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK); |
| 172 | chooserIntent.addFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK); |
| 173 | |
| 174 | // Android SDK <28 only requires starting the chooser Intent straight forwardly |
| 175 | if (SDK_VERSION < MIN_URI_SHARE_RESTRICTED_APK_VERSION) { |
| 176 | Trace.write(`detected sdk version ${SDK_VERSION} (< ${MIN_URI_SHARE_RESTRICTED_APK_VERSION}), using simple openFile`, Trace.categories.Debug); |
| 177 | intent.setDataAndType(android.net.Uri.fromFile(new java.io.File(filePath)), mimeType); |
| 178 | context.startActivity(chooserIntent); |
| 179 | |
| 180 | return true; |
| 181 | } |
| 182 | |
| 183 | Trace.write(`detected sdk version ${SDK_VERSION} (>= ${MIN_URI_SHARE_RESTRICTED_APK_VERSION}), using URI openFile`, Trace.categories.Debug); |
| 184 | |
| 185 | // Android SDK 24+ introduced file system permissions changes that disallow |
| 186 | // exposing URIs between applications |
| 187 | // |
| 188 | // see: https://developer.android.com/reference/android/os/FileUriExposedException |
| 189 | // see: https://github.com/NativeScript/NativeScript/issues/5661#issuecomment-456405380 |
| 190 | const providerName = `${context.getPackageName()}.provider`; |
| 191 | Trace.write(`fully-qualified provider name [${providerName}]`, Trace.categories.Debug); |
| 192 | |
| 193 | const apkURI = androidx.core.content.FileProvider.getUriForFile(context, providerName, new java.io.File(filePath)); |
| 194 | |
| 195 | // Set flags & URI as data type on the view action |
| 196 | intent.addFlags(android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION); |
| 197 | chooserIntent.addFlags(android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION); |
| 198 | |
| 199 | // Finish intent setup |
nothing calls this directly
no test coverage detected