How to open PDF file in xamarin forms - xamarin.forms

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();
}

Related

How to fix Applink only open Safari Xamarin iOS

I am facing problem with AppLink in Xamarin iOS/ I followed the article https://www.xamboy.com/2019/01/08/applinks-in-xamarin-forms/. Everything I configured seems fine:
Enable Associated Domains
Website configuration (apple-app-site-association). I also checked on https://branch.io/resources/aasa-validator/
Your domain is valid (valid DNS). Your file is served over HTTPS.
Your server does not return error status codes greater than 400.
Your file's 'content-type' header was found :)
Your JSON is validated.
iOS project
Go to the Entitlements.plist file, enable the property Associated Domain and add the domain of the website with the format applinks:mydomain.com and applinks:*.mydomain.com and applinks:mydomain and applinks:*.mydomain
PageOne.xaml.cs
private async void _viewmore_Tapped(object sender, EventArgs e)
{
string linkapp = _linkapp.Text;
await Browser.OpenAsync(linkapp, BrowserLaunchMode.SystemPreferred);
}
AppDelegate.cs
public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options)
{
var uri = new Uri(url.ToString());
var formsApp = Xamarin.Forms.Application.Current;
formsApp.SendOnAppLinkRequestReceived(uri);
return true;
}
App.cs
protected override async void OnAppLinkRequestReceived(Uri uri)
{
base.OnAppLinkRequestReceived(uri);
if (uri.Host.ToLower() == "mydomain.com" && uri.Segments != null && uri.Segments.Length == 3)
{
string action = uri.Segments[1].Replace("/", "");
bool isActionParamsValid = int.TryParse(uri.Segments[2], out int productId);
if (action == "ProductDetail" && isActionParamsValid)
{
if (productId > 0)
{
App.Current.MainPage = new NavigationPage(new MainView(1));
}
else
{
// it can be security attack => navigate to home page or login page.
App.Current.MainPage = new NavigationPage(new MainView(0));
}
}
}
}
Clear, rebuild,... however I try clicking the _viewmore_Tapped link. It opens again on a Safari page. I checked it on click: Open in it also doesn't have anything related to my application.
How can it open directly in the app? I have consulted the posts, however it does not solve the problem. Looking for solutions from everyone. Thank you

ERROR_UNKNOWN downloading file from Firebase Storage

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");

how to resolve this error.....i am trying to implement custom firebase notification application

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.

Web Api - How to detect when a response has finished being sent

In a web api method I am generating a file and then streaming it to the response like so
public async Task<HttpResponseMessage> GetFile() {
FileInfo file = generateFile();
var msg = Request.CreateResponse(HttpStatusCode.OK);
msg.Content = new StreamContent(file.OpenRead());
msg.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
msg.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") {FileName = file.Name};
return msg;
}
because this a generated file I want to delete it after the response has finished streaming but I can't seem to find a hook in the pipeline for this.
I suppose that I can put a reference to the file in a static and set up a custom MessageHandler that pulls values out of this same static variable and deletes. However, this seems like it can't possibly be right both because of the use of a static (when this should all be per-request) and because I'd have to register a separate route.
I've seen this question but it seems to not really have much of a useful response.
Nice scenario!...the problem with using message handlers is that response writing happens at the host layers and below message handlers layer, so they are not ideal...
Following is an example of how you could do it:
msg.Content = new CustomStreamContent(generatedFilePath);
public class CustomStreamContent : StreamContent
{
string filePath;
public CustomStreamContent(string filePath)
: this(File.OpenRead(filePath))
{
this.filePath = filePath;
}
private CustomStreamContent(Stream fileStream)
: base(content: fileStream)
{
}
protected override void Dispose(bool disposing)
{
//close the file stream
base.Dispose(disposing);
try
{
File.Delete(this.filePath);
}
catch (Exception ex)
{
//log this exception somewhere so that you know something bad happened
}
}
}
By the way, are you generating this file because you are converting some data into PDF. If yes, then I think you could use PushStreamContent for this purpose by directly writing the converted data into the response stream. This way you need not generate a file first and then worry about deleting it later.
We performed same action in WebAPI. I needed to delete file just after it downloaded form server.
We can create custom response message class. It takes file path as parameter and delete it once its transmitted.
public class FileResponseMessage : HttpResponseMessage
{
private readonly string _filePath;
public FileHttpResponseMessage(string filePath)
{
this._filePath= filePath;
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
Content.Dispose();
File.Delete(_filePath);
}
}
Use this class as below code and it will delete your file once it will be written on response stream.
var response = new FileResponseMessage(filePath);
response.StatusCode = HttpStatusCode.OK;
response.Content = new StreamContent(new FileStream(filePath, FileMode.Open, FileAccess.Read));
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = "MyReport.pdf"
};
return response;

.ashx HTTP handler unable to write image from network share to HTTP response

I am trying to write an HTTP handler in C# that loads images from a network drive and writes them to the HTTP response. This is currently not working for me as I keep getting HTTP 302 responses which results in the broken file image being displayed. Below is my HTTP handler. Access permissions have been set so anonymous users have read access to the share but ideally this will not be permanent.
public class SecCamImage : IHttpHandler, IRequiresSessionState
{
public void ProcessRequest(HttpContext context)
{
Configuration config = WebConfigurationManager.OpenWebConfiguration("~/Web.Config");
KeyValueConfigurationElement setting = null;
if(config.AppSettings.Settings.Count > 0)
{
setting = config.AppSettings.Settings["CameraBaseURL"];
}
if(setting != null)
{
string baseURL = setting.Value;
string location = context.Request["location"].ToString();
string camera = context.Request["camera"].ToString();
string image = context.Request["image"].ToString();
if (!(string.Compare(image, "no-image.jpg", true) == 0))
{
if (!string.IsNullOrEmpty(location) && !string.IsNullOrEmpty(camera) && !string.IsNullOrEmpty(image))
{
string fullPath = string.Format(baseURL, location, camera, image);
System.IO.FileInfo imageFile = new System.IO.FileInfo(fullPath);
if (imageFile.Exists)
{
if (context.User.Identity.IsAuthenticated)
{
context.Response.ContentType = "image/jpeg";
context.Response.WriteFile(imageFile.FullName);
context.Response.End();
}
}
}
}
else
{
context.Response.ContentType = "image/jpeg";
context.Response.WriteFile(image);
context.Response.End();
}
}
}
public bool IsReusable
{
get { return false; }
}
}
The URL stored in the config file is structured like this:-
\\\\host\\directory\\{0}\\{1}\\{2}
{0} and {1} are directories and {2} is the file.
I managed to get this working by adding a Virtual Directory to our Website on IIS. The .ashx handler now references the Virutal Directory and not the directory on the network drive.

Resources