• 使用Cordova插件实现两个app之间的相互调用和通讯


    几年前使用Cordova 进行两个app之间的相互调用和通讯;当时也是几经折腾,今天把它整理出来,理一下思路,也方便有同样需求的朋友参考

    一、require引入 plugin

    
    require("cordova!com.lampa.startapp-master");
    
    

    这个插件下载 https://github.com/dengxiaoning/com.lampa.startapp
    (申明:该插件参考https://github.com/lampaa/com.lampa.startapp自己实现了ios的参数传递以及 downloadApps应用下载的功能)

    二、源文件分析

    首选来看看这个插件的实现

    plugin.xml

      <js-module src="www/startApp.js" name="startapp">
            <merges target="startApp" />
        </js-module>
    

    指定了js module 的路径和调用时的名称target="startApp"

        <!-- android -->
        <platform name="android">
            <config-file target="res/xml/config.xml" parent="/*">
                <feature name="startApp">
                    <param name="android-package" value="com.lampa.startapp.startApp"/>
                </feature>
            </config-file>
    
            <source-file src="src/android/startApp.java" target-dir="src/com/lampa/startapp" />
        </platform>
    
    
    	<platform name="ios">
    		<config-file target="config.xml" parent="/*">
    			<feature name="startApp">
    				<param name="ios-package" value="startApp"/>
    			</feature>
    		</config-file>
    		
    		<header-file src="src/ios/startApp.h"/>
    		<source-file src="src/ios/startApp.m"/>
    	</platform>
    

    指定插件源文件路径,根据不同平台,定义插件包名、将文件写入平台指定的路径下

    startApp.js

    var exec = require('cordova/exec');
    module.exports = {
    	set: function(params, extra) {
    		var output = [params];
    		if(extra != undefined) {
    			output.push(extra);
    		}
    		else {
    			output.push(null);
    		}
    		
    		return {
    			start: function(completeCallback, errorCallback) {
    				completeCallback = completeCallback || function() {};
    				errorCallback = errorCallback || function() {};
    				
    				exec(completeCallback, errorCallback, "startApp", "start", output);
    			},
    	},
    	/**
    	 * extra values
    	 */
    	getExtras: function(completeCallback, errorCallback) {
    		exec(completeCallback, errorCallback, "startApp", "getExtras", []);
    	},
    
    }
    

    该js 实现了使用Cordova 调用android 和 ios 原生接口然后返回参数,
    如:exec(completeCallback, errorCallback, "startApp", "start", output); 其中startApp指定调用的类名
    【ios是@interface startApp : CDVPlugin,android是public class startApp extends CordovaPlugin】;
    start指定调用该类的方法名;其他参数就是cordova 导出的成功、错误回调和携带返回数据。

    startApp.java(中增加方法)

    
    	/**
    	 * download application from market
    	 * */
    	public void downloadApps(JSONArray args, CallbackContext callback){
    		JSONObject params;
    		try {
    			if(args.get(0) instanceof JSONObject){
    				params = args.getJSONObject(0);
    				if(params.has("application")) {
    					Uri uri = Uri.parse("market://details?id="+params.getString("application")+""); 
    			        Intent it = new Intent(Intent.ACTION_VIEW, uri); 
    			        cordova.getActivity().startActivity(it);
    				}
    				if(params.has("downloadurl")){
    					cordova.getActivity().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(params.getString("downloadurl"))));
    				}
    			}
    		}
    		catch (JSONException e) {
    			callback.error("JSONException: " + e.getMessage());
    			e.printStackTrace();
    		}
    		catch (ActivityNotFoundException e) {
    			callback.error("ActivityNotFoundException: " + e.getMessage());
    			e.printStackTrace();
    		}
    	}
    	
    

    增加Android 根据路径下载apk的方法

    startApp.h(中增加方法)

    
    - (void)getExtras:(CDVInvokedUrlCommand*)command;
    - (void)downloadApps:(CDVInvokedUrlCommand*)command;
    - (void)exitApplication:(CDVInvokedUrlCommand*)command;
    
    

    增加ISO平台下 获取应用调用时传入的参数,在未安装时根据url下载应用

    startApp.m(中增加方法)

    
    - (void)getExtras:(CDVInvokedUrlCommand*)command{
    	 CDVPluginResult* pluginResult = nil;
    	// 从 url中获取保存的参数,将其返回给Cordova
    	 NSString *userurl = [[NSUserDefaults standardUserDefaults] objectForKey:@"url"];
    	if(userurl == nil || userurl == NULL){
    		 NSString *addResult = @"returnFalse";
    		 pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:addResult];
    		
    	}else{
    		pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:userurl];
    		[[NSUserDefaults standardUserDefaults] setObject:nil forKey:@"url"];
    	}
    	[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
    }
    
    -(void)downloadApps:(CDVInvokedUrlCommand*)command{
    	 CDVPluginResult* pluginResult = nil;
        
        NSString* scheme = [command.arguments objectAtIndex:0];
        
        if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:scheme]]) {
    		
    		[[UIApplication sharedApplication] openURL:[NSURL URLWithString:scheme]];
    
            pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsBool:(true)];
        }
        else {
            pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsBool:(false)];
        }
    
        [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
    }
    - (void)exitApplication:(CDVInvokedUrlCommand*)command {
    	exit(0);
    }
    
    

    三、配置应用Scheme

    3.1 使用xcode 手动配置

    首先将该ios文件导入xcode,点击.xcodeproj后缀的文件,xcode将会自动打开,再找到 LSApplicationQueriesScheme 为应用添加允许访问的app的白名单。 然后添加Scheme(只有这样另一个app在添加白名单时才知道写什么)。具体操作如下图

    找到info
    添加白名单
    配置应用Scheme
    配置Scheme
    注意这个配置Scheme是需要调用者app和被调用app都需要设置的

    同时配置ios访问设备的一些权限,否则无权限访问时应用会崩溃
    找到 你的项目名-info.plist 文件打开,在最后一个array标签下加入配置

    
    <!-- 相册 --> 
    <key>NSPhotoLibraryUsageDescription</key> 
    <string>App需要您的同意,才能访问相册</string> 
    <!-- 相机 --> 
    <key>NSCameraUsageDescription</key> 
    <string>App需要您的同意,才能访问相机</string> 
    <!-- 麦克风 --> 
    <key>NSMicrophoneUsageDescription</key> 
    <string>App需要您的同意,才能访问麦克风</string> 
    <!-- 位置 --> 
    <key>NSLocationUsageDescription</key> 
    <string>App需要您的同意,才能访问位置</string> 
    <!-- 在使用期间访问位置 --> 
    <key>NSLocationWhenInUseUsageDescription</key> 
    <string>App需要您的同意,才能在使用期间访问位置</string> 
    <!-- 始终访问位置 --> 
    <key>NSLocationAlwaysUsageDescription</key> 
    <string>App需要您的同意,才能始终访问位置</string> 
    <!-- 日历 --> 
    <key>NSCalendarsUsageDescription</key> 
    <string>App需要您的同意,才能访问日历</string> 
    <!-- 提醒事项 --> 
    <key>NSRemindersUsageDescription</key> 
    <string>App需要您的同意,才能访问提醒事项</string> 
    <!-- 运动与健身 --> 
    <key>NSMotionUsageDescription</key> <string>App需要您的同意,才能访问运动与健身</string> 
    <!-- 健康更新 --> 
    <key>NSHealthUpdateUsageDescription</key> 
    <string>App需要您的同意,才能访问健康更新 </string> 
    <!-- 健康分享 --> 
    <key>NSHealthShareUsageDescription</key> 
    <string>App需要您的同意,才能访问健康分享</string> 
    <!-- 蓝牙 --> 
    <key>NSBluetoothPeripheralUsageDescription</key> 
    <string>App需要您的同意,才能访问蓝牙</string> 
    <!-- 媒体资料库 --> 
    <key>NSAppleMusicUsageDescription</key> 
    <string>App需要您的同意,才能访问媒体资料库</string>
    
    

    操作截图

    找到 项目名-info.plist 文件
    添加配置

    3.2 使用plugin.xml自动配置

    自己写的一个配置ios 相关权限和Scheme的xml

    在这里插入图片描述
    创建如上类似文件夹考入即可:

    
    <?xml version="1.0" encoding="UTF-8"?>
     
    <plugin xmlns="http://apache.org/cordova/ns/plugins/1.0" 
    	xmlns:android="http://schemas.android.com/apk/res/android" 
    	id="cordova-plugin-plistconfig" version="5.3.0">
     
        <name>开启第三方应用</name>
        <description>新开启第三方应用相关配置</description>
        <license>MIT</license>
        <keywords>cordova,sina</keywords>
         
        <!--require cordova version -->
        <engines>
            <engine name="cordova" version=">=3.5.0" />
        </engines>
         
        <!-- ios -->
        <platform name="ios">
            <!-- 允许访问的应用的 Scheme白名单,如打包A应用;此处应写B应用的scheme,(假如 将A定义为 aapp B定义为bapp 配置如下)。  反之打包的是B应用下面的配置就要反过来写了 -->
            <config-file platform="ios" target="*-Info.plist" parent="LSApplicationQueriesSchemes">
                <array>
                    <string>bapp</string>
                </array>
            </config-file>
            <!-- 当前应用自己的 Scheme -->
            <config-file platform="ios" target="*-Info.plist" parent="CFBundleURLTypes">
                <array>
                	<dict>
                		<key>CFBundleTypeRole</key>
                		<string>Editor</string>
                	     <key>CFBundleURLSchemes</key>
                		<array>
                   			 <string>aapp</string>
                    	</array>
                    </dict>
                </array>
            </config-file>
            <!-- 配置相关权限 -->
            <config-file platform="ios" target="*-Info.plist" parent="NSAppleMusicUsageDescription">
    			<string>App需要您的同意,才能访问媒体资料库</string>
    		</config-file>  
    		<config-file platform="ios" target="*-Info.plist" parent="NSBluetoothPeripheralUsageDescription">
    			<string>App需要您的同意,才能访问蓝牙</string>
    		</config-file>  
    		<config-file platform="ios" target="*-Info.plist" parent="NSCalendarsUsageDescription">
    			<string>App需要您的同意,才能访问日历</string>
    		</config-file>  
    		<config-file platform="ios" target="*-Info.plist" parent="NSCameraUsageDescription">
    			<string>App需要您的同意,才能访问相机</string>
    		</config-file>  
    		<config-file platform="ios" target="*-Info.plist" parent="NSHealthShareUsageDescription">
    			<string>App需要您的同意,才能访问健康分享</string>
    		</config-file>  
    		<config-file platform="ios" target="*-Info.plist" parent="NSHealthUpdateUsageDescription">
    			<string>App需要您的同意,才能访问健康更新 </string>
    		</config-file>  
    		<config-file platform="ios" target="*-Info.plist" parent="NSLocationAlwaysUsageDescription">
    			<string>App需要您的同意,才能始终访问位置</string>
    		</config-file>  
    		<config-file platform="ios" target="*-Info.plist" parent="NSLocationUsageDescription">
    			<string>App需要您的同意,才能访问位置</string>
    		</config-file>  
    		<config-file platform="ios" target="*-Info.plist" parent="NSLocationWhenInUseUsageDescription">
    			<string>App需要您的同意,才能在使用期间访问位置</string>
    		</config-file>  
    		<config-file platform="ios" target="*-Info.plist" parent="NSMainNibFile">
    			<string></string>
    		</config-file>  
    		<config-file platform="ios" target="*-Info.plist" parent="NSMainNibFile~ipad">
    			<string></string>
    		</config-file>  
    		<config-file platform="ios" target="*-Info.plist" parent="NSMicrophoneUsageDescription">
    			<string>App需要您的同意,才能访问麦克风</string>
    		</config-file>  
    		<config-file platform="ios" target="*-Info.plist" parent="NSMotionUsageDescription">
    			<string>App需要您的同意,才能访问运动与健身</string>
    		</config-file>  
    		<config-file platform="ios" target="*-Info.plist" parent="NSPhotoLibraryUsageDescription">
    			<string>App需要您的同意,才能访问相册</string>
    		</config-file>  
    		<config-file platform="ios" target="*-Info.plist" parent="NSRemindersUsageDescription">
    			<string>App需要您的同意,才能访问提醒事项</string>
            </config-file>
        </platform>
    
    </plugin>
    

    3.4 在ios 的 AppDelegate.m中增后参数接收(这个是重点)

    
    // 在该方法中新增如下代码
    - (BOOL)application:(UIApplication*)application openURL:(NSURL*)url sourceApplication:(NSString*)sourceApplication annotation:(id)annotation{
    	 NSString *URLString= [url absoluteString]; 
    	
    	  [[NSUserDefaults standardUserDefaults] setObject:URLString forKey:@"url"];
    	
    	  [[NSUserDefaults standardUserDefaults] synchronize]; 
    }
     
    

    操作截图
    在这里插入图片描述

    四、js中调用

    4.1 android平台

    A应用调用B应用的方法

    invokeBapp(){
    	var sApp;
    	sApp = startApp.set({// 设置应用包名----注意修改----该包名对应【被叫application】
    		"application" : "com.myapplication.bapp"// 替换为你真实的包名
    		}, {//传递给B应用的参数
    			"username" : "lili"
    			"userId" : "123456"
    		});
    
    		/*
    		 * 监测应用是否安装
    		 */
    		cordova.plugins.fileOpener2.appIsInstalled(packageName, {
    			success : function(res) {
    				if (res.status === 0) {
    				     startApp.downloadApps({
    				"downloadurl":“https://192.168.1.18080/bapp/bapp.apk” //替换为你服务器真实的apk路径
    			},function(success){
    				console.log("success");
    			},function(error){
    				alert(error);
    			});
    				} else {
    					sApp.start(function(success) { // success
    						console.log("OK");
    					}, function(error) { // fail
    						alert(error);
    					});
    				}
    			}
    		});
    }
    

    4.2 iOS平台

    A应用调用B应用的方法

    invokeBapp(){
    	var sApp;
    	var sendParams = "username:lili;userId:123456"; //传递给B应用的参数(ios不能传递json对象)
    	var twitter = “bapp://; // B应用的Scheme(就是上面 第三 步配置的那个  再加上冒号和双斜杠就ok了)
    	sApp = startApp.set(twitter + sendParams + "");
    		/* 监测是否安装应用 */
    		sApp.check(function(values) {
    			sApp.start(function(success) { // success
    			}, function(error) { // fail
    				alert(error);
    			});
    		}, function(error) {
    		   startApp.downloadApps({
    				"downloadurl":"itms-services:///?action=download-manifest&url=https://192.168.1.1:8080/bapp/dependence.plist" //替换为你服务器真实的plis路径(这里使用的是plist进行ipa下载,如果你已经发布到AppStore那就直接写AppStore下载路径了)
    		});
    }
    
    

    4.3 B应用接收参数

    
    receiveAappParams(){
    	startApp.getExtras(function(res){
    		
    		// to do something...
    		console.log(res);
    	});
    }
    
    

    五、配置 plist文件

    由于没u有上传到商店,ipa无法在ios应用中下载,所有使用plis进行ipa映射,然后调用Safari进行下载安装

    
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
    	<key>items</key>
    	<array>
    		<dict>
    			<key>assets</key>
    			<array>
    				<dict>
    					<key>kind</key>
    					<string>software-package</string>
    					<key>url</key>
    					<!-- ipa位于服务器的真实路径 -->
    					<string>https://192.168.1.1:8080/bapp/bapp.ipa</string>
    				</dict>
    				<dict>
    					<key>kind</key>
    					<string>full-size-image</string>
    					<key>needs-shine</key>
    					<true/>
    					<key>url</key>
    					<!-- app下载时显示的图标 -->
    					<string>https://192.168.1.1:8080/bapp/icon.png</string>
    				</dict>
    				<dict>
    					<key>kind</key>
    					<string>display-image</string>
    					<key>needs-shine</key>
    					<true/>
    					<key>url</key>
    					<!-- app下载时显示的图标 -->
    					<string>https://192.168.1.1:8080/bapp/icon.png</string>
    				</dict>
    			</array>
    			<key>metadata</key>
    			<dict>
    				<key>bundle-identifier</key>
    				<!-- app包名 -->
    				<string>com.myapplication.bapp</string>
    				<key>bundle-version</key>
    				<!-- app当前版本 -->
    				<string>1.0.0</string>
    				<key>kind</key>
    				<string>software</string>
    				<key>title</key>
    				<!-- app名称 -->
    				<string>客户咨询平台</string>
    			</dict>
    		</dict>
    	</array>
    </dict>
    </plist>
    
    

    ok到这里就结束了,写得不对 的地方请指正,有更好的方法请分享

  • 相关阅读:
    JavaScript原型链详解
    Js作用域与闭包
    tjs 在嵌套函数中this关键字引用head对象
    NodeJS stream 一:Buffer
    NodeJS Stream 二:什么是 Stream
    NodeJS Stream 三:readable
    NodeJS Stream 四:Writable
    VSS又一次出错了,神出鬼没的
    VS2005的关于母版页嵌套的一个小技巧
    【转】SQL Server数据库开发的二十一条军规
  • 原文地址:https://www.cnblogs.com/dengxiaoning/p/11681255.html
Copyright © 2020-2023  润新知