首页 文章 精选 留言 我的

精选列表

搜索[物理交互],共10000篇文章
优秀的个人博客,低调大师

Cordova插件中JavaScript代码与Java的交互细节介绍

在Cordova官网中有这么一张架构图:大家看右下角蓝色的矩形框"Custom Plugin"——自定义插件。意思就是如果您用Cordova打包Mobile应用时,发现您的移动应用里需要使用一些功能,这些功能用普通的JavaScript无法实现,而是需要调用移动平台的一些原生API才能实现时,我们就需要自己实现自定义插件。这些插件通过在特定的移动平台上采用原生开发实现,比如Android Studio中的Java开发,然后再通过JavaScript wrapper的方式暴露给您的Mobile应用。比如您是用Cordova在Android平台上打包生成APK文件,那么您的Mobile代码(JavaScript)里还是不会直接调用您用Java实现的Custom Plugin,而是调用Custom Plugin对应的JavaScript wrapper。 那么JavaScript wrapper本身是JavaScript代码,它是怎么调用到Custom Plugin的Java实现的?本文就会介绍这个细节。 下图是OData离线存储插件(OData Offline Store)的JavaScript实现代码的一部分。下图第232行会调用设备的native API进行离线存储的打开操作: exec(win, error, 'OData', 'openOfflineStore', [this, options ? options : {}]); 这个exec函数从哪里来?由Cordova框架实现,通过语句 require(‘cordova/exec’)返回。 那么当应用执行到JavaScript代码:exec(win, error, 'OData', 'openOfflineStore', [this, options ? options : {}]); 的时候,程序流是如何从这个JavaScript的exec函数进入到Android平台的原生API执行呢? 打开PackagedApp文件夹里的android子文件夹,有一个JavaScript文件:cordova.js: 里面能看到函数exec的定义和实现: 进而去查看androidExec函数的实现细节: 第938行:var msgs = nativeApiProvider.get().exec(bridgeSecret, service, action, callbackId, argsJson); 第943行的五个参数含义: success, fail, service, action, args success & fail: JavaScript回调函数,当移动平台上的Java原生API执行完毕后,这个JavaScript回调函数会被调用到。 service: 待执行的Java Native API的Java实现类名称。 action: 待执行的Java Native API的Java实现类的方法名称。 args: JavaScript传递给Java native API的参数数组。 2. 在安卓平台上,JavaScript调用Java的技术实现方式有两种:定义在下图JavaScript代码中的jsToNativeModes对象中:PROMPT和JS_OBJECT。相对应的,Java调用JavaScript有三种模式:POLLING, LOAD_URL和ONLINE_EVENT: 看下面这段Java代码,暴露了一个方法getSomeString给JavaScript端消费: import android.app.Activity; import android.os.Bundle; import android.webkit.WebView; public class WebViewGUI extends Activity { WebView mWebView; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mWebView = new WebView(this); mWebView.getSettings().setJavaScriptEnabled(true); mWebView.addJavascriptInterface(new JavaScriptInterface(), "jsinterface"); mWebView.loadUrl("file:///android_asset/www/index.html"); setContentView(mWebView); } final class JavaScriptInterface { JavaScriptInterface() { } public String getSomeString() { return "string"; } } } 在JavaScript代码里消费上述Java代码暴露的getSomeString方法: <script> var String = window.jsinterface.getSomeString(); </script> 我们再回过头来看看AndroidExec的实现: var msgs = nativeApiProvider.get().exec(bridgeSecret, service, action, callbackId, argsJson); 在AndroidExec的实现里, nativeApiProvider的get方法返回一个实例,然后执行exec方法。而881行代码说明nativeApiProvider的实现位于文件夹cordova/android下面的nativeapiprovider.js里: 打开nativeapiprovider.js,在第21行的注释里我们得到了重要信息: currentApi要么来自Java文件ExposedJsApi.java,要么来自PromptBasedNativeApi.java。 Java文件ExposedJsApi.java可以在这个文件夹内找到: platform/android/CordovaLib/src/org/apache/cordova ExposedJsApi实际就是个Java interface,上面声明了一个exec方法: JavaScript到Java的执行通过prompt调用完成: Java类SystemExposedJsApi实现了这个interface,再将执行流转交给类CordovaBridge的实例. CordovaBridge再调用PluginManager: PluginManager首先根据名字找到负责处理该请求的Java plugin的实现类,再调用该实现类的方法: 以OData离线存储的实现类为例,我们在其实现代码里能发现有大量的IF-ELSE分支,每个分支处理不同的离线存储操作请求。 要获取更多Jerry的原创技术文章,请关注公众号"汪子熙"或者扫描下面二维码:

优秀的个人博客,低调大师

Android--okhttp与php交互,文件上传下载

版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/chaoyu168/article/details/77880320 okhttp配置: okhttp的下载地址:http://square.github.io/okhttp/ okio的下载地址:https://github.com/square/okio 两个jar包导入到工程中,放在libs目录下,右键点击jar包,选择Add As Library就行了,两个包都要添加。 import java.io.FileOutputStream; import java.io.IOException; import android.Manifest; import android.app.Activity; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.net.Uri; import android.os.Build; import android.os.Environment; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.concurrent.TimeUnit; import okhttp3.Call; import okhttp3.Callback; import okhttp3.Interceptor; import okhttp3.MediaType; import okhttp3.MultipartBody; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; import okhttp3.ResponseBody; import okio.Buffer; import okio.BufferedSink; import okio.BufferedSource; import okio.ForwardingSink; import okio.ForwardingSource; import okio.Okio; import okio.Sink; import okio.Source; public class MainActivity extends AppCompatActivity { private OkHttpClient okHttpClient; private TextView textView; private File tempFile; private File targetFile; private String path; private Button button1; private Button button2; private Button button3; private Button button4; //private long time; private static final int REQUEST_EXTERNAL_STORAGE = 1; private static final int FILE_SELECT_CODE = 1; private static String[] PERMISSIONS_STORAGE = { Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setTitle("上传文件并显示进度"); //verifyStoragePermissions(MainActivity.this); textView = (TextView) findViewById(R.id.tv1); button1 = (Button) findViewById(R.id.btn_choose); button2 = (Button) findViewById(R.id.btn_upload); button3 = (Button) findViewById(R.id.btn_download); button4 = (Button) findViewById(R.id.btn_display); path = ""; okHttpClient = new OkHttpClient.Builder() .readTimeout(60, TimeUnit.SECONDS) .connectTimeout(10, TimeUnit.SECONDS) .writeTimeout(120, TimeUnit.SECONDS) .build(); button1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { showFileChooser(); } }); button2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startUploadClick(); } }); button3.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startDownloadClick(); } }); button4.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(MainActivity.this,DisplayActivity.class); startActivity(intent); } }); } //打开文件选择器 private void showFileChooser() { Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType("*/*"); intent.addCategory(Intent.CATEGORY_OPENABLE); try { startActivityForResult( Intent.createChooser(intent, "Select a File to Upload"), FILE_SELECT_CODE); } catch (android.content.ActivityNotFoundException ex) { Toast.makeText(this, "Please install a File Manager.", Toast.LENGTH_SHORT).show(); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case FILE_SELECT_CODE: if (resultCode == RESULT_OK) { // Get the Uri of the selected file Uri uri = data.getData(); path = FileUtils.getPath(this, uri); } break; } super.onActivityResult(requestCode, resultCode, data); } public String getFileName(String pathandname){ int start=pathandname.lastIndexOf("/"); //int end=pathandname.lastIndexOf(""); if(start!=-1 ){ return pathandname.substring(start+1); }else{ return null; } } //点击按钮开始上传文件 public void startUploadClick() { //tempFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "test1.txt"); //showFileChooser(); String fileName = ""; tempFile = new File(path); //tempFile = new File("/data/data/upload/man.jpg"); if (tempFile.getName() == null){ Toast.makeText(MainActivity.this, "找不到该文件!", Toast.LENGTH_SHORT).show(); } else { fileName = getFileName(path); } RequestBody requestBody = new MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart("file", fileName, RequestBody.create(MediaType.parse("image/jpg"), tempFile)) .build(); //ProgressRequestBody progressRequestBody = new ProgressRequestBody(requestBody, progressListener); Request request = new Request.Builder() .url("http://xxx.xxx.xxx.xx/receive_file.php") .post(requestBody) .build(); //上面url中的内容请改成自己php文件的所在地址 okHttpClient.newCall(request).enqueue(callback_upload); } //点击按钮开始下载文件 public void startDownloadClick() { targetFile = new File("/data/data/com.example.ywy.mycloud1/cache/" + "test1.jpg"); Request request = new Request.Builder() .url("http://xxx.xxx.xxx.xx/downloads/woman.jpg") .build(); okHttpClient.newCall(request).enqueue(callback_download); //上面url中的内容请改成自己想要下载的文件的所在地址 } //上传请求后的回调方法 private Callback callback_upload = new Callback() { @Override public void onFailure(Call call, IOException e) { setResult(e.getMessage(), false); } @Override public void onResponse(Call call, Response response) throws IOException { setResult(response.body().string(), true); } }; private Callback callback_download = new Callback() { @Override public void onFailure(Call call, IOException e) { setResult(e.getMessage(),false); } @Override public void onResponse(Call call, Response response) throws IOException { if(response != null) { //下载完成,保存数据到文件 //verifyStoragePermissions(MainActivity.this); InputStream is = response.body().byteStream(); FileOutputStream fos = new FileOutputStream(targetFile); byte[] buf = new byte[1024]; int hasRead = 0; while((hasRead = is.read(buf)) > 0) { fos.write(buf, 0, hasRead); } fos.close(); is.close(); setResult("下载成功", true); } } }; //显示请求返回的结果 private void setResult(final String msg, final boolean success) { runOnUiThread(new Runnable() { @Override public void run() { if (success) { Toast.makeText(MainActivity.this, "请求成功", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(MainActivity.this, "请求失败", Toast.LENGTH_SHORT).show(); } textView.setText(msg); } }); } } import android.content.Context; import android.database.Cursor; import android.net.Uri; /** * Created by YWY on 2016/11/9. */ public class FileUtils { public static String getPath(Context context, Uri uri) { if ("content".equalsIgnoreCase(uri.getScheme())) { String[] projection = { "_data" }; Cursor cursor = null; try { cursor = context.getContentResolver().query(uri, projection,null, null, null); int column_index = cursor.getColumnIndexOrThrow("_data"); if (cursor.moveToFirst()) { return cursor.getString(column_index); } } catch (Exception e) { // Eat it } } else if ("file".equalsIgnoreCase(uri.getScheme())) { return uri.getPath(); } return null; } } import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.ImageView; public class DisplayActivity extends AppCompatActivity { private ImageView imageView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_display); imageView = (ImageView)findViewById(R.id.iv); Bitmap bitmap = BitmapFactory.decodeFile("/data/data/com.example.ywy.mycloud1/cache/test1.jpg"); imageView.setImageBitmap(bitmap); } } 权限: <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> PHP: <?php $base_path = "./text/"; //存放目录 if(!is_dir($base_path)){ mkdir($base_path,0777,true); } $target_path = $base_path . basename ( $_FILES ['file'] ['name'] ); if (move_uploaded_file ( $_FILES ['file'] ['tmp_name'], $target_path )) { $array = array ( "status" => true, "msg" => $_FILES ['file'] ['name'] ); echo json_encode ( $array ); } else { $array = array ( "status" => false, "msg" => "There was an error uploading the file, please try again!" . $_FILES ['file'] ['error'] ); echo json_encode ( $array ); } ?>

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册