首页 > 解决方案 > 反应本机铃声管理器

问题描述

我正在使用https://github.com/millerbennett/react-native-ringtone-manager

但不幸的是 RingtoneManager.getRingtones(RingtoneManager.TYPE_ALL) 总是返回“未定义”。

我没有错误,有人知道这个问题吗?

我正在使用模拟器,但我可以看到参数中存在铃声。

编辑

我又回到了这个问题上。

我不明白为什么它不起作用。

我阅读了https://github.com/millerbennett/react-native-ringtone-manager并与经理的代码进行比较,没有发现任何问题。

事实上,对象 RingtoneManager 本身被标记为undefined

编辑

所以这是我的代码:

import React from 'react';
import { Text, View} from 'react-native';
import RingtoneManager from 'react-native-ringtone-manager';


export default class FormRingtones extends React.Component {

static navigationOptions = {
  title: 'Rings',
};
constructor(props) {
super(props);

}
rings;

componentDidMount() {
this.getRings();
}

getRings() {
console.log("1 : " + RingtoneManager);
 this.rings =  RingtoneManager.getRingtones(RingtoneManager.TYPE_ALL);
 if(this.rings != null) {this.rings = this.rings.map((item,index) =>{<Text>{item.title}</Text>})};
   console.log("2 " + this.rings.length);

}

render() {   
return (
  <View>
    <View >
      {this.rings}
    </View>
  </View>
)
};
}

我刚刚安装了评论中提到的最新版本,现在该应用程序显示一个很好的“未知”错误,调试工具中没有其他任何内容......

清除缓存并重新启动所有工具救了我。

但现在我有 RingtoneManager 的 [object Object] 和环的undefined ......

谢谢您的帮助。

编辑

抱歉,我之前没有时间发布我的解决方案。

问题是 getRingtones() 在 react-native-ringtone-manager 中只是空的....当您为此安装此组件时非常烦人。

好吧,我做了什么:

node_modules\react-native-ringtone-manager\android\src\main\java\com\reactlibrary,在RNRingtoneManagerModule.java

@ReactMethod
public void getRingtones(Callback successCallback) {
    getRingsByType(RingtoneManager.TYPE_ALL, successCallback);
}

@ReactMethod
public void getRingsByType(int ringtoneType, Callback successCallback)          {
    RingtoneManager manager = new RingtoneManager(this.reactContext);
    manager.setType(ringtoneType);
    Cursor cursor = manager.getCursor();
    WritableMap data = Arguments.createMap();

    while (cursor.moveToNext()) {
        String notificationTitle = cursor.getString(RingtoneManager.TITLE_COLUMN_INDEX);
        Uri notificationUri =Uri.parse(cursor.getString(RingtoneManager.URI_COLUMN_INDEX) + "/" + cursor.getString(RingtoneManager.ID_COLUMN_INDEX));
        data.putString(notificationTitle, notificationUri);

    }
    successCallback.invoke(data);
}

现在,一切正常,我可以按类型列出铃声,播放它们的声音等......

这是我有生以来第一次安装我必须写的东西:)

编辑

这就是我调用 RNRingtoneManagerModule 的方式:

getRingtones(type) {
RingtoneManager.getRingsByType(type, (data) => {
  this.setState({ selected: type, datas: data, selectedItem: data[0] });
});
}

ItemRingtone 只是每个项目的视图。

标签: react-nativeringtonemanager

解决方案


此外,我发布了我的整个代码。它还没有完全完成,因为我解决了 RingToneManager 的主要问题,所以我在我的应用程序的其他部分工作。但对于遇到铃声困难的人来说,这是一个好的开始:

RNR铃声管理器模块

package com.reactlibrary;

import android.content.ContentResolver;
import android.content.ContentValues;
import android.media.RingtoneManager;
import android.net.Uri;
import android.provider.MediaStore;
import android.database.Cursor;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.Arguments;

import java.io.File;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.annotation.SuppressLint;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;

import java.net.URISyntaxException;

public class RNRingtoneManagerModule extends ReactContextBaseJavaModule {

private final ReactApplicationContext reactContext;
private static final String TYPE_ALARM_KEY = "TYPE_ALARM";
private static final String TYPE_ALL_KEY = "TYPE_ALL";
private static final String TYPE_NOTIFICATION_KEY = "TYPE_NOTIFICATION";
private static final String TYPE_RINGTONE_KEY = "TYPE_RINGTONE";

final static class SettingsKeys {
    public static final String URI = "uri";
    public static final String TITLE = "title";
    public static final String ARTIST = "artist";
    public static final String SIZE = "size";
    public static final String MIME_TYPE = "mimeType";
    public static final String DURATION = "duration";
    public static final String RINGTONE_TYPE = "ringtoneType";
}

public RNRingtoneManagerModule(ReactApplicationContext reactContext) {
    super(reactContext);
    this.reactContext = reactContext;
}

@Override
public String getName() {
    return "RingtoneManager";
}

@ReactMethod
public void getRingtones(Callback successCallback) {
    getRingsByType(RingtoneManager.TYPE_ALL, successCallback);
}

@ReactMethod
public void getRingsByType(int ringtoneType, Callback successCallback) {
    RingtoneManager manager = new RingtoneManager(this.reactContext);
    manager.setType(ringtoneType);
    Cursor cursor = manager.getCursor();

    WritableArray result = Arguments.createArray();
    int key= 0;
    while (cursor.moveToNext()) { 
        WritableMap data = Arguments.createMap();
        String notificationTitle = cursor.getString(RingtoneManager.TITLE_COLUMN_INDEX);
        Uri notificationUri = Uri.parse(cursor.getString(RingtoneManager.URI_COLUMN_INDEX) + "/"
                + cursor.getString(RingtoneManager.ID_COLUMN_INDEX));
        String notification = getPathFromUri(this.reactContext, notificationUri);
        data.putInt("key", key);
        data.putString("title", notificationTitle);
        data.putString("uri", notification);
        result.pushMap(data);
        key=key+1;
    }
    successCallback.invoke(result);
}

@SuppressLint("NewApi")
public String getPathFromUri(Context context, Uri uri) {
    final boolean needToCheckUri = Build.VERSION.SDK_INT >= 19;
    String selection = null;
    String[] selectionArgs = null;
    // Uri is different in versions after KITKAT (Android 4.4), we need to
    // deal with different Uris.
    if (needToCheckUri && DocumentsContract.isDocumentUri(context.getApplicationContext(), uri)) {
        if (isExternalStorageDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            return Environment.getExternalStorageDirectory() + "/" + split[1];
        } else if (isDownloadsDocument(uri)) {
            final String id = DocumentsContract.getDocumentId(uri);
            uri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
        } else if (isMediaDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];
            if ("image".equals(type)) {
                uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
            } else if ("video".equals(type)) {
                uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
            } else if ("audio".equals(type)) {
                uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
            }
            selection = "_id=?";
            selectionArgs = new String[] { split[1] };
        }
    }
    if ("content".equalsIgnoreCase(uri.getScheme())) {
        String[] projection = { MediaStore.Images.Media.DATA };
        Cursor cursor = null;
        try {
            cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
            int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            if (cursor.moveToFirst()) {
                return cursor.getString(column_index);
            }
        } catch (Exception e) {
        }
    } else if ("file".equalsIgnoreCase(uri.getScheme())) {
        return uri.getPath();
    }
    return null;
}

/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is ExternalStorageProvider.
 */
public static boolean isExternalStorageDocument(Uri uri) {
    return "com.android.externalstorage.documents".equals(uri.getAuthority());
}

/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is DownloadsProvider.
 */
public static boolean isDownloadsDocument(Uri uri) {
    return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}

/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is MediaProvider.
 */
public static boolean isMediaDocument(Uri uri) {
    return "com.android.providers.media.documents".equals(uri.getAuthority());
}

@ReactMethod
public void createRingtone(ReadableMap settings) {
    String uriStr = settings.getString(SettingsKeys.URI);
    File ringtone = new File(uriStr);
    ContentValues values = new ContentValues();
    values.put(MediaStore.MediaColumns.DATA, ringtone.getAbsolutePath());
    values.put(MediaStore.MediaColumns.TITLE, settings.getString(SettingsKeys.TITLE));
    values.put(MediaStore.MediaColumns.SIZE, settings.getInt(SettingsKeys.SIZE));
    values.put(MediaStore.MediaColumns.MIME_TYPE, settings.getString(SettingsKeys.MIME_TYPE));
    values.put(MediaStore.Audio.Media.ARTIST, settings.getString(SettingsKeys.ARTIST));
    values.put(MediaStore.Audio.Media.DURATION, settings.getInt(SettingsKeys.DURATION));
    int ringtoneType = settings.getInt(SettingsKeys.RINGTONE_TYPE);
    values.put(MediaStore.Audio.Media.IS_RINGTONE, isRingtoneType(ringtoneType, RingtoneManager.TYPE_RINGTONE));
    values.put(MediaStore.Audio.Media.IS_NOTIFICATION,
            isRingtoneType(ringtoneType, RingtoneManager.TYPE_NOTIFICATION));
    values.put(MediaStore.Audio.Media.IS_ALARM, isRingtoneType(ringtoneType, RingtoneManager.TYPE_ALARM));
    values.put(MediaStore.Audio.Media.IS_MUSIC, false);
    if (ringtone.exists() && getCurrentActivity() != null) {
        ContentResolver contentResolver = getCurrentActivity().getContentResolver();
        Uri uri = MediaStore.Audio.Media.getContentUriForPath(ringtone.getAbsolutePath());
        contentResolver.insert(uri, values);
    }
}

@ReactMethod
public void setRingtone(String uri) {

}

@ReactMethod
public void pickRingtone() {

}

@Override
public Map<String, Object> getConstants() {
    final Map<String, Object> constants = new HashMap<>();
    constants.put(TYPE_ALARM_KEY, RingtoneManager.TYPE_ALARM);
    constants.put(TYPE_ALL_KEY, RingtoneManager.TYPE_ALL);
    constants.put(TYPE_NOTIFICATION_KEY, RingtoneManager.TYPE_NOTIFICATION);
    constants.put(TYPE_RINGTONE_KEY, RingtoneManager.TYPE_RINGTONE);
    return constants;
}

/**
 * Returns true when the given ringtone type matches the ringtone to compare.
 * Will default to true if the given ringtone type is RingtoneManager.TYPE_ALL.
 * 
 * @param ringtoneType          ringtone type given
 * @param ringtoneTypeToCompare ringtone type to compare to
 * @return true if the type matches or is TYPE_ALL
 */
private boolean isRingtoneType(int ringtoneType, int ringtoneTypeToCompare) {
    return ringtoneTypeToCompare == ringtoneType || RingtoneManager.TYPE_ALL == ringtoneType;
}
}

形成铃声

import React from 'react';
import { Text, Button, TouchableOpacity, FlatList, View, ScrollView, StyleSheet,   TouchableHighlight } from 'react-native';
import RingtoneManager from 'react-native-ringtone-manager';
import FontAwesome5 from 'react-native-vector-icons/FontAwesome5';
import Slider from 'react-native-slider';
import Sound from 'react-native-sound';
/*
Param   Type    Description
uri     String  The full file path to the ringtone on the file system.
title   String  The title of the ringtone. Will appear in the picker with this title.
artist  String  The artist of the ringtone.
size    Integer     The size of the ringtone file.
mimeType    String  The mime type of the ringtone, for example: audio/mp3
duration    Integer     The duration of the ringtone in seconds.
ringtoneType    RINGTONE_TYPE   The ringtone type: TYPE_ALL, TYPE_RINGTONE,   TYPE_NOTIFICATION, TYPE_ALARM
*/
class MyListItem extends React.PureComponent {
_onPress = () => {
this.props.onPressItem(this.props.datas);
};


render() {
console.log("this.props.uri " + this.props.uri + "this.props.selected " + this.props.selected)
const textColor = this.props.uri === this.props.selected ? 'black' : 'white';
const backgroundColor = this.props.uri === this.props.selected ? 'orange' : '#444444';

return (
  <TouchableOpacity onPress={this._onPress}>
    <View style={{
      backgroundColor: backgroundColor, borderRadius: 14, paddingHorizontal: 10, paddingVertical: 4,marginBottom:4, shadowColor: "#000",
      shadowOffset: {
        width: 0,
        height: 9,
      },
      shadowOpacity: 0.48,
      shadowRadius: 11.95,

      elevation: 18,
    }}>
      <Text style={{ fontSize: 16, color: textColor }}>{this.props.title}</Text>
      <Text style={{ fontSize: 16, color: textColor }}>{this.props.duration}    </Text>
    </View>
  </TouchableOpacity>
 );
 }
}

结果

请参阅我关于更新代码的媒体文章:

铃声管理器

代码不干净,我会在再次处理此问题时更新...

您可以在以下位置查看视频插图:

https://www.youtube.com/watch?v=72UF2ichH8I&feature=youtu.be

(我在网络上的第一个视频 :) )


推荐阅读