Run task when app enter background.

本文介绍如何在iOS应用中设置VoIP后台模式,确保应用程序在后台时仍能接收到来电通知。主要内容包括在Info.plist文件中添加UIBackgroundModes键,并将其值设置为包含voip字符串的数组;此外还提供了applicationDidEnterBackground方法的具体实现代码。

1. Add the UIBackgroundModes key to your application’s Info.plist file. Set the value of this key to an array that includes the voip string.


2.

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    /*
     Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
     If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
     */
    
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 40000    
    if([[UIDevice currentDevice] respondsToSelector:@selector(isMultitaskingSupported)] && [[UIDevice currentDevice] isMultitaskingSupported])
    {
        NSLog(@"Keep timeout alive");            
        
        [application setKeepAliveTimeout:600 handler: ^{
            NSLog(@"applicationDidEnterBackground:: setKeepAliveTimeout:handler^");//task as you want to do
        }];
    }
    
#else
    LogInfo(@"applicationDidEnterBackground (Not supported)");
#endif
    
}


package com.st.launcher.adapter; import static org.junit.Assert.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.powermock.api.mockito.PowerMockito.mockStatic; import android.content.ComponentName; import android.content.Context; import android.content.pm.LauncherActivityInfo; import android.graphics.drawable.Drawable; import android.view.LayoutInflater; import android.view.View; import android.widget.ImageView; import android.widget.TextView; import androidx.databinding.DataBindingUtil; import com.st.launcher.R; import com.st.launcher.databinding.AppListItemBinding; import com.st.base.util.ImageUtils; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import org.robolectric.RuntimeEnvironment; import java.util.ArrayList; import java.util.List; @RunWith(PowerMockRunner.class) @PrepareForTest({DataBindingUtil.class, ImageUtils.class}) public class AppListAdapterRobolectricTest { private Context context; private AppListAdapter adapter; private List<LauncherActivityInfo> appInfoList; @Mock private Drawable mockDrawable; @Before public void setUp() { MockitoAnnotations.openMocks(this); context = RuntimeEnvironment.getApplication(); // 模拟 ImageUtils.getCropDrawable 的行为 Drawable dummyDrawable = mock(Drawable.class); when(dummyDrawable.getIntrinsicWidth()).thenReturn(100); when(dummyDrawable.getIntrinsicHeight()).thenReturn(100); // 使用 PowerMock 或直接使用 Mockito 模拟静态方法 mockStatic(ImageUtils.class); when(ImageUtils.getCropDrawable(any(Drawable.class), anyInt(), anyInt(), anyInt(), any(Context.class))) .thenReturn(dummyDrawable); // 初始化数据 appInfoList = new ArrayList<>(); for (int i = 0; i < 3; i++) { LauncherActivityInfo info = mock(LauncherActivityInfo.class); ComponentName componentName = mock(ComponentName.class); when(info.getComponentName()).thenReturn(componentName); when(componentName.getClassName()).thenReturn("com.example.App" + i); when(info.getLabel()).thenReturn("App" + i); when(info.getIcon(0)).thenReturn(mockDrawable); appInfoList.add(info); } adapter = new AppListAdapter(context, appInfoList); } @Test public void testOnBindViewHolder_setsUpCorrectData() { mockStatic(DataBindingUtil.class); // // 创建 ViewHolder // AppListItemBinding binding = DataBindingUtil.inflate( // LayoutInflater.from(context), // R.layout.app_list_item, // null, // false // ); LayoutInflater inflater = LayoutInflater.from(context); View view = inflater.inflate(R.layout.app_list_item, null, false); AppListItemBinding binding = AppListItemBinding.bind(view); AppListAdapter.ViewHolder viewHolder = new AppListAdapter.ViewHolder(binding); // 调用 onBindViewHolder adapter.onBindViewHolder(viewHolder, 1); // position = 1 // 验证 TextView 设置了正确的文本 TextView appNameTextView = viewHolder.itemView.findViewById(R.id.app_list_item_name); assertNotNull(appNameTextView); assertEquals("App1", appNameTextView.getText().toString()); // 验证 ImageView 设置了图片(非空) ImageView imageView = viewHolder.itemView.findViewById(R.id.app_list_item_im); assertNotNull(imageView.getDrawable()); } @Test public void testOnBindViewHolder_clickStartsActivity() { mockStatic(DataBindingUtil.class); // 创建 ViewHolder AppListItemBinding binding = DataBindingUtil.inflate( LayoutInflater.from(context), R.layout.app_list_item, null, false ); AppListAdapter.ViewHolder viewHolder = new AppListAdapter.ViewHolder(binding); // 调用 onBindViewHolder adapter.onBindViewHolder(viewHolder, 0); // 触发点击事件 viewHolder.itemView.findViewById(R.id.cl_root).performClick(); } } package com.st.launcher.adapter; import android.annotation.SuppressLint; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.LauncherActivityInfo; import android.graphics.drawable.Drawable; import android.util.Log; import android.util.TypedValue; import android.view.LayoutInflater; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.recyclerview.widget.RecyclerView; import com.st.base.util.ImageUtils; import com.st.launcher.R; import com.st.launcher.databinding.AppListItemBinding; import java.util.List; public class AppListAdapter extends RecyclerView.Adapter<AppListAdapter.ViewHolder> { private static final String TAG = "AppListAdapter"; private Context mContext; private List<LauncherActivityInfo> mLauncherAppList; private boolean isBootComplete = false; private float mSizeScale = 1.0f; public AppListAdapter(Context context, List<LauncherActivityInfo> appInfoList) { mLauncherAppList = appInfoList; mContext = context; } public void setLauncherAppList(List<LauncherActivityInfo> mLauncherAppList) { if (!mLauncherAppList.isEmpty()) this.mLauncherAppList = mLauncherAppList; Log.i(TAG, "setLauncherAppList: " + this.mLauncherAppList.size()); } public List<LauncherActivityInfo> getLauncherAppList() { return mLauncherAppList; } public void setLocalAppInfo(List<LauncherActivityInfo> mLauncherLocalAppList) { if (!mLauncherLocalAppList.isEmpty()) mLauncherAppList = mLauncherLocalAppList; notifyDataSetChanged(); } public void setBootComplete(boolean isBootComplete) { this.isBootComplete = isBootComplete; } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { return new ViewHolder(AppListItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)); } @SuppressLint("ClickableViewAccessibility") @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { holder.itemIm.setBackground(null); holder.itemView.setFocusable(true); holder.itemView.setFocusableInTouchMode(true); holder.itemTv.setTextColor(0); holder.itemTv.setTextColor(mContext.getResources().getColor(R.color.app_name, null)); Log.i(TAG, "onBindViewHolder: position = " + position + ", Label = " + mLauncherAppList.get(position).getLabel()); holder.itemTv.setText(mLauncherAppList.get(position).getLabel().toString()); holder.itemTv.setTextSize(TypedValue.COMPLEX_UNIT_PX, 32 * mSizeScale); Drawable drawable = mLauncherAppList.get(position).getIcon(0); holder.itemIm.setImageDrawable(ImageUtils.getCropDrawable(drawable, 148, 148, 36, mContext)); ComponentName componentName = null; componentName = mLauncherAppList.get(position).getComponentName(); Log.i(TAG, "onClick: componentName=" + componentName.getClassName() + ";.getLabel()=" + mLauncherAppList.get(position).getLabel().toString()); holder.itemView.findViewById(R.id.cl_root).setOnClickListener(view -> { new Thread(() -> { ComponentName componentName1; componentName1 = mLauncherAppList.get(position).getComponentName(); Log.i(TAG, "onClick: componentName" + componentName1.getClassName()); Intent intent = new Intent(Intent.ACTION_MAIN); intent.setComponent(componentName1); intent.putExtra("source", "home"); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { Log.d(TAG, "onclick: enter :" + componentName1); mContext.startActivity(intent); } catch (Throwable e) { Log.d(TAG, "exception occurred" + e); } }).start(); }); } @Override public int getItemCount() { return mLauncherAppList.size(); } public void setTextSize(float sizeScale) { this.mSizeScale = sizeScale; notifyDataSetChanged(); } static class ViewHolder extends RecyclerView.ViewHolder { private ConstraintLayout itemRoot; private ImageView itemIm; private TextView itemTv; public ViewHolder(@NonNull AppListItemBinding binding) { super(binding.getRoot()); // View itemView = binding.getRoot(); itemIm = binding.appListItemIm; itemRoot = binding.clRoot; itemTv = binding.appListItemName; // itemView.setTag(R.id.focus_type, AbsFocusEffectView.FocusType.FOCUS_NORMAL); // itemView.setTag(R.id.focus_type_is_scale_anim, false); // itemView.setTag(R.id.focus_type_is_translate, false); } } } 重新修改,我不希望涉及到 xml文件操作,不能重构代码且没有Android 环境,只能使用 jvm环境进行测试
08-05
package com.st.launcher.adapter; import android.annotation.SuppressLint; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.LauncherActivityInfo; import android.graphics.drawable.Drawable; import android.util.Log; import android.util.TypedValue; import android.view.LayoutInflater; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.recyclerview.widget.RecyclerView; import com.st.base.util.ImageUtils; import com.st.launcher.R; import com.st.launcher.databinding.AppListItemBinding; import java.util.List; public class AppListAdapter extends RecyclerView.Adapter<AppListAdapter.ViewHolder> { private static final String TAG = "AppListAdapter"; private Context mContext; private List<LauncherActivityInfo> mLauncherAppList; private boolean isBootComplete = false; private float mSizeScale = 1.0f; public AppListAdapter(Context context, List<LauncherActivityInfo> appInfoList) { mLauncherAppList = appInfoList; mContext = context; } public void setLauncherAppList(List<LauncherActivityInfo> mLauncherAppList) { if (!mLauncherAppList.isEmpty()) this.mLauncherAppList = mLauncherAppList; Log.i(TAG, "setLauncherAppList: " + this.mLauncherAppList.size()); } public List<LauncherActivityInfo> getLauncherAppList() { return mLauncherAppList; } public void setLocalAppInfo(List<LauncherActivityInfo> mLauncherLocalAppList) { if (!mLauncherLocalAppList.isEmpty()) mLauncherAppList = mLauncherLocalAppList; notifyDataSetChanged(); } public void setBootComplete(boolean isBootComplete) { this.isBootComplete = isBootComplete; } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { return new ViewHolder(AppListItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)); } @SuppressLint("ClickableViewAccessibility") @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { holder.itemIm.setBackground(null); holder.itemView.setFocusable(true); holder.itemView.setFocusableInTouchMode(true); holder.itemTv.setTextColor(0); holder.itemTv.setTextColor(mContext.getResources().getColor(R.color.app_name, null)); Log.i(TAG, "onBindViewHolder: position = " + position + ", Label = " + mLauncherAppList.get(position).getLabel()); holder.itemTv.setText(mLauncherAppList.get(position).getLabel().toString()); holder.itemTv.setTextSize(TypedValue.COMPLEX_UNIT_PX, 32 * mSizeScale); Drawable drawable = mLauncherAppList.get(position).getIcon(0); holder.itemIm.setImageDrawable(ImageUtils.getCropDrawable(drawable, 148, 148, 36, mContext)); ComponentName componentName = null; componentName = mLauncherAppList.get(position).getComponentName(); Log.i(TAG, "onClick: componentName=" + componentName.getClassName() + ";.getLabel()=" + mLauncherAppList.get(position).getLabel().toString()); holder.itemView.findViewById(R.id.cl_root).setOnClickListener(view -> { new Thread(() -> { ComponentName componentName1; componentName1 = mLauncherAppList.get(position).getComponentName(); Log.i(TAG, "onClick: componentName" + componentName1.getClassName()); Intent intent = new Intent(Intent.ACTION_MAIN); intent.setComponent(componentName1); intent.putExtra("source", "home"); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { Log.d(TAG, "onclick: enter :" + componentName1); mContext.startActivity(intent); } catch (Throwable e) { Log.d(TAG, "exception occurred" + e); } }).start(); }); } @Override public int getItemCount() { return mLauncherAppList.size(); } public void setTextSize(float sizeScale) { this.mSizeScale = sizeScale; notifyDataSetChanged(); } static class ViewHolder extends RecyclerView.ViewHolder { private ConstraintLayout itemRoot; private ImageView itemIm; private TextView itemTv; public ViewHolder(@NonNull AppListItemBinding binding) { super(binding.getRoot()); // View itemView = binding.getRoot(); itemIm = binding.appListItemIm; itemRoot = binding.clRoot; itemTv = binding.appListItemName; // itemView.setTag(R.id.focus_type, AbsFocusEffectView.FocusType.FOCUS_NORMAL); // itemView.setTag(R.id.focus_type_is_scale_anim, false); // itemView.setTag(R.id.focus_type_is_translate, false); } } } 生成单元测试但不能使用Android环境测试,可以使用PowerMock和mockito和robolectric
08-05
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值