Android WebView and network-security-configuration - android

I'm developing on Android 8 (26 API, Oreo) and I use android.webkit.WebView in my app.
I would implement "secure network connection" when I load pages with my WebView (in other words I would avoid man-in-the-middle problems and self-signed certificates)
To do this I used network security configuration (on Android from version 7.0 N, 24 API)
So:
In res>xml>network_security_config.xml
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config>
<domain includeSubdomains="true">MY_DOMAIN.com</domain>
<pin-set>
<pin digest="SHA-256">MY_PIN</pin>
</pin-set>
</domain-config>
</network-security-config>
I found MY_PIN inserting MY_DOMAIN.com here: https://report-uri.com/home/pkp_hash
In manifest>AndoridManifest.xml
...
<application
android:networkSecurityConfig="#xml/network_security_config"
...
</application>
In the onCreate of my app I simply do:
WebView webView = new WebView(this);
webView.setWebViewClient(new WebViewClient() {
#Override
public void onReceivedSslError(..)..
#Override
public void onPageFinished()..
...});
webView.loadUrl(MY_DOMAIN.com);
According to Android docs I'm doing it right but I have a problem: it's like network_security_config.xml is never checked because I can set every "random" and "wrong" value for the pin and it works normally (URL MY_DOMAIN.com is loaded normally without blocking behavior).
So that means that if some man-in-the-middle return back one different pin of those I've written in res>xml>network_security_config.xml the application continue running well and with no secure behavior.
It also does not execute one of the overridden error method of WebViewClient.
Please help I can not understand my error.

[SOLVED]
In AndoridManifest.xml I declared
<application
android:networkSecurityConfig="#xml/network_security_config"
...
</application>
Editor warned about a problem related to the SDK version but I didn't see it.
This is the warning.
[SOLUTION]
Add this tools:targetApi="n" to the Manifest like the following:
<application
android:networkSecurityConfig="#xml/network_security_config"
...
tools:targetApi="n">
[EDIT]
SSL error is handled in public void onReceivedSslError(...) of WebViewClient (See the following code)
webView.setWebViewClient(new WebViewClient() {
public void onReceivedSslError(WebView view,
final SslErrorHandler handler, SslError error) {
//HANDLE HERE THE ERROR!!!
...
}
...
});

Related

Android webview is not working in latest android version

I know that this question is ask many times in stackoverflow, but their solution is didnt work for me. Thats why I am asking this question.
Now the question is that I am developing an app by android webview, now this app is working perfect in older version of android version but didnt working in latest android version i.e. 9
I tried many things from other solution like
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setLoadWithOverviewMode(true);
webView.getSettings().setUseWideViewPort(true);
added this code in onCreate method but didnt work.
Another I try is add the #xml/network-security-config file but this also didnt work.
Here is my network-security-config code
<?xml version ="1.0" encoding ="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain>onlineawaz.in</domain>
</domain-config>
</network-security-config>
public class MainActivity extends AppCompatActivity {
WebView webView;
ProgressBar bar;
#SuppressLint("NewApi")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = (WebView) findViewById(R.id.webView2);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setLoadWithOverviewMode(true);
webView.getSettings().setUseWideViewPort(true);
bar =(ProgressBar) findViewById(R.id.progressBar2);
webView.loadUrl("http://onlineawaz.in/");
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new myWebClient());
}
public class myWebClient extends WebViewClient{
//page event
}
}
Try adding below code in the AndroidManifest.xml under application tag
android:usesCleartextTraffic="true"
tools:ignore="UnusedAttribute"
First-line will allow you to use HTTP URLs(Not recommended in Pie). The second line is used to ignore the warning for SDK less than 23.

NLog log file on Xamarin - Android issues

I have been trying to use NLog from android, and it works whilst using a console based output. However when i try to target an external storage area/file nothing happens....there is no log file created...
My manifest contains the following lines:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
My Nlog.config
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd"
autoReload="true"
throwExceptions="false"
internalLogLevel="Off" internalLogFile="c:\temp\nlog-internal.log">
<targets>
<target name="logfile" xsi:type="File" fileName="storage\emulated\0\Download\log.txt" />
</targets>
<rules>
<!-- add your logging rules here -->
<logger name="*" minlevel="Error" writeTo="logfile" />
</rules>
</nlog>
My activity MainActivity.cs :
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Logger sm_logger = LogManager.GetCurrentClassLogger();
sm_logger.Debug("test output");
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
}
All of this code runs, no errors seem to be thrown, however no file is created either...using the console logger does infact output to the console however... Any help would be appreciated.
Note:
Im using both the emulator and a device, neither have a log file created.
Im building for android 7.1 level 25 of api.
The NLog.config file is bundled as a androidasset, and seems to load as it can find the targets etc
It is not enough to have
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
you also need to request the persmission with something like
ActivityCompat.RequestPermissions(Adapter.Activity, new String[] { Manifest.Permission.WriteExternalStorage }, 1234);
(which is incomplete, you also need to handle the permission result, but there are good resources out there on how to do that).
This needs to happen before the NLog FileTarget is created.

Glide not loading real image and stuck with placeholder

I have a pretty basic load image from server line code:
Glide.with(view.getContext()).load(url).placeholder(R.drawable.default_profile).into(view);
For some reason, I'm always stuck with the placeholder being displayed and never the real image!
I have made sure that a valid and working url is being passed. And, if I use the same code without the placeholder it works fine
Glide.with(view.getContext()).load(url).into(view);
Any ideas why?
Try to add .dontAnimate()
It caused by TransitionDrawable too and it seems so because after scroll there's no animation because it's cached.
The correct code is
Glide.with(view.getContext()).load(url).placeholder(R.drawable.default_profile).dontAnimate().into(view);
I hope it will be helpful for you.
Check if you have added Internet permission in the manifest:
<uses-permission android:name="android.permission.INTERNET"/>
Glide does not fire exception if there is no Internet connectivity.
Add android:usesCleartextTraffic="true" in the application tag in manifest and check the internet permission is mentioned or not in the same manifest file:-
Add this permission below to access resource endpoint/url
<uses-permission android:name="android.permission.INTERNET"/>
If your target endpoint/url only has http add this code below in your manifest.xml. Starting with Android 9 (API level 28), cleartext support is disabled by default.
android:usesCleartextTraffic="true"
Because of that, if you get resource from your unencrypted HTTP API don't forget to add
res/xml/network_security_config.xml
So the code will be like these
network_security_config.xml
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">urweb.id</domain>
<domain includeSubdomains="true">localhost</domain>
...
<domain includeSubdomains="true">111.222.333.444</domain>
</domain-config>
</network-security-config>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
<uses-permission android:name="android.permission.INTERNET"/>
<application
...
android:usesCleartextTraffic="true"
...>
<activity>
...
</activity>
</application>
</manifest>
Use ProgressBar as loading gif
Glide.with(context).
load(url)
.listener(new RequestListener<String, GlideDrawable>() {
#Override
public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
progressBar.setVisibility(View.GONE);
return false;
}
#Override
public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
progressBar.setVisibility(View.GONE);
return false;
}
})
.crossFade(1000)
.into(imageView);
If someone comes across this in the future you may need to add
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
Unsure of the exact reason for this change, nonetheless my code didn't work without that permission, and now does with it.
Below is a weird fix that worked for me.
The following always fails for me (12 trials) - I never see the real image:
Glide.with(context)
.load(url)
.asBitmap()
.into(new SimpleTarget<Bitmap>(iconWidth, iconHeight) { ... }
The following always succeeds for me (12 trials) - I always see the real image:
Glide.with(context)
.load(url)
.asBitmap()
.listener(new RequestListener() {
public boolean onException(Exception e,Object o,Target t,boolean b)
{return false;}
public boolean onResourceReady(Object o,Object p,Target t,boolean b,boolean c)
{return false;}})
.into(new SimpleTarget<Bitmap>(iconWidth, iconHeight) { ... }
As you can see, the only difference here is that I added a listener. Makes little sense, but these trials were done pretty carefully, so I'm going with it.
None of the solutions above worked for me. The issue may be at the placeholder you're using. If the view you're using to load the image has a placeholder, it causes some issues. Removing that placeholder for some reason seems to fix it.
So, if the (Image)View you're trying to inflate has a placeholder, such as android:src="#mipmap/placeholder", remove it.
<ImageView
android:id="#+id/imgGallery"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:src="#mipmap/rugova1" />
like this
<ImageView
android:id="#+id/imgGallery"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
/>
It worked for me.
If you are tried following steps :
INTERNET permission is already added both in Manifest and Programmatically
usesCleartextTraffic : if already mentioned in Manifest
Even though image is not loading in ImageView
Then try this :
add this line application tag of Manifest
android:usesCleartextTraffic="true"
add following code in the activity or fragment at top in which you are trying to perform the operation
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
Seems strange but only thing I could guess is Your URL is valid as You already said. Your remote is getting downloaded even getting applied on your image view but your placeholder is somehow hiding it.
Glide has some bugs related to placeholder stuff.
My suggestion would be to try below:
Glide.with(view.getContext()).load(url).
placeholder(R.drawable.default_profile).fitCenter().into(view);
So the trick is placeholder is set via setImageDrawable() so the ImageView will just display it as usual, but you tell Glide to use the fitCenter explicitly which will fit the loaded image nicely within the ImageView's laid out size via a Transformation and then set it via setImageDrawable(). Since the fitted image is a perfect fit, center will just draw the image covering the whole area of the view.
Give it a try.
Dont use transition or animation for Glide.It will solve your problem
Code :
Glide.with(context)
.load(horizontalHappyHourList.get(position).getImage())
// .transition(DrawableTransitionOptions.withCrossFade(400)) //Optional
.apply(RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.RESOURCE)
.error(R.drawable.no_image))
.into(holder.imageView);
May help someone :)
My issue was network security policy exception. The URL requested by Glide was blocked by android due to security policy.
Fixed by whitelisting desired domain. Check here
com.bumptech.glide.load.engine.GlideException: Failed to load resource
There was 1 cause:
java.net.UnknownServiceException(CLEARTEXT communication to maps.googleapis.com not permitted by the network security policy)
call GlideException#logRootCauses(String) for more detail
The toughest thing is it was not shown in the normal log.
Incase none of the above solves it, and you're setting the 'src' property on the ImageView, it won't work. I was mistakenly setting the 'src' on the ImageView in xml and taking that out solved it for me.
In my case, I had a problem with the layout_height attr that I set in xml
<ImageView
android:id="#+id/image_view_image"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:visibility="gone"
app:layout_constraintBottom_toTopOf="#id/linear_layout_content"
app:layout_constraintDimensionRatio="16:9"
app:layout_constraintLeft_toLeftOf="#id/linear_layout_content"
app:layout_constraintRight_toRightOf="#id/linear_layout_content"
app:layout_constraintTop_toTopOf="#id/linear_layout_content" />
Glide was giving a line of warning in the logcat which I don't remember what it was but it was suggesting to avoid using wrap_content for width and height.
So all I did was modify the layout to avoid using wrap_content and the problem was solved.
I tried to regenerate that problem to get the warning line after the problem was solved but I couldn't. It seems to be a cache problem in the library.
Make sure to check the url (link) as it may be a page link not an exact image address, try copying the link and paste it to the browser to see if it opens just image or a web page and if it opens a web page then no doubt that is the problem it is a page link and again not an image address.
Just uninstall app and reinstall it. It will work

I get "nextRation is null!" error trying to use Adwhirl + AdMob in Android

I've been trying to solve this problem for weeks. There are some other similar questions in StackOverflow, and there are some (apparently solved) similar issues in AdWhirl documentation website (one and two), but this error is still bothering me.
AdWhirl documentation is rather incomplete and confusing. The steps I've followed:
I created an AdMob account and I got the AdMob ID.
I created an AdWhirl account, I put there the AdMob ID and I got the AdWhirl ID.
I added in my Java Build Path the AdMob SDK Jar 4.3.1 and the AdWhirl SDK Jar 3.1.1
In my Manifest file I added the following lines:
.
<manifest>
[...]
<application>
[...]
<activity android:name="com.google.ads.AdActivity"
android:configChanges="orientation|keyboard|keyboardHidden|screenLayout|uiMode|screenSize|smallestScreenSize" />
<meta-data android:value="[AdWhirl ID]" android:name="ADWHIRL_KEY"/>
</application>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
</manifest>
In all the layouts I want ads I added the following lines:
.
<com.adwhirl.AdWhirlLayout
android:id="#+id/adwhirl_layout"
android:layout_width="fill_parent"
android:layout_height="72dip" />
In all the activities related to those layouts I added the following lines:
.
public class XXX extends ListActivity implements AdWhirlInterface {
[...]
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.YYY);
initAds();
[...]
}
[...]
private void initAds() {
AdWhirlManager.setConfigExpireTimeout(1000 * 60 * 5);
AdWhirlTargeting.setTestMode(false);
AdWhirlLayout adWhirlLayout = (AdWhirlLayout)findViewById(R.id.adwhirl_layout);
adWhirlLayout.setAdWhirlInterface(this);
}
public void adWhirlGeneric() {
Log.e(AdWhirlUtil.ADWHIRL, "In adWhirlGeneric()");
}
}
Project Build Target: Google API Android 4.0
Emulator: Google APIs 2.1 (API 7)
What am I doing wrong?
I see no ads and all the time I get the "nextRation is null!" error.
This looks like pretty much like the minimalistic AdWhirl implementation. FYI, you don't need the adWhirlGeneric() method.
There are a couple of reasons nextRation may be null.
The AdWhirl servers may have been down during the time you had this issue, or that you misconfigured some settings in the AdWhirl UI. These errors are unlikely.
AdWhirl tried to request an AdMob ad, and it failed for whatever reason (my money is on lack of inventory), and AdWhirl had no next ration, meaning there are no more ad networks to try to request an ad from (and it will try again on next refresh).
NOTE: A Ration in AdWhirl represents an ad network settings, like network name and it's corresponding network id.
Check the logcat output again, and see what leads up to the nextRation is null error. Is it a JSONException? If so, that means you have issue #1. Do the logs say you found an AdMob ration, then AdMob responded with onFailedToReceiveAd, and then you get nextRation is null? Then you have issue #2.
I had the same issue and found a solution following this post:
http://code.google.com/p/adwhirl/issues/detail?id=27
Hope it can help you too.

Unable to resolve activity for: Intent

I am having a problem in running Android unit test. I got this error when I tried to run a simple test.
Here's the log:
Blockquote
java.lang.RuntimeException: Unable to resolve activity for: Intent { act=android.intent.action.MAIN flg=0x10000000 cmp=com.wsandroid.Activities/.SplashActivity }
at android.app.Instrumentation.startActivitySync(Instrumentation.java:371)
at android.test.InstrumentationTestCase.launchActivityWithIntent(InstrumentationTestCase.java:120)
at android.test.InstrumentationTestCase.launchActivity(InstrumentationTestCase.java:98)
at android.test.ActivityInstrumentationTestCase2.getActivity(ActivityInstrumentationTestCase2.java:87)
at com.wsandroid.test.activity.TestEULA.setUp(TestEULA.java:15)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:169)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:154)
at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:430)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1447)
This error occurs for Android less than 2.2. It works fine for Android 2.2 emulator. Yet Android 2.2 emulator has a bug of sending a key twice even though we only press it one. Application to be tested runs on Android 2.2 platform.
Appreciate if anyone of you can help me.
Dzung.
This can also be cause by a missing
Make sure you have a corresponding entry in your manifest.
<activity android:name=".SplashActivity" ...
I had a similar problem with a simple test project for an app that was just a splash screen. I found that I had implemented the constructor wrong. My initial implementation of the constructor was this...
public SplashScreenTest(){
super("com.mycomp.myapp.SplashScreen", SplashScreen.class);
}
After some beating my head against the wall, I somehow decided to remove the SplashScreen from the pkg argument of super(). My successful implementation is now like this...
public SplashScreenTest() {
super("com.mycomp.myapp", SplashScreen.class);
}
I hope that this helps you or others solve the problem.
Try to check your Manifest.xml file:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tablet.test"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="#drawable/icon" android:label="#string/app_name">
<uses-library android:name="android.test.runner" />
</application>
<uses-sdk android:minSdkVersion="8" />
<!-- This line below! -->
<instrumentation android:targetPackage="com.tablet.tablet"
android:name="android.test.InstrumentationTestRunner" />
</manifest>
You need to check the following line:
<instrumentation android:targetPackage="com.tablet.tablet"
android:name="android.test.InstrumentationTestRunner" />
So the targetPackage must be the same as in your code.
I had specific similar problem while using the AndroidAnnotations lib.
Later, I found out it was due to forgetting to use the generated class (MyActivity_ instead of MyActivity).
In my case the problem was that TestFragmentActivity, meaning the Activity used in our test
extends ActivityInstrumentationTestCase2<TestFragmentActivity>
must be available in the package defined in Manifest.xml as targetPackage:
<instrumentation
android:name="android.test.InstrumentationTestRunner"
android:targetPackage="de.my.androidhd" />
My solution was to move TestFragmentActivity into tested application package.
For the keys being sent twice issue, are you sure you're not now getting both the Down and Up actions? I had this issue when using Robotium, and generated this to make things easier:
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.widget.EditText;
import com.jayway.android.robotium.solo.Solo;
public static void type(Solo robot, EditText edit, String text) {
int index = 0;
//Find the index of this control, as Robotium doesn't seem to like R.id
for (int i = 0; i < robot.getCurrentEditTexts().size(); i++) {
if (robot.getCurrentEditTexts().get(i).getId() == edit.getId()) {
index = i;
}
}
robot.clickOnEditText(index);
KeyCharacterMap map = KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD);
KeyEvent[] events = map.getEvents(text.toCharArray());
for (int event = 0; event < events.length; event++) {
if (events[event].getAction() == KeyEvent.ACTION_DOWN) {
robot.sendKey(events[event].getKeyCode());
}
}
}
I've had two activities with same name in different packages. Issue was about importing from the wrong package. I spend much time on it maybe it will save someone some time.

Categories

Resources