Open page in WebView by clicking on an external link - java

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

Related

Wrong activity displayed when implicit intent received from another app with Action.SEND

I have an app with two activities: MainActivity, which contains a URL entry field where the user can enter a YouTube video URL and press a submit button, to start the second activity, VideoActivity, which displays some information about this video (fetched from another web server).
The app also has a feature to receive intent via the Youtube application. When user presses the share button within the Youtube app, my app appears in the share list. Upon pressing share from the Youtube app, MainActivity should be brought to the front, and the URL should be posted within the MainActivity's URL field.
However, this only happens correctly on the first share. If the app is in the background when user shares from Youtube app, they are taken to whatever the last visible activity was, whether it is MainActivity or VideoActivity, (and even if it is MainActivity, the URL is not posted into the URL field, but the field is left in whatever state it was in when the app was last visible).
Here is my current AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.youcmt.youdmcapp">
<uses-permission android:name="android.permission.INTERNET"/>
<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"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
</activity>
<activity
android:name=".VideoActivity"
android:parentActivityName=".MainActivity"/>
<service
android:name=".FetchVideoService"
android:exported="false"/>
</application>
</manifest>
Here is my MainActivity.java code:
public class MainActivity extends AppCompatActivity {
private ResponseReceiver mReceiver;
private EditText mUrlEditText;
private Button mSearchButton;
private ProgressBar mProgressBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_main);
super.onCreate(savedInstanceState);
mUrlEditText = findViewById(R.id.url_search_et);
Intent intent = getIntent();
if (intent.getType()!=null &&
intent.getType().equals("text/plain")) {
Bundle extras = getIntent().getExtras();
String value = extras.getString(Intent.EXTRA_TEXT);
if(value!=null)
{
mUrlEditText.setText(value);
}
}
mProgressBar = findViewById(R.id.progress_bar);
mSearchButton = findViewById(R.id.search_button);
mSearchButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
try {
askForVideo(mUrlEditText.getText().toString());
mSearchButton.setVisibility(View.INVISIBLE);
mProgressBar.setVisibility(View.VISIBLE);
} catch (Exception e) {
mUrlEditText.setText("");
mUrlEditText.setHint(e.getMessage());
e.printStackTrace();
}
}
});
}
#Override
protected void onResume() {
super.onResume();
//register the ResponseReceiver
mReceiver = new ResponseReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(FETCH_VIDEO_INFO);
registerReceiver(mReceiver, intentFilter);
}
private void askForVideo (String url) throws Exception {
try {
Intent intent = FetchVideoService.newIntent(this, url);
startService(intent);
} catch (Exception e) {
mUrlEditText.setText(e.getMessage());
}
}
public class ResponseReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
int status = intent.getIntExtra(EXTRA_VIDEO_STATUS, FAIL);
mProgressBar.setVisibility(View.INVISIBLE);
mSearchButton.setVisibility(View.VISIBLE);
if(status==FAIL)
{
mUrlEditText.setText("");
mUrlEditText.setHint("Error retrieving video!");
}
else if(status==SUCCESS) {
Video video = intent.getParcelableExtra(EXTRA_VIDEO);
Intent videoActivityIntent =
VideoActivity.newIntent(getApplicationContext(), video);
startActivity(videoActivityIntent);
}
}
}
#Override
protected void onPause() {
unregisterReceiver(mReceiver);
super.onPause();
}
}
I do not think any of the other files will be useful in understanding the problem. Although this seems like something many app creators should have to deal with, I can find no answers to this problem. Please comment if you feel I should add any additional information and thank you in advance for any help!
Update: testing demonstrates that after the first use of "Share" from YouTube (and considering app remains in the background), the MainActivity no longer receives any new intent on further shares. However, my app is still brought to the foreground somehow. This is very confusing to me.
When you share from another app, your MainActivity is brought to the front and onNewIntent() is called on it. You don't override onNewIntent() so you never see the share Intent.

How to direct user to its specific activity?

I am building an app in which when the user first installs it, In the MainActivity(Launcher Activity) the app asks what type of user he is(Let's say Driver or Rider)? Based on the user selection he is directed to the corresponding login screen. After the user is logged in he directed to HomeActivity. If he closes the app without logging out, next time he opens the app he should directly see the HomeActivity(based on what usertype he selected). For one user the code in the MainActivity would be like:
#Override
protected void onStart() {
super.onStart();
// Check if user is signed in (non-null) and update UI accordingly.
FirebaseAuth mAuth = FirebaseAuth.getInstance();
FirebaseUser currentUser = mAuth.getCurrentUser();
if (currentUser != null) {
sendToStart();
}
}
private void sendToStart() {
Intent startIntent = new Intent(MainActivity.this,DriverHomeActivity.class);
startActivity(startIntent);
finish();
}
I am new to Android and Firebase. I don't how this should be done for two types users.
Create one login screen, in that screen the user can choose work type(two buttons or radio buttons).
If he chooses Driver, then create a Driver node in the database with the information he wrote and direct him to the home activity:
FirebaseUser user=FirebaseAuth.getInstance().getCurrentUser();
DatabaseReference ref=FirebaseDatabase.getInstance().getReference().child("Drivers").child(user.getUid());
ref.child("name").setValue(name);
Intent startIntent = new Intent(MainActivity.this,DriverHomeActivity.class);
startActivity(startIntent);
finish();
Also do the same for Rider.
If the user, closes the app without logging out. In the first activity that should open (ex: splash activity), check if there is a current user and check type of user:
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
DatabaseReference driver = FirebaseDatabase.getInstance().getReference().child("Drivers");
DatabaseReference rider = FirebaseDatabase.getInstance().getReference().child("Riders");
if (user != null) {
driver.child(user.getUid()).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
Intent i = new Intent(SplashActivity.this, DriverHomeActivity.class);
startActivity(i);
finish();
} else {
Intent intent = new Intent(SplashActivity.this, RiderHomeActivity.class);
startActivity(intent);
finish();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Here in the splash activity, it will check if there is a current user(if user is logged in) user.getUid() will return the current userid and then it will check if this userid is under the Drivers node, and then it directs him to the driver's home activity.
Your issue can be solved by the usage of SharedPreference mechanism.
Here you can keep the login status in SharedPreference like below:-.
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences();
prefs.edit().putBoolean("login", true).commit();
when the user won't logged out and coming back, you should check the login status in splash screen using the SharedPreference variable and moved the user to corresponding activity.
Boolean loginStatus = prefs.getBoolean("login", false);
if (loginStatus) {
// Move to Home activity
} else {
//Move to login screen
}
Little bit documentation here
You might consider keeping a LauncherActivity in your android application which will decide which activity to launch further. A sample LauncherActivity might look like the following.
public class LauncherActivity extends AppCompatActivity {
private boolean loggedIn = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
boolean isLoggedInAsDriver = getSharedPreferences.getBoolean("is_driver", false);
startApplication(isLoggedInAsDriver);
finish();
}
private void startApplication(boolean isLoggedInAsDriver) {
Intent intent;
if (isLoggedInAsDriver) {
intent = new Intent(LauncherActivity.this, DriverActivity.class);
startActivity(intent);
finish();
} else {
intent = new Intent(LauncherActivity.this, RiderActivity.class);
startActivity(intent);
finish();
}
}
}
Your application can have only one launcher, so mark the LauncherActivity as the launcher of your android application in the AndroidManifest.xml like the following.
<activity
android:name=".LauncherActivity"
android:label="Your app name"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Now you may have noticed that I have used a flag (i.e. isLoggedInAsDriver) to start the desired activity from the LauncherActivity. This is a preference data that you need to store in your SharedPreferences when you can determine if the user is a driver or rider. Then each time your application launches via your LauncherActivity, check the stored value and get the user type. Based on the user type, launch the second activity.
use this code in manifest
and also
you should save user type with user ID in database and at start app check this first and then show home page.
<activity android:name=".MainActivity/>
<activity android:name=".DriverHomeActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

Download instead of load url in WebView when url contains x

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

How to open Urls in the phone and get my app as choice with other browsers?

I already have a web view activity but I don't know how to add it to the other browsers as option to handle the url? like on the picture below. I was searching already here but I did not manage to find any answer which would help me. Thanks
add url schemes as intent filters to your activity in manifest.
for example to handle http://yoursite.com/path/etc... use this:
<activity
android:name="com.app.BrowserActivity" >
<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="yoursite.com"
android:pathPattern="/path/..*"
android:scheme="http" />
</intent-filter>
</activity>
and in your activity get url:
// get url
final Intent intent = getIntent();
String url = intent.getDataString();
Use the code when you want to open url with a web browser as follow:
Intent browserIntent = new Intent(Intent.ACTION_VIEW,Uri.parse("http://www.google.com"));
startActivity(browserIntent);
If you want to open the link of your WebView, you need to implement the WebViewClient code as follow:
WebView webView = (WebView) findViewById(R.id.webView);
webView.setWebViewClient(new MyWebViewClient());
String url = "http://javatechig.com";
webView.getSettings().setJavaScriptEnabled(true);
webView.loadUrl(url);
implement the WebViewClient
private class MyWebViewClient extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// use the url to open other web browser
Intent browserIntent = new Intent(Intent.ACTION_VIEW,Uri.parse(url));
startActivity(browserIntent);
// don't load the url by your webview
//view.loadUrl(url);
return true;
}
}

Killing the activity when user clicks the home button

Okey, this is weird.
I have two activities (well, more than two, but they don't matter) - AppActivity and PopupActivity. AppActivity is my main application activity and it contains my app's settings. PopupActivity is a dialog that gets opened when user clicks the button in the notification (it's a RemoteViews notification). Well, it works. Works great. But only if user closed the AppActivity by clicking the back button. If they clicked home, PopupActivity opens after a few seconds after clicking the button. Same thing happens when user closes the PopupActivity with a home button. Clicking the button in the notification doesn't open the PopupActivity instantly, but it takes a few seconds to kill the previous activity that still exists somewhere in the background.
I've tried calling finish() in the onStop and onPause methods, but it doesn't fix my problem.
Edit: Here's the code I have:
Manifest:
<activity
android:name="cc.lupine.quicksocial.AppActivity"
android:label="#string/app_name"
android:configChanges="orientation|screenSize" android:noHistory="true" android:clearTaskOnLaunch="true" android:finishOnTaskLaunch="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:configChanges="orientation|screenSize"
android:excludeFromRecents="true"
android:showOnLockScreen="false"
android:theme="#android:style/Theme.Holo.Light.Dialog.NoActionBar.MinWidth"
android:name="cc.lupine.quicksocial.PopupActivity"
android:noHistory="true"
android:launchMode="singleInstance"
android:taskAffinity=""
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<service android:name="cc.lupine.quicksocial.ShareService"></service>
ShareService.java (just a function that gets called when user clicks a button in the notification):
public static void startSharing(Context ctx, int n) {
Log.d("sn", "startsharing called in shareservice");
if(n == 1 || n == 2)
{
Intent i = new Intent(ThisApplication.getAppContext(), PopupActivity.class);
i.putExtra("shareType", n);
i.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY|
Intent.FLAG_ACTIVITY_CLEAR_TOP|
Intent.FLAG_ACTIVITY_SINGLE_TOP|
Intent.FLAG_ACTIVITY_CLEAR_TASK|
Intent.FLAG_FROM_BACKGROUND|
Intent.FLAG_ACTIVITY_NEW_TASK);
ctx.startActivity(i);
} else if(n == 3) {
// doesn't matter for now
}
}
PopupActivity.java (fragments):
public class PopupActivity extends Activity implements OnDataPass {
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.d("sn", "oncreate called in popupactivity");
super.onCreate(savedInstanceState);
instanceOfPopupActivity = this;
setContentView(R.layout.activity_popup);
ShareFragment sfrag = new ShareFragment();
Bundle args = new Bundle();
Bundle extras = getIntent().getExtras();
try {
//doesn't matter
} catch(Exception e) { e.printStackTrace(); finish(); }
sfrag.setArguments(args);
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.contFragment, sfrag);
fragmentTransaction.commit();
}
#Override
public void onPause()
{
Log.d("sn", "onpause called in popupactivity");
finish();
super.onPause();
}
#Override
public void onStop() {
Log.d("sn", "onstop called in popupactivity");
super.onStop();
}
#Override
public void onDestroy()
{
Log.d("sn", "ondestroy called in popupactivity");
super.onDestroy();
}
}
And if I open the popup for the first time:
05-26 14:37:14.149: D/sn(7218): startsharing called in shareservice
05-26 14:37:14.179: D/sn(7218): oncreate called in popupactivity
But when I close the popup with a home button and try to open it again:
05-26 14:38:11.620: D/sn(7218): startsharing called in shareservice
05-26 14:38:14.103: D/sn(7218): oncreate called in popupactivity
It takes a lot of time for onCreate to be called. And now, what's the reason?
I think you are focusing on the wrong problem (killing the activity) instead of focusing on the real problem (10 seconds to start it again).
First you need to understand WHY it is taking 10 seconds to open it if you exited the other acitivty with the home key!
If you posted more details (with source code) it would have been easier to understand and help you!
call finish() when you want to close app. Call finish() on both activities and watch out popup window has to be focusable to handle click.

Categories

Resources