首页 > 编程技术 > android

Android开发中WebView与原生JS的数据交互详解

发布时间:2016-9-20 19:57

分本文来分享详细的在Android开发中,如何利用WebView与原生JS的数据交互,本教程附有代码和效果图,是一个不可多得的好教程。

关于WebView

我们知道目前android市场上的一些应用采用的开发方式大致分为三种:Native App、Web App、Hybrid App。本文主要是Hybrid App中实现的主要技术native组件与js的数据交互的理解以及实现。

Android API中提供了WebView组件来实现对html的渲染。所谓的HybridApp开发方式即是汇集了HTML5、CSS3、jS的相关开发技术,以及数据交换格式json/XML。这显然是Web开发工程师的技能。正是因为如此,众多中小企业选择了这种开发方式来减少对android开发工程师的过度依赖,至于这三种开发方式的比较与优劣不在本文考虑之列。

有了WebView这个组件,Android应用开发技术也就转嫁到html与java数据交互上来。说白了就是js与WebView的数据交互,这就是本文所要讨论的。


WebView与js的数据交互

1.        WebView中载入静态页面

 
将WebView添加到应用中。和原生控件一样,在layout引入WebView控件。代码片段如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/linearLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#000"
    android:orientation="horizontal" >
<WebView
    android:id="@+id/webview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    />
</LinearLayout>

载入页面:

 

webView = (WebView) findViewById(R.id.webview);
webView.loadUrl("file:///file:///android_asset/page.html");

page.html存储在工程文件的assets根目录下。

2.        引入jquery mobile

引入js框架让我们编写的html页面更接近于原生控件的显示效果。目前主流的移动应用js框架有:jquery mobile和sencha touch(jquery mobile与sencha touch的选型不在本文讨论范围)。本文选择使用jquery mobile。

 

首先,在webview添加对js的支持:

WebSettings setting = webView.getSettings();
setting.setJavaScriptEnabled(true);//支持js

增加对中文的支持:

WebSettings setting = webView.getSettings();
setting.setDefaultTextEncodingName("GBK");//设置字符编码

设置页面滚动条风格:

webView.setScrollBarStyle(0);//滚动条风格,为0指滚动条不占用空间,直接覆盖在网页上

jquery mobile提供的标准页面模板TemplateForJQuery.html:

<!DOCTYPE html>
<html>
    <head>
    <title>Page Title</title>
    
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <link rel="stylesheet" href="css/jquery.mobile-1.1.1.min.css" />
    <script" width=100% src="js/jquery.js"></script>
    <script" width=100% src="js/jquery.mobile-1.1.1.min.js"></script>
</head>
<body>

<div data-role="page">

    <div data-role="header">
        <h1>Page Title</h1>
    </div><!-- /header -->

    <div data-role="content">    
        <p>Page content goes here.</p>        
    </div><!-- /content -->

    <div data-role="footer">
        <h4>Page Footer</h4>
    </div><!-- /footer -->
</div><!-- /page -->

</body>
</html>

页面依赖的js库、css等均放在assets目录下,目录组织结构如下:



运行应用后的截图:


下面是button 的截图,与原生控件没什么明显区别,有种以假乱真的感觉:


3.        良好的用户体验

运行我们的应用发现,在拥有大量js的页面被载入时,一直处于等待中,这是很糟糕的用户体验。可以加入进度条解决。注意到webview提供的两个方法:setWebViewClient和setWebChromeClient。其中setWebChromeClient方法正是可以处理progress的加载,此外,还可以处理js对话框,在webview中显示icon图标等。对于处理progress的代码片段如下:

webView.setWebChromeClient(new WebChromeClient() {
    public void onProgressChanged(WebView view, int progress) {// 载入进度改变而触发
            if (progress == 100) {
                    handler.sendEmptyMessage(1);// 如果全部载入,隐藏进度对话框
            }
                super.onProgressChanged(view, progress);
        }
});

其中通过handler 消息机制来处理UI线程的更新:

 

        handler = new Handler() {
            public void handleMessage(Message msg) {// 定义一个Handler,用于处理下载线程与UI间通讯
                if (!Thread.currentThread().isInterrupted()){
                    switch (msg.what) {
                    case 0:
                        pd.show();// 显示进度对话框
                        break;
                    case 1:
                        pd.hide();// 隐藏进度对话框,不可使用dismiss()、cancel(),否则再次调用show()时,显示的对话框小圆圈不会动。
                        break;
                    }
                }
                super.handleMessage(msg);
            }
        };

对于setWebViewClient方法,一般用来处理html的加载(需要重载onPageStarted(WebView view, String url, Bitmap favicon))、关闭(需要重载onPageFinished(WebViewview, String url)方法)。

 

setWebViewClient和setWebChromeClient的作用:前者主要用于处理webView的控制问题,如加载、关闭、错误处理等;后者主要处理js对话框、图标、页面标题等。

4.        获取java中的数据

单独构建一个接口,作为处理js与java的数据交互的桥梁,本文封装的代码AndroidToastForJs.java如下:

public class AndroidToastForJs {
    
    private Context mContext;

public AndroidToastForJs(Context context){
        this.mContext = context;
    }
    
//webview中调用toast原生组件
public void showToast(String toast) {
        Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
    }
    
//webview中求和
public int sum(int a,int b){
        return a+b;
    }
    
 //以json实现webview与js之间的数据交互
public String jsontohtml(){
        JSONObject map;
        JSONArray array = new JSONArray();
        try {
            map = new JSONObject();
            map.put("name","aaron");
            map.put("age", 25);
            map.put("address", "中国上海");
            array.put(map);
            
            map = new JSONObject();
            map.put("name","jacky");
            map.put("age", 22);
            map.put("address", "中国北京");
            array.put(map);
            
            map = new JSONObject();
            map.put("name","vans");
            map.put("age", 26);
            map.put("address", "中国深圳");
            map.put("phone","13888888888");
            array.put(map);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return array.toString();
    }
}


 

Webview提供的传入js的方法:

webView.addJavascriptInterface(new AndroidToastForJs(mContext), "JavaScriptInterface");

Html页面jsonData.html设计的部分代码如下:

    <script type="text/javascript">
    var result = JavaScriptInterface.jsontohtml();
    var obj = eval("("+result+")");//解析json字符串
    function showAndroidToast(toast)
    {        
        JavaScriptInterface.showToast(toast);
    }
    function getjsonData(){
        var result = JavaScriptInterface.jsontohtml();
        var obj = eval("("+result+")");//解析json字符串
        for(i=0;i<obj.length;i++){
            var user=obj[i];
            document.write("<p>姓名:"+user.name+"</p>");
            document.write("<p>年龄:"+user.age+"</p>");
            document.write("<p>地址:"+user.address+"</p>");
            if(user.phone!=null){
                document.write("<p>手机号码:"+user.address+"</p>");
            }
        }
    }    
    function list(){
        document.write("<div data-role='header'><p>another</p></div>");
    }
    </script>
</head>
<body>
<div data-role="page" >
    <div data-role="header" data-theme="c">
        <h1>Android via Interface</h1>
    </div><!-- /header -->
    <div data-role="content">    
        <button value="say hello" onclick="showAndroidToast('Hello,Android!')" data-theme="e"></button>
        <button value="get json data" onclick="getjsonData()" data-theme="e"></button>    
    </div><!-- /content -->
<div data-role="collapsible" data-theme="c" data-content-theme="f">
   <h3>I'm <script>document.write(obj[0].name);</script>,click to see my info</h3>
   <p><script>document.write("<p>姓名:"+obj[0].name+"</p>");</script></p>
   <p><script>document.write("<p>年龄:"+obj[0].age+"</p>");</script></p>
   <p><script>document.write("<p>地址:"+obj[0].address+"</p>");</script></p>
</div>
    <div data-role="footer" data-theme="c">
        <h4>Page Footer</h4>
    </div><!-- /footer -->
</div><!-- /page -->
</body>

点击say hello按钮运行的截图如下:




另外一篇关于webview与js交互

对于android初学者应该都了解webView这个组件。之前我也是对其进行了一些简单的了解,但是在一个项目中不得不用webview的时候,发现了webview的强大之处,今天就分享一下使用webview的一些经验。

 
1、首先了解一下webview。

webview介绍的原文如下:A View that displays web pages. This class is the basis upon which you can roll your own web browser or simply display some online content within your Activity. It uses the WebKit rendering engine to display web pages and includes methods to navigate forward and backward through a history, zoom in and out, perform text searches and more.

从上面你应该了解到了基本功能,也就是显示网页。之所以我说webview功能强大是因为它和js的交互非常方便,很简单就可以实现。

 

2、webview能做什么?

①webView可以利用html做界面布局,虽然目前还比较少人这么使用,不过我相信当一些客户端需要复杂的图文(图文都是动态生成)混排的时候它肯定是个不错的选择。

②直接显示网页,这功能当然也是它最基本的功能。

③和js交互。(如果你的js基础比java基础好的话那么采用这种方式做一些复杂的处理是个不错的选择)。

 

3、如何使用webview?

这里直接用一个svn上取下的demo,先上demo后讲解。demo的结构图如下:

 
WebViewDemo.java

package com.google.android.webviewdemo;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.webkit.JsResult;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;

/**
 * Demonstrates how to embed a WebView in your activity. Also demonstrates how
 * to have javascript in the WebView call into the activity, and how the activity
 * can invoke javascript.
 * <p>
 * In this example, clicking on the android in the WebView will result in a call into
 * the activities code in {@link DemoJavaScriptInterface#clickOnAndroid()}. This code
 * will turn around and invoke javascript using the {@link WebView#loadUrl(String)}
 * method.
 * <p>
 * Obviously all of this could have been accomplished without calling into the activity
 * and then back into javascript, but this code is intended to show how to set up the
 * code paths for this sort of communication.
 *
 */
public class WebViewDemo extends Activity {

    private static final String LOG_TAG = "WebViewDemo";

    private WebView mWebView;

    private Handler mHandler = new Handler();

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.main);
        mWebView = (WebView) findViewById(R.id.webview);

        WebSettings webSettings = mWebView.getSettings();
        webSettings.setSavePassword(false);
        webSettings.setSaveFormData(false);
        webSettings.setJavaScriptEnabled(true);
        webSettings.setSupportZoom(false);

        mWebView.setWebChromeClient(new MyWebChromeClient());

        mWebView.addJavascriptInterface(new DemoJavaScriptInterface(), "demo");

        mWebView.loadUrl("file:///android_asset/demo.html");
    }

    final class DemoJavaScriptInterface {

        DemoJavaScriptInterface() {
        }

        /**
         * This is not called on the UI thread. Post a runnable to invoke
         * loadUrl on the UI thread.
         */
        public void clickOnAndroid() {
            mHandler.post(new Runnable() {
                public void run() {
                    mWebView.loadUrl("javascript:wave()");
                }
            });

        }
    }

    /**
     * Provides a hook for calling "alert" from javascript. Useful for
     * debugging your javascript.
     */
    final class MyWebChromeClient extends WebChromeClient {
        @Override
        public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
            Log.d(LOG_TAG, message);
            result.confirm();
            return true;
        }
    }
}

 

demo.html

<html>
    <script language="javascript">
        /* This function is invoked by the activity */
        function wave() {
            alert("1");
            document.getElementById("droid").src="android_waving.png";
            alert("2");
        }
    </script>
    <body>
        <!-- Calls into the javascript interface for the activity -->
        <a onClick="window.demo.clickOnAndroid()"><div style="width:80px;
            margin:0px auto;
            padding:10px;
            text-align:center;
            border:2px solid #202020;" >
                <img id="droid"" width=100% src="android_normal.png"/><br>
                Click me!
        </div></a>
    </body>
</html>

 

main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    
    <TextView  
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/intro"
        android:padding="4dip"
        android:textSize="16sp"
        />
    
    <WebView
        android:id="@+id/webview"
        android:layout_width="fill_parent"
        android:layout_height="0dip"
        android:layout_weight="1"
        />
        
</LinearLayout>

 

4、如何交互?

①android如何调用js。

调用 形式:

mWebView.loadUrl("javascript:wave()");

其中wave()是js中的一个方法,当然你可以把这个方法改成其他的方法,也就是android调用其他的方法。

②js如何调用android。

调用形式:

<a onClick="window.demo.clickOnAndroid()">

代码中的“demo”是在android中指定的调用名称,即

 mWebView.addJavascriptInterface(new DemoJavaScriptInterface(), "demo");

代码中的clickOnAndroid()是“demo”对应的对象:new DemoJavaScriptInterface() 中的一个方法。

③双向交互。

当然是把前面的两种方式组合一下就可以了。

 

5、讲解demo。

现在你一定了解了android和js的交互了。是时候分析一些demo了,根据上面讲的你也应该比较清楚了。具体交互流程如下:

①点击图片,则在js端直接调用android上的方法clickOnAndroid();

②clickOnAndroid()方法(利用线程)调用js的方法。

③被②调用的js直接控制html。

 

个人总结:利用webView的这种方式在有些时候UI布局就可以转成相应的html代码编写了,而html布局样式之类有DW这样强大的工具,而且网上很多源码,很多代码片。在UI和视觉效果上就会节省很多时间,重复发明轮子没有任何意义。

本文我们来分享一批Android开发中最常用的组件下载地址及使用说明,都是开源免费的,绝对的干货。

了解常见的开源项目,可以扩大我们的视野,知道有哪些可以利用的资源,对于我们平常的设计和开发很有好处

UI相关

WebApp

推送

语音识别

音频视频图像

地图定位

广告平台

统计分析

网络通信

Http访问

XMPP协议

应用授权

社交分享

移动支付

Data解析

序列化

ORM

网盘

异常收集分析

服务器

Event Bus

Dependency Injection

图标资源

其他组件

不常用组件




UI框架

游戏引擎

其他组件


本文我们来讲讲在eclipse开发工具中将android工程生成可安装的apk文件的图文步骤教程,学习android开发的朋友可以参考一下。

eclipse生成andoid安装文件apk的图文步骤如下

1.)生成keystore

按照下面的命令行 在C:\Program Files\Java\jdk1.6.0_10\bin>目录下,输入keytool -genkey -alias android.keystore -keyalg RSA -validity 100000 -keystore android.keystore

参数意义:-validity主要是证书的有效期,写100000天;空格,退格键 都算密码。

命令执行后会在C:\Program Files\Java\jdk1.6.0_10\bin>目录下生成 android.keystore文件。如图-1

 

\

图-1命令行下生成android.keystore

2.)eclipse生成apk文件

选择要打包的项目,右键点击–>Android tools–>Export Signed Application Package…如图-2

 

\

图-2 eclipse 打包工具

接下来的步骤就是不断的next。下面仅贴出图片,不解释。

 

\

step 2:选择打包的项目

 

\

step 3: 选择生成的android.keystore文件并输入密码

 

\

step 4:选择alias key并输入密码

 

\

step 5:最后选择生成android apk文件的目录及文件名

 

\

最终生成的apk文件

以下是本人如何关闭整个Android应用程序呢总结的几种比较简单的实现方法,后面附了一个详细的例子源码。

1. Dalvik VM的本地方法

  android.os.Process.killProcess(android.os.Process.myPid())    //获取PID
  System.exit(0);   //常规java、c#的标准退出法,返回值为0代表正常退出

 

2. 任务管理器方法

   首先要说明该方法运行在Android 1.5 API Level为3以上才可以,同时需要权限

  ActivityManager am = (ActivityManager)getSystemService (Context.ACTIVITY_SERVICE);
  am.restartPackage(getPackageName());
  系统会将,该包下的 ,所有进程,服务,全部杀掉,就可以杀干净了,要注意加上
  <uses-permission android:name=\"android.permission.RESTART_PACKAGES\"></uses-permission>

3. 根据Activity的声明周期

我们知道Android的窗口类提供了历史栈,我们可以通过stack的原理来巧妙的实现,这里我们在A窗口打开B窗口时在Intent中直接加入标 志     Intent.FLAG_ACTIVITY_CLEAR_TOP,这样开启B时将会清除该进程空间的所有Activity。

在A窗口中使用下面的代码调用B窗口

Intent intent = new Intent();
intent.setClass(Android123.this, CWJ.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);  //注意本行的FLAG设置
startActivity(intent);

接下来在B窗口中需要退出时直接使用finish方法即可全部退出。

 

4.自定义一个Actiivty 栈,道理同上,不过利用一个单例模式的Activity栈来管理所有Activity。并提供退出所有Activity的方法。代码如下:

   public class ScreenManager {
 private static Stack<Activity> activityStack;
 private static ScreenManager instance;
 private  ScreenManager(){
 }
 public static ScreenManager getScreenManager(){
  if(instance==null){
   instance=new ScreenManager();
  }
  return instance;
 }
//退出栈顶Activity
 public void popActivity(Activity activity){
  if(activity!=null){
   activity.finish();
   activityStack.remove(activity);
   activity=null;
  }
 }

//获得当前栈顶Activity
 public Activity currentActivity(){
  Activity activity=activityStack.lastElement();
  return activity;
 }

//将当前Activity推入栈中
 public void pushActivity(Activity activity){
  if(activityStack==null){
   activityStack=new Stack<Activity>();
  }
  activityStack.add(activity);
 }
 //退出栈中所有Activity
 public void popAllActivityExceptOne(Class cls){
  while(true){
   Activity activity=currentActivity();
   if(activity==null){
    break;
   }
   if(activity.getClass().equals(cls) ){
    break;
   }
   popActivity(activity);
  }
 }
}



android 完全退出应用程序实现代码

android退出应用程序会调用android.os.Process.killProcess(android.os.Process.myPid())或是System.exit(0),这只是针对第一个Activity(也就是入口的Activity)时生效。如果有A,B,C三个Activity,而想在B或C中Activity退出,调用上面的方法,往往会销毁当前的Activity返回上一个Activity。当然也可以逐个返回上一个Activity,直到跳转到入口的Activity,最后退出应用程序。但这样比较麻烦,而且逐个返回的体验并不友好。

网上比较流行的方法是定义栈,写一个ExitApplication类,利用单例模式管理Activity,在每个在Activity的onCreate()方法中调用ExitApplication.getInstance().addActivity(this)方法,在退出时调用ExitApplication.getInstance().exit()方法,就可以完全退出应用程序了。
ExitApplication类

import java.util.LinkedList;
import java.util.List;

import android.app.Activity;
import android.app.Application;

public class ExitApplication extends Application {

 private List activityList = new LinkedList();
 private static ExitApplication instance;

 private ExitApplication()
 {
 }
 //单例模式中获取唯一的ExitApplication实例
 public static ExitApplication getInstance()
 {
 if(null == instance)
 {
 instance = new ExitApplication();
 }
 return instance;

 }
 //添加Activity到容器中
 public void addActivity(Activity activity)
 {
 activityList.add(activity);
 }
 //遍历所有Activity并finish

 public void exit()
 {

 for(Activity activity:activityList)
 {
 activity.finish();
 }

 System.exit(0);

 }
 }

 下面的三个类IndexActivity, BActivity,CActivity是简单的例子,分别是IndexActivity?>BActivity?>CActivity的跳转顺序。在每个Activity类中onCreate()方法中调用ExitApplication.getInstance().addActivity(Activity activity)方法。在任何一个Activity界面退出应用程序时,只要调用ExitApplication.getInstance().exit()方法,就可以在任何一个Activity中完全退出应用程序。
IndexActivity 类源代码:

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class IndexActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Button next=(Button)findViewById(R.id.next_to_b);
        next.setOnClickListener(nextClick);

        Button exit=(Button)findViewById(R.id.exit_main);
        exit.setOnClickListener(exitClick);
        ExitApplication.getInstance().addActivity(this);

    }

    OnClickListener nextClick=new OnClickListener() {

  @Override
  public void onClick(View v) {
   // TODO Auto-generated method stub

   Intent intent=new Intent(IndexActivity.this,BActivity.class);
   startActivity(intent);

  }
 };

    OnClickListener exitClick=new OnClickListener() {

  @Override
  public void onClick(View v) {
   // TODO Auto-generated method stub
   ExitApplication.getInstance().exit();
  }
 };
}

BActivity 类源代码:

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class BActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);

setContentView(R.layout.b);
Button next_to_c=(Button)findViewById(R.id.next_to_c);
next_to_c.setOnClickListener(next_to_cClick);

Button exit_b=(Button)findViewById(R.id.exit_b);
exit_b.setOnClickListener(exitClick);
ExitApplication.getInstance().addActivity(this);

}

OnClickListener next_to_cClick=new OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub

Intent intent=new Intent(BActivity.this,CActivity.class);
startActivity(intent);

}
};

OnClickListener exitClick=new OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
ExitApplication.getInstance().exit();
}
};
}

CActivity 类源代码:

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class CActivity extends Activity{

@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);

setContentView(R.layout.c);

Button exit_c=(Button)findViewById(R.id.exit_c);
exit_c.setOnClickListener(exitClick);
ExitApplication.getInstance().addActivity(this);

}

OnClickListener exitClick=new OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
ExitApplication.getInstance().exit();
//如果只是调用以下其中的一个方法,并不会完全退出应用
//android.os.Process.killProcess(android.os.Process.myPid());
//System.exit(0);
}
};
}

Android应用项目有时为了方便需要调用第三方文件或者库,本文我们来讲讲如何在Android NDK中调用第三方库文件(.so),及Android JNI找不到第三方库的解决方案。

如何在Android NDK中调用第三方库文件(.so)



1.在project/jni目录下创建prebuilt子目录(目录名可自定义).

2.将第三方.so放到prebuilt中,并创建Android.mk, 内容如下:

    LOCAL_PATH := $(call my-dir)

    include $(CLEAR_VARS)

    LOCAL_MODULE := xxx

    LOCAL_SRC_FILES := libxxx.so

    include $(PREBUILT_SHARED_LIBRARY)

3.在project/jni/Android.mk中加入

    LOCAL_SHARED_LIBRARIES := xxx

4.在project/jni/android.mk的最后加入

    include $(LOCAL_PATH)/prebuilt/Android.mk

5.运行cygwin, 到project目录下, 运行$NDK/ndk-build




Android JNI找不到第三方库的解决方案 cannot load library



    最近做一个jni项目,拿到的so库需要用jni封装一层,等于是在jni的C++代码里调用第三方库的方法,然后整个项目在Android上运行出结果。

    自己用jni生成的so是libaa.so 使用的第三方库是libbb.so。

    到目前为止,遇到的问题是libbb各种找不到。libbb库去哪儿了?

     

    E/AndroidRuntime(11626): Caused by: java.lang.UnsatisfiedLinkError:
    Cannot load library: soinfo_link_image(linker.cpp:1640):
    could not load library libbb.so needed by libaa.so;

    caused by load_library(linker.cpp:750): library libbb.so not found

     

    以上错误是在运行阶段发生的,事实上编译阶段也发生过找不到第三方的问题,表现就是库里实现的方法undefined。

    分两方面解决

     

    1,编译阶段找不到库,需要修改MK文件。

    1.libbb.so放在jni/prebuilt文件夹(自己新建),同时把Android.mk复制一份到prebuilt下。

    2.libbb.so的mk如下:
    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_MODULE := bb
    LOCAL_SRC_FILES := libbb.so
    include $(PREBUILT_SHARED_LIBRARY)
    (<Dream>如果第三方提供的是.so文件则无须前面两个步骤)

    3.libaa.so的mk文件需要引入上面的mk。
    LOCAL_PATH := $(call my-dir)
     include $(CLEAR_VARS)
     LOCAL_MODULE    := aa
    LOCAL_SRC_FILES := aa.cpp
    LOCAL_LDLIBS := -llog
     LOCAL_SHARED_LIBRARIES := bb
    include $(BUILD_SHARED_LIBRARY)
    include $(LOCAL_PATH)/prebuilt/Android.mk
    (<Dream>可以静态链接,这样只产生一个.so,做法如下)
    Android.mak
    include $(BUILD_STATIC_LIBRARY)
    Application.mak
    APP_MODULES:=aa

    这样在编译阶段就可以连接到第三方库咯。

    2.运行阶段找不到库

    在运行阶段找不到库就是Android的事情了。后来发现是load库的顺序(默哀一个,破顺序。。)。

     
    static
        {
            System.loadLibrary(bb);
            System.loadLibrary(aa);
        }
    (<Dream>静态链接,这样就不需要load两个了库)
    先load第三方库,再load自己的库,因为aa库要用bb库里的方法,是依赖于bb库的,所以要先load。。

    这样在运行阶段也可以找到库咯。

标签:[!--infotagslink--]

您可能感兴趣的文章: