3

我正在开发一款适用于 iOS 的 PhoneGap 应用程序,它可以让您收听 MP3 和观看 MP4。

通常,我只会使用<a href="file.mp3">file.mp3</a><video src="file.mp3"></video>播放文件并让系统媒体播放器处理事情。这一次,要求在屏幕关闭时继续播放音频。默认处理是在屏幕锁定时淡出并暂停媒体。PhoneGap API 文档提供了一些示例代码,其中包含playAudioWhenScreenIsLocked选项。该代码似乎可以正常工作,因为当屏幕锁定时 MP3 会继续播放。

我遇到的问题是所述文件开始播放需要相当长的时间。例如,一个 27MB 的 MP3 文件在 iPhone 4s (3g) 上开始播放需要 1 分 50 秒,而在 iPad 2 (WiFi) 上需要 2 分钟。在我的桌面上下载同一个文件需要几秒钟。似乎它必须在开始播放之前下载整个文件。这似乎没有必要。为了补充这个理论,如果我尝试播放 MP4(使用media.play()),它需要更长的时间然后关闭应用程序。

config.xml(可识别部分替换为 xxx):

<?xml version="1.0" encoding="UTF-8"?>
<!-- config.xml reference: https://build.phonegap.com/docs/config-xml -->
<widget xmlns = "http://www.w3.org/ns/widgets" xmlns:gap = "http://phonegap.com/ns/1.0" id = "org.xxx.xxxbeta" version = "2.0">
    <name>xxx Beta</name>
    <description>xxx Live   ///   Design update</description>
    <author href="http://www.xxx.org" email="xxx@xxx.org">xxx</author>
    <!-- Enable individual API permissions by defining each here.  The 'device' permission is required for the 'deviceready' event. -->
    <feature name="http://api.phonegap.com/1.0/device" />

    <!-- Customize your app and platform with the preference element. -->
    <!-- If you do not want any permissions to be added to your app, add the following tag to your config.xml; you will still have the INTERNET permission on your app, which PhoneGap requires. -->
    <preference name="permissions" value="none"/>
    <preference name="phonegap-version" value="2.9.0" /> <!-- all: current version of PhoneGap -->
    <preference name="orientation" value="default" /> <!-- all: default means both landscape and portrait are enabled -->
    <preference name="target-device" value="universal" /> <!-- all: possible values handset, tablet, or universal -->
    <preference name="fullscreen" value="false" /> <!-- all: hides the status bar at the top of the screen -->
    <preference name="webviewbounce" value="true" /> <!-- ios: control whether the screen 'bounces' when scrolled beyond the top -->
    <preference name="prerendered-icon" value="false" /> <!-- ios: if icon is prerendered, iOS will not apply it's gloss to the app's icon on the user's home screen -->
    <preference name="stay-in-webview" value="false" /> <!-- ios: external links should open in the default browser, 'true' would use the webview the app lives in -->
    <preference name="ios-statusbarstyle" value="black-opaque" /> <!-- ios: black-translucent will appear black because the PhoneGap webview doesn't go beneath the status bar -->
    <preference name="detect-data-types" value="true" /> <!-- ios: controls whether data types (such as phone no. and dates) are automatically turned into links by the system -->
    <preference name="exit-on-suspend" value="false" /> <!-- ios: if set to true, app will terminate when home button is pressed -->
    <preference name="show-splash-screen-spinner" value="false" /> <!-- ios: if set to false, the spinner won't appear on the splash screen during app loading -->
    <preference name="auto-hide-splash-screen" value="true" /> <!-- ios: if set to false, the splash screen must be hidden using a JavaScript API -->
    <preference name="disable-cursor" value="false" /> <!-- blackberry: prevents a mouse-icon/cursor from being displayed on the app -->
    <preference name="android-minSdkVersion" value="14" /> <!-- android: MIN SDK version supported on the target device. MAX version is blank by default. -->
    <preference name="android-installLocation" value="auto" /> <!-- android: app install location. 'auto' will choose. 'internalOnly' is device memory. 'preferExternal' is SDCard. -->

    <!-- Plugins can also be added here.  A list of available plugins are available at https://build.phonegap.com/docs/plugins-->
    <!--<gap:plugin name="GAPlugin" />-->

    <!-- Define app icon for each platform. -->
    <icon src="images/logo.png" />
    <icon src="images/Icons/icon-57.png" gap:platform="ios" width="57" height="57" />
    <icon src="images/Icons/icon-72.png" gap:platform="ios" width="72" height="72" />
    <icon src="images/Icons/icon-114.png" gap:platform="ios" width="114" height="114" />
    <icon src="images/Icons/icon-144.png" gap:platform="ios" width="144" height="144" />

    <!-- Define app splash screen for each platform. -->
    <gap:splash src="images/LaunchScreens/launch-iphone-app-P.png" gap:platform="ios" width="320" height="480" />
    <gap:splash src="images/LaunchScreens/launch-iphone-app-P-2x.png" gap:platform="ios" width="640" height="960" />
    <gap:splash src="images/LaunchScreens/launch-iphone-5-app-P.png" gap:platform="ios" width="640" height="1136" />
    <gap:splash src="images/LaunchScreens/launch-ipad-app-P.png" gap:platform="ios" width="768" height="1024" />
    <gap:splash src="images/LaunchScreens/launch-ipad-app-P-2x.png" gap:platform="ios" width="1536" height="2048" />
    <gap:splash src="images/LaunchScreens/launch-ipad-app-L.png" gap:platform="ios" width="1024" height="768" />
    <gap:splash src="images/LaunchScreens/launch-ipad-app-L-2x.png" gap:platform="ios" width="2048" height="1536" />

    <!-- Define access to external domains. -->
    <!-- 
    <access /> - A blank access tag denies access to all external resources.
    <access origin="*" /> - A wildcard access tag allows access to all external resource.
    <access origin="http://127.0.0.1*"/> - allow local pages only
    <access origin="http://phonegap.com" /> - allow any secure requests to http://phonegap.com/
    <access origin="http://xxx.org" subdomains="true" /> - same as above, but including subdomains, such as http://build.phonegap.com/
    <access origin="http://xxx.org" browserOnly="true" /> - only allows http://phonegap.com to be opened by the child browser.
    -->
</widget>

HTML(可识别部分替换为 xxx):

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Featured Series | xxx Live</title>
    <!-- required for the redirectToSystemBrowser() function -->
    <script src="phonegap.js"></script>
    <!-- used to change the formats of dates -->
    <script src="date.js"></script>
    <!-- jquery (we might as well use it) -->
    <script src="jquery-1.10.1.min.js"></script>
    <!-- our javascripts -->
    <script src="xxxlive.js"></script>
</head>
<body class="featuredseries">
    <header>
        <h1><a href="index.html"><abbr title="xxx">xxx</abbr> <span>Live</span></a></h1>
    </header>
    <section id="content">
    </section>
    <!-- page specific javascripts -->
    <script>
        // load the featured series content
        seriesDownload(featuredseries);
    </script>
</body>
</html>

JavaScript(可识别部分替换为 xxx):

// phonegap api media playing
function playAudio(url) {
    // Play the audio file at url
    var my_media = new Media(url,
        // success callback
        function () {
            console.log("playAudio():Audio Success");
        },
        // error callback
        function (err) {
            console.log("playAudio():Audio Error: " + err);
        }
    );
    // Play audio even if the screen is off
    my_media.play({ playAudioWhenScreenIsLocked : true });
}

// generic get JSON data function
function fetchJSONFile(path, callback) {
    var httpRequest = new XMLHttpRequest();
    httpRequest.onreadystatechange = function() {
        if (httpRequest.readyState === 4) {
            if (httpRequest.status === 200) {
                var data = JSON.parse(httpRequest.responseText);
                if (callback) callback(data);
            }
        }
    };
    // false tells it to be synchronous instead of asynchronous
    httpRequest.open('GET', path, false);
    httpRequest.send(); 
}

// get a bunch of series information from a json api
function seriesDownload(seriestitle) {
    var series, number, description;
    // tell the function where the JSON data is
    fetchJSONFile('http://www.xxx.org/api/seriesdownload/?series=' + seriestitle, function(data) {
        // do something with your data
        // alert(JSON.stringify(data));
        // alert(data.title + ', ' + data.camelcase);
        series = data.series;
        number = data.seriesnumber;
        description = data.description;
        $('#content').append('<h2>' + series + '</h2>');
        $('#content').append('<blockquote><p>' + description + '</p></blockquote>');
        for (var i = 0, l = data.sermons.length; i < l; i++) {
            var date, speaker, seriespart, sermon, sermonpart, sermonsubtitle, sermonsubtitlepart, mp3, mp4;
            //alert(data.events[i].name);
            date = data.sermons[i].date;
            // date.js doesn't seem to like the iso8601 time zone offset
            var date_readable = Date.parse(date.substring(0, 19)).toString('dddd, MMMM d, yyyy');
            speaker = data.sermons[i].speaker;
            seriespart = data.sermons[i].seriespart;
            sermon = data.sermons[i].sermon;
            // replace non-alphanumeric characters with nothing
            var sermon_camelcase = sermon.replace(/[^a-zA-Z0-9]+/g, '');
            sermonpart = data.sermons[i].sermonpart;
            sermonsubtitle = data.sermons[i].sermonsubtitle;
            sermonsubtitlepart = data.sermons[i].sermonsubtitlepart;
            mp3 = data.sermons[i].downloadlinks.mp3;
            mp4 = data.sermons[i].downloadlinks.mp4;
            $('#content').append('<h3>Pt. ' + seriespart + ' - ' + sermon + '</h3>');
            $('#content').append('<dl id="' + sermon_camelcase + '">');
            $('#content #' + sermon_camelcase).append('<dt>Date Preached</dt>');
            $('#content #' + sermon_camelcase).append('<dd><time datetime="' + date + '">' + date_readable + '</time></dd>');
            $('#content #' + sermon_camelcase).append('<dt>Speaker</dt>');
            $('#content #' + sermon_camelcase).append('<dd>' + speaker + '</dd>');
            $('#content #' + sermon_camelcase).append('<dt>Download Links</dt>');
            $('#content #' + sermon_camelcase).append('<dd id="' + sermon_camelcase + '-downloadlinks">');
            $('#content #' + sermon_camelcase + ' #' + sermon_camelcase + '-downloadlinks').append('<ul>');
            $('#content #' + sermon_camelcase + ' #' + sermon_camelcase + '-downloadlinks ul').append('<li class="link" onclick="playAudio(\'' + mp3 + '\')">Audio (MP3)</li>');
            $('#content #' + sermon_camelcase + ' #' + sermon_camelcase + '-downloadlinks ul').append('<li class="link" onclick="playAudio(\'' + mp4 + '\')">Video (MP4)</li>');
            $('#content #' + sermon_camelcase + ' #' + sermon_camelcase + '-downloadlinks').append('</ul>');
            $('#content #' + sermon_camelcase).append('</dd>');
            $('#content').append('</dl>');
        }
    });
}

因此,基本上,该页面调用一个 JavaScript 函数,该函数调用 JSON API 并将该数据转换为一堆文本。该文本包含指向播放音频的功能的链接(没有,特别是疯狂)。

有什么明显的,我做错了,或者PhoneGap Media API实际上只需要那么长时间来操作吗?我不这么认为,否则人们会对此感到哗然。我还没有阅读其他关于人们遇到类似问题的报告。

不幸的是,我无法在我的桌面上真正测试它,因为我的浏览器无法访问所有PhoneGap Build的东西(我认为 Build 值得注意,因为存在一些差异)。

还可能值得注意的是,我尝试通过添加到我的 config.xml 来包含媒体插件。<gap:plugin name="org.apache.cordova.media" />当我更新应用程序时,它给了我这个错误(Unable to create app: plugin unsupported: org.apache.cordova.media)。该代码是他们在其网站上推荐的。config.xml 使用<gap:plugin name="GAPlugin" />,所以我也尝试<gap:plugin name="Media" />过。我遇到了类似的错误(Unable to create app: plugin unsupported: media)。

我之前没有使用过PhoneGap插件,所以可能是缺少插件导致播放前长时间停顿。我不这么认为,因为这应该是 API 的内置核心功能。

4

0 回答 0