Skip to content

Commit

Permalink
开启RecordApp Native支持,功能未完成
Browse files Browse the repository at this point in the history
  • Loading branch information
xiangyuecn committed Aug 14, 2019
1 parent 43c3288 commit 4a661cc
Show file tree
Hide file tree
Showing 40 changed files with 1,178 additions and 432 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# :open_book:Recorder用于html5录音

[在线测试](https://xiangyuecn.github.io/Recorder/),支持大部分已实现`getUserMedia`的移动端、PC端浏览器;主要包括:Chrome、Firefox、Safari、Android WebView、腾讯Android X5内核(QQ、微信);不支持:UC系内核(典型的支付宝,大部分国产手机厂商的浏览器)。快捷方式: [查看caniuse浏览器支持情况](https://caniuse.com/#search=getUserMedia) , [【工具】裸(RAW、WAV)PCM转WAV播放测试和转码](https://xiangyuecn.github.io/Recorder/assets/%E5%B7%A5%E5%85%B7-%E8%A3%B8PCM%E8%BD%ACWAV%E6%92%AD%E6%94%BE%E6%B5%8B%E8%AF%95.html)
[在线测试](https://xiangyuecn.github.io/Recorder/),支持大部分已实现`getUserMedia`的移动端、PC端浏览器;主要包括:Chrome、Firefox、Safari、Android WebView、腾讯Android X5内核(QQ、微信);不支持:UC系内核(典型的支付宝,大部分国产手机厂商的浏览器)。快捷方式: [RecordApp测试](https://jiebian.life/web/h5/github/recordapp.aspx)[Android App Demo](https://github.com/xiangyuecn/Recorder/tree/master/app-support-sample/demo_android)[IOS App Demo](https://github.com/xiangyuecn/Recorder/tree/master/app-support-sample/demo_ios)[查看caniuse浏览器支持情况](https://caniuse.com/#search=getUserMedia) , [【工具】裸(RAW、WAV)PCM转WAV播放测试和转码](https://xiangyuecn.github.io/Recorder/assets/%E5%B7%A5%E5%85%B7-%E8%A3%B8PCM%E8%BD%ACWAV%E6%92%AD%E6%94%BE%E6%B5%8B%E8%AF%95.html)

录音默认输出mp3格式,另外可选wav格式(raw pcm format此格式录音文件超大);有限支持ogg(beta)、webm(beta)、amr(beta)格式;支持任意格式扩展(前提有相应编码器)。

Expand Down Expand Up @@ -450,7 +450,7 @@ public void onPermissionRequest(PermissionRequest request) {
如果不出意外,App内显示的网页就能正常录音了。

### 附带测试项目
`assets/android_test`目录中提供了Android测试源码(如果不想自己打包可以用打包好的apk来测试,位于`assets/android_test/app-debug-xxx.apk`)。提供了`系统自带WebView`、和`腾讯X5内核`两个测试界面
[app-support-sample/demo_android](https://github.com/xiangyuecn/Recorder/tree/master/app-support-sample/demo_android)目录中提供了Android测试源码(如果不想自己打包可以用打包好的apk来测试,文件名为`app-debug-xxx.apk.zip`,自行去掉.zip后缀)



Expand Down
1 change: 1 addition & 0 deletions app-support-sample/demo_android/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
待编写
Binary file added app-support-sample/demo_android/app-debug.apk.zip
Binary file not shown.
16 changes: 16 additions & 0 deletions app-support-sample/demo_android/app/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
apply plugin: 'com.android.application'

android {
compileSdkVersion 28
defaultConfig {
applicationId "com.github.xianyuecn.recorder"
minSdkVersion 15
targetSdkVersion 28
versionCode 1
versionName "1.0"
}
}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
}
35 changes: 35 additions & 0 deletions app-support-sample/demo_android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.github.xianyuecn.recorder">

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>

<application
android:icon="@drawable/icon"
android:label="Recorder Demo"
android:allowBackup="true"
android:supportsRtl="true"
android:networkSecurityConfig="@xml/network_security_config"
android:theme="@style/AppTheme">

<meta-data android:name="android.max_aspect" android:value="9.9"/>

<activity android:name=".MainActivity"
android:launchMode="singleTask"
android:configChanges="screenLayout|screenSize|keyboardHidden|orientation"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />

<action android:name="android.intent.action.VIEW" />
</intent-filter>
</activity>

</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
package com.github.xianyuecn.recorder;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.webkit.ConsoleMessage;
import android.webkit.PermissionRequest;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceRequest;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.EditText;
import android.widget.Toast;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class MainActivity extends Activity {
static private final String LogTag="MainActivity";

private WebView webView;
private EditText logs;
private RecordAppJsBridge jsBridge;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);


webView = findViewById(R.id.main_webview);
logs=findViewById(R.id.main_logs);
logs.append("日志输出已开启");

//******调用核心方法*********************
//注入JsBridge, 实现api接口,简单demo无视4.2以下版本
jsBridge=new RecordAppJsBridge(this, webView, permissionReq, Log);
//*******以下内容无关紧要*****************

//设置基本信息,如开启js、storage、权限处理
initWebSet();
}



//权限处理 小功能就不用我的Android-UsesPermission库了,手撸一个简洁版的
private RecordAppJsBridge.UsesPermission permissionReq= new RecordAppJsBridge.UsesPermission() {
@Override
public void Request(String[] keys, final Runnable True, final Runnable False) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
PermissionCall=new Runnable() {
@Override
public void run() {
if(HasPermission) {
True.run();
}else{
//无权限
False.run();
}
}
};
MainActivity.this.requestPermissions(keys, ReqCode);
}else{
//无需授权
True.run();
}
}
};

private RecordAppJsBridge.ILog Log=new RecordAppJsBridge.ILog() {
@Override
public void i(String tag, String msg) {
android.util.Log.i(tag, msg);

logs.append("\n\n["+time()+"][i]["+tag+"]"+msg);
}

@Override
public void e(String tag, String msg) {
android.util.Log.e(tag, msg);

logs.append("\n\n["+time()+"][e]["+tag+"]"+msg);
}

private String time(){
SimpleDateFormat formatter=new SimpleDateFormat ("HH:mm:ss", Locale.CHINA);
return formatter.format(new Date());
}
};



@Override
protected void onDestroy() {
jsBridge.close();

super.onDestroy();
}




/**
* WebView基本信息设置
*/
@SuppressLint("SetJavaScriptEnabled")
private void initWebSet(){
WebSettings set=webView.getSettings();
set.setJavaScriptEnabled(true);
set.setDefaultTextEncodingName("utf-8");
set.setDomStorageEnabled(true);

File cacheDir=getExternalCacheDir();
File fileDir=getExternalFilesDir(null);
if(cacheDir==null){
cacheDir=getCacheDir();
}
if(fileDir==null){
fileDir=getFilesDir();
}
set.setAppCacheEnabled(true);
set.setAppCachePath(cacheDir.getAbsolutePath());
set.setDatabaseEnabled(true);
set.setDatabasePath(fileDir.getAbsolutePath());
set.setGeolocationEnabled(true);
set.setGeolocationDatabasePath(fileDir.getAbsolutePath());


if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
set.setMediaPlaybackRequiresUserGesture(false);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
set.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}

webView.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if(url.startsWith("http")){
return false;
}
return super.shouldOverrideUrlLoading(view, url);
}
});

//网页权限请求处理
webView.setWebChromeClient(new WebChrome());

webView.setBackgroundColor(0xffff6600);

String url="https://xiangyuecn.github.io/Recorder/app-support-sample/";
webView.loadUrl(url);
Log.i(LogTag, "打开页面:"+url);
}










/**
* 录音权限处理
*/
public class WebChrome extends WebChromeClient{
@Override
public void onPermissionRequest(final PermissionRequest request) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
String key="";
final String[] types=request.getResources();
for(String s:types) {
if (PermissionRequest.RESOURCE_AUDIO_CAPTURE.equals(s)) {
key="android.permission.RECORD_AUDIO";
}
}

if(key.length()==0){
request.deny();
return;
}

permissionReq.Request(new String[]{key}, new Runnable() {
@Override
public void run() {
request.grant(types);
}
}, new Runnable() {
@Override
public void run() {
request.deny();
}
});
}
}

@Override
public boolean onConsoleMessage(ConsoleMessage msg) {
String str=msg.sourceId()+":"+msg.lineNumber()+"\n"+msg.message();
switch (msg.messageLevel()){
case ERROR:
Log.e("Console", str);
break;
default:
Log.i("Console", str);
}

return super.onConsoleMessage(msg);
}
}
private Runnable PermissionCall;
private boolean HasPermission;

static private final int ReqCode=123;
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);

if(requestCode==ReqCode && PermissionCall!=null) {
StringBuilder noGrant=new StringBuilder();
for(int i=0; i<permissions.length;i++){
String item=permissions[i];
if(grantResults[i]!= PackageManager.PERMISSION_GRANTED){
if(noGrant.length()>0)noGrant.append(",");
noGrant.append(item);
}
}

HasPermission=noGrant.length()==0;
if(!HasPermission){
Toast.makeText(MainActivity.this, "请给app权限:"+noGrant, Toast.LENGTH_LONG).show();
}
PermissionCall.run();
PermissionCall=null;
}
}
}
Loading

0 comments on commit 4a661cc

Please sign in to comment.