Picasso是否支持下载使用https协议的图片?

16

你好,我正在使用Picasso库从URL下载图片。

URL: https://fbcdn-profile-a.akamaihd.net/hprofile-ak-prn2/t1.0-1/s200x200/1472865_191408954385576_14109897_n.jpg

URL使用https协议,在使用Picasso下载使用https协议的图片时出现问题。

它不支持下载使用https协议的图片吗?只有在我使用http协议时才能正常工作?

我正在尝试获取使用https协议的位图。

com.squareup.picasso.Target target = new com.squareup.picasso.Target() {

@Override
public void onBitmapLoaded(Bitmap bitmap, LoadedFrom loadedFrom) {
    userProfile.setBitmap(bitmap);
    // call the Web API to register the walker here
    new AudioStreetAsyncTask(getActivity(), userProfile, getString(R.string.registration_processing_message), new TaskCompleteListener() {
        @Override
        public void onTaskCompleted(String jsonResponse) {
           Log.d(TAG, jsonResponse);
        }
    });
}

@Override
public void onBitmapFailed(Drawable drawable) {
    userProfile.setBitmap(null);
    // call the Web API to register the walker here
    new AudioStreetAsyncTask(getActivity(), userProfile, getString(R.string.registration_processing_message), new TaskCompleteListener() {
        @Override
        public void onTaskCompleted(String jsonResponse) {
           Log.d(TAG, jsonResponse);
        }
    }).execute();
}

@Override
public void onPrepareLoad(Drawable drawable) {}
};

Picasso.with(getActivity()).load(imgUrl.toString()).into(target);

有任何想法吗?


你能否请点赞并接受我的解决方案,因为它是最新的,而nexus700120提供的解决方案已经过时了。 - Hrishikesh Kadam
5个回答

36

在您的Gradle中使用这些依赖项:

compile 'com.squareup.okhttp:okhttp:2.2.0'
compile 'com.squareup.okhttp:okhttp-urlconnection:2.2.0'
compile 'com.squareup.picasso:picasso:2.4.0'

而这个类代替了原来的 Picasso

Picasso 类:

 public class PicassoTrustAll {

    private static Picasso mInstance = null;

    private PicassoTrustAll(Context context) {
        OkHttpClient client = new OkHttpClient();
        client.setHostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String s, SSLSession sslSession) {
                return true;
            }
        });
        TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
            @Override
            public void checkClientTrusted(
                    java.security.cert.X509Certificate[] x509Certificates,
                    String s) throws java.security.cert.CertificateException {
            }

            @Override
            public void checkServerTrusted(
                    java.security.cert.X509Certificate[] x509Certificates,
                    String s) throws java.security.cert.CertificateException {
            }

            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return new java.security.cert.X509Certificate[] {};
            }
        } };
        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            client.setSslSocketFactory(sc.getSocketFactory());
        } catch (Exception e) {
            e.printStackTrace();
        }

        mInstance = new Picasso.Builder(context)
                .downloader(new OkHttpDownloader(client))
                .listener(new Picasso.Listener() {
                    @Override
                    public void onImageLoadFailed(Picasso picasso, Uri uri, Exception exception) {
                        Log.e("PICASSO", exception);
                    }
                }).build();

    }

    public static Picasso getInstance(Context context) {
        if (mInstance == null) {
             new PicassoTrustAll(context);
        }
        return mInstance;
    }
}

使用示例:

PicassoTrustAll.getInstance(context)
                .load(url)
                .into(imageView);

它只与那些依赖关系很好地工作。https://dev59.com/UGAf5IYBdhLWcg3w31-O#28251889 - Sami Eltamawy
它在某些设备上运行良好,但并非所有设备都适用。例如Nexus4。 - user1517638
它像冠军一样工作。非常感谢您提供的解决方案。 - KishuDroid
5
你能否更新代码,使用okhttp3来完成?你现在不应该再使用之前的依赖库,因为这样会导致你的应用程序崩溃(java.util.NoSuchElementException)。Retrofit 2并不需要okhttp依赖库,如果你仍在使用它,就会混用依赖库,这是不好的。谢谢。 - crubio
完美的解决方案! - Krupa Kakkad
谢谢,你的解决方案帮了我大忙。但是由于我在项目中使用了Retrofit2,所以我不得不使用okhttp3并相应地更新了上面的解决方案。但是这种方法在我使用的最新Picasso版本(2.71828)上不起作用,我不得不将Picasso版本降级到2.4,就像你的解决方案一样!我们如何将此解决方案应用于使用okhttp3的Picasso 2.71828?@crubio也提到了这一点,我不知道他是否能找到兼容的依赖项。 - Reyhane Farshbaf

3

@nexus700120的解决方案已经过时。

@Neha Tyagi的解决方案有效,但会在每个活动实例中创建多个Picasso实例,导致内存泄漏。

因此,我设计了一个最新的单例解决方案来重定向图像URL -

CustomPicasso.java

import android.content.Context;
import android.util.Log;

import com.jakewharton.picasso.OkHttp3Downloader;
import com.squareup.picasso.Picasso;

/**
 * Created by Hrishikesh Kadam on 19/12/2017
 */

public class CustomPicasso {

    private static String LOG_TAG = CustomPicasso.class.getSimpleName();
    private static boolean hasCustomPicassoSingletonInstanceSet;

    public static Picasso with(Context context) {

        if (hasCustomPicassoSingletonInstanceSet)
            return Picasso.with(context);

        try {
            Picasso.setSingletonInstance(null);
        } catch (IllegalStateException e) {
            Log.w(LOG_TAG, "-> Default singleton instance already present" +
                    " so CustomPicasso singleton cannot be set. Use CustomPicasso.getNewInstance() now.");
            return Picasso.with(context);
        }

        Picasso picasso = new Picasso.Builder(context).
                downloader(new OkHttp3Downloader(context))
                .build();

        Picasso.setSingletonInstance(picasso);
        Log.w(LOG_TAG, "-> CustomPicasso singleton set to Picasso singleton." +
                " In case if you need Picasso singleton in future then use Picasso.Builder()");
        hasCustomPicassoSingletonInstanceSet = true;

        return picasso;
    }

    public static Picasso getNewInstance(Context context) {

        Log.w(LOG_TAG, "-> Do not forget to call customPicasso.shutdown()" +
                " to avoid memory leak");

        return new Picasso.Builder(context).
                downloader(new OkHttp3Downloader(context))
                .build();
    }
}

build.gradle (模块:app)

android {

    ...

}

dependencies {

    ...

    compile 'com.squareup.picasso:picasso:2.5.2'
    compile 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0'
}

用法 -

CustomPicasso.with(context)
    .load("http://i.imgur.com/DvpvklR.png")
    .into(imageView);

请查看 CustomPicasso gist 获取最新版本 - https://gist.github.com/hrishikesh-kadam/09cef31c736de088313f1a102f5ed3a3


1
我在我的应用程序中尝试了这个解决方案,但它不适用于 HTTPS 协议。请记住这就是问题所在。 - crubio
@crubio,您能告诉我您正在访问哪个URL吗? - Hrishikesh Kadam
@crubio,我的朋友,它正在工作。创建了一个播放应用程序,请拉取并让我知道如果它不起作用-https://github.com/hrishikesh-kadam/custom-picasso-play - Hrishikesh Kadam
最终它起作用了,我想我遇到了服务器缓存的问题。无论如何,我检测到了一个 hasCustomPicassoSingletonInstanceSet 的问题。它似乎使用原始的 Picasso,而我不希望这种情况发生。 - crubio
@crubio仍然遇到SSL握手错误,但multiestetica.com/img/img_et/avatar/i-avatar-15.jpg图片正常工作,请提出建议。 - RAHULRSANNIDHI
显示剩余4条评论

2
 final OkHttpClient client = new OkHttpClient.Builder()
                    .protocols(Collections.singletonList(Protocol.HTTP_1_1))
                    .build();

            Picasso picasso = new Picasso.Builder(mContext)
                    .downloader(new OkHttp3Downloader(client))
                    .build();
picasso .with(mContext).load(YOUR_URL).into(YOUR_IMAGEVIEW);

添加

compile 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0'

1
以下代码可以很好地处理这些依赖项:
implementation 'com.squareup.okhttp3:okhttp:3.0.1'
implementation 'com.squareup.picasso:picasso:2.71828'

首先,定义一个客户端来接受证书:

public class SelfSignCertHttpClient {
    public static OkHttpClient getSelfSignOkHttpClient(List<Interceptor> interceptors) {
        try {
            final TrustManager[] trustAllCerts = new TrustManager[] {
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return new java.security.cert.X509Certificate[]{};
                        }
                    }
            };

            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());

            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

            OkHttpClient.Builder builder = new OkHttpClient.Builder();
            builder.sslSocketFactory(sslSocketFactory, (X509TrustManager)trustAllCerts[0]);
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });

            for (Interceptor interceptor : interceptors) {
                builder.addInterceptor(interceptor);
            }

            OkHttpClient okHttpClient = builder.build();
            return okHttpClient;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

来源: https://futurestud.io/tutorials/retrofit-2-how-to-trust-unsafe-ssl-certificates-self-signed-expired

我还添加了在创建客户端时传递拦截器列表的选项。

然后,您可以定义一个PicasoTrustAll类:

public class PicassoTrustAll {

    private static Picasso mInstance = null;

    private PicassoTrustAll(Context context) {
        List<Interceptor> interceptors = new ArrayList<>();
        // Add any interceptors you wish (e.g Authorization Header interceptor)

        mInstance = new Picasso.Builder(context)
                .downloader(new OkHttp3Downloader(SelfSignCertHttpClient.getSelfSignOkHttpClient(interceptors)))
                .listener((picasso, uri, exception) -> Log.e("PICASSO", exception.getMessage())).build();

    }

    public static Picasso getInstance(Context context) {
        if (mInstance == null) {
            new PicassoTrustAll(context);
        }
        return mInstance;
    }
}

使用示例:

PicassoTrustAll.getInstance(this).load("https://10.0.2.2/path/to/picture").into(mainPictureView);

1

只需将此代码放入您的Application类中:

final OkHttpClient client = new OkHttpClient.Builder()
        .protocols(Collections.singletonList(Protocol.HTTP_1_1))
        .build();

final Picasso picasso = new Picasso.Builder(this)
        .downloader(new OkHttp3Downloader(client))
        .build();

Picasso.setSingletonInstance(picasso);

从这个链接检查它。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接