位置: 编程技术 - 正文

Unity3d接入googleplay内购详细说明(二)(unity快速接入第三方sdk)

发布时间:2024-02-27

推荐整理分享Unity3d接入googleplay内购详细说明(二)(unity快速接入第三方sdk),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:unity3d接入云渲染,unity chrome,unity3d接入云渲染,unity接入google内购,unity3d接入抖音广告api,unity3d接入云渲染,unity3d接入抖音广告api,unity3d接入 asr,内容如对您有帮助,希望把文章链接给更多的朋友!

因为本文内容比较多,整理花费时间比较长,故分几篇完成,以下为本文目录结构,方便查阅:

Unity3d接入googleplay内购详细说明(一)

引言

一、准备条件:

二、谷歌开发者后台应用创建说明:

Unity3d接入googleplay内购详细说明(二)

三、Unity3d向安卓通信以及接受通信

四、Unity导出安卓Apk正式签名说明

五、使用Eclipse运行unity导出的工程

六、Java代码接入谷歌内购:

七、谷歌内购Java代码

Unity3d接入googleplay内购详细说明(三)

八、Apk上传谷歌商店测试版以及添加测试者

九、Zipalign处理APK文件

十、添加google&#;群组并邀请其成为测试者

十一、测试机googleplay安装以及配置:

Unity3d接入googleplay内购详细说明(四)

十二、真机测试中出现的常见错误以及解决方式:

十三、成功测试购买以及正式版发布

————————————————————————————————————————————————————————————

三、Unity3d向安卓通信以及接受通信

1、作为测试的是临时写的unity3ddemo,只具有最基本的支付功能。首先解决unity安卓通信,这个基本上都是固定的代码。

例子里面分别添加了2种有效商品,后台中sku分别为jb_1,lb_1;

2、其中主要就几句代码,基本通用,需要改的仅是“Pay”方法,以及注意传入的string参数(用来区分不同sku):

private void UnityToAndroid(string buykey)

{

AndroidJavaClass m_unityPlayer = newAndroidJavaClass("com.unity3d.player.UnityPlayer");

AndroidJavaObject m_curActivity = m_unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");

m_curActivity.Call("Pay",buykey);

}

3、所有代码如下:

using UnityEngine;

usingSystem.Collections;

public classGUIpay : MonoBehaviour

{

private int i = 0;

private int j = 0;

private string key;//suk

private string MessageFromAndroid;//从安卓端接受的消息

void OnGUI(){

if(GUILayout.Button("金币1",GUILayout.Height(),GUILayout.Width())){

i&#;&#;;

key="jb_1";

UnityToAndroid(key);

}

if(GUILayout.Button("&#;包1",GUILayout.Height(),GUILayout.Width())){

j&#;&#;;

key ="lb_1";

UnityToAndroid(key);

}

GUILayout.Button("购买:"&#;key&#;"分别:"&#;i.ToString()&#;"次/"&#;j.ToString()&#;"次",GUILayout.Height(),GUILayout.Width());

GUILayout.Button("AndroidMessage:"&#;MessageFromAndroid,GUILayout.Height(),GUILayout.Width());

}

//安卓支付通信

private void UnityToAndroid(stringbuykey){

AndroidJavaClass m_unityPlayer =new AndroidJavaClass("com.unity3d.player.UnityPlayer");

AndroidJavaObject m_curActivity =m_unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");

if(m_curActivity == null)

{

Debug.LogError("获得不到JAVA对象");

return;

}

m_curActivity.Call("Pay",buykey);

}

//从安卓端接受消息,因为本脚本挂在一直存在的MainCamera对象上,将从其上获取消息,对应java代码要将消息发送对象指定为MainCamera

void Messgae(string message)

{

MessageFromAndroid = message;

}

}

4、运行效果如下,点击会报错,所以只能在真机上测试:

5、接下来,打开设置,勾选导出安卓工程,icon,应用名字,起始页等如果仅做测试可以不必正式。就是说如果不是正式发布的apk,仅需要正式的包名,正式的签名,正式发布记得修改其他icon、起始页等信息:

6、上传到谷歌商店需要正式的签名,不能为debug模式签名,否则上传失败。签名制作方式如下:

四、Unity导出安卓Apk正式签名说明

一、签名的意义

为了保证每个应用程序开发商合法ID,防止部分开放商可能通过使用相同的Package Name来混淆替换已经安装的程序,我们需要对我们发布的APK文件进行唯一签名,保证我们每次发布的版本的一致性(如自动更新不会因为版本不一致而无法安装)。

这里详细解释一下:

安装包apk的名字,在世界范围内,有众多开发者,很可能命名重复,当命名重复的时候就需要有一个唯一的识别符加以区分。这就是安卓中的签名。这个签名不用向谷歌申请,而是自己在本机签名即可。

这个签名唯一,相当重要,务必保管好,是制作后续版本更新的重要依据。如果更换,即使是同一个应用,也不会覆盖安装,而是单独当做另外一个新的应用安装。而且当你提交应用时,如果更换签名,就不会当成之前应用的后续更新版本。

二、.签名的步骤(仅安卓需要签名)

一般来说,安卓的apk安装包都是由eclipse编译而成,而他自带了签名插件。包括正式签名和dubug测试签名。

而我们这里并不用eclipse,而是利用unity自带签名功能。  

1、工程确认无bug后,需要倒出apk文件时:

2、打开导出设置选项:

3、这publishing settings下面默认是debug签名,如果仅仅自己测试,就不需要修改,上传谷歌商店,需要制作签名。

4、选择 create new keystore,下面选择保存位置,

5、点击key

6、填写详细签名信息,务必记住密码,因为在eclipes里面要使用。存储到可靠位置,丢失后无法找回:

7、证书如下,命令行工具能打开,需要安装jdk:

验证签名信息:

命令行输入 jarsigner -verify -verbose -certs XXX.apk(apk 完整路径) 可以看到 比对签名信息(需要安装了jdk)

8、签名栏默认是unsigned,不签名,debug模式

以后再次导出apk时,必须先选中该签名,还需要在编译前输入原始密码

9、如果为debug签名,那么在上传到谷歌应用商店时会遇到这样情况:

、签名正确即可正确上传

、当然也可以利用eclipes来签名,具体请百度。接下来我们要在eclipes里面接入谷歌内购api:

五、使用Eclipse运行unity导出的工程

1、打开eclipes,创建工作空间。

2、新建安卓工程:

3、填写跟unity一样的包名,其他默认即可,下一步·····下一步

5、这是刚创建的空工程

6、接下来将unity导出的工程,里面的文件夹直接拖动到hnn工程下,选择全部覆盖,我们的工程内容将被替换为unity内容:

7、为了试验一下是否能够在真机上运行,可以编译一下工程:

8、找到编译出来的apk安装到真机上测试,能够启动即可,按钮什么的当然现在还没有作用:

六、Java代码接入谷歌内购:

以下是开发者中心对内购的详细解释,英文文档,可以谷歌翻译一下。链接地址:

In-appBilling Overview

PreparingYour In-app Billing Application

1、首先我们需要下载内购sdk。在eclipes里面可以下载到,目前因为禁止链接外网,下载时可能需要vpn,内购demo文件并不大。

这个是他的官方demo,介绍了如何在安卓工程中接入内购,这就是为什么我们选择unity导出安卓工程,而不选择eclipes打jar文件,放到unity中编译apk:

我们需要的就是:IInAppBillingService.aidl这个文件。

2、将该文件拖入到我们的工程src目录下、路径请自己设定好。

3、此外还需要加入必备的工具类。

也就是util文件夹下面的所有代码。同样拖动到我们的工程目录下,拖进来后可能会报引入路径错,注意修改成符合你自己工程的正常路径。例如我的工程导入完毕后结构大约如此。

从上至下依次为内购必须文件、unity自带类、内购工具类。文件目录结构:

4、AndroidMainfest文件添加权限,如果你还做了其他接入功能,例如分享等,权限做合并。

<uses-permission android:name="com.android.vending.BILLING"/>

5、接着我们在java代码中写入被unity调用以及向unity回传消息的代码。

前文说道:

6、向uinty中发送消息,一般用来传送是否购买成功等等。

7、Unity中接受内容继续做处理:

8、内购方面,需要写入base ras公共密钥。就是前文说的再谷歌开发者后台申请的key

9、再写入sku,这个sku就是内购项目的唯一id,可以从unity中传过来,也可以写在java中,我们这里做传入。

、其他添加内购时的各种监听,是否登录,是否符合测试条件,是否绑定银行卡等等,主要借鉴其demo中的代码。

七、谷歌内购Java代码

以下为unity导出的默认类中所有代码:

packagecom.taojinzhe.hnn;

importcom.unity3d.player.*;

importandroid.app.NativeActivity;

importandroid.content.res.Configuration;

importandroid.graphics.PixelFormat;

importandroid.os.Bundle;

importandroid.view.KeyEvent;

import android.view.MotionEvent;

importandroid.view.View;

importandroid.view.Window;

importandroid.view.WindowManager;

importandroid.app.Activity;

importandroid.app.AlertDialog;

importandroid.content.Intent;

importandroid.content.SharedPreferences;

import android.util.Log;

importandroid.widget.ImageView;

importandroid.widget.Toast;

importcom.util.IabHelper;

importcom.util.IabResult;

importcom.util.Inventory;

importcom.util.Purchase;

public classUnityPlayerNativeActivity extends NativeActivity

{

protected UnityPlayer mUnityPlayer; // don't change the name of thisvariable; referenced from native code

//___________________________________________________________

//The helper object

IabHelper mHelper;

// Debug tag, for logging

static final String TAG ="hongneinei";

// Does the user have the premium upgrade?

boolean mIsPremium = false;

// Does the user have an activesubscription to the infinite gas plan?

boolean mSubscribedToInfiniteGas = false;

// SKUs for our products: the premiumupgrade (non-consumable) and gas (consumable)

static String SKU_consume ="";

static String SKU_noconsume ="";

//static final String SKU_GAS="";

//SKU for our subscription (infinite gas)

//static final String SKU_INFINITE_GAS ="infinite_gas";

// (arbitrary) request code for the purchaseflow

static final int RC_REQUEST = ;

//___________________________________________________________

// Setup activity layout

@Override protected void onCreate (BundlesavedInstanceState)

{

requestWindowFeature(Window.FEATURE_NO_TITLE);

super.onCreate(savedInstanceState);

getWindow().takeSurface(null);

setTheme(android.R.style.Theme_NoTitleBar_Fullscreen);

getWindow().setFormat(PixelFormat.RGB_);

mUnityPlayer = newUnityPlayer(this);

if (mUnityPlayer.getSettings().getBoolean ("hide_status_bar", true))

getWindow ().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,

WindowManager.LayoutParams.FLAG_FULLSCREEN);

setContentView(mUnityPlayer);

mUnityPlayer.requestFocus();

//___________________________________________________________

/* baseEncodedPublicKey should be YOURAPPLICATION'S PUBLIC KEY

* (that you got from the Google Playdeveloper console). This is not your

* developer public key, it's the*app-specific* public key.

*

* Instead of just storing the entireliteral string here embedded in the

* program, construct the key at runtime from pieces or

* use bit manipulation (for example,XOR with some other string) to hide

* the actual key. The key itself is not secret information, butwe don't

Unity3d接入googleplay内购详细说明(二)(unity快速接入第三方sdk)

* want to make it easy for an attackerto replace the public key with one

* of their own and then fake messagesfrom the server.

*/

String baseEncodedPublicKey ="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtBVdoRrdD/oCWHYgzhT4TBIh0AZn0Sf1uXD8gWQ1H9LdpOB4MX4QG9RP9pBbS0e6W8f7EbjKyicEa6LetTxpg1Gf&#;3N0L0c9E2G3RwIO9SXaRUNfzjHN2lzaspLQKj5&#;SLpT8JD6ISVuro7OS4nxmi7xQT0lx/dPOAOs8mQ/1qmlgwsJRybqWQ&#;hAvu1fchMggTTAyG1RyqKTJNErlNYTvog7ZQjjvCZXW5aDBnGeEjFoILnt5XAoaUpuObmbkoCOkJeSiUTQqD&#;mqAQCvXnBhUso2klLDlOhTz0FUT7XKZOU1Q&#;lXqNlJ6GurXzhFguvhdo&#;3DQIDAQAB";

// Create the helper, passing it our contextand the public key to verify signatures with

Log.d(TAG, "Creating IABhelper.");

mHelper = new IabHelper(this,baseEncodedPublicKey);

// enable debug logging (for aproduction application, you should set this to false).

mHelper.enableDebugLogging(true);

// Start setup. This is asynchronousand the specified listener

// will be called once setup completes.

Log.d(TAG, "Startingsetup.");

mHelper.startSetup(newIabHelper.OnIabSetupFinishedListener() {

public voidonIabSetupFinished(IabResult result) {

Log.d(TAG, "Setupfinished.");

if (!result.isSuccess()) {

// Oh noes, there was a problem.

complain("Problemsetting up in-app billing: " &#; result);

return;

}

// Have we been disposed of inthe meantime? If so, quit.

if (mHelper == null) return;

// IAB is fully set up. Now, let'sget an inventory of stuff we own.

Log.d(TAG, "Setupsuccessful. Querying inventory.");

mHelper.queryInventoryAsync(mGotInventoryListener);

}

});

//___________________________________________________________

}

//___________________________________________________________

protected void Pay(final String buykey)

{

/* TODO: for security, generate your payloadhere for verification. See the comments on

* verifyDeveloperPayload() for more info.Since this is a SAMPLE, we just use

* an empty string, but on a productionapp you should carefully generate this. */

if(buykey.contains("jb_"))

{

SKU_consume = buykey;

}

if(buykey.contains("lb_"))

{

SKU_noconsume = buykey;

}

runOnUiThread(new Runnable()

{

public void run()

{

Toast.makeText(getApplicationContext(),buykey,Toast.LENGTH_SHORT).show();

SendToUnityMessage(buykey);

}

});

String payload = "";

mHelper.launchPurchaseFlow(this,buykey, RC_REQUEST,

mPurchaseFinishedListener,payload);

}

//Listener that's called when we finish querying the items and subscriptions weown 购买侦听器完成

IabHelper.OnIabPurchaseFinishedListenermPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener(){

public void onIabPurchaseFinished(IabResult result, Purchase purchase){

Log.d(TAG, "Purchase finished: " &#; result &#; ", purchase:" &#; purchase);

if (result.isFailure()) {

//complain("Error purchasing: " &#;result);

//setWaitScreen(false);

return;

}

if (!verifyDeveloperPayload(purchase)) {

complain("Error purchasing.Authenticity verification failed.");

// setWaitScreen(false);

return;

}

Log.d(TAG, "Purchase successful.");

if (purchase.getSku().equals(SKU_consume)) {

Log.d(TAG, "Purchase is gas.Starting gas consumption.");

mHelper.consumeAsync(purchase,mConsumeFinishedListener);

}

else if (purchase.getSku().equals(SKU_noconsume)) {

Log.d(TAG, "Purchase ispremium upgrade. Congratulating user.");

alert("Thank you forupgrading to premium!");

mIsPremium = true;

}

}

};

// Listener that's called when we finishquerying the items and subscriptions we own

IabHelper.QueryInventoryFinishedListener mGotInventoryListener = newIabHelper.QueryInventoryFinishedListener() {

public void onQueryInventoryFinished(IabResult result, Inventoryinventory) {

Log.d(TAG, "Query inventoryfinished.");

// Have we been disposed of in themeantime? If so, quit.

if (mHelper == null) return;

// Is it a failure?

if (result.isFailure()) {

complain("Failed to queryinventory: " &#; result);

return;

}

Log.d(TAG, "Query inventorywas successful.");

/*

* Check for items we own. Noticethat for each purchase, we check

* the developer payload to see ifit's correct! See

* verifyDeveloperPayload().

*/

// Do we have the premium upgrade?

Purchase premiumPurchase =inventory.getPurchase(SKU_noconsume);

mIsPremium = (premiumPurchase !=null && verifyDeveloperPayload(premiumPurchase));

Log.d(TAG, "User is " &#;(mIsPremium ? "PREMIUM" : "NOT PREMIUM"));

// Check for gas delivery -- if weown gas, we should fill up the tank immediately

Purchase gasPurchase =inventory.getPurchase(SKU_consume);

if (gasPurchase != null &&verifyDeveloperPayload(gasPurchase)) {

Log.d(TAG, "We have gas.Consuming it.");

mHelper.consumeAsync(inventory.getPurchase(SKU_consume),mConsumeFinishedListener);

return;

}

Log.d(TAG, "Initial inventoryquery finished; enabling main UI.");

}

};

//Called when consumption is complete

IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = newIabHelper.OnConsumeFinishedListener() {

public voidonConsumeFinished(Purchase purchase, IabResult result) {

Log.d(TAG, "Consumptionfinished. Purchase: " &#; purchase &#; ", result: " &#; result);

// if we were disposed of in themeantime, quit.

if (mHelper == null) return;

// We know this is the"gas" sku because it's the only one we consume,

// so we don't check which sku wasconsumed. If you have more than one

// sku, you probably shouldcheck...

if (result.isSuccess()) {

// successfully consumed, so weapply the effects of the item in our

// game world's logic, which inour case means filling the gas tank a bit

Log.d(TAG, "Consumptionsuccessful. Provisioning.");

}

else {

complain("Error whileconsuming: " &#; result);

}

Log.d(TAG, "End consumptionflow.");

}

};

/** Verifies the developer payload of apurchase. */

boolean verifyDeveloperPayload(Purchase p){

String payload =p.getDeveloperPayload();

/*

* TODO: verify that the developerpayload of the purchase is correct. It will be

* the same one that you sent wheninitiating the purchase.

*

* WARNING: Locally generating a randomstring when starting a purchase and

* verifying it here might seem like agood approach, but this will fail in the

* case where the user purchases anitem on one device and then uses your app on

* a different device, because on theother device you will not have access to the

* random string you originallygenerated.

*

* So a good developer payload hasthese characteristics:

*

* 1. If two different users purchasean item, the payload is different between them,

* so that one user's purchase can't be replayed to another user.

*

* 2. The payload must be such that youcan verify it even when the app wasn't the

* one who initiated the purchase flow (so that items purchased by the useron

* one device work on other devices owned by the user).

*

* Using your own server to store andverify developer payloads across app

* installations is recommended.

*/

return true;

}

void complain(String message) {

Log.e(TAG, "**** TrivialDrive Error: " &#; message);

alert("Error: " &#; message);

}

void alert(String message) {

AlertDialog.Builder bld = new AlertDialog.Builder(this);

bld.setMessage(message);

bld.setNeutralButton("OK", null);

Log.d(TAG, "Showing alert dialog: " &#; message);

bld.create().show();

}

//___________________________________________________________

//向unity发送消息

void SendToUnityMessage(String Sendmessage)

{

UnityPlayer.UnitySendMessage("MainCamera","Messgae",Sendmessage);

}

// Quit Unity

@Override protected void onDestroy ()

{

mUnityPlayer.quit();

super.onDestroy();

}

// Pause Unity

@Override protected void onPause()

{

super.onPause();

mUnityPlayer.pause();

}

// Resume Unity

@Override protected void onResume()

{

super.onResume();

mUnityPlayer.resume();

}

// This ensures the layout will becorrect.

@Override public voidonConfigurationChanged(Configuration newConfig)

{

super.onConfigurationChanged(newConfig);

mUnityPlayer.configurationChanged(newConfig);

}

// Notify Unity of the focus change.

@Override public voidonWindowFocusChanged(boolean hasFocus)

{

super.onWindowFocusChanged(hasFocus);

mUnityPlayer.windowFocusChanged(hasFocus);

}

// For some reason the multiple keyeventtype is not supported by the ndk.

// Force event injection by overridingdispatchKeyEvent().

@Override public booleandispatchKeyEvent(KeyEvent event)

{

if (event.getAction() ==KeyEvent.ACTION_MULTIPLE)

return mUnityPlayer.injectEvent(event);

returnsuper.dispatchKeyEvent(event);

}

// Pass any events not handled by(unfocused) views straight to UnityPlayer

@Override public boolean onKeyUp(intkeyCode, KeyEvent event) { returnmUnityPlayer.injectEvent(event); }

@Override public boolean onKeyDown(intkeyCode, KeyEvent event) { returnmUnityPlayer.injectEvent(event); }

@Override public booleanonTouchEvent(MotionEvent event) { return mUnityPlayer.injectEvent(event); }

/*API*/ public boolean onGenericMotionEvent(MotionEventevent) { returnmUnityPlayer.injectEvent(event); }

}

本片结语:

至此,unity,eclipes代码部分基本上完结,接下来我们将编译出apk进行测试。

Unity3d接入googleplay内购详细说明(三) 因为本文内容比较多,整理花费时间比较长,故分几篇完成,以下为本文目录结构,方便查阅:Unity3d接入googleplay内购详细说明(一)引言一、准备条件

Unity3D Vuforia Android 拨打电话 ?xmlversion=1.0encoding=utf-8?manifestxmlns:android=

Unity3D中的Prefab使用方法 Prefabs(预设)是最常用的一种资源类型,是一种可被重复使用的游戏对象。1、特点:1、它可以被置入多个场景中,也可以在一个场景中多次置入。2、当

标签: unity快速接入第三方sdk

本文链接地址:https://www.jiuchutong.com/biancheng/382560.html 转载请保留说明!

上一篇:Unity3d接入googleplay内购详细说明(一)(unity3d接入抖音广告api)

下一篇:Unity3d接入googleplay内购详细说明(三)(unity接入google内购)

  • 符合条件的小型微利企业所得税税率为
  • 公司支付的房租押金怎么入账
  • 存货核算的内容是什么
  • 处置资产开啥发票
  • 建筑业企业生产经营情况表
  • 非货币性资产交换准则
  • 生产企业的安全员好干吗
  • 子公司向母公司借款
  • 买空调交税是谁交税
  • 被合并企业评估什么意思
  • 普通发票需要做分录吗?
  • 税控盘清盘怎么做
  • 代购本无罪,逃避关税须处罚
  • 全国失信人员信息
  • 信息服务业税收优惠政策
  • 残保金退回属于政府补助吗
  • 免征增值税项目销售额含税吗
  • 出口信用证议付支出是什么
  • 食堂购买蔬菜计算公式
  • 工资薪金与劳务报酬的区别有哪些
  • 稽查补交的税款怎么处理
  • linux系统如何更改主机名
  • win11测试版后续怎么变正式版
  • w11怎么创建快捷方式
  • 账务处理程序有什么
  • 企业备用金预借多久到账
  • 原始凭证必须具备的基本要素
  • 外购货物应抵扣的进项税额
  • 基建期土地摊销
  • 商贸企业税收优惠政策
  • 承包租赁
  • 小刺猬 (© lorenzo104/Getty Images)
  • php实战
  • 实缴资本多久可以取出随便用吗
  • elementui的upload组件详解
  • centos php7.4
  • 前端跨域解决方案设计
  • 法院判定支付对方诉讼费,我可以入账吗
  • 全连接神经网络是什么意思
  • win11预览版22000.51
  • php计时函数
  • stp 命令
  • 公司搞研发是什么意思
  • 酒的增值税专票可抵扣不
  • 广告费支出税前扣除标准30
  • 个人退税证明怎么开具
  • 购买黄金会计分录怎么写
  • 人力资源投资收益
  • 3步搞定纯真ip数量
  • sqlserver存储过程声明变量
  • 什么是企业会计确认计量和报告的空间范围
  • 注册资本认缴出资日期是什么意思
  • 银行利息支出税率是多少
  • 餐厅打包盒收费标准通知
  • 小规模纳税人购买税控设备
  • 企业购买国债逆回购怎么操作
  • 旅客运送的一般规定
  • 公司控股的子公司 法人能被追加吗
  • 预付款项为什么属于资产
  • 预收账款账务处理流程图
  • 保险公司理赔款如何入账
  • 物流运输公司的运营盈利模式
  • 各单位都需设置的是
  • mysql安装不成功怎么办
  • mysql join实现原理
  • my sql命令
  • vs显示进程已退出
  • 怎么修复windows update
  • 微软今天正式停产了吗
  • win7更新和安全在哪里
  • winxp如何设置文件共享
  • windows网络诊断在哪
  • JavaScript中的NaN代表什么
  • unity3d需要什么语言
  • 物理引擎演示
  • 上海网上纳税申报流程
  • 柳州 税务
  • 浙江省税务师事务所排名
  • 回迁房办房产证需要交多少钱
  • 税收收入弹性值
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号