安卓:使用WebView播放资源声音

12
我正在尝试在我的应用程序的WebView中,当用户点击一个标签时,从assets文件夹中播放声音。我发现可以使用一个扩展了WebViewClient的新类来检测链接的扩展名是否为mp3文件,如果是,则可以通过默认的音频播放器播放它。但我希望在活动中播放,而不启动新的活动。
我参考了以下链接:
Sound in WebviewError creating MediaPlayer with Uri or file in assets,但没有成功。
我尝试使用以下代码实现:
package com.rangga.test.webview.sound;

import android.content.Intent;
import android.content.res.AssetFileDescriptor;
import android.media.MediaPlayer;
import android.net.Uri;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class MyWebViewClient extends WebViewClient{

    public MediaPlayer mp;

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url){
        if(url.endsWith(".mp3")){
            mp = new MediaPlayer();
            AssetFileDescriptor afd = getAssets().openFd(url);
            mp.setDataSource(afd.getFileDescriptor());
            mp.start();

            return true;
        }else{
            return true;
        }


    }

}

在getAssets()方法上,我收到了一个未定义的方法错误。我尝试通过谷歌搜索解决问题,并发现需要传递一个Context参数。由于我非常新手,对Android和面向对象编程不是很熟悉,因此想知道这是否是正确的方法,并且是否有一个简单的解释可以说明什么是Context。谢谢。

以下是我的完整代码:

MainActivity.class

package com.rangga.test.webview.sound;

import android.app.Activity;
import android.os.Bundle;
import android.webkit.WebView;

public class MainActivity extends Activity {

    WebView webMain;

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

        webMain = (WebView) findViewById(R.id.webMain);

        webMain.loadUrl("file:///android_asset/webpages/test.html");
        webMain.setWebViewClient(new MyWebViewClient());
    }


}

编辑

代码由https://stackoverflow.com/users/488241/squonk的帮助下工作,但现在出现了另一个问题,我将MyWebViewClient更新为以下内容:

package com.rangga.test.webview.sound;

import java.io.IOException;

import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.media.MediaPlayer;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class MyWebViewClient extends WebViewClient{

    public MediaPlayer mp;
    private Context context = null;

    public MyWebViewClient(Context c){
        this.context = c;
    }

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url){
        if(url.endsWith(".mp3")){

            mp = new MediaPlayer();
            try {
                AssetFileDescriptor afd = context.getAssets().openFd(url);
                mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
                afd.close();
                mp.prepare();
                mp.start();
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalStateException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }


            return true;
        }else{
            return true;
        }   
    }
}

但是我遇到了java.io.FileNotFoundException的问题,尽管路径看起来是正确的。我将2个mp3文件放在assets/webpages/sounds/1.mp3和assets/webpages/1.mp3中,并使用以下HTML代码进行测试:

<html>
    <head>
        <title>Test Audio</title>
    </head>
    <body>
        <a href="file:///android_asset/webpages/sounds/1.mp3">File Asset</a><br/>
        <a href="1.mp3">Same Folder</a>
    </body>
</html>

但是我在 LogCat 上收到以下错误:

06-11 06:20:37.955: W/System.err(377): java.io.FileNotFoundException: file:///android_asset/webpages/1.mp3
06-11 06:20:37.966: W/System.err(377):  at android.content.res.AssetManager.openAssetFd(Native Method)
06-11 06:20:37.974: W/System.err(377):  at android.content.res.AssetManager.openFd(AssetManager.java:314)
06-11 06:20:37.974: W/System.err(377):  at com.rangga.test.webview.sound.MyWebViewClient.shouldOverrideUrlLoading(MyWebViewClient.java:30)
06-11 06:20:37.985: W/System.err(377):  at android.webkit.CallbackProxy.uiOverrideUrlLoading(CallbackProxy.java:193)
06-11 06:20:38.000: W/System.err(377):  at android.webkit.CallbackProxy.handleMessage(CallbackProxy.java:304)
06-11 06:20:38.005: W/System.err(377):  at android.os.Handler.dispatchMessage(Handler.java:99)
06-11 06:20:38.005: W/System.err(377):  at android.os.Looper.loop(Looper.java:123)
06-11 06:20:38.014: W/System.err(377):  at android.app.ActivityThread.main(ActivityThread.java:4363)
06-11 06:20:38.014: W/System.err(377):  at java.lang.reflect.Method.invokeNative(Native Method)
06-11 06:20:38.024: W/System.err(377):  at java.lang.reflect.Method.invoke(Method.java:521)
06-11 06:20:38.024: W/System.err(377):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
06-11 06:20:38.024: W/System.err(377):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
06-11 06:20:38.054: W/System.err(377):  at dalvik.system.NativeStart.main(Native Method)

我调用文件的方式有问题吗?先谢谢。

已解决

感谢squonk的建议,我尝试了以下代码使其正常工作,它很好地解决了我的问题,谢谢squonk!

package com.rangga.test.webview.sound;

import java.io.IOException;

import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.media.MediaPlayer;
import android.util.Log;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class MyWebViewClient extends WebViewClient{

    public MediaPlayer mp;
    private Context context = null;

    public MyWebViewClient(Context c){
        this.context = c;
        mp = new MediaPlayer();
    }

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url){
        if(url.endsWith(".mp3")){
            url = url.replace("file:///android_asset/webpages/", "");
            Log.i("MyWebViewClient", url);
            try {
                AssetFileDescriptor afd = context.getAssets().openFd(url);
                mp = new MediaPlayer();
                mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
                afd.close();
                mp.prepare();
                mp.start();
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalStateException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }


            return true;
        }else{
            return true;
        }   
    }
}

还有用于测试的 HTML 代码:

<html>
    <head>
        <title>Test Audio</title>
    </head>
    <body>
        <a href="webpages/1.mp3">File Asset</a><br/>
    </body>
</html>

虽然我不断地点击它,确实遇到了一个错误,但这是另一个问题 :D 如何关闭问题? >.<

1个回答

3
在您在MyWebViewClient中声明MediaPlayer的地方,添加以下内容...
public class MyWebViewClient extends WebViewClient{

    public MediaPlayer mp;
    private Context context = null; // Add this line

    ...
}

然后在MyWebViewClient中添加如下构造函数...
public MyWebViewClient(Context context) {
    this.context = context;
}

然后,在 shouldOverrideUrlLoading(...) 中按以下方式获取您的资产...
AssetFileDescriptor afd = context.getAssets().openFd(url);

在你的MainActivity中,通过将this(即活动Context)传递如下方式设置WebViewClient...
webMain.setWebViewClient(new MyWebViewClient(this));

如果url以'.mp3'结尾,您应该从'shouldOverrideUrlLoading(...)'返回false - 这表明您的WebView正在处理事情,'host'应用程序不应启动股票Web浏览器实例。同时您需要注意,如果要从assets目录播放音频文件,需要以不同的方式设置数据源,请参考play-audio-file-from-the-assets-directory的答案。此外,在调用'mp.start()'之前,您应该先调用'mp.prepare()'。

哇,谢谢,现在至少它可以运行了,您先生是传奇..等待..达里!但是当我点击链接1和3时,它会出现java.oi.FileNotFoundException错误,似乎链接路径有误 >.< 而链接2只是打开了不可用的网页。在资产文件中播放声音的方法是什么?或者应该在原始文件或SD卡中播放? - Rangga Wiratno
是的,实际上我也尝试了以下方法。我在afd上添加了参数,并在mp.start()之前添加了mp.prepare()和afd.close(),在阅读了http://droidapp.co.uk/?p=272之后做出这些更改。但奇怪的是,即使路径正确,我仍然会收到java.io.FileNotFoundException的错误消息。我尝试调整html,但还是无法解决<a href="file:///android_asset/webpages/sounds/1.mp3">File Asset</a><br/>和<a href="1.mp3">Same Folder</a>的问题。我已经放了两个文件进行测试,在assets>webpages>1.mp3和assets>webpages>sounds>1.mp3。 - Rangga Wiratno
我已经编辑了我的问题,希望这能帮助你回答它,再次感谢:D - Rangga Wiratno
1
是的,但不幸的是它也没有起作用,我会尝试使用一些其他类似的项目进行测试。好的,非常感谢你:D - Rangga Wiratno
抱歉回复晚了,我会在有时间的时候处理,目前接下来的三天有点忙。再次感谢你的建议 :) - Rangga Wiratno
显示剩余3条评论

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