Im trying to download a file *.Apk from the storage and install when is completed.
i revised the rules from storage and the uses.
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read : if request.auth.uid != null;
}
}
}
on rules monitor all operations are accepted but the file can't be donwloaded
fragment of donwload code is:
public void downloadUpdate() {
StorageReference gsReference = FirebaseStorage.getInstance("filename.apk");
final String rutadestino = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/";
final String nombrearchivo = "LeaderBoard-Upd.apk";
final Uri archivodestino = Uri.parse("file://" + rutadestino+nombrearchivo);
File localFile = new File(rutadestino+nombrearchivo);
if (localFile.exists()) {
localFile.delete();
}
gsReference.getFile(localFile).addOnSuccessListener(new OnSuccessListener<FileDownloadTask.TaskSnapshot>() {
#Override
public void onSuccess(FileDownloadTask.TaskSnapshot taskSnapshot) {
//Local temp file has been created
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Uri contentUri = FileProvider.getUriForFile(getApplicationContext(), BuildConfig.APPLICATION_ID + ".provider", new File(rutadestino+nombrearchivo));
Intent install = new Intent(Intent.ACTION_VIEW);
install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
install.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
install.setData(contentUri);
startActivity(install);
//unregisterReceiver(this);
finish();
} else {
Intent install = new Intent(Intent.ACTION_VIEW);
install.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
install.setDataAndType(archivodestino,
"application/vnd.android.package-archive");
startActivity(install);
//unregisterReceiver(this);
finish();
}
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
// Handle any errors
int errorCode = ((StorageException) exception).getErrorCode();
String errorMessage = exception.getMessage();
Emergente.ErrorCode(1,getApplicationContext());
}
});
}
i received
errorcode "13000"
errorMessage "An unknown error occurred, please check the HTTP result code and inner exception for server response."
cause "open failed: EACCES (Permission denied)"
Maybe another code fragment is wrong, but in this momment im stucked on the OnFailureListener
The problem is on the app permissions, when app tries to download files and write it on a wrong directory/file without the required permission it will trow the "ERROR_UNKNOWN" message.
The solution is create the file on the same app directory, when doing so the permission is not required unles the API <= 18 then the permission will be necessary.
Solution:
File localFile = new File(getExternalFilesDir(null), "file.apk");
Related
PROBLEM: I'm using GoogleBilling V5 to process in-app purchases. I use a Firebase firestore to store purchase tokens for verification. I am attempting to use Volley to check the store to see if a token exists. However, Volley never processes the POST method and instead returns with
E/Volley: [591] NetworkUtility.shouldRetryException: Unexpected response code 403 for https://MY_URL.cloudfunctions.net/verifyPurchases?PurchaseToken=REALLY_LONG_PURCHASE_TOKEN_STRING&purchaseTime=TIMESTAMP_LONG&orderId=ORDER_ID_STRING/
Where REALLY_LONG_PURCHASE_TOKEN_STRING, TIMESTAMP_LONG, and ORDER_ID_STRING look acceptable. That is, the token is being generated, the timestamp is appearing as a Long datatype (correct), and the OrderId is consistent with GoogleBilling.
SETUP:
Added dependencies in gradle
def billing_version = '5.0.0'
implementation "com.android.billingclient:billing:$billing_version"
def volley_version = "1.2.1"
implementation "com.android.volley:volley:$volley_version"
Verified that purchaseToken,purchaseTime,and orderId all match EXACTLY with what was updated to the the firebase functions.
Curent Firestore Rules are:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
Followed this tutorial
(Selling In-App Products on Android: Implementing Google Play Billing V4): https://www.youtube.com/watch?v=KYFM2z5KPq0
Migrated to V5 per Google's migration guide: https://developer.android.com/google/play/billing/migrate-gpblv5
I instantiate the BillingClient within my singleton class as follows. The verifyInAppPurchase function is called within the PurchasesUpdatedListener.
...
billingClient = BillingClient.newBuilder(mContext)
.enablePendingPurchases()
.setListener(new PurchasesUpdatedListener() {
#Override
public void onPurchasesUpdated(#androidx.annotation.NonNull BillingResult billingResult, #Nullable #org.jetbrains.annotations.Nullable List<Purchase> list) {
//Once we receive a response from Google, we have to verify whether or not the purchase has been made
//via our Firestore database
if(billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && list != null){
for(Purchase purchase : list){
if(purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED && !purchase.isAcknowledged()){
//Now that we've verified that there is indeed a purchase, we have to verify that the purchase token hasn't been used
// and is valid. We do this by storing all the purchase tokens in a database. New purchases won't be in the database yet.
verifyInAppPurchase(purchase);
}
}
}
}
}).build();
...
verifyInAppPurchase:
I'm almost positive the issue is in here somewhere.
Should I be using my app's SHA1 key somewhere to validate the client?
NOTE: When I just copy/paste the requestURL into a browser, I get a PERMISSION DENIED page
public void verifyInAppPurchase(Purchase purchase){
String requestURL = "https://MY_URL.cloudfunctions.net/verifyPurchases?"
+ "purchaseToken=" + purchase.getPurchaseToken() + "&"
+ "purchaseTime=" + purchase.getPurchaseTime() + "&"
+ "orderId=" + purchase.getOrderId() + "/";
Log.d("verifyInAppPurchase", "verifyInAppPurchase::RequestURL: " + requestURL); //This is as far as it gets. No other LOG messages appear (the onResponse Listener is never invoked)
StringRequest stringRequest = new StringRequest(
Request.Method.POST,
requestURL,
new Response.Listener<String>(){
#Override
public void onResponse(String response){
/* Once we made it in here, we know the user did *something* so we have to
* figure that out.
*/
try{
JSONObject purchaseInfoFromServer = new JSONObject(response);
Log.d("verifyInAppPurchase", "verifyInAppPurchase::Was the purchase valid?"); //never gets here
//Was the purchase valid?
if(purchaseInfoFromServer.getBoolean("isValid")){
//(yes!) Okay, cool. Well, we should acknowledge that (or we don't get paid)
Log.d("verifyInAppPurchase", "verifyInAppPurchase::Was the purchase valid? YES!");
AcknowledgePurchaseParams ackPurchaseParams = AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(purchase.getPurchaseToken())
.build();
//So we acknowledge here and then set up a listener for when Google responds to our acknowledgement.
billingClient.acknowledgePurchase(
ackPurchaseParams,
new AcknowledgePurchaseResponseListener() {
#Override
public void onAcknowledgePurchaseResponse(#NonNull BillingResult billingResult) {
Log.d("verifyInAppPurchase", "verifyInAppPurchase::onAcknowledgePurchaseResponse: Acknowledged!");
//Google responded! Now, we have to deliver the goods!
if(billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK){
Log.d("verifyInAppPurchase", "verifyInAppPurchase::onAcknowledgePurchaseResponse: BillingResponseCode OK");
handlePurchase(purchase);
}
}
}
);
}
} catch (Exception e){
Log.d("verifyInAppPurchase", "verifyInAppPurchase::onResponse ERROR: " + e.toString());
}
}
},
new Response.ErrorListener(){
#Override
public void onErrorResponse(VolleyError error){
NetworkResponse response = error.networkResponse;
if (error instanceof ServerError && response != null) {
try {
String res = new String(response.data, HttpHeaderParser.parseCharset(response.headers, "utf-8"));
// Now you can use any deserializer to make sense of data
JSONObject obj = new JSONObject(res);
//Log.d("verifyInAppPurchase", "verifyInAppPurchase::Volley ERROR: " + obj.toString());
} catch (UnsupportedEncodingException e1) {
// Couldn't properly decode data to string
e1.printStackTrace();
//Log.d("verifyInAppPurchase", "verifyInAppPurchase::Volley ERROR: " + e1.toString());
} catch (JSONException e2) {
// returned data is not JSONObject?
e2.printStackTrace();
//Log.d("verifyInAppPurchase", "verifyInAppPurchase::Volley ERROR: " + e2.toString());
}
}
Log.d("verifyInAppPurchase", "verifyInAppPurchase::Volley ERROR: " + error.toString());
}
}
){
#Override
public String getBodyContentType(){
return "application/json";
}
};
// Volley should run on UI thread per
//https://google.github.io/volley/simple.html
Handler mainHandler = new Handler(mContext.getMainLooper());
Runnable myRunnable = () -> Volley.newRequestQueue(mContext).add(stringRequest);
mainHandler.post(myRunnable);
}
Incidentally, what changes will I have to make to ensure this is only ever accessed by my app? I'm currently thinking I'll have to change the rules to reference the 'auth' variable per (https://firebase.google.com/docs/database/security/rules-conditions), but that involves using the whole Firebase Authentication SDK which feels overkill. Is there a cleaner way of securing the function without forcing users to log in?
I downloaded a PDF file as byte[] and save it into internal storage using File.WriteAllBytes(path, response);.
Now cannot access to it from android emulator, how could I save it on download folder? And what I need to be able to open it from pdf reader installed into emulator?
how could I save it on download folder?
For android, you can save pdf file in download folder by following path.
string rootPath = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.AbsolutePath, Android.OS.Environment.DirectoryDownloads);
For ios, use this directory to store user documents and application data files.
var documents = Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments);
About open pdf in Anaroid, you can use the following code:
public void openpdf()
{
string path = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.AbsolutePath, Android.OS.Environment.DirectoryDownloads, "file.pdf");
// Get the uri for the saved file
Android.Net.Uri file = Android.Support.V4.Content.FileProvider.GetUriForFile(MainActivity.mactivity, MainActivity.mactivity.PackageName + ".fileprovider", new Java.IO.File(path));
Intent intent = new Intent(Intent.ActionView);
intent.SetDataAndType(file, "application/pdf");
intent.SetFlags(ActivityFlags.ClearWhenTaskReset | ActivityFlags.NewTask | ActivityFlags.GrantReadUriPermission | ActivityFlags.NewTask|ActivityFlags.NoHistory);
try
{
MainActivity.mactivity.ApplicationContext.StartActivity(intent);
}
catch (Exception)
{
Toast.MakeText(Xamarin.Forms.Forms.Context, "No Application Available to View PDF", ToastLength.Short).Show();
}
}
you need to add permission WRITE_EXTERNAL_STORAGE and READ_EXTERNAL_STORAGE in AndroidMainfeast.xml, then you also need to Runtime Permission Checks in Android 6.0.
private void checkpermission()
{
if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.WriteExternalStorage) == (int)Permission.Granted)
{
// We have permission, go ahead and use the writeexternalstorage.
}
else
{
// writeexternalstorage permission is not granted. If necessary display rationale & request.
ActivityCompat.RequestPermissions(this, new String[] { Manifest.Permission.WriteExternalStorage }, 1);
}
if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.ReadExternalStorage) == (int)Permission.Granted)
{
// We have permission, go ahead and use the ReadExternalStorage.
}
else
{
// ReadExternalStorage permission is not granted. If necessary display rationale & request.
ActivityCompat.RequestPermissions(this, new String[] { Manifest.Permission.ReadExternalStorage }, 1);
}
}
Also add a provider in the AndroidManifest.xml file:
<application android:label="PdfSample.Android">
<provider android:name="android.support.v4.content.FileProvider" android:authorities="com.companyname.fileprovider" android:exported="false" android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="#xml/file_paths"></meta-data>
</provider>
</application>
And add an external path in Resources/xml/file_paths.xml
<external-path name="external_files" path="."/>
MainActivity.mactivity is static property in MainActivity.cs:
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
public static MainActivity mactivity;
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
mactivity = this;
About open pdf in ios, you can take a look:
How to view PDF file using Xamarin Forms
Update:
My answer is also using DependencyService, you can create iterface in shared project.
public interface Iopenpdf
{
void openpdf();
}
In Android platform, implement this interface.
[assembly: Xamarin.Forms.Dependency(typeof(openpdfhandle))]
namespace PdfSample.Droid
{
class openpdfhandle : Iopenpdf
{
public void openpdf()
{
string path = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.AbsolutePath, Android.OS.Environment.DirectoryDownloads, "file.pdf");
//string path = Path.Combine(Android.App.Application.Context.GetExternalFilesDir(Environment.DirectoryDownloads).ToString(), "file.pdf");
// Get the uri for the saved file
Android.Net.Uri file = Android.Support.V4.Content.FileProvider.GetUriForFile(MainActivity.mactivity, MainActivity.mactivity.PackageName + ".fileprovider", new Java.IO.File(path));
Intent intent = new Intent(Intent.ActionView);
intent.SetDataAndType(file, "application/pdf");
intent.SetFlags(ActivityFlags.ClearWhenTaskReset | ActivityFlags.NewTask | ActivityFlags.GrantReadUriPermission | ActivityFlags.NewTask|ActivityFlags.NoHistory);
try
{
MainActivity.mactivity.ApplicationContext.StartActivity(intent);
}
catch (Exception)
{
Toast.MakeText(Xamarin.Forms.Forms.Context, "No Application Available to View PDF", ToastLength.Short).Show();
}
}
}
}
In shared code project, open pdf in button.click
private void btnopen_Clicked(object sender, EventArgs e)
{
DependencyService.Get<Iopenpdf>().openpdf();
}
I am using CameraX API to take pictures in my android app, save them and then display them from their path. With the previous version alpha-09 I was able to do so with onImageSaved(File file). However with the alpha-10 I have to use onImageSaved(OutputFileResults outputFileResults) and then get the path from the uri retrieved by the outputFileResults. But the Uri I get is always wrong. For instance when my image is saved at: "/external/images/media/1581680878237.jpg" I get the uri's path: "/external/images/media/113758".
Here is my code:
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, "NEW_IMAGE");
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpg");
ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.Builder(
activity.getContentResolver(),
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
contentValues).build();
imageCapture.takePicture(outputFileOptions, Runnable::run, new ImageCapture.OnImageSavedCallback() {
#Override
public void onImageSaved(#NonNull ImageCapture.OutputFileResults outputFileResults) {
Uri uri = outputFileResults.getSavedUri();
if(uri != null){
System.out.println("URI PATH" + uri.getPath());
System.out.println("URI PATH" + uri.toString());
activity.runOnUiThread(cameraProvider::unbindAll);
galleryAddPic(uri);
Bundle params = new Bundle();
params.putString("FILE_PATH", uri.getPath());
Navigation.findNavController(root).navigate(R.id.navigation_edit_image, params);
}
}
#Override
public void onError(#NonNull ImageCaptureException exception) {
exception.printStackTrace();
}
});
So I finally managed to save the image taken by ImageCapture by using an other method (especially an other ImageCapture.OutputFileOptions.Builde). I didn't use an Uri object to save the image but a File object.
File mImageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "YOUR_DIRECTORY");
boolean isDirectoryCreated = mImageDir.exists() || mImageDir.mkdirs();
if(isDirectoryCreated){
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "/YOUR_DIRECTORY", "YOUR_IMAGE.jpg");
ImageCapture.OutputFileOptions.Builder outputFileOptionsBuilder =
new ImageCapture.OutputFileOptions.Builder(file);
imageCapture.takePicture(outputFileOptionsBuilder.build(), Runnable::run, new ImageCapture.OnImageSavedCallback() {
#Override
public void onImageSaved(#NonNull ImageCapture.OutputFileResults outputFileResults) {
Bundle params = new Bundle();
params.putString("FILE_PATH", file.getPath());
Navigation.findNavController(root).navigate(R.id.navigation_edit_image, params);
}
#Override
public void onError(#NonNull ImageCaptureException exception) {
exception.printStackTrace();
}
});
}
Be aware that if you use outputFileResults.getSavedUri() with this method you will always have a null uri.
As of CameraX alpha 10, ImageCapture supports 3 types of save location: File, MediaStore URI and OutputStream, depending on which OutputFileOptions.Builder() is used.
The Uri field in OutputFileResults is only populated if the OutputFileOptions is MediaStore URI type. For File type, the caller should have the save location already, there is no need to return the info; for OutputStream type, the save location is unknown to CameraX. See the JavaDoc:
public Uri getSavedUri ()
Returns the Uri of the saved file.
This field is only returned if the ImageCapture.OutputFileOptions is
backed by MediaStore constructed with #Builder(ContentResolver, Uri,
ContentValues).
For more info, please checkout the developer doc.
Error:(29, 44) error: cannot access AbstractSafeParcelable
class file for com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable not found
public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {
private static final String TAG = MyFirebaseInstanceIDService.class.getSimpleName();
#Override
public void onTokenRefresh() {
super.onTokenRefresh();
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
// Saving reg id to shared preferences
storeRegIdInPref(refreshedToken);
// sending reg id to your server
sendRegistrationToServer(refreshedToken);
// Notify UI that registration has completed, so the progress indicator can be hidden.
Intent registrationComplete = new Intent(Config.REGISTRATION_COMPLETE);
registrationComplete.putExtra("token", refreshedToken);
LocalBroadcastManager.getInstance(this).sendBroadcast(registrationComplete);
}
private void sendRegistrationToServer(final String token) {
// sending gcm token to server
Log.e(TAG, "sendRegistrationToServer: " + token);
}
private void storeRegIdInPref(String token) {
SharedPreferences pref = getApplicationContext().getSharedPreferences(Config.SHARED_PREF, 0);
SharedPreferences.Editor editor = pref.edit();
editor.putString("regId", token);
editor.commit();
}
}
In your Gradle file all the versions of google-play-service and firebase should all use the same version.
As you are using :
compile 'com.google.firebase:firebase-core:10.0.1'
You should use :
compile 'com.google.firebase:firebase-messaging:10.0.1' // and not 9.4.0
So if you are using google-play-services, please update the version to 10.0.1.
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.