Is there a way to get the stock Android browser to auto-open a PDF, Word or other typical file without having to go through the process of downloading the file and then getting the user to open the file from the Downloads app or the Notification bar?
We have a web application that has a lot of documents that we'd like to include and not have to convert to HTML, but making the user download the file and manually open it is not easy to train users on.
On iOS, these files all display inline in the browser. I'd like a way to get the browser to auto-launch the files into Acrobat Reader or QuickOffice or whatever program the user has to display them.
Does anyone know a way to do that? I know that Google Docs has some PDF viewing support, but people using our web app may not have public Internet access in all cases, and may be hitting on a local web server.
You can open a file PDF in Google Docs Viewer by appending the URL to:
https://docs.google.com/gview?embedded=true&url=<URL of a supported doc>
This would open a PDF file in the default browser or a WebView.
A list of supported formats is given here.
You can use this format as of 2017-04-06.
https://docs.google.com/viewerng/viewer?url=http://yourfile.pdf
Just replace http://yourfile.pdf with the link you use.
String format = "https://drive.google.com/viewerng/viewer?embedded=true&url=%s";
String fullPath = String.format(Locale.ENGLISH, format, "PDF_URL_HERE");
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(fullPath));
startActivity(browserIntent);
I needed this too, and the links above stopped working so this is what I found to work with the New Google Drive:
Google has a service that creates the link for PDF's Not in GDrive:
https://docs.google.com/viewer
Just add your URL and it creates a link, and IFrame code
(Look closely and you will see the pattern and create links without this web service)
Also, there is a way to do it for PDF's stored in Google Drive:
https://docs.google.com/viewer?srcid=YOUR_GDRIVE_PDF_DOC_ID_HERE&pid=explorer&efh=false&a=v&chrome=false&embedded=true
(this can be a link or the src URL of an iframe)
I've tested on Android and it brings up the PDF viewer nicely.
Specifically, to install the pdf.js plugin for Firefox, you do not use the app store. Instead, go to addons.mozilla.org from inside Mozilla and install it from there.
Also, to see if it's installed properly, go to the menu Tools → Add-ons (not the "about:plugins" URL as you might think from the desktop version).
Unfortunately the native browser present on Android devices not support this type of file. Let's see if in the 4.0 we will be able to do that.
Try this code
This worked for me.
package ak.wp.meto.activity;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.KeyEvent;
import android.widget.TextView;
import android.widget.Toast;
import com.github.barteksc.pdfviewer.PDFView;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import ak.wp.meto.R;
public class PdfViewer extends Activity {
private TextView txt; // You can remove if you don't want this
private PDFView pdf;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_custom_pdf);
pdf = (PDFView) findViewById(R.id.pdfView); //github.barteksc
txt = findViewById(R.id.txtPdf);
String pdfUrl = "https://www.rkiinstruments.com/pdf/71-0136RK.pdf";
try{
new RetrievePdfStream().execute(pdfUrl);
}
catch (Exception e){
Toast.makeText(this, "Failed to load Url :" + e.toString(), Toast.LENGTH_SHORT).show();
}
}
class RetrievePdfStream extends AsyncTask<String, Void, InputStream> {
#Override
protected InputStream doInBackground(String... strings) {
InputStream inputStream = null;
try {
URL url = new URL(strings[0]);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
if (urlConnection.getResponseCode() == 200) {
inputStream = new BufferedInputStream(urlConnection.getInputStream());
}
} catch (IOException e) {
return null;
}
return inputStream;
}
#Override
protected void onPostExecute(InputStream inputStream) {
pdf.fromStream(inputStream).load();
}
}
}
add library in build.gradle
implementation 'com.github.barteksc:android-pdf-viewer:3.1.0-beta.1'
implementation 'com.github.barteksc:android-pdf-viewer:2.8.2'
create activity_custom_pdf.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
tools:context=".activity.PdfViewer">
<com.github.barteksc.pdfviewer.PDFView
android:id="#+id/pdfView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<TextView
android:id="#+id/txtPdf"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"/>
</RelativeLayout>
You can use this
webView.loadUrl("https://docs.google.com/viewer?url=" + "url of pdf file");
public class MainActivity extends AppCompatActivity {
Button button;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
openURL("http://docs.google.com/viewer?url=" + " your pdf link ");
}
});
}
private void openURL(String s) {
Uri uri = Uri.parse(s);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri,"text/html");
startActivity(intent);
}
}
Try the following. It worked for me.
WebView view = (WebView) findViewById(R.id.yourWebView);
view.getSettings().setJavaScriptEnabled(true);
view.getSettings().setPluginState(WebSettings.PluginState.ON);
view.loadUrl("http://docs.google.com/gview?embedded=true&url="
+"your document link(pdf,doc,docx...etc)");
Download the Acrobat Reader .apk file for Android to display PDF files
Put your PDF files on an SD card
Use the snippet of code below
File file = new File("/sdcard/test.pdf");
Uri path = Uri.fromFile(file);
Intent i = new Intent(Intent.ACTION_VIEW);
i.setDataAndType(path,"application/pdf");
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
I tried clicking on the button on my code but the application keeps on crashing i want to know if my code is wrong or my device used for running is wrong.here is the code
package com.example.pnrcompanion;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
public class LoginActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
getSupportActionBar().hide();
setContentView(R.layout.activity_login);
TextView text1=findViewById(R.id.txt_signup2);
TextView text2=findViewById(R.id.txt_3);
Button btn1=findViewById(R.id.btnLogin);
btn1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(LoginActivity.this, ProfileActivity.class));
}
});
text1.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
startActivity(new Intent(LoginActivity.this, RegisterActivity.class));
}
});
text2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(LoginActivity.this, ForgetPasswordActivity.class));
}
});
}
}
I want to try to fix this code so that i can run it for my project.
Yeah, it's a bit difficult to tell what's going on because you have multiple onClick listeners (two for Textviews). Each one is bringing you to a specific Class/XML layout so anything in the XML layout or the code for those classes could be causing the crash.
If it's crashing when you click on btn1 then I would check the ProfileActivity.java or its corresponding XML file.
Start your program with the debugger which is the little green icon in the top right (over from the run options) and then go click the button that's crashing it. If you open up your logcat (and ensure it's showing errors) you should see something there. That'll give you more of an idea of what's going on.
I'm trying to scrape this page with HtmlUnit. In the Xml, it says "You are currently browsing with JavaScript turned off which means you can't use our search functionality." I've been able to scrape it before using Python and Selenium, but I haven't been able to get it to work with Java and
import java.io.IOException;
import java.net.MalformedURLException;
import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.SilentCssErrorHandler;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
public class WebScraper {
public static void main(String[] args) throws MalformedURLException, IOException {
try {
WebClient webClient = new WebClient(BrowserVersion.CHROME);
webClient.getOptions().setJavaScriptEnabled(true);
webClient.waitForBackgroundJavaScript(2000);
webClient.setCssErrorHandler(new SilentCssErrorHandler());
HtmlPage page = webClient.getPage("https://doaj.org/search?source=%7B%22query%22%3A%7B%22filtered%22%3A%7B%22filter%22%3A%7B%22bool%22%3A%7B%22must%22%3A%5B%7B%22term%22%3A%7B%22index.classification.exact%22%3A%22Biology%20(General)%22%7D%7D%5D%7D%7D%2C%22query%22%3A%7B%22match_all%22%3A%7B%7D%7D%7D%7D%2C%22sort%22%3A%5B%7B%22created_date%22%3A%7B%22order%22%3A%22desc%22%7D%7D%5D%7D");
System.out.println(page.asXml());
webClient.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
Most of the content of the web page are rendered by javascript started async. You have to wait a bit to get the content....
String url = "https://doaj.org/search?source=%7B%22query%22%3A%7B%22filtered%22%3A%7B%22filter%22%3A%7B%22bool%22%3A%7B%22must%22%3A%5B%7B%22term%22%3A%7B%22index.classification.exact%22%3A%22Biology%20(General)%22%7D%7D%5D%7D%7D%2C%22query%22%3A%7B%22match_all%22%3A%7B%7D%7D%7D%7D%2C%22sort%22%3A%5B%7B%22created_date%22%3A%7B%22order%22%3A%22desc%22%7D%7D%5D%7D";
try (final WebClient webClient = new WebClient(BrowserVersion.FIREFOX)) {
// js is enabled by default
webClient.waitForBackgroundJavaScriptStartingBefore(1_000);
HtmlPage page = webClient.getPage(url);
webClient.waitForBackgroundJavaScript(10_000);
System.out.println(page.asText());
}
Works here with version 2.42.0-SNAPSHOT but should work also with the 2.41.0 release.
My application is completely styled in a web document form (HTML, CSS & JavaScript), and I'm only using JavaFX WebView to load it as a normal resource.
I would like to invoke a method from one of my classes (a Java code) using JavaScript.
Like for example, a simple Hello World to the console:
public class Hello {
public void world() {
System.out.println("Hello World!");
}
}
How can I invoke the world() method in this case?
So my code from the page is something like this:
<!-- onlick action from a button calls hello() function -->
<button onclick="hello();" value="Invoke"></button>
<script>
function hello() {
/* CODE WHICH INVOKE A JAVA METHOD */
}
</script>
Any way to achieve this?
UPDATE
Notice: For those people who were looking for a complete and simple example about how to achieve this, you can test all the following codes written below.
I've finally achieved my goal, thanks to sir #Oshan_Mendis' answer. This example is based from this tutorial from Oracle docs: 6 Making Upcalls from JavaScript to JavaFX.
But here, I'll be using my own code, the main goal is to call a method from Java code using JavaScript from the HTML page.
File contents:
Controller.java /* Controller class for WebView */
Hello.java /* Class in which method(s) will be invoked */
Main.java /* Main class (launches the application) */
main.fxml /* Main layout (WebView) */
index.html /* Main layout web page content */
1. Creating the Main-Class (Main.java)
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage stage) throws Exception {
/* The root layout of the application, an FXML contains the WebView layout. */
Parent root = FXMLLoader.load(Main.class.getResource("/main.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
2. Preparing the Main layout (main.fxml)
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.web.WebView?>
<?import javafx.scene.layout.VBox?>
<VBox xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="Controller" <!-- The controller class for this layout -->
prefHeight="400.0"
prefWidth="300.0">
<children>
<!-- Given the webView ID to initiate the web page -->
<WebView fx:id="webView" />
</children>
</VBox>
3. Setting up the web page (Controller.java)
import java.net.URL;
import java.util.ResourceBundle;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker.State;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import netscape.javascript.JSObject;
public class Controller implements Initializable {
private WebEngine webEngine;
#FXML private WebView webView;
#Override
public void initialize(URL location, ResourceBundle resources) {
/* Load the web page URL (location of the resource) */
URL url = Controller.class.getResource("/index.html");
webEngine = webView.getEngine();
webEngine.load(url.toExternalForm());
/* Set the State listener as well as the name of the JavaScript object and its
* corresponding Java object (the class in which methods will be invoked) that
* will serve as the bridge for the two objects.
*/
webEngine.getLoadWorker().stateProperty().addListener(new ChangeListener<State>() {
#Override
public void changed(ObservableValue<? extends State> observableValue, State oldState, State newState) {
if (newState == State.SUCCEEDED) {
JSObject window = (JSObject) webEngine.executeScript("window");
/* The two objects are named using the setMember() method. */
window.setMember("invoke", new Hello());
}
}
});
}
}
4. Preferred class and its method to invoke (Hello.java)
public class Hello {
public void world() {
System.out.println("Hello World!");
}
}
5. Main layout web page content (index.html)
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script>
function helloWorld() {
/* JavaScript object name and the method to invoke */
invoke.world();
}
</script>
</head>
<body>
<!-- onlick event calls helloWorld() function -->
<button onclick="helloWorld()">INVOKE</button>
</body>
</html>
Note: You can perform other mouse-related events other than onclick event in this case like: onmouseenter, onmouseover, onmousemove, onmouseup, etc.. But I'm not really sure if these are the only supported events of invoking methods.
This is well explained in the Java API Documentation under Calling back to Java from JavaScript
public class JavaApplication {
public void exit() {
Platform.exit();
}
}
...
JavaApplication javaApp = new JavaApplication();
JSObject window = (JSObject) webEngine.executeScript("window");
window.setMember("app", javaApp);
You can then refer to the object and the method from your HTML page:
Click here to exit application
I am trying to show rewarded video ads in my app and every time i try and load the ad, it goes straight to the "failed to load ad" method.
For my phone i get the error:
W/Ads: Fail to instantiate adapter com.google.ads.mediation.chartboost.ChartboostAdapter
android.os.RemoteException
at com.google.android.gms.internal.zzgy.zzbx(Unknown Source)
at com.google.android.gms.internal.zzgy.zzbw(Unknown Source)
at com.google.android.gms.internal.zzgy.zzbu(Unknown Source)
at com.google.android.gms.internal.zzgz$zza.onTransact(Unknown Source)
at android.os.Binder.transact(Binder.java:387)
at com.google.android.gms.ads.internal.mediation.client.d.a(:com.google.android.gms.DynamiteModulesA:94)
at com.google.android.gms.ads.internal.reward.c.b(:com.google.android.gms.DynamiteModulesA:220)
at com.google.android.gms.ads.internal.reward.mediation.j.a(:com.google.android.gms.DynamiteModulesA:1140)
at com.google.android.gms.ads.internal.util.b.run(:com.google.android.gms.DynamiteModulesA:19)
at com.google.android.gms.ads.internal.util.y.call(:com.google.android.gms.DynamiteModulesA:1055)
at com.google.android.gms.ads.internal.util.z.run(:com.google.android.gms.DynamiteModulesA:75)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:423)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
For the emulator I am using, I get the error:
There was a problem getting an ad response. ErrorCode: 0
Also, I am assuming that the problem is not with admob as I have implemented banner ads with no problem. I am using chartboost as a meditaion.
import com.google.ads.mediation.admob.AdMobAdapter;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdView;
import com.google.android.gms.ads.MobileAds;
import com.google.android.gms.ads.reward.RewardItem;
import com.google.android.gms.ads.reward.RewardedVideoAd;
import com.google.android.gms.ads.reward.RewardedVideoAdListener;
import com.chartboost.sdk.Chartboost;
import com.chartboost.sdk.CBLocation;
import com.chartboost.sdk.ChartboostDelegate;
public class Settings extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener, RewardedVideoAdListener {
SharedPreferences data;
final String filename = "Data";
Button btnAds;
Button btnResetData;
Button btnHelp;
long adtime;
private RewardedVideoAd mAd;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Chartboost.startWithAppId(this, "I have insterted my app id here", "and my app signature here");
Chartboost.onCreate(this);
setContentView(R.layout.activity_settings);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
btnAds = (Button) findViewById(R.id.btnAds);
btnResetData = (Button) findViewById(R.id.btnResetData);
btnHelp = (Button) findViewById(R.id.btnHelp);
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
btnAds.setText("Loading ad...");
// Load an ad into the AdMob banner view.
AdView adView = (AdView) findViewById(R.id.adView);
AdRequest adRequest = new AdRequest.Builder()
.setRequestAgent("android_studio:ad_template").build();
adView.loadAd(adRequest);
mAd = MobileAds.getRewardedVideoAdInstance(this);
mAd.setRewardedVideoAdListener(this);
loadRewardedVideoAd();
}
private void loadRewardedVideoAd() {
mAd.loadAd("I have inserted my app unit id here", new AdRequest.Builder().build());
}
}
I've also got the other "after reward" methods and "on back" methods after
It looks as though you are trying to initialize the Chartboost SDK alongside the AdMob mediation. This has been proven to be quite problematic in my own projects as the SDK and the SDK adapter do not play nice with each other.
You need to only use the AdMob methods to call Chartboost, trying to initialize separately will cause the Chartboost adapter to fail.
This IS a bit annoying given that AdMob only inits ad network SDKs as it calls them (which makes downloading assets an annoyance) but this is how AdMob is designed.
Omitting the Chartboost startwith methods and replacing them with the normal AdMob method to initialize the AdMob SDK should solve this issue.