I have an Android app that is pretty much a WebView containing a mobile website. I have minimum control over the code of the website but can inject javascript.
The website contains download links to PDF, DOC, ZIP etc. files, with most of them only accessible if the user is logged in. At first I simply made the app open links containing "FileHandler.axd" (the script that handles files) in the normal browser, but if users are not logged in through the app ánd browser they'll just get an error.
So now I'm trying to make the app use the download manager if a link is tapped but am having some trouble as it's not really working at all. I don't have a lot of experience developing Android apps so any lead on where I'm doing it wrong would be greatly appreciated.
These are my permissions:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
I marked the code I added last with a "DOWNLOAD MANAGER CODE BELOW" comment block.
This is part of my MainActivity.java:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mWebView = (WebView) findViewById(R.id.activity_main_webview);
if(CheckNetwork.isInternetAvailable(MainActivity.this)) {
// Enable Javascript
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setDomStorageEnabled(true);
// Get current UserAgent
String curua = mWebView.getSettings().getUserAgentString();
// Add -comapp string to useragent for detection
mWebView.getSettings().setUserAgentString(curua + "-comapp");
// Use remote resource
mWebView.loadUrl("https://www.onsplatform.tv/comapp");
// Stop local links and redirects from opening in browser instead of WebView
mWebView.setWebViewClient(new MyAppWebViewClient(){
#Override
public void onPageFinished(WebView view, String url) {
//hide loading image
findViewById(R.id.imageLoading1).setVisibility(View.GONE);
}
});
/////////////////////////////////
// DOWNLOAD MANAGER CODE BELOW //
/////////////////////////////////
if(mWebView.getUrl().contains("FileHandler.axd")){
String url = mWebView.getUrl();
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "download");
// You can change the name of the downloads, by changing "download" to everything you want, such as the mWebview title...
DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
dm.enqueue(request);
}
} else {
//no connection
Toast toast = Toast.makeText(MainActivity.this, "geen internet / no internet", Toast.LENGTH_LONG);
toast.show();
}
}
Edit
I'm getting a feeling I put the code in the wrong place. I'm guessing I need a public method for the WebViewClient? But which one, onLoadResource()? I've been reading the documentation but I don't really know if I'm looking at the right stuff.
I'm guessing there's a sort of event handler that fires when a link is loading, maybe being able to intercept that, start the download manager for that url and prevent the url from loading in the webview?
I have a class that extends WebViewClient, I'm guessing that would be the place:
public class MyAppWebViewClient extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (Uri.parse(url).getHost().endsWith("onsplatform.tv")) { // && !url.toLowerCase().contains("filehandler")) {
return false;
}
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
view.getContext().startActivity(intent);
return true;
}
}
Related
i have webview where if you create a url ending in m3u8 it will open an external player,
#Override
// Force links to be opened inside WebView and not in Default Browser
// Thanks http://stackoverflow.com/a/33681975/1815624
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.endsWith(".m3u8") || url.endsWith(".ts") || url.endsWith(".mpd") || url.endsWith(".mp4"))
{
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(url), "video/*");
intent.setPackage("com.genuine.leone");
view.getContext().startActivity(intent);
return true; // to tell the WebView that it should not load the URL because you handled it by yourself
}
catch (ActivityNotFoundException e) {
// Player is not installed, you may want to open the play store link
}
}
the problem now, m3u8 requires a widevine license to play, how to send a widevine license url to the external player
i have to research but not find anything, any idea?
I have a website that has a web version and a webview. It is necessary to open directly in the app (if installed) the link to recover password that the user receives in his email.
After adding the code below to AndroidManifest.xml, I was able to open the app by clicking on the link.
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:host="*" android:scheme="myapp"/>
</intent-filter>
Link I created to test:
Click
However, it always opens the home page in the app, instead of opening the specific page in the link.
Do I need to make any further modifications to the app to interpret this type of link?
MainActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = findViewById(R.id.webview);
webView.loadUrl("https://www.site.app");
webView.setWebViewClient(new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(WebView wv, String url) {
}
#Override
public void onPageFinished(WebView view, String url) {
}
});
}
SOLUTION:
Intent intent = getIntent();
Uri data = intent.getData();
if (data != null && data.toString().startsWith("myapp:")) {
urlIntent = data.toString().replace("myapp", "https");
} else {
urlIntent = "https://www.site.app";
}
webView.loadUrl(urlIntent);
Deeplinks normally just triggers the app to be opened, they don't help you navigate or open a specific location unless you define Fragment or Activity based intent-filters or manually handle.
You should get the data which includes URL from intent first then give it to WebView as a URL. You can do that inside either onNewIntent or onCreate methods like so;
override fun onNewIntent(intent: Intent){
super.onNewIntent(intent)
val uri = intent.data
}
then load it in WebView like;
webview.loadUrl(uri.toString())
I tried making a app with the instructions from here:
https://developer.android.com/guide/topics/connectivity/nfc/nfc
But when I compile the code and hold a card against my phone, I get a weird sound
My nfc is turned on, and I have a oneplus 6 running android 9
When I check logcat I see that I'm getting an error:
56:27.888 7834-7850/com.appname D/DecorView: onWindowFocusChangedFromViewRoot hasFocus: true, DecorView#6302a6f[MainActivity]
2019-10-12 22:56:27.913 7834-7834/com.appname W/RenderThread: type=1400 audit(0.0:2504791): avc: denied { read } for name="u:object_r:vendor_default_prop:s0" dev="tmpfs" ino=21655 scontext=u:r:untrusted_app:s0:c16,c257,c512,c768 tcontext=u:object_r:vendor_default_prop:s0 tclass=file permissive=0
2019-10-12 22:56:27.928 7834-7880/com.appname E/libc: Access denied finding property "vendor.debug.egl.swapinterval"
Why am I getting this error instead of the textview displaying the info of the nfc card im scanning (I tried mulitple nfc cards but its gives the same error)
I found someone with somewhat of the same problem. they say you should follow the link and then watch comment #3. and then they say it has something to do with not being allowed to write to a tmp directory due to a security issue.
Please help me resolve this issue, here is my MainActivity.java:
package com.packagename;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.NfcAdapter.CreateNdefMessageCallback;
import android.nfc.NfcEvent;
import android.os.Bundle;
import android.os.Parcelable;
import android.renderscript.RenderScript;
import android.widget.TextView;
import android.widget.Toast;
import static android.nfc.NdefRecord.createMime;
public class MainActivity extends AppCompatActivity implements CreateNdefMessageCallback {
NfcAdapter nfcAdapter;
TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Check for available NFC Adapter
nfcAdapter = NfcAdapter.getDefaultAdapter(this);
if (nfcAdapter == null) {
Toast.makeText(this, "NFC is not available", Toast.LENGTH_LONG).show();
finish();
return;
}
// Register callback
nfcAdapter.setNdefPushMessageCallback(this, this);
}
#Override
public NdefMessage createNdefMessage(NfcEvent event) {
String text = ("Beam me up, Android!\n\n" +
"Beam Time: " + System.currentTimeMillis());
NdefMessage msg = new NdefMessage(
new NdefRecord[] { createMime(
"application/vnd.com.example.android.beam", text.getBytes())
/**
* The Android Application Record (AAR) is commented out. When a device
* receives a push with an AAR in it, the application specified in the AAR
* is guaranteed to run. The AAR overrides the tag dispatch system.
* You can add it back in to guarantee that this
* activity starts when receiving a beamed message. For now, this code
* uses the tag dispatch system.
*/
//,NdefRecord.createApplicationRecord("com.example.android.beam")
});
return msg;
}
#Override
public void onResume() {
super.onResume();
// Check to see that the Activity started due to an Android Beam
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
processIntent(getIntent());
}
}
#Override
public void onNewIntent(Intent intent) {
// onResume gets called after this to handle the intent
setIntent(intent);
}
/**
* Parses the NDEF Message from the intent and prints to the TextView
*/
void processIntent(Intent intent) {
textView = findViewById(R.id.textView);
Parcelable[] rawMsgs = intent.getParcelableArrayExtra(
NfcAdapter.EXTRA_NDEF_MESSAGES);
// only one message sent during the beam
NdefMessage msg = (NdefMessage) rawMsgs[0];
// record 0 contains the MIME type, record 1 is the AAR, if present
textView.setText(new String(msg.getRecords()[0].getPayload()));
}
}
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.packagename">
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
and here a picture of my activity_main.xml:
Thanks!
As NFC reading is handled by the Android OS, this will always make a sound when the card is read.
Depending on what NDEF records on the card and what you application is trying to do determines what the OS does with the NFC data.
You can download a generic NFC Application like https://play.google.com/store/apps/details?id=com.wakdev.wdnfc&hl=en_US to check what is on the card and write some sample data for you application to read.
It looks like you are trying to run this app on 2 phones and get them to talk using the deprecated Android Beam functionality https://developer.android.com/reference/android/nfc/NfcAdapter.CreateNdefMessageCallback (Which I found was never reliable - which is why they are removing it)
But you say
Why am I getting this error instead of the textview displaying the
info of the nfc card im scanning
Which suggest you are trying to read an NFC card and the methods used are not for this.
The question is are you wanting to do with NFC?
1) Have a NFC card cause you APP to be launched by the Android OS?
Then use the data on the NFC some how.
If yes then you should just be putting the correct intent filters in your manifest and handle them in your MainActivity as you would do for any other intent, and the parsing the NDEF message from the intent data.
See https://developer.android.com/guide/components/intents-filters#ExampleFilters for some non NFC examples on how your App can register to the OS what Intent types it can handle.
2) In you App handle reading from the NFC card at certain times
This seems more what you are trying to do (and what my Apps do)
To do this you use enable the NFC Foreground dispatcher https://developer.android.com/reference/android/nfc/NfcAdapter.html#enableForegroundDispatch(android.app.Activity,%20android.app.PendingIntent,%20android.content.IntentFilter%5B%5D,%20java.lang.String%5B%5D%5B%5D)
I use the following type of code to do this in my Activity
public class ViewNFCCardsActivity extends AppCompatActivity {
private NfcAdapter mNfcAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_nfccards);
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
}
#Override
protected void onResume() {
super.onResume();
IntentFilter tagDetected = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
IntentFilter ndefDetected = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
IntentFilter techDetected = new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED);
IntentFilter[] nfcIntentFilter = new IntentFilter[]{techDetected,tagDetected,ndefDetected};
try {
ndefDetected.addDataType("*/*");
} catch (IntentFilter.MalformedMimeTypeException e) {}
PendingIntent pendingIntent = PendingIntent.getActivity(
this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
if(mNfcAdapter!= null)
mNfcAdapter.enableForegroundDispatch(this, pendingIntent, nfcIntentFilter, null);
}
#Override
protected void onPause() {
super.onPause();
if(mNfcAdapter!= null)
mNfcAdapter.disableForegroundDispatch(this);
}
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
TextView textView = (TextView) findViewById(R.id.MessageText);
// High level way to get Ndef records from what is already been read from the tag
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
Parcelable[] rawMessages = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
if (rawMessages != null) {
// Only need the first message
NdefMessage msg = (NdefMessage) rawMessages[0];
// Only need the first record in message
String message = new String(msg.getRecords()[0].getPayload());
textView.setText(message);
}
}
}
The onResume stuff tells Android OS to send all NFC card type messages to my Application and the onNewIntent method gets the Intent passed to it by the OS and processes the Message if it is an NDEF message.
You can also when creating the Foreground Dispatcher in onResume add additional filters like
try {
ndefDetected.addDataType("custom/text");
} catch (IntentFilter.MalformedMimeTypeException e) {}
or remove filters for non NDEF cards (Usually add all types because I don't want other card types like contactless bank cards triggering other apps while my app is in the foreground)
So I've been practising download manager and i was trying out some program.
A first button will download a said Pdf to a location in my phone.
The second button is supposed to open the Pdf file with a Pdf reader installed by the user such as WP Reader etc..
The download works fine, but when i open the pdf , it says invalid format.
I uploaded a sample Pdf to the google drive , so I know that the uploaded file isnt corrupted in any case. There muse be some problem when the file is being downloaded from the server. Please help me find the mistake. And I am relatively new to Android.
And the download button uses an Onclicklistener while the loadPdf is given in the xml file android:onClick="downloadPdf" .
public class MainActivity extends AppCompatActivity {
String myHTTPUrl = "https://drive.google.com/open?id=0B5Pev9zz5bVjZTFFZ1dLZVp1WVU";
String TAG = "My app";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button download = (Button) findViewById(R.id.download);
download.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.v(TAG,"download method called");
downloadPdf();
Toast.makeText(MainActivity.this,"Listener Called",Toast.LENGTH_SHORT).show();
Log.v(TAG,"On Click Listener Called");
}
});
}
public void loadPdf(View view) {
Log.v(TAG,"Pdf load called");
File pdfFile = new File(Environment.getExternalStorageDirectory()+"/notes","ssp.pdf");
if(pdfFile.exists())
{
Uri path = Uri.fromFile(pdfFile);
Intent pdfIntent = new Intent(Intent.ACTION_VIEW);
pdfIntent.setDataAndType(path, "application/pdf");
pdfIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Intent intent = Intent.createChooser(pdfIntent, "Open File");
try
{
startActivity(intent);
}
catch(ActivityNotFoundException e)
{
Toast.makeText(MainActivity.this, "No Application available to view pdf", Toast.LENGTH_LONG).show();
}
}
else
{
Toast.makeText(MainActivity.this,"Pdf not found",Toast.LENGTH_SHORT).show();
}
}
public void downloadPdf()
{
DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(myHTTPUrl));
request.setTitle("Solid State Physics");
request.setDescription("File is being Downloaded...");
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setDestinationInExternalPublicDir("/notes","ssp.pdf");
manager.enqueue(request);
}}
EDITED :
This is the exact error I'm facing with screenshot
Error : File format error , Cannot be opened
Screenshot of the error.
You're not downloading the PDF, you're downloading the web-page displaying the contents of the PDF. If you want to download the PDF file directly, use the following URL:
String myHTTPUrl = "https://drive.google.com/uc?export=download&id=0B5Pev9zz5bVjZTFFZ1dLZVp1WVU";
and your application should work.
(Don't forget to delete the invalid notes/ssp.pdf file first, otherwise the DownloadManager will download the file under a different name, like notes/ssp-1.pdf.)
I'm developing a material design app.
I want to open my app's facebook page when user clicks on the 'like on facebook' text (layout) in my app.
I've managed to open the facebook app but I am unable to figure out how can I open my page directly!
Here's what I've done so far:
LinearLayout linearLayoutFacebookContainer = (LinearLayout) findViewById(R.id.facebook_container);
linearLayoutFacebookContainer.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
final Handler handler3 = new Handler();
handler3.postDelayed(new Runnable() {
#Override
public void run() {
Intent facebookIntent = getPackageManager().getLaunchIntentForPackage("com.facebook.katana");
if (facebookIntent != null) {
// We found the activity now start the activity
facebookIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
facebookIntent.setData(Uri.parse("https://www.facebook.com/HumaneHelper/"));
startActivity(facebookIntent);
} else {
// Bring user to the market or let them choose an app?
facebookIntent = new Intent(Intent.ACTION_VIEW);
facebookIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
facebookIntent.setData(Uri.parse("https://www.facebook.com/HumaneHelper/"));
startActivity(facebookIntent);
}
}
}, 200);
}
});
Please let me know.
I'm a beginner, please cooperate.
Thanks in advance.
fb://page/{id} is the way to go:
final String url = "fb://page/" + facebookID
Intent facebookAppIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
facebookAppIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
startActivity(facebookAppIntent);
Are you sure you are using the ID number of your Facebook page and NOT the username?
What I mean is that if, for example, you want to open the Facebook page of Facebook itself (i.e. https://www.facebook.com/facebook) you have to use:
fb://page/20531316728
Since 20531316728 is the ID of the Facebook page (while facebook is the username).
If you don't know the ID of your Facebook page, you can retrieve it opening:
https://graph.facebook.com/{username}
Courtesy: Open Facebook page via Facebook app