信任锚不仅在设备上找到,而且在模拟器上运行?

Posted

技术标签:

【中文标题】信任锚不仅在设备上找到,而且在模拟器上运行?【英文标题】:Trust anchors not found only on device but running on emulator? 【发布时间】:2017-10-03 06:52:38 【问题描述】:

一切都在标题中,我不明白为什么我的代码在模拟器中有效,但在我的设备上无效。它抛出“未找到信任锚异常”!怎么可能?我尝试了关于 trustManager 的 okhttp.builder 的实现,但仍然......请帮助!!

这是我的课:

public abstract class NewsFragment extends Fragment 

    private static final String TAAG = NewsFragment.class.getSimpleName();
    protected ItemAdapter mArticleAdapter;
    protected RecyclerView mRecyclerView;
    protected NewsFragment.OnNewSelectedInterface mListener;
    protected ItemAdapter.OnNewsInsertedInterface mListener2;
    protected RecyclerView.LayoutManager mManager;
    protected SwipeRefreshLayout mSwipeRefreshLayout;

    public static final String KEY_LIST = "key_list";

    public interface OnNewSelectedInterface 
        void onListNewSelected(int index, ArrayList<Article> articles);
    

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) 

        setHasOptionsMenu(true);

        View view = inflater.inflate(R.layout.list_present_news, container, false);

        mListener = (NewsFragment.OnNewSelectedInterface) getActivity();
        mListener2 = (ItemAdapter.OnNewsInsertedInterface) getActivity();
        mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipeContainer);
        mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerview);
        mManager = new LinearLayoutManager(getActivity());
        mArticleAdapter = new ItemAdapter(getActivity(), new ArrayList<>(), mListener, mListener2);

        if (!isNetworkAvailable()) alertUserAboutError();

        mRecyclerView.setAdapter(mArticleAdapter);
        mRecyclerView.setLayoutManager(mManager);

        mSwipeRefreshLayout.setRefreshing(true);
        new Downloader().execute(getUrl());
        //new Downloader().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, getUrl());

        refreshData();

        setDividerRecyclerView();

        return view;
    

    private void setDividerRecyclerView() 
        DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView
                .getContext(), DividerItemDecoration.VERTICAL);
        mRecyclerView.addItemDecoration(dividerItemDecoration);
    

    private void alertUserAboutError() 
        AlertDialogFragment alertDialogFragment = new AlertDialogFragment();
        alertDialogFragment.show(getActivity().getFragmentManager(), "error_dialog");
    

    protected abstract String[] getUrl();

    private boolean isNetworkAvailable() 
        ConnectivityManager manager = (ConnectivityManager)
                getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = manager.getActiveNetworkInfo();
        boolean isAvailable = false;
        if (networkInfo != null && networkInfo.isConnected()) 
            isAvailable = true;
        
        return isAvailable;
    

    private void refreshData() 
        mSwipeRefreshLayout.setOnRefreshListener(() -> 
            mArticleAdapter.clear();
            new Downloader().execute(getUrl());
        );

        mSwipeRefreshLayout.setColorSchemeResources(
                android.R.color.holo_orange_light,
                android.R.color.holo_red_light);
    

    private class Downloader extends AsyncTask<String, Void, ArrayList<Article>> 

        ArrayList<Article> mArticleArrayList = new ArrayList<>();
            OkHttpClient mClient = new OkHttpClient();


        @Override
        protected ArrayList<Article> doInBackground(String... strings) 

            for (String aMUrl : getUrl()) 
                Request mRequest = new Request.Builder().url(aMUrl).build();
                try 
                    Response response = mClient.newCall(mRequest).execute();
                    try 
                        if (response.isSuccessful()) 
                            String json = response.body().string();
                            mArticleArrayList = getMultipleUrls(json);
                        
                     catch (IOException | JSONException e) 
                        e.printStackTrace();
                    
                 catch (IOException e) 
                    e.printStackTrace();
                
            
            return mArticleArrayList;
        

        @Override
        protected void onPostExecute(ArrayList<Article> articles) 
            mArticleAdapter.addAll(articles);
            mSwipeRefreshLayout.setRefreshing(false);
            Log.v(TAAG, String.valueOf(mArticleAdapter.getItemCount()));
        

        private ArrayList<Article> getMultipleUrls(String jsonData) throws JSONException 

            if (mArticleArrayList == null || mArticleArrayList.size() == 0) 
                mArticleArrayList = getArticleForecast(jsonData);
             else 
                mArticleArrayList.addAll(getArticleForecast(jsonData));
            

            return mArticleArrayList;
        

        private ArrayList<Article> getArticleForecast(String jsonData) throws JSONException 
            JSONObject forecast = new JSONObject(jsonData);
            JSONArray articles = forecast.getJSONArray("articles");

            ArrayList<Article> listArticles = new ArrayList<>(articles.length());

            for (int i = 0; i < articles.length(); i++) 
                JSONObject jsonArticle = articles.getJSONObject(i);
                Article article = new Article();

                String urlImage = jsonArticle.getString("urlToImage");

                article.setTitle(jsonArticle.getString("title"));
                article.setDescription(jsonArticle.getString("description"));
                article.setImageView(urlImage);
                article.setArticleUrl(jsonArticle.getString("url"));
                article.setUrlToImage(jsonArticle.getString("urlToImage"));

                listArticles.add(i, article);
            

            return listArticles;
        
    

这是日志:

05-04 23:39:01.382 9856-9997/com.silho.ideo.knewsproject W/System.err: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
05-04 23:39:01.382 9856-9997/com.silho.ideo.knewsproject W/System.err:     at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:306)
05-04 23:39:01.382 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:242)
05-04 23:39:01.382 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:200)
05-04 23:39:01.382 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.connection.RealConnection.buildConnection(RealConnection.java:174)
05-04 23:39:01.382 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:114)
05-04 23:39:01.382 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:196)
05-04 23:39:01.382 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:132)
05-04 23:39:01.382 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:101)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:120)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:179)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.RealCall.execute(RealCall.java:63)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at com.silho.ideo.knewsproject.Fragments.PresentNews.NewsFragment$Downloader.doInBackground(NewsFragment.java:170)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at com.silho.ideo.knewsproject.Fragments.PresentNews.NewsFragment$Downloader.doInBackground(NewsFragment.java:143)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at android.os.AsyncTask$2.call(AsyncTask.java:288)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at java.util.concurrent.FutureTask.run(FutureTask.java:237)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at java.lang.Thread.run(Thread.java:818)

我也在 okhttp 网站上找到了这个,但它也不起作用:

public OkHttpClient.Builder sslSocketFactory(SSLSocketFactory sslSocketFactory, X509TrustManager 信任管理器) 设置用于保护 HTTPS 连接的套接字工厂和信任管理器。如果未设置,将使用系统默认值。 大多数应用程序不应调用此方法,而是使用系统默认值。这些类包括特殊的优化,如果实现被修饰,这些优化可能会丢失。

如有必要,您可以使用以下代码自行创建和配置默认值:

TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
       TrustManagerFactory.getDefaultAlgorithm());
   trustManagerFactory.init((KeyStore) null);
   TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
   if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) 
     throw new IllegalStateException("Unexpected default trust managers:"
         + Arrays.toString(trustManagers));
   
   X509TrustManager trustManager = (X509TrustManager) trustManagers[0];

   SSLContext sslContext = SSLContext.getInstance("TLS");
   sslContext.init(null, new TrustManager[]  trustManager , null);
   SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

   OkHttpClient client = new OkHttpClient.Builder()
       .sslSocketFactory(sslSocketFactory, trustManager);
       .build();

【问题讨论】:

【参考方案1】:

我的 android 应用程序(以及我的 Spring Boot 后端服务器)也有类似的问题。我认为您的问题与您使用的是自签名证书有关。解决方案是在应用的 assets 文件夹中嵌入一个包含受信任证书的信任管理器(PKCS12 格式)。

1.在资产文件夹中添加您的密钥库和证书:

2. 然后以这种方式使用您的嵌入式信任管理器配置 OkHttpClient: (用你的密码修改)

fun getOkHttpClient(context: Context): OkHttpClient 

val password = "keystore_password".toCharArray()

val keyStore = KeyStore
    .getInstance("PKCS12").apply 
        load(context.assets.open("trust_store.p12"), password)
    

val trustManagerFactory = TrustManagerFactory
    .getInstance(TrustManagerFactory.getDefaultAlgorithm())
    .apply  init(keyStore) 

val keyManagerFactory = KeyManagerFactory
    .getInstance(KeyManagerFactory.getDefaultAlgorithm())
    .apply  init(keyStore, password) 

val sslContext = SSLContext.getInstance("SSL")
    .apply 
        init(keyManagerFactory.keyManagers, trustManagerFactory.trustManagers, SecureRandom())
    

return OkHttpClient.Builder()
    .sslSocketFactory(sslContext.socketFactory,
        trustManagerFactory.trustManagers[0] as X509TrustManager)
    .hostnameVerifier  hostname, _ -> hostname == apiHostname  // Return true if you want to trust all hostnames
    .build()


如果您想信任所有主机名,只需在 hostnameVerifier 功能块中返回 true,但我不建议您这样做,因为它会使您的应用面临安全威胁。

请注意,使用自定义信任库时,您的应用将仅信任该信任库中包含的证书。

【讨论】:

以上是关于信任锚不仅在设备上找到,而且在模拟器上运行?的主要内容,如果未能解决你的问题,请参考以下文章

iPad应用程序仅在设备上而不是在模拟器中加载笔尖时崩溃

在设备上运行但适用于模拟器时的 iOS 配置文件问题

通过 DDMS 在 Android 设备上模拟模拟位置

无法找到最新的可用模拟器运行时 - 在 iOS 上构建 RN 应用程序时出现 Image.xcassets

视图创建时浮动操作按钮锚点更改

NSFileManager 在模拟器上运行良好,但在设备上运行良好